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,47 @@
|
|
1
|
+
module SemanticLogger::Utils
|
2
|
+
|
3
|
+
def self.constantize_symbol(symbol, namespace = 'SemanticLogger::Appender')
|
4
|
+
klass = "#{namespace}::#{camelize(symbol.to_s)}"
|
5
|
+
begin
|
6
|
+
if RUBY_VERSION.to_i >= 2
|
7
|
+
Object.const_get(klass)
|
8
|
+
else
|
9
|
+
klass.split('::').inject(Object) { |o, name| o.const_get(name) }
|
10
|
+
end
|
11
|
+
rescue NameError
|
12
|
+
raise(ArgumentError, "Could not convert symbol: #{symbol.inspect} to a class in: #{namespace}. Looking for: #{klass}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Borrow from Rails, when not running Rails
|
17
|
+
def self.camelize(term)
|
18
|
+
string = term.to_s
|
19
|
+
string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
|
20
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
21
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
22
|
+
string
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the visibility for an instance method
|
26
|
+
def self.method_visibility(mod, method_name)
|
27
|
+
method_name = method_name.to_sym
|
28
|
+
if mod.instance_methods.include?(method_name)
|
29
|
+
:public
|
30
|
+
elsif mod.private_instance_methods.include?(method_name)
|
31
|
+
:private
|
32
|
+
elsif mod.protected_instance_methods.include?(method_name)
|
33
|
+
:protected
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
SELF_PATTERN = File.join('lib', 'semantic_logger')
|
38
|
+
|
39
|
+
# Extract the backtrace leaving out the last few Semantic Logger lines.
|
40
|
+
def self.cleanse_backtrace(stack = caller)
|
41
|
+
while (first = stack.first) && first.include?(SELF_PATTERN)
|
42
|
+
stack.shift
|
43
|
+
end
|
44
|
+
stack
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module Appender
|
4
|
+
class AsyncBatchTest < Minitest::Test
|
5
|
+
describe SemanticLogger::Appender::Async do
|
6
|
+
include InMemoryAppenderHelper
|
7
|
+
|
8
|
+
let :appender do
|
9
|
+
InMemoryBatchAppender.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'with default batch_size' do
|
13
|
+
let :appender_options do
|
14
|
+
{appender: appender, batch: true}
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'uses the batch proxy' do
|
18
|
+
assert_instance_of SemanticLogger::Appender::AsyncBatch, added_appender
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'logs messages after a flush' do
|
22
|
+
logger.info('hello world1')
|
23
|
+
refute appender.message
|
24
|
+
|
25
|
+
logger.info('hello world2')
|
26
|
+
refute appender.message
|
27
|
+
|
28
|
+
logger.info('hello world3')
|
29
|
+
refute appender.message
|
30
|
+
|
31
|
+
# Calls flush
|
32
|
+
assert logs = log_message
|
33
|
+
assert_equal 3, logs.size, logs
|
34
|
+
assert_equal 'hello world1', logs[0].message
|
35
|
+
assert_equal 'hello world2', logs[1].message
|
36
|
+
assert_equal 'hello world3', logs[2].message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# :batch_size, :batch_seconds
|
41
|
+
describe 'with batch_size 1' do
|
42
|
+
let :appender_options do
|
43
|
+
{appender: appender, batch: true, batch_size: 1}
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'uses the batch proxy' do
|
47
|
+
assert_instance_of SemanticLogger::Appender::AsyncBatch, added_appender
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'logs message immediately' do
|
51
|
+
logger.info('hello world')
|
52
|
+
|
53
|
+
assert logs = log_message
|
54
|
+
assert_equal 1, logs.size, logs
|
55
|
+
assert_equal 'hello world', logs.first.message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module Appender
|
4
|
+
class AsyncTest < Minitest::Test
|
5
|
+
describe SemanticLogger::Appender::Async do
|
6
|
+
include InMemoryAppenderHelper
|
7
|
+
|
8
|
+
describe 'with capped queue' do
|
9
|
+
let :appender_options do
|
10
|
+
{appender: appender, async: true}
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'uses the async proxy' do
|
14
|
+
assert_instance_of SemanticLogger::Appender::Async, added_appender
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'logs message immediately' do
|
18
|
+
logger.info('hello world')
|
19
|
+
|
20
|
+
assert log = log_message
|
21
|
+
assert_equal 'hello world', log.message
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'uses an capped queue' do
|
25
|
+
assert_instance_of SizedQueue, added_appender.queue
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'with uncapped queue' do
|
30
|
+
let :appender_options do
|
31
|
+
{appender: appender, async: true, max_queue_size: -1}
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'uses the async proxy' do
|
35
|
+
assert_instance_of SemanticLogger::Appender::Async, added_appender
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'uses an uncapped queue' do
|
39
|
+
assert_instance_of Queue, added_appender.queue
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -47,10 +47,10 @@ module Appender
|
|
47
47
|
@appender.send(level, 'Reading File', exc)
|
48
48
|
end
|
49
49
|
hash = JSON.parse(request.body)
|
50
|
-
|
50
|
+
assert_equal 'Reading File', hash['message'], hash
|
51
51
|
assert exception = hash['exception']
|
52
|
-
|
53
|
-
|
52
|
+
assert_equal 'NameError', exception['name']
|
53
|
+
assert_match 'undefined local variable or method', exception['message']
|
54
54
|
assert_equal level.to_s, hash['level']
|
55
55
|
assert exception['stack_trace'].first.include?(__FILE__), exception
|
56
56
|
end
|
@@ -4,79 +4,241 @@ require_relative '../test_helper'
|
|
4
4
|
module Appender
|
5
5
|
class ElasticsearchTest < Minitest::Test
|
6
6
|
describe SemanticLogger::Appender::Elasticsearch do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
describe 'providing a url' do
|
8
|
+
let :appender do
|
9
|
+
if ENV['ELASTICSEARCH']
|
10
|
+
SemanticLogger::Appender::Elasticsearch.new(url: 'http://localhost:9200')
|
11
|
+
else
|
12
|
+
Elasticsearch::Transport::Client.stub_any_instance(:bulk, true) do
|
13
|
+
SemanticLogger::Appender::Elasticsearch.new(url: 'http://localhost:9200')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
let :log_message do
|
19
|
+
'AppenderElasticsearchTest log message'
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
let :log do
|
23
|
+
log = SemanticLogger::Log.new('User', :info)
|
24
|
+
log.message = log_message
|
25
|
+
log
|
26
26
|
end
|
27
|
-
assert_equal "semantic_logger-#{Time.now.strftime('%Y.%m.%d')}", index
|
28
|
-
end
|
29
27
|
|
30
|
-
|
31
|
-
|
28
|
+
let :exception do
|
29
|
+
exc = nil
|
30
|
+
begin
|
31
|
+
Uh oh
|
32
|
+
rescue Exception => e
|
33
|
+
exc = e
|
34
|
+
end
|
35
|
+
exc
|
36
|
+
end
|
37
|
+
|
38
|
+
after do
|
39
|
+
appender.close
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'synchronous' do
|
43
|
+
it 'logs to daily indexes' do
|
44
|
+
bulk_index = nil
|
45
|
+
appender.stub(:write_to_elasticsearch, ->(messages) { bulk_index = messages.first }) do
|
46
|
+
appender.info log_message
|
47
|
+
end
|
48
|
+
index = bulk_index['index']['_index']
|
49
|
+
assert_equal "semantic_logger-#{Time.now.strftime('%Y.%m.%d')}", index
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'logs message' do
|
53
|
+
request = stub_client { appender.log(log) }
|
54
|
+
|
55
|
+
assert hash = request[:body][1]
|
56
|
+
assert_equal log_message, hash[:message]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'logs level' do
|
60
|
+
request = stub_client { appender.log(log) }
|
61
|
+
|
62
|
+
assert hash = request[:body][1]
|
63
|
+
assert_equal :info, hash[:level]
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'logs exception' do
|
67
|
+
log.exception = exception
|
68
|
+
request = stub_client { appender.log(log) }
|
69
|
+
|
70
|
+
assert hash = request[:body][1]
|
71
|
+
assert exception = hash[:exception]
|
72
|
+
assert_equal 'NameError', exception[:name]
|
73
|
+
assert_match 'undefined local variable or method', exception[:message]
|
74
|
+
assert exception[:stack_trace].first.include?(__FILE__), exception
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'logs payload' do
|
78
|
+
h = {key1: 1, key2: 'a'}
|
79
|
+
log.payload = h
|
80
|
+
request = stub_client { appender.log(log) }
|
81
|
+
|
82
|
+
assert hash = request[:body][1]
|
83
|
+
refute hash[:stack_trace]
|
84
|
+
assert_equal h, hash[:payload], hash
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'async batch' do
|
89
|
+
it 'logs message' do
|
90
|
+
request = stub_client { appender.batch([log]) }
|
91
|
+
|
92
|
+
assert hash = request[:body][1]
|
93
|
+
assert_equal log_message, hash[:message]
|
94
|
+
assert_equal :info, hash[:level]
|
95
|
+
end
|
96
|
+
|
97
|
+
let :logs do
|
98
|
+
Array.new(3) do |i|
|
99
|
+
l = log.dup
|
100
|
+
l.message = "hello world#{i + 1}"
|
101
|
+
l
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'logs multiple messages' do
|
106
|
+
request = stub_client { appender.batch(logs) }
|
107
|
+
|
108
|
+
assert body = request[:body]
|
109
|
+
assert_equal 4, body.size, body
|
110
|
+
index = body[0]['index']['_index']
|
111
|
+
assert_equal "semantic_logger-#{Time.now.strftime('%Y.%m.%d')}", index
|
112
|
+
|
113
|
+
assert_equal 'hello world1', body[1][:message]
|
114
|
+
assert_equal 'hello world2', body[2][:message]
|
115
|
+
assert_equal 'hello world3', body[3][:message]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def stub_client(&block)
|
32
120
|
request = nil
|
33
|
-
|
34
|
-
|
121
|
+
appender.client.stub(:bulk, ->(r) { request = r; {'status' => 201} }, &block)
|
122
|
+
request
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'elasticsearch parameters' do
|
127
|
+
let :appender do
|
128
|
+
Elasticsearch::Transport::Client.stub_any_instance(:bulk, true) do
|
129
|
+
SemanticLogger::Appender::Elasticsearch.new(
|
130
|
+
hosts: [{host: 'localhost', port: 9200}]
|
131
|
+
)
|
35
132
|
end
|
133
|
+
end
|
134
|
+
|
135
|
+
let :log_message do
|
136
|
+
'AppenderElasticsearchTest log message'
|
137
|
+
end
|
36
138
|
|
37
|
-
|
38
|
-
|
39
|
-
|
139
|
+
let :log do
|
140
|
+
log = SemanticLogger::Log.new('User', :info)
|
141
|
+
log.message = log_message
|
142
|
+
log
|
40
143
|
end
|
41
144
|
|
42
|
-
|
145
|
+
let :exception do
|
43
146
|
exc = nil
|
44
147
|
begin
|
45
148
|
Uh oh
|
46
149
|
rescue Exception => e
|
47
150
|
exc = e
|
48
151
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
152
|
+
exc
|
153
|
+
end
|
154
|
+
|
155
|
+
after do
|
156
|
+
appender.close
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'synchronous' do
|
160
|
+
it 'logs to daily indexes' do
|
161
|
+
bulk_index = nil
|
162
|
+
appender.stub(:write_to_elasticsearch, ->(messages) { bulk_index = messages.first }) do
|
163
|
+
appender.info log_message
|
164
|
+
end
|
165
|
+
index = bulk_index['index']['_index']
|
166
|
+
assert_equal "semantic_logger-#{Time.now.strftime('%Y.%m.%d')}", index
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'logs message' do
|
170
|
+
request = stub_client { appender.log(log) }
|
171
|
+
|
172
|
+
assert hash = request[:body][1]
|
173
|
+
assert_equal log_message, hash[:message]
|
52
174
|
end
|
53
175
|
|
54
|
-
|
176
|
+
it 'logs level' do
|
177
|
+
request = stub_client { appender.log(log) }
|
55
178
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
179
|
+
assert hash = request[:body][1]
|
180
|
+
assert_equal :info, hash[:level]
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'logs exception' do
|
184
|
+
log.exception = exception
|
185
|
+
request = stub_client { appender.log(log) }
|
186
|
+
|
187
|
+
assert hash = request[:body][1]
|
188
|
+
assert exception = hash[:exception]
|
189
|
+
assert_equal 'NameError', exception[:name]
|
190
|
+
assert_match 'undefined local variable or method', exception[:message]
|
191
|
+
assert exception[:stack_trace].first.include?(__FILE__), exception
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'logs payload' do
|
195
|
+
h = {key1: 1, key2: 'a'}
|
196
|
+
log.payload = h
|
197
|
+
request = stub_client { appender.log(log) }
|
198
|
+
|
199
|
+
assert hash = request[:body][1]
|
200
|
+
refute hash[:stack_trace]
|
201
|
+
assert_equal h, hash[:payload], hash
|
202
|
+
end
|
62
203
|
end
|
63
204
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
205
|
+
describe 'async batch' do
|
206
|
+
it 'logs message' do
|
207
|
+
request = stub_client { appender.batch([log]) }
|
208
|
+
|
209
|
+
assert hash = request[:body][1]
|
210
|
+
assert_equal log_message, hash[:message]
|
211
|
+
assert_equal :info, hash[:level]
|
68
212
|
end
|
69
213
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
214
|
+
let :logs do
|
215
|
+
Array.new(3) do |i|
|
216
|
+
l = log.dup
|
217
|
+
l.message = "hello world#{i + 1}"
|
218
|
+
l
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'logs multiple messages' do
|
223
|
+
request = stub_client { appender.batch(logs) }
|
224
|
+
|
225
|
+
assert body = request[:body]
|
226
|
+
assert_equal 4, body.size, body
|
227
|
+
index = body[0]['index']['_index']
|
228
|
+
assert_equal "semantic_logger-#{Time.now.strftime('%Y.%m.%d')}", index
|
229
|
+
|
230
|
+
assert_equal 'hello world1', body[1][:message]
|
231
|
+
assert_equal 'hello world2', body[2][:message]
|
232
|
+
assert_equal 'hello world3', body[3][:message]
|
233
|
+
end
|
77
234
|
end
|
78
|
-
end
|
79
235
|
|
236
|
+
def stub_client(&block)
|
237
|
+
request = nil
|
238
|
+
appender.client.stub(:bulk, ->(r) { request = r; {'status' => 201} }, &block)
|
239
|
+
request
|
240
|
+
end
|
241
|
+
end
|
80
242
|
end
|
81
243
|
end
|
82
244
|
end
|