semantic_logger 4.1.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|