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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/lib/semantic_logger.rb +6 -13
  3. data/lib/semantic_logger/ansi_colors.rb +10 -10
  4. data/lib/semantic_logger/appender.rb +42 -26
  5. data/lib/semantic_logger/appender/async.rb +179 -0
  6. data/lib/semantic_logger/appender/async_batch.rb +95 -0
  7. data/lib/semantic_logger/appender/bugsnag.rb +2 -1
  8. data/lib/semantic_logger/appender/elasticsearch.rb +113 -81
  9. data/lib/semantic_logger/appender/elasticsearch_http.rb +1 -3
  10. data/lib/semantic_logger/appender/file.rb +1 -3
  11. data/lib/semantic_logger/appender/graylog.rb +6 -5
  12. data/lib/semantic_logger/appender/honeybadger.rb +0 -2
  13. data/lib/semantic_logger/appender/http.rb +25 -10
  14. data/lib/semantic_logger/appender/kafka.rb +1 -3
  15. data/lib/semantic_logger/appender/mongodb.rb +1 -3
  16. data/lib/semantic_logger/appender/new_relic.rb +7 -3
  17. data/lib/semantic_logger/appender/sentry.rb +6 -7
  18. data/lib/semantic_logger/appender/splunk.rb +1 -2
  19. data/lib/semantic_logger/appender/splunk_http.rb +3 -4
  20. data/lib/semantic_logger/appender/syslog.rb +1 -3
  21. data/lib/semantic_logger/appender/tcp.rb +7 -9
  22. data/lib/semantic_logger/appender/udp.rb +0 -2
  23. data/lib/semantic_logger/appender/wrapper.rb +0 -2
  24. data/lib/semantic_logger/base.rb +76 -19
  25. data/lib/semantic_logger/formatters.rb +37 -0
  26. data/lib/semantic_logger/formatters/base.rb +10 -3
  27. data/lib/semantic_logger/formatters/json.rb +2 -6
  28. data/lib/semantic_logger/formatters/one_line.rb +18 -0
  29. data/lib/semantic_logger/formatters/raw.rb +8 -2
  30. data/lib/semantic_logger/formatters/signalfx.rb +169 -0
  31. data/lib/semantic_logger/log.rb +23 -14
  32. data/lib/semantic_logger/loggable.rb +88 -15
  33. data/lib/semantic_logger/logger.rb +0 -20
  34. data/lib/semantic_logger/metric/new_relic.rb +75 -0
  35. data/lib/semantic_logger/metric/signalfx.rb +123 -0
  36. data/lib/semantic_logger/{metrics → metric}/statsd.rb +20 -8
  37. data/lib/semantic_logger/processor.rb +67 -169
  38. data/lib/semantic_logger/semantic_logger.rb +7 -31
  39. data/lib/semantic_logger/subscriber.rb +32 -36
  40. data/lib/semantic_logger/utils.rb +47 -0
  41. data/lib/semantic_logger/version.rb +1 -1
  42. data/test/appender/async_batch_test.rb +61 -0
  43. data/test/appender/async_test.rb +45 -0
  44. data/test/appender/elasticsearch_http_test.rb +3 -3
  45. data/test/appender/elasticsearch_test.rb +211 -49
  46. data/test/appender/file_test.rb +9 -8
  47. data/test/appender/mongodb_test.rb +3 -3
  48. data/test/appender/newrelic_rpm.rb +6 -0
  49. data/test/appender/sentry_test.rb +3 -1
  50. data/test/appender/wrapper_test.rb +29 -0
  51. data/test/concerns/compatibility_test.rb +64 -60
  52. data/test/debug_as_trace_logger_test.rb +62 -77
  53. data/test/formatters/one_line_test.rb +61 -0
  54. data/test/formatters/signalfx_test.rb +200 -0
  55. data/test/formatters_test.rb +36 -0
  56. data/test/in_memory_appender.rb +9 -0
  57. data/test/in_memory_appender_helper.rb +43 -0
  58. data/test/in_memory_batch_appender.rb +9 -0
  59. data/test/in_memory_metrics_appender.rb +14 -0
  60. data/test/loggable_test.rb +15 -30
  61. data/test/logger_test.rb +181 -135
  62. data/test/measure_test.rb +212 -113
  63. data/test/metric/new_relic_test.rb +36 -0
  64. data/test/metric/signalfx_test.rb +78 -0
  65. data/test/semantic_logger_test.rb +58 -65
  66. data/test/test_helper.rb +19 -2
  67. metadata +33 -7
  68. data/lib/semantic_logger/metrics/new_relic.rb +0 -30
  69. data/lib/semantic_logger/metrics/udp.rb +0 -80
  70. 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
@@ -1,3 +1,3 @@
1
1
  module SemanticLogger #:nodoc
2
- VERSION = '4.1.1'
2
+ VERSION = '4.2.0'
3
3
  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
- assert 'Reading File', hash['message']
50
+ assert_equal 'Reading File', hash['message'], hash
51
51
  assert exception = hash['exception']
52
- assert 'NameError', exception['name']
53
- assert 'undefined local variable or method', exception['message']
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
- before do
8
- skip('Concurrent::TimerTask issue is preventing the process from stopping.') if defined? JRuby
9
- Elasticsearch::Transport::Client.stub_any_instance(:bulk, true) do
10
- @appender = SemanticLogger::Appender::Elasticsearch.new(
11
- url: 'http://localhost:9200',
12
- batch_size: 1 # immediate flush
13
- )
14
- end
15
- @message = 'AppenderElasticsearchTest log message'
16
- end
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
- after do
19
- @appender.close if @appender
20
- end
18
+ let :log_message do
19
+ 'AppenderElasticsearchTest log message'
20
+ end
21
21
 
22
- it 'logs to daily indexes' do
23
- index = nil
24
- @appender.stub(:enqueue, ->(ind, json) { index = ind['index']['_index'] }) do
25
- @appender.info @message
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
- SemanticLogger::LEVELS.each do |level|
31
- it "send #{level}" do
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
- @appender.client.stub(:bulk, -> r { request = r; {"status" => 201} }) do
34
- @appender.send(level, @message)
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
- message = request[:body][1]
38
- assert_equal @message, message[:message]
39
- assert_equal level, message[:level]
139
+ let :log do
140
+ log = SemanticLogger::Log.new('User', :info)
141
+ log.message = log_message
142
+ log
40
143
  end
41
144
 
42
- it "sends #{level} exceptions" do
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
- request = nil
50
- @appender.client.stub(:bulk, -> r { request = r; {"status" => 201} }) do
51
- @appender.send(level, 'Reading File', exc)
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
- hash = request[:body][1]
176
+ it 'logs level' do
177
+ request = stub_client { appender.log(log) }
55
178
 
56
- assert 'Reading File', hash[:message]
57
- assert exception = hash[:exception]
58
- assert 'NameError', exception[:name]
59
- assert 'undefined local variable or method', exception[:message]
60
- assert_equal level, hash[:level]
61
- assert exception[:stack_trace].first.include?(__FILE__), exception
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
- it "sends #{level} custom attributes" do
65
- request = nil
66
- @appender.client.stub(:bulk, -> r { request = r; {"status" => 201} }) do
67
- @appender.send(level, @message, {key1: 1, key2: 'a'})
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
- message = request[:body][1]
71
- assert_equal @message, message[:message]
72
- assert_equal level, message[:level]
73
- refute message[:stack_trace]
74
- assert payload = message[:payload], message
75
- assert_equal 1, payload[:key1], message
76
- assert_equal 'a', payload[:key2], message
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