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.
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