semantic_logger 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/semantic_logger.rb +6 -13
- data/lib/semantic_logger/ansi_colors.rb +10 -10
- data/lib/semantic_logger/appender.rb +42 -26
- data/lib/semantic_logger/appender/async.rb +179 -0
- data/lib/semantic_logger/appender/async_batch.rb +95 -0
- data/lib/semantic_logger/appender/bugsnag.rb +2 -1
- data/lib/semantic_logger/appender/elasticsearch.rb +113 -81
- data/lib/semantic_logger/appender/elasticsearch_http.rb +1 -3
- data/lib/semantic_logger/appender/file.rb +1 -3
- data/lib/semantic_logger/appender/graylog.rb +6 -5
- data/lib/semantic_logger/appender/honeybadger.rb +0 -2
- data/lib/semantic_logger/appender/http.rb +25 -10
- data/lib/semantic_logger/appender/kafka.rb +1 -3
- data/lib/semantic_logger/appender/mongodb.rb +1 -3
- data/lib/semantic_logger/appender/new_relic.rb +7 -3
- data/lib/semantic_logger/appender/sentry.rb +6 -7
- data/lib/semantic_logger/appender/splunk.rb +1 -2
- data/lib/semantic_logger/appender/splunk_http.rb +3 -4
- data/lib/semantic_logger/appender/syslog.rb +1 -3
- data/lib/semantic_logger/appender/tcp.rb +7 -9
- data/lib/semantic_logger/appender/udp.rb +0 -2
- data/lib/semantic_logger/appender/wrapper.rb +0 -2
- data/lib/semantic_logger/base.rb +76 -19
- data/lib/semantic_logger/formatters.rb +37 -0
- data/lib/semantic_logger/formatters/base.rb +10 -3
- data/lib/semantic_logger/formatters/json.rb +2 -6
- data/lib/semantic_logger/formatters/one_line.rb +18 -0
- data/lib/semantic_logger/formatters/raw.rb +8 -2
- data/lib/semantic_logger/formatters/signalfx.rb +169 -0
- data/lib/semantic_logger/log.rb +23 -14
- data/lib/semantic_logger/loggable.rb +88 -15
- data/lib/semantic_logger/logger.rb +0 -20
- data/lib/semantic_logger/metric/new_relic.rb +75 -0
- data/lib/semantic_logger/metric/signalfx.rb +123 -0
- data/lib/semantic_logger/{metrics → metric}/statsd.rb +20 -8
- data/lib/semantic_logger/processor.rb +67 -169
- data/lib/semantic_logger/semantic_logger.rb +7 -31
- data/lib/semantic_logger/subscriber.rb +32 -36
- data/lib/semantic_logger/utils.rb +47 -0
- data/lib/semantic_logger/version.rb +1 -1
- data/test/appender/async_batch_test.rb +61 -0
- data/test/appender/async_test.rb +45 -0
- data/test/appender/elasticsearch_http_test.rb +3 -3
- data/test/appender/elasticsearch_test.rb +211 -49
- data/test/appender/file_test.rb +9 -8
- data/test/appender/mongodb_test.rb +3 -3
- data/test/appender/newrelic_rpm.rb +6 -0
- data/test/appender/sentry_test.rb +3 -1
- data/test/appender/wrapper_test.rb +29 -0
- data/test/concerns/compatibility_test.rb +64 -60
- data/test/debug_as_trace_logger_test.rb +62 -77
- data/test/formatters/one_line_test.rb +61 -0
- data/test/formatters/signalfx_test.rb +200 -0
- data/test/formatters_test.rb +36 -0
- data/test/in_memory_appender.rb +9 -0
- data/test/in_memory_appender_helper.rb +43 -0
- data/test/in_memory_batch_appender.rb +9 -0
- data/test/in_memory_metrics_appender.rb +14 -0
- data/test/loggable_test.rb +15 -30
- data/test/logger_test.rb +181 -135
- data/test/measure_test.rb +212 -113
- data/test/metric/new_relic_test.rb +36 -0
- data/test/metric/signalfx_test.rb +78 -0
- data/test/semantic_logger_test.rb +58 -65
- data/test/test_helper.rb +19 -2
- metadata +33 -7
- data/lib/semantic_logger/metrics/new_relic.rb +0 -30
- data/lib/semantic_logger/metrics/udp.rb +0 -80
- data/test/mock_logger.rb +0 -29
@@ -0,0 +1,200 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module SemanticLogger
|
5
|
+
module Formatters
|
6
|
+
class SignalfxTest < Minitest::Test
|
7
|
+
describe SemanticLogger::Formatters::Signalfx do
|
8
|
+
let :average_metric_name do
|
9
|
+
'Application.average'
|
10
|
+
end
|
11
|
+
|
12
|
+
let :counter_metric_name do
|
13
|
+
'Application.counter'
|
14
|
+
end
|
15
|
+
|
16
|
+
let :log do
|
17
|
+
metric = '/user/login'
|
18
|
+
log = SemanticLogger::Log.new('User', :debug)
|
19
|
+
log.metric = metric
|
20
|
+
log
|
21
|
+
end
|
22
|
+
|
23
|
+
let :logs do
|
24
|
+
3.times.collect do |i|
|
25
|
+
l = log.dup
|
26
|
+
l.metric = "/user/login#{i+1}"
|
27
|
+
l
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
let :same_logs do
|
32
|
+
3.times.collect do |i|
|
33
|
+
l = log.dup
|
34
|
+
l.metric = "/user/login"
|
35
|
+
l
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
let :dimensions do
|
40
|
+
{action: 'hit', user: 'jbloggs', state: 'FL'}
|
41
|
+
end
|
42
|
+
|
43
|
+
let :all_dimensions do
|
44
|
+
dims = dimensions.merge(
|
45
|
+
host: SemanticLogger.host,
|
46
|
+
application: SemanticLogger.application,
|
47
|
+
environment: 'test'
|
48
|
+
)
|
49
|
+
string_keys = {}
|
50
|
+
dims.each_pair { |k, v| string_keys[k.to_s] = v }
|
51
|
+
string_keys
|
52
|
+
end
|
53
|
+
|
54
|
+
let :appender do
|
55
|
+
Net::HTTP.stub_any_instance(:start, true) do
|
56
|
+
SemanticLogger::Metric::Signalfx.new(token: 'TEST')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
let :formatter do
|
61
|
+
appender.formatter
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'format single log' do
|
65
|
+
let :result do
|
66
|
+
JSON.parse(formatter.call(log, appender))
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'send counter metric when there is no duration' do
|
70
|
+
hash = result
|
71
|
+
assert counters = hash['counter'], hash
|
72
|
+
assert counter = counters.first, hash
|
73
|
+
assert_equal counter_metric_name, counter['metric'], counter
|
74
|
+
assert_equal 1, counter['value'], counter
|
75
|
+
assert_equal (log.time.to_i * 1_000).to_i, counter['timestamp'], counter
|
76
|
+
assert counter.has_key?('dimensions')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'send gauge metric when log includes duration' do
|
80
|
+
log.duration = 1234
|
81
|
+
hash = result
|
82
|
+
assert counters = hash['gauge'], hash
|
83
|
+
assert counter = counters.first, hash
|
84
|
+
assert_equal average_metric_name, counter['metric'], counter
|
85
|
+
assert_equal 1234, counter['value'], counter
|
86
|
+
assert_equal (log.time.to_i * 1_000).to_i, counter['timestamp'], counter
|
87
|
+
assert counter.has_key?('dimensions')
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'also sends counter metric when gauge metric is sent' do
|
91
|
+
log.duration = 1234
|
92
|
+
hash = result
|
93
|
+
assert counters = hash['counter'], hash
|
94
|
+
assert counter = counters.first, hash
|
95
|
+
assert_equal counter_metric_name, counter['metric'], counter
|
96
|
+
assert_equal 1, counter['value'], counter
|
97
|
+
assert_equal (log.time.to_i * 1_000).to_i, counter['timestamp'], counter
|
98
|
+
assert counter.has_key?('dimensions')
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'only forwards whitelisted dimensions from named_tags' do
|
102
|
+
log.named_tags = {user_id: 47, tracking_number: 7474, session_id: 'hsdhngsd'}
|
103
|
+
formatter.dimensions = [:user_id, :application]
|
104
|
+
hash = result
|
105
|
+
assert counters = hash['counter'], hash
|
106
|
+
assert counter = counters.first, hash
|
107
|
+
assert_equal({'class' => 'user', 'action' => 'login', 'environment' => 'test', 'user_id' => '47', 'host' => SemanticLogger.host, 'application' => SemanticLogger.application}, counter['dimensions'], counter)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'raises exception with both a whitelist and blacklist' do
|
111
|
+
assert_raises ArgumentError do
|
112
|
+
SemanticLogger::Formatters::Signalfx.new(token: 'TEST', dimensions: [:user_id], exclude_dimensions: [:tracking_number])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'send custom counter metric when there is no duration' do
|
117
|
+
log.metric = 'Filter/count'
|
118
|
+
log.dimensions = dimensions
|
119
|
+
hash = result
|
120
|
+
|
121
|
+
assert counters = hash['counter'], hash
|
122
|
+
assert counter = counters.first, hash
|
123
|
+
assert_equal 'Filter.count', counter['metric'], counter
|
124
|
+
assert_equal 1, counter['value'], counter
|
125
|
+
assert_equal (log.time.to_i * 1_000).to_i, counter['timestamp'], counter
|
126
|
+
assert_equal all_dimensions, counter['dimensions']
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'format batch logs' do
|
131
|
+
let :result do
|
132
|
+
JSON.parse(formatter.batch(logs, appender))
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'send metrics' do
|
136
|
+
hash = result
|
137
|
+
|
138
|
+
assert counters = hash['counter'], hash
|
139
|
+
assert_equal 3, counters.size
|
140
|
+
assert_equal counter_metric_name, counters[0]['metric']
|
141
|
+
assert_equal 1, counters[0]['value']
|
142
|
+
assert_equal counter_metric_name, counters[1]['metric']
|
143
|
+
assert_equal counter_metric_name, counters[2]['metric']
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'sends gauge metrics' do
|
147
|
+
logs.each { |log| log.duration = 3.5 }
|
148
|
+
hash = result
|
149
|
+
assert gauges = hash['gauge'], hash
|
150
|
+
assert_equal 3, gauges.size
|
151
|
+
assert_equal average_metric_name, gauges[0]['metric']
|
152
|
+
assert_equal 3.5, gauges[0]['value']
|
153
|
+
assert_equal average_metric_name, gauges[1]['metric']
|
154
|
+
assert_equal average_metric_name, gauges[2]['metric']
|
155
|
+
end
|
156
|
+
|
157
|
+
describe 'send custom' do
|
158
|
+
let :logs do
|
159
|
+
3.times.collect do |i|
|
160
|
+
l = log.dup
|
161
|
+
l.metric = 'Filter/count'
|
162
|
+
l.dimensions = dimensions
|
163
|
+
l
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'counter metric when there is no duration' do
|
168
|
+
hash = result
|
169
|
+
|
170
|
+
assert counters = hash['counter'], hash
|
171
|
+
assert counter = counters.first, hash
|
172
|
+
assert_equal 'Filter.count', counter['metric'], counter
|
173
|
+
assert_equal 3, counter['value'], counter
|
174
|
+
assert_equal (log.time.to_i * 1_000).to_i, counter['timestamp'], counter
|
175
|
+
assert_equal all_dimensions, counter['dimensions']
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'format batch logs with aggregation' do
|
182
|
+
let :result do
|
183
|
+
JSON.parse(formatter.batch(same_logs, appender))
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'sends counter metrics' do
|
187
|
+
hash = result
|
188
|
+
|
189
|
+
assert counters = hash['counter'], hash
|
190
|
+
assert_equal 1, counters.size
|
191
|
+
assert_equal counter_metric_name, counters[0]['metric']
|
192
|
+
assert_equal 3, counters[0]['value']
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class FormattersTest < Minitest::Test
|
4
|
+
describe SemanticLogger::Formatters do
|
5
|
+
describe '.factory' do
|
6
|
+
let :log do
|
7
|
+
SemanticLogger::Log.new('Test', :info)
|
8
|
+
end
|
9
|
+
|
10
|
+
let :appender do
|
11
|
+
SemanticLogger::Appender::File.new(io: STDOUT)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'from a symbol' do
|
15
|
+
assert formatter = SemanticLogger::Formatters.factory(:raw)
|
16
|
+
assert formatter.is_a?(SemanticLogger::Formatters::Raw)
|
17
|
+
assert_equal 'Test', formatter.call(log, appender)[:name]
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'from a Hash (Symbol with options)' do
|
21
|
+
assert formatter = SemanticLogger::Formatters.factory(raw: {time_format: "%Y%m%d"})
|
22
|
+
assert formatter.is_a?(SemanticLogger::Formatters::Raw)
|
23
|
+
assert result = formatter.call(log, appender)
|
24
|
+
assert_equal 'Test', result[:name]
|
25
|
+
assert_equal Time.now.strftime("%Y%m%d"), result[:time]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'from block' do
|
29
|
+
my_formatter = -> log, appender { log.name }
|
30
|
+
assert formatter = SemanticLogger::Formatters.factory(my_formatter)
|
31
|
+
assert formatter.is_a?(Proc)
|
32
|
+
assert_equal 'Test', formatter.call(log, appender)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'minitest/shared_description'
|
2
|
+
|
3
|
+
InMemoryAppenderHelper = shared_description do
|
4
|
+
let :log_message do
|
5
|
+
SemanticLogger.flush
|
6
|
+
appender.message
|
7
|
+
end
|
8
|
+
|
9
|
+
let :appender do
|
10
|
+
InMemoryAppender.new
|
11
|
+
end
|
12
|
+
|
13
|
+
let :thread_name do
|
14
|
+
Thread.current.name
|
15
|
+
end
|
16
|
+
|
17
|
+
let :payload do
|
18
|
+
{session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
|
19
|
+
end
|
20
|
+
|
21
|
+
let :logger do
|
22
|
+
SemanticLogger['TestLogger']
|
23
|
+
end
|
24
|
+
|
25
|
+
let :appender_options do
|
26
|
+
{appender: appender}
|
27
|
+
end
|
28
|
+
|
29
|
+
let :added_appender do
|
30
|
+
SemanticLogger.add_appender(appender_options)
|
31
|
+
end
|
32
|
+
|
33
|
+
before do
|
34
|
+
SemanticLogger.default_level = :trace
|
35
|
+
SemanticLogger.backtrace_level = :trace
|
36
|
+
SemanticLogger.flush
|
37
|
+
added_appender
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
SemanticLogger.appenders.each { |appender| SemanticLogger.remove_appender(appender) }
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Store in memory the last log message received.
|
2
|
+
class InMemoryMetricsAppender < SemanticLogger::Subscriber
|
3
|
+
attr_accessor :message
|
4
|
+
|
5
|
+
def log(log)
|
6
|
+
self.message = log
|
7
|
+
end
|
8
|
+
|
9
|
+
# Only forward log entries that contain metrics.
|
10
|
+
def should_log?(log)
|
11
|
+
log.metric && meets_log_level?(log) && !filtered?(log)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/test/loggable_test.rb
CHANGED
@@ -73,43 +73,28 @@ class AppenderFileTest < Minitest::Test
|
|
73
73
|
end
|
74
74
|
|
75
75
|
describe 'logger' do
|
76
|
-
|
77
|
-
@time = Time.new
|
78
|
-
@io = StringIO.new
|
79
|
-
@appender = SemanticLogger::Appender::File.new(io: @io)
|
80
|
-
SemanticLogger.default_level = :trace
|
81
|
-
@mock_logger = MockLogger.new
|
82
|
-
@appender = SemanticLogger.add_appender(logger: @mock_logger)
|
83
|
-
@hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
|
84
|
-
@hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
|
85
|
-
@thread_name = Thread.current.name
|
86
|
-
end
|
87
|
-
|
88
|
-
after do
|
89
|
-
SemanticLogger.remove_appender(@appender)
|
90
|
-
end
|
76
|
+
include InMemoryAppenderHelper
|
91
77
|
|
92
78
|
describe 'for each log level' do
|
93
79
|
# Ensure that any log level can be logged
|
94
80
|
SemanticLogger::LEVELS.each do |level|
|
95
|
-
it "
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
81
|
+
it "logs #{level} information with class attribute" do
|
82
|
+
TestAttribute.logger.send(level, "hello #{level}", payload)
|
83
|
+
|
84
|
+
assert log = log_message
|
85
|
+
assert_equal "hello #{level}", log.message
|
86
|
+
assert_equal level, log.level
|
87
|
+
assert_equal 'TestAttribute', log.name
|
88
|
+
assert_equal payload, log.payload
|
103
89
|
end
|
104
90
|
|
105
91
|
it "log #{level} information with instance attribute" do
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
92
|
+
TestAttribute.new.logger.send(level, "hello #{level}", payload)
|
93
|
+
assert log = log_message
|
94
|
+
assert_equal "hello #{level}", log.message
|
95
|
+
assert_equal level, log.level
|
96
|
+
assert_equal 'TestAttribute', log.name
|
97
|
+
assert_equal payload, log.payload
|
113
98
|
end
|
114
99
|
end
|
115
100
|
end
|
data/test/logger_test.rb
CHANGED
@@ -3,174 +3,210 @@ require_relative 'test_helper'
|
|
3
3
|
# Unit Test for SemanticLogger::Logger
|
4
4
|
class LoggerTest < Minitest::Test
|
5
5
|
describe SemanticLogger::Logger do
|
6
|
-
|
7
|
-
# Use a mock logger that just keeps the last logged entry in an instance
|
8
|
-
# variable
|
9
|
-
SemanticLogger.default_level = :trace
|
10
|
-
SemanticLogger.backtrace_level = nil
|
11
|
-
@mock_logger = MockLogger.new
|
12
|
-
@appender = SemanticLogger.add_appender(logger: @mock_logger)
|
13
|
-
|
14
|
-
# Use this test's class name as the application name in the log output
|
15
|
-
@logger = SemanticLogger[LoggerTest]
|
16
|
-
@hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
|
17
|
-
@hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
|
18
|
-
@thread_name = Thread.current.name
|
19
|
-
@file_name_reg_exp = ' logger_test.rb:\d+'
|
20
|
-
|
21
|
-
assert_equal [], SemanticLogger.tags
|
22
|
-
assert_equal 65535, SemanticLogger.backtrace_level_index
|
23
|
-
end
|
6
|
+
include InMemoryAppenderHelper
|
24
7
|
|
25
|
-
|
26
|
-
|
8
|
+
let :dimensions do
|
9
|
+
{action: 'hit', user: 'jbloggs', state: 'FL'}
|
27
10
|
end
|
28
11
|
|
29
12
|
# Ensure that any log level can be logged
|
30
13
|
SemanticLogger::LEVELS.each do |level|
|
31
|
-
level_char = level.to_s.upcase[0]
|
32
14
|
|
33
15
|
describe "##{level}" do
|
34
16
|
describe 'positional parameter' do
|
35
17
|
it 'logs message' do
|
36
|
-
|
37
|
-
|
38
|
-
|
18
|
+
logger.send(level, 'hello world')
|
19
|
+
|
20
|
+
assert log = log_message
|
21
|
+
assert_equal 'hello world', log.message
|
39
22
|
end
|
40
23
|
|
41
24
|
it 'adds message from block' do
|
42
|
-
|
43
|
-
|
44
|
-
|
25
|
+
logger.send(level, 'hello world') { 'Calculations' }
|
26
|
+
|
27
|
+
assert log = log_message
|
28
|
+
assert_equal 'hello world -- Calculations', log.message
|
45
29
|
end
|
46
30
|
|
47
31
|
it 'logs message and payload' do
|
48
|
-
|
49
|
-
hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
|
50
|
-
@logger.send(level, 'Hello world', hash)
|
51
|
-
SemanticLogger.flush
|
52
|
-
assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
|
53
|
-
end
|
32
|
+
logger.send(level, 'hello world', payload)
|
54
33
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
SemanticLogger.flush
|
59
|
-
assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
|
34
|
+
assert log = log_message
|
35
|
+
assert_equal 'hello world', log.message
|
36
|
+
assert_equal payload, log.payload
|
60
37
|
end
|
61
38
|
|
62
39
|
it 'logs with backtrace' do
|
63
40
|
SemanticLogger.stub(:backtrace_level_index, 0) do
|
64
|
-
|
65
|
-
|
66
|
-
|
41
|
+
logger.send(level, 'hello world', payload) { 'Calculations' }
|
42
|
+
|
43
|
+
assert log = log_message
|
44
|
+
assert_equal 'hello world -- Calculations', log.message
|
45
|
+
assert_equal payload, log.payload
|
46
|
+
assert log.backtrace
|
47
|
+
assert log.backtrace.size > 0, log.backtrace
|
67
48
|
end
|
68
49
|
end
|
69
50
|
|
70
51
|
it 'logs with backtrace and exception' do
|
71
52
|
SemanticLogger.stub(:backtrace_level_index, 0) do
|
72
53
|
exc = RuntimeError.new('Test')
|
73
|
-
|
74
|
-
|
75
|
-
|
54
|
+
logger.send(level, 'hello world', exc)
|
55
|
+
|
56
|
+
assert log = log_message
|
57
|
+
assert_equal 'hello world', log.message
|
58
|
+
assert log.backtrace
|
59
|
+
assert log.backtrace.size > 0, log.backtrace
|
60
|
+
|
61
|
+
assert log.exception
|
62
|
+
refute log.exception.backtrace
|
63
|
+
assert_equal 'RuntimeError', log.exception.class.name
|
76
64
|
end
|
77
65
|
end
|
78
66
|
end
|
79
67
|
|
80
|
-
describe '
|
68
|
+
describe 'keyword arguments' do
|
81
69
|
it 'logs message' do
|
82
|
-
|
83
|
-
|
84
|
-
|
70
|
+
logger.send(level, message: 'hello world')
|
71
|
+
|
72
|
+
assert log = log_message
|
73
|
+
assert_equal 'hello world', log.message
|
85
74
|
end
|
86
75
|
|
87
76
|
it 'logs payload and message' do
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
77
|
+
logger.send(level, message: 'hello world', payload: payload)
|
78
|
+
|
79
|
+
assert log = log_message
|
80
|
+
assert_equal 'hello world', log.message
|
81
|
+
assert_equal payload, log.payload
|
93
82
|
end
|
94
83
|
|
95
84
|
it 'logs payload and message from block' do
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
85
|
+
logger.send(level) { {message: 'hello world', payload: payload} }
|
86
|
+
|
87
|
+
assert log = log_message
|
88
|
+
assert_equal 'hello world', log.message
|
89
|
+
assert_equal payload, log.payload
|
101
90
|
end
|
102
91
|
|
103
92
|
it 'logs payload only' do
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
93
|
+
logger.send(level, payload: payload)
|
94
|
+
|
95
|
+
assert log = log_message
|
96
|
+
refute log.message
|
97
|
+
assert_equal payload, log.payload
|
109
98
|
end
|
110
99
|
|
111
100
|
it 'logs duration' do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
101
|
+
logger.send(level, duration: 123.44, message: 'hello world', payload: payload)
|
102
|
+
|
103
|
+
assert log = log_message
|
104
|
+
assert_equal 'hello world', log.message
|
105
|
+
assert_equal payload, log.payload
|
106
|
+
assert_equal 123.44, log.duration
|
118
107
|
end
|
119
108
|
|
120
109
|
it 'does not log when below min_duration' do
|
121
|
-
|
122
|
-
|
123
|
-
|
110
|
+
logger.send(level, min_duration: 200, duration: 123.45, message: 'hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
|
111
|
+
|
112
|
+
refute log_message
|
124
113
|
end
|
125
114
|
|
126
115
|
it 'logs metric' do
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
116
|
+
metric_name = '/my/custom/metric'
|
117
|
+
logger.send(level, metric: metric_name, duration: 123.44, message: 'hello world', payload: payload)
|
118
|
+
|
119
|
+
assert log = log_message
|
120
|
+
assert_equal 'hello world', log.message
|
121
|
+
assert_equal payload, log.payload
|
122
|
+
assert_equal 123.44, log.duration
|
123
|
+
assert_equal metric_name, log.metric
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'metrics appender' do
|
127
|
+
let :appender do
|
128
|
+
InMemoryMetricsAppender.new
|
131
129
|
end
|
132
130
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
131
|
+
it 'logs metric only events' do
|
132
|
+
metric_name = '/my/custom/metric'
|
133
|
+
logger.send(level, metric: metric_name, dimensions: dimensions)
|
134
|
+
|
135
|
+
assert log = log_message
|
136
|
+
assert_equal metric_name, log.metric
|
137
|
+
assert_equal dimensions, log.dimensions
|
138
|
+
refute log.message
|
139
|
+
end
|
141
140
|
end
|
142
141
|
|
142
|
+
it 'for compatibility handles random payload logged as keyword arguments' do
|
143
|
+
logger.send(level, payload)
|
144
|
+
|
145
|
+
assert log = log_message
|
146
|
+
refute log.message
|
147
|
+
refute log.exception
|
148
|
+
refute log.metric
|
149
|
+
assert_equal payload, log.payload
|
150
|
+
end
|
143
151
|
end
|
144
152
|
|
145
153
|
describe '#filter' do
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
154
|
+
describe 'at the appender level' do
|
155
|
+
it 'Proc' do
|
156
|
+
appender.filter = -> log { (/\AExclude/ =~ log.message).nil? }
|
157
|
+
logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
|
158
|
+
|
159
|
+
refute log_message
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'RegExp' do
|
163
|
+
filter = /\ALogger/
|
164
|
+
appender.filter = -> log { (/\AExclude/ =~ log.message).nil? }
|
165
|
+
logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
|
166
|
+
|
167
|
+
refute log_message
|
168
|
+
end
|
151
169
|
end
|
152
170
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
171
|
+
describe 'at the logger level' do
|
172
|
+
it 'Proc' do
|
173
|
+
logger.filter = -> log { (/\AExclude/ =~ log.message).nil? }
|
174
|
+
logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
|
175
|
+
|
176
|
+
refute log_message
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'RegExp' do
|
180
|
+
filter = /\ALogger/
|
181
|
+
logger.filter = -> log { (/\AExclude/ =~ log.message).nil? }
|
182
|
+
logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
|
183
|
+
|
184
|
+
refute log_message
|
185
|
+
end
|
160
186
|
end
|
187
|
+
|
161
188
|
end
|
162
189
|
end
|
163
190
|
end
|
164
191
|
|
192
|
+
describe 'when level is too high' do
|
193
|
+
it 'does not log' do
|
194
|
+
SemanticLogger.default_level = :error
|
195
|
+
logger.info('Exclude this log message')
|
196
|
+
|
197
|
+
refute log_message
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
165
201
|
describe 'Compatibility' do
|
166
202
|
# Ensure that any log level can be logged
|
167
203
|
Logger::Severity.constants.each do |level|
|
168
204
|
it "log Ruby logger #{level} info" do
|
169
|
-
|
205
|
+
logger.level = Logger::Severity.const_get(level)
|
170
206
|
if level.to_s == 'UNKNOWN'
|
171
|
-
assert_equal Logger::Severity.const_get('ERROR')+1,
|
207
|
+
assert_equal Logger::Severity.const_get('ERROR')+1, logger.send(:level_index)
|
172
208
|
else
|
173
|
-
assert_equal Logger::Severity.const_get(level)+1,
|
209
|
+
assert_equal Logger::Severity.const_get(level)+1, logger.send(:level_index)
|
174
210
|
end
|
175
211
|
end
|
176
212
|
end
|
@@ -179,68 +215,76 @@ class LoggerTest < Minitest::Test
|
|
179
215
|
describe '#level?' do
|
180
216
|
it 'return true for debug? with :trace level' do
|
181
217
|
SemanticLogger.default_level = :trace
|
182
|
-
assert_equal :trace,
|
183
|
-
assert_equal true,
|
184
|
-
assert_equal true,
|
218
|
+
assert_equal :trace, logger.level
|
219
|
+
assert_equal true, logger.debug?
|
220
|
+
assert_equal true, logger.trace?
|
185
221
|
end
|
186
222
|
|
187
223
|
it 'return false for debug? with global :debug level' do
|
188
224
|
SemanticLogger.default_level = :debug
|
189
|
-
assert_equal :debug,
|
190
|
-
assert_equal true,
|
191
|
-
assert_equal false,
|
225
|
+
assert_equal :debug, logger.level, logger.inspect
|
226
|
+
assert_equal true, logger.debug?, logger.inspect
|
227
|
+
assert_equal false, logger.trace?, logger.inspect
|
192
228
|
end
|
193
229
|
|
194
230
|
it 'return true for debug? with global :info level' do
|
195
231
|
SemanticLogger.default_level = :info
|
196
|
-
assert_equal :info,
|
197
|
-
assert_equal false,
|
198
|
-
assert_equal false,
|
232
|
+
assert_equal :info, logger.level, logger.inspect
|
233
|
+
assert_equal false, logger.debug?, logger.inspect
|
234
|
+
assert_equal false, logger.trace?, logger.inspect
|
199
235
|
end
|
200
236
|
|
201
237
|
it 'return false for debug? with instance :debug level' do
|
202
|
-
|
203
|
-
assert_equal :debug,
|
204
|
-
assert_equal true,
|
205
|
-
assert_equal false,
|
238
|
+
logger.level = :debug
|
239
|
+
assert_equal :debug, logger.level, logger.inspect
|
240
|
+
assert_equal true, logger.debug?, logger.inspect
|
241
|
+
assert_equal false, logger.trace?, logger.inspect
|
206
242
|
end
|
207
243
|
|
208
244
|
it 'return true for debug? with instance :info level' do
|
209
|
-
|
210
|
-
assert_equal :info,
|
211
|
-
assert_equal false,
|
212
|
-
assert_equal false,
|
245
|
+
logger.level = :info
|
246
|
+
assert_equal :info, logger.level, logger.inspect
|
247
|
+
assert_equal false, logger.debug?, logger.inspect
|
248
|
+
assert_equal false, logger.trace?, logger.inspect
|
213
249
|
end
|
214
250
|
end
|
215
251
|
|
216
252
|
describe '.tagged' do
|
253
|
+
it 'sets global defaults' do
|
254
|
+
assert_equal [], SemanticLogger.tags
|
255
|
+
assert_equal 0, SemanticLogger.backtrace_level_index
|
256
|
+
end
|
257
|
+
|
217
258
|
it 'add tags to log entries' do
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
259
|
+
logger.tagged('12345', 'DJHSFK') do
|
260
|
+
logger.info('hello world')
|
261
|
+
|
262
|
+
assert log = log_message
|
263
|
+
assert_equal 'hello world', log.message
|
264
|
+
assert_equal %w(12345 DJHSFK), log.tags
|
222
265
|
end
|
223
266
|
end
|
224
267
|
|
225
268
|
it 'add embedded tags to log entries' do
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
269
|
+
logger.tagged('First Level', 'tags') do
|
270
|
+
logger.tagged('Second Level') do
|
271
|
+
assert_equal ['First Level', 'tags', 'Second Level'], logger.tags
|
272
|
+
logger.info('hello world')
|
273
|
+
|
274
|
+
assert log = log_message
|
275
|
+
assert_equal 'hello world', log.message
|
276
|
+
assert_equal ['First Level', 'tags', 'Second Level'], log.tags
|
231
277
|
end
|
232
|
-
assert_equal
|
233
|
-
assert_equal 'First Level', @logger.tags.first
|
234
|
-
assert_equal 'tags', @logger.tags.last
|
278
|
+
assert_equal ['First Level', 'tags'], logger.tags
|
235
279
|
end
|
236
280
|
end
|
237
281
|
|
238
282
|
it 'also supports named tagging' do
|
239
|
-
|
283
|
+
logger.tagged(level1: 1) do
|
240
284
|
assert_equal({level1: 1}, SemanticLogger.named_tags)
|
241
|
-
|
285
|
+
logger.tagged(level2: 2, more: 'data') do
|
242
286
|
assert_equal({level1: 1, level2: 2, more: 'data'}, SemanticLogger.named_tags)
|
243
|
-
|
287
|
+
logger.tagged(level3: 3) do
|
244
288
|
assert_equal({level1: 1, level2: 2, more: 'data', level3: 3}, SemanticLogger.named_tags)
|
245
289
|
end
|
246
290
|
end
|
@@ -248,10 +292,12 @@ class LoggerTest < Minitest::Test
|
|
248
292
|
end
|
249
293
|
|
250
294
|
it 'is compatible with rails logging that uses arrays and nils' do
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
295
|
+
logger.tagged('', ['12345', 'DJHSFK'], nil) do
|
296
|
+
logger.info('hello world')
|
297
|
+
|
298
|
+
assert log = log_message
|
299
|
+
assert_equal 'hello world', log.message
|
300
|
+
assert_equal %w(12345 DJHSFK), log.tags
|
255
301
|
end
|
256
302
|
end
|
257
303
|
end
|