loga 2.4.0 → 2.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe Loga::Sidekiq do
4
4
  describe '.configure_logging' do
5
- context 'when sidekiq version is 5.1' do
5
+ context 'when sidekiq is defined' do
6
6
  it 'gets invoked on Loga.configure' do
7
7
  allow(described_class).to receive(:configure_logging)
8
8
 
@@ -18,7 +18,7 @@ RSpec.describe Loga::Sidekiq do
18
18
  expect(described_class).to have_received(:configure_logging)
19
19
  end
20
20
 
21
- it 'assigns our custom sidekiq job logger' do
21
+ it 'assigns our custom sidekiq job logger depending on the sidekiq version' do
22
22
  Loga.reset
23
23
 
24
24
  Loga.configure(
@@ -28,7 +28,14 @@ RSpec.describe Loga::Sidekiq do
28
28
  format: :gelf,
29
29
  )
30
30
 
31
- expect(::Sidekiq.options[:job_logger]).to eq(Loga::Sidekiq::JobLogger)
31
+ m = ENV['BUNDLE_GEMFILE'].match(/sidekiq(?<version>\d+)/)
32
+
33
+ case m['version']
34
+ when '51'
35
+ expect(::Sidekiq.options[:job_logger]).to eq(Loga::Sidekiq5::JobLogger)
36
+ when '6'
37
+ expect(::Sidekiq.options[:job_logger]).to eq(Loga::Sidekiq6::JobLogger)
38
+ end
32
39
  end
33
40
  end
34
41
 
data/spec/spec_helper.rb CHANGED
@@ -29,14 +29,23 @@ when /sinatra/
29
29
  when /unit/
30
30
  rspec_pattern = 'unit/**/*_spec.rb'
31
31
  require 'loga'
32
- when /sidekiq/
33
- sidekiq_specs = [
34
- 'integration/sidekiq_spec.rb',
35
- 'spec/loga/sidekiq/**/*_spec.rb',
36
- 'spec/loga/sidekiq_spec.rb',
37
- ]
38
-
39
- rspec_pattern = sidekiq_specs.join(',')
32
+ when /sidekiq(?<version>\d+)/
33
+ case $LAST_MATCH_INFO['version']
34
+ when '51'
35
+ rspec_pattern = [
36
+ 'spec/integration/sidekiq5_spec.rb',
37
+ 'spec/loga/sidekiq5/**/*_spec.rb',
38
+ 'spec/loga/sidekiq_spec.rb',
39
+ ].join(',')
40
+ when '6'
41
+ rspec_pattern = [
42
+ 'spec/integration/sidekiq6_spec.rb',
43
+ 'spec/loga/sidekiq6/**/*_spec.rb',
44
+ 'spec/loga/sidekiq_spec.rb',
45
+ ].join(',')
46
+ else
47
+ raise 'FIXME: Unknown sidekiq - update this file.'
48
+ end
40
49
 
41
50
  require 'sidekiq'
42
51
  require 'sidekiq/cli'
@@ -166,6 +166,49 @@ describe Loga::Formatters::GELFFormatter do
166
166
  end
167
167
  end
168
168
 
169
+ context 'when working with sidekiq context' do
170
+ let(:options) { { message: 'Wooden house' } }
171
+ let(:message) { Loga::Event.new(options) }
172
+ let(:sidekiq_context) { { class: 'MyWorker', jid: '123' } }
173
+
174
+ before do
175
+ klass = Class.new do
176
+ class << self
177
+ attr_accessor :current
178
+ end
179
+ end
180
+ klass.current = sidekiq_context
181
+ stub_const('::Sidekiq::Context', klass)
182
+ end
183
+
184
+ it 'includes the ::Sidekiq::Context.current data' do
185
+ expect(json['_class']).to eq('MyWorker')
186
+ expect(json['_jid']).to eq('123')
187
+ end
188
+
189
+ include_examples 'valid GELF message'
190
+
191
+ describe 'overwriting sidekiq context data with manual one' do
192
+ let(:options) { { message: 'Test', data: { class: 'CoolTest' } } }
193
+
194
+ it 'uses the manual data instead of the sidekiq context' do
195
+ expect(json['_class']).to eq('CoolTest')
196
+ end
197
+
198
+ include_examples 'valid GELF message'
199
+ end
200
+
201
+ describe ':elapsed in the sidekiq context' do
202
+ let(:sidekiq_context) { { class: 'MyWorker', jid: '123', elapsed: '22.2' } }
203
+
204
+ it 'transforms it to _duration' do
205
+ expect(json['_duration']).to eq(22.2)
206
+ end
207
+
208
+ include_examples 'valid GELF message'
209
+ end
210
+ end
211
+
169
212
  {
170
213
  'DEBUG' => 7,
171
214
  'INFO' => 6,
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'rack/test'
3
3
 
4
- # rubocop:disable RSpec/SubjectStub, RSpec/MessageSpies, RSpec/VerifiedDoubles
4
+ # rubocop:disable RSpec/VerifiedDoubles RSpec/MessageSpies
5
5
  describe Loga::Rack::Logger do
6
- subject { described_class.new(app) }
6
+ subject(:middleware) { described_class.new(app) }
7
7
 
8
8
  let(:env) { Rack::MockRequest.env_for('/about_us?limit=1', options) }
9
9
  let(:options) { {} }
@@ -21,18 +21,25 @@ describe Loga::Rack::Logger do
21
21
  )
22
22
  end
23
23
 
24
- before { Loga.instance_variable_set(:@configuration, configuration) }
24
+ let(:started_at) { Time.new(2021, 1, 2, 9, 30, 4.500, '+00:00') }
25
+
26
+ around do |example|
27
+ Timecop.freeze(Time.new(2021, 1, 2, 9, 30, 5.000, '+00:00'), &example)
28
+ end
29
+
30
+ before do
31
+ allow(Loga).to receive(:configuration).and_return(configuration)
32
+ end
25
33
 
26
34
  shared_examples 'logs the event' do |details|
27
35
  let(:level) { details[:level] }
28
36
 
29
- before do
30
- allow(subject).to receive(:started_at).and_return(:timestamp)
31
- allow(subject).to receive(:duration_in_ms).with(any_args).and_return(5)
32
- end
33
-
34
37
  it 'instantiates a Loga::Event' do
35
- expect(Loga::Event).to receive(:new).with(
38
+ allow(Loga::Event).to receive(:new).and_call_original
39
+
40
+ middleware.call(env, started_at)
41
+
42
+ expect(Loga::Event).to have_received(:new).with(
36
43
  data: {
37
44
  request: {
38
45
  'status' => response_status,
@@ -42,21 +49,19 @@ describe Loga::Rack::Logger do
42
49
  'request_id' => nil,
43
50
  'request_ip' => nil,
44
51
  'user_agent' => nil,
45
- 'duration' => 5,
52
+ 'duration' => 500,
46
53
  },
47
54
  },
48
55
  exception: logged_exception,
49
56
  message: %r{^GET \/about_us\?limit=1 #{response_status} in \d+ms$},
50
- timestamp: :timestamp,
57
+ timestamp: started_at,
51
58
  type: 'request',
52
59
  )
53
-
54
- subject.call(env)
55
60
  end
56
61
 
57
62
  it "logs the Loga::Event with severity #{details[:level]}" do
58
63
  allow(logger).to receive(level)
59
- subject.call(env)
64
+ middleware.call(env, started_at)
60
65
  expect(logger).to have_received(level).with(an_instance_of(Loga::Event))
61
66
  end
62
67
  end
@@ -65,12 +70,35 @@ describe Loga::Rack::Logger do
65
70
  let(:exception) { StandardError.new }
66
71
  let(:logged_exception) { nil }
67
72
  let(:response_status) { 200 }
73
+ let(:exception_class) { Class.new(StandardError) }
68
74
 
69
75
  context 'when an exception is raised' do
70
- let(:app) { ->(_env) { raise exception } }
71
-
72
- it 'does not rescue the exception' do
73
- expect { subject.call(env) }.to raise_error(StandardError)
76
+ let(:app) { ->(_env) { raise exception_class } }
77
+ let(:response_status) { 500 }
78
+
79
+ it 'raises error, but still logs an event' do
80
+ allow(Loga::Event).to receive(:new).and_call_original
81
+
82
+ expect { middleware.call(env, started_at) }.to raise_error(exception_class)
83
+
84
+ expect(Loga::Event).to have_received(:new).with(
85
+ data: {
86
+ request: {
87
+ 'status' => response_status,
88
+ 'method' => 'GET',
89
+ 'path' => '/about_us',
90
+ 'params' => { 'limit' => '1' },
91
+ 'request_id' => nil,
92
+ 'request_ip' => nil,
93
+ 'user_agent' => nil,
94
+ 'duration' => 500,
95
+ },
96
+ },
97
+ exception: logged_exception,
98
+ message: %r{^GET \/about_us\?limit=1 #{response_status} in \d+ms$},
99
+ timestamp: started_at,
100
+ type: 'request',
101
+ )
74
102
  end
75
103
  end
76
104
 
@@ -112,28 +140,21 @@ describe Loga::Rack::Logger do
112
140
  end
113
141
 
114
142
  context 'when the logger is tagged' do
115
- let(:logger) { double(:logger, tagged: true) }
116
-
117
- before do
118
- allow(subject).to receive(:call_app).with(any_args).and_return(:response)
119
- allow(subject).to receive(:compute_tags).with(any_args).and_return(:tag)
120
- allow(logger).to receive(:tagged).with('hello') do |&block|
121
- block.call
122
- end
123
- end
143
+ let(:logger) { Loga::TaggedLogging.new(Logger.new('/dev/null')) }
144
+ let(:fake_tag_proc) { double(:proc, call: true) }
145
+
146
+ let(:tags) { [->(request) { fake_tag_proc.call(request) }] }
147
+
148
+ include_examples 'logs the event', level: :info
124
149
 
125
- context 'when tags are present' do
126
- let(:tags) { [:foo] }
150
+ it 'calls the tags and computes them' do
151
+ middleware.call(env)
127
152
 
128
- it 'yields the app with tags' do
129
- allow(logger).to receive(:tagged)
130
- subject.call(env)
131
- expect(logger).to have_received(:tagged).with(:tag) do |&block|
132
- expect(block.call).to eq(:response)
133
- end
134
- end
153
+ expect(fake_tag_proc)
154
+ .to have_received(:call)
155
+ .with(instance_of(Loga::Rack::Request))
135
156
  end
136
157
  end
137
158
  end
138
159
  end
139
- # rubocop:enable RSpec/SubjectStub, RSpec/MessageSpies, RSpec/VerifiedDoubles
160
+ # rubocop:enable RSpec/VerifiedDoubles RSpec/MessageSpies
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loga
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Funding Circle
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-09 00:00:00.000000000 Z
11
+ date: 2021-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -56,14 +56,14 @@ dependencies:
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.6'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.6'
69
69
  - !ruby/object:Gem::Dependency
@@ -259,7 +259,9 @@ files:
259
259
  - gemfiles/rails42.gemfile
260
260
  - gemfiles/rails50.gemfile
261
261
  - gemfiles/rails52.gemfile
262
+ - gemfiles/rails60.gemfile
262
263
  - gemfiles/sidekiq51.gemfile
264
+ - gemfiles/sidekiq6.gemfile
263
265
  - gemfiles/sinatra14.gemfile
264
266
  - gemfiles/unit.gemfile
265
267
  - lib/loga.rb
@@ -279,7 +281,8 @@ files:
279
281
  - lib/loga/railtie.rb
280
282
  - lib/loga/service_version_strategies.rb
281
283
  - lib/loga/sidekiq.rb
282
- - lib/loga/sidekiq/job_logger.rb
284
+ - lib/loga/sidekiq5/job_logger.rb
285
+ - lib/loga/sidekiq6/job_logger.rb
283
286
  - lib/loga/tagged_logging.rb
284
287
  - lib/loga/utilities.rb
285
288
  - lib/loga/version.rb
@@ -290,13 +293,16 @@ files:
290
293
  - spec/fixtures/rails42.rb
291
294
  - spec/fixtures/rails50.rb
292
295
  - spec/fixtures/rails52.rb
296
+ - spec/fixtures/rails60.rb
293
297
  - spec/fixtures/random_bin
294
298
  - spec/integration/rails/action_mailer_spec.rb
295
299
  - spec/integration/rails/railtie_spec.rb
296
300
  - spec/integration/rails/request_spec.rb
297
- - spec/integration/sidekiq_spec.rb
301
+ - spec/integration/sidekiq5_spec.rb
302
+ - spec/integration/sidekiq6_spec.rb
298
303
  - spec/integration/sinatra_spec.rb
299
- - spec/loga/sidekiq/job_logger_spec.rb
304
+ - spec/loga/sidekiq5/job_logger_spec.rb
305
+ - spec/loga/sidekiq6/job_logger_spec.rb
300
306
  - spec/loga/sidekiq_spec.rb
301
307
  - spec/spec_helper.rb
302
308
  - spec/support/gethostname_shared.rb
@@ -345,13 +351,16 @@ test_files:
345
351
  - spec/fixtures/rails42.rb
346
352
  - spec/fixtures/rails50.rb
347
353
  - spec/fixtures/rails52.rb
354
+ - spec/fixtures/rails60.rb
348
355
  - spec/fixtures/random_bin
349
356
  - spec/integration/rails/action_mailer_spec.rb
350
357
  - spec/integration/rails/railtie_spec.rb
351
358
  - spec/integration/rails/request_spec.rb
352
- - spec/integration/sidekiq_spec.rb
359
+ - spec/integration/sidekiq5_spec.rb
360
+ - spec/integration/sidekiq6_spec.rb
353
361
  - spec/integration/sinatra_spec.rb
354
- - spec/loga/sidekiq/job_logger_spec.rb
362
+ - spec/loga/sidekiq5/job_logger_spec.rb
363
+ - spec/loga/sidekiq6/job_logger_spec.rb
355
364
  - spec/loga/sidekiq_spec.rb
356
365
  - spec/spec_helper.rb
357
366
  - spec/support/gethostname_shared.rb
@@ -1,147 +0,0 @@
1
- require 'spec_helper'
2
- require 'timecop'
3
- require 'fakeredis'
4
-
5
- dummy_redis_config = ConnectionPool.new(size: 5) { Redis.new }
6
-
7
- Sidekiq.configure_client do |config|
8
- config.redis = dummy_redis_config
9
- end
10
-
11
- Sidekiq.configure_server do |config|
12
- config.redis = dummy_redis_config
13
- end
14
-
15
- class MySidekiqWorker
16
- include Sidekiq::Worker
17
-
18
- def perform(_name); end
19
- end
20
-
21
- describe 'Sidekiq client logger' do
22
- let(:target) { StringIO.new }
23
-
24
- def read_json_log(line:)
25
- target.rewind
26
- JSON.parse(target.each_line.drop(line - 1).first)
27
- end
28
-
29
- before do
30
- Redis.current.flushall
31
-
32
- Loga.reset
33
-
34
- Loga.configure(
35
- service_name: 'hello_world_app',
36
- service_version: '1.0',
37
- device: target,
38
- format: :gelf,
39
- )
40
- end
41
-
42
- it 'has the proper job logger' do
43
- job_logger = Loga::Sidekiq::JobLogger
44
-
45
- expect(Sidekiq.options[:job_logger]).to eq job_logger
46
- end
47
-
48
- it 'has the proper logger Sidekiq::Logging.logger' do
49
- expect(Sidekiq::Logging.logger).to eq Loga.logger
50
- end
51
-
52
- it 'has the proper logger for Sidekiq.logger' do
53
- expect(Sidekiq.logger).to eq Loga.logger
54
- end
55
-
56
- it 'pushes a new element in the default queue' do
57
- MySidekiqWorker.perform_async('Bob')
58
-
59
- last_element = JSON.parse(Redis.current.lpop('queue:default'))
60
-
61
- aggregate_failures do
62
- expect(last_element['class']).to eq 'MySidekiqWorker'
63
- expect(last_element['args']).to eq ['Bob']
64
- expect(last_element['retry']).to eq true
65
- expect(last_element['queue']).to eq 'default'
66
- end
67
- end
68
-
69
- if ENV['BUNDLE_GEMFILE'] =~ /sidekiq51/
70
- # https://github.com/mperham/sidekiq/blob/97363210b47a4f8a1d8c1233aaa059d6643f5040/test/test_actors.rb#L57-L79
71
- let(:mgr) do
72
- Class.new do
73
- attr_reader :latest_error, :mutex, :cond
74
-
75
- def initialize
76
- @mutex = ::Mutex.new
77
- @cond = ::ConditionVariable.new
78
- end
79
-
80
- def processor_died(_inst, err)
81
- @latest_error = err
82
-
83
- @mutex.synchronize { @cond.signal }
84
- end
85
-
86
- def processor_stopped(_inst)
87
- @mutex.synchronize { @cond.signal }
88
- end
89
-
90
- def options
91
- {
92
- concurrency: 3,
93
- queues: ['default'],
94
- job_logger: Loga::Sidekiq::JobLogger,
95
- }
96
- end
97
- end
98
- end
99
-
100
- it 'logs the job processing event' do
101
- MySidekiqWorker.perform_async('Bob')
102
-
103
- require 'sidekiq/processor'
104
- Sidekiq::Processor.new(mgr.new).start
105
- sleep 0.5
106
-
107
- expected_attributes = {
108
- '_queue'=> 'default',
109
- '_retry'=> true,
110
- '_params'=> ['Bob'],
111
- '_class'=> 'MySidekiqWorker',
112
- '_type'=> 'sidekiq',
113
- '_service.name'=> 'hello_world_app',
114
- '_service.version'=> '1.0',
115
- '_tags'=> '',
116
- 'level'=> 6,
117
- 'version'=> '1.1',
118
- }
119
-
120
- json_line = read_json_log(line: 1)
121
-
122
- aggregate_failures do
123
- expect(json_line).to include(expected_attributes)
124
-
125
- %w[_created_at _enqueued_at _jid _duration timestamp host].each do |key|
126
- expect(json_line).to have_key(key)
127
- end
128
-
129
- expect(json_line['short_message']).to match(/MySidekiqWorker with jid:*/)
130
- end
131
-
132
- # This was a bug - the duration was constantly incresing based on when
133
- # the logger was created. https://github.com/FundingCircle/loga/pull/117
134
- #
135
- # Test that after sleeping for few seconds the duration is still under 500ms
136
- sleep 1
137
-
138
- MySidekiqWorker.perform_async('Bob')
139
-
140
- sleep 1
141
-
142
- json_line = read_json_log(line: 2)
143
-
144
- expect(json_line['_duration']).to be < 500
145
- end
146
- end
147
- end