loga 2.5.1 → 2.6.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.
@@ -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
@@ -69,9 +74,31 @@ describe Loga::Rack::Logger do
69
74
 
70
75
  context 'when an exception is raised' do
71
76
  let(:app) { ->(_env) { raise exception_class } }
72
-
73
- it 'does not rescue the exception' do
74
- expect { subject.call(env) }.to raise_error(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
+ )
75
102
  end
76
103
  end
77
104
 
@@ -113,28 +140,21 @@ describe Loga::Rack::Logger do
113
140
  end
114
141
 
115
142
  context 'when the logger is tagged' do
116
- let(:logger) { double(:logger, tagged: true) }
117
-
118
- before do
119
- allow(subject).to receive(:call_app).with(any_args).and_return(:response)
120
- allow(subject).to receive(:compute_tags).with(any_args).and_return(:tag)
121
- allow(logger).to receive(:tagged).with('hello') do |&block|
122
- block.call
123
- end
124
- 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
125
149
 
126
- context 'when tags are present' do
127
- let(:tags) { [:foo] }
150
+ it 'calls the tags and computes them' do
151
+ middleware.call(env)
128
152
 
129
- it 'yields the app with tags' do
130
- allow(logger).to receive(:tagged)
131
- subject.call(env)
132
- expect(logger).to have_received(:tagged).with(:tag) do |&block|
133
- expect(block.call).to eq(:response)
134
- end
135
- end
153
+ expect(fake_tag_proc)
154
+ .to have_received(:call)
155
+ .with(instance_of(Loga::Rack::Request))
136
156
  end
137
157
  end
138
158
  end
139
159
  end
140
- # 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.5.1
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Funding Circle
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-02 00:00:00.000000000 Z
11
+ date: 2021-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -44,26 +44,26 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.2.0
47
+ version: '2.4'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.2.0
54
+ version: '2.4'
55
55
  - !ruby/object:Gem::Dependency
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
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 4.7.3
103
+ version: '4.7'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 4.7.3
110
+ version: '4.7'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: guard-rubocop
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: 3.7.0
187
+ version: '3.7'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: 3.7.0
194
+ version: '3.7'
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: rubocop
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -260,7 +260,10 @@ files:
260
260
  - gemfiles/rails50.gemfile
261
261
  - gemfiles/rails52.gemfile
262
262
  - gemfiles/rails60.gemfile
263
+ - gemfiles/rails61.gemfile
264
+ - gemfiles/rails70.gemfile
263
265
  - gemfiles/sidekiq51.gemfile
266
+ - gemfiles/sidekiq6.gemfile
264
267
  - gemfiles/sinatra14.gemfile
265
268
  - gemfiles/unit.gemfile
266
269
  - lib/loga.rb
@@ -280,7 +283,8 @@ files:
280
283
  - lib/loga/railtie.rb
281
284
  - lib/loga/service_version_strategies.rb
282
285
  - lib/loga/sidekiq.rb
283
- - lib/loga/sidekiq/job_logger.rb
286
+ - lib/loga/sidekiq5/job_logger.rb
287
+ - lib/loga/sidekiq6/job_logger.rb
284
288
  - lib/loga/tagged_logging.rb
285
289
  - lib/loga/utilities.rb
286
290
  - lib/loga/version.rb
@@ -292,13 +296,17 @@ files:
292
296
  - spec/fixtures/rails50.rb
293
297
  - spec/fixtures/rails52.rb
294
298
  - spec/fixtures/rails60.rb
299
+ - spec/fixtures/rails61.rb
300
+ - spec/fixtures/rails70.rb
295
301
  - spec/fixtures/random_bin
296
302
  - spec/integration/rails/action_mailer_spec.rb
297
303
  - spec/integration/rails/railtie_spec.rb
298
304
  - spec/integration/rails/request_spec.rb
299
- - spec/integration/sidekiq_spec.rb
305
+ - spec/integration/sidekiq5_spec.rb
306
+ - spec/integration/sidekiq6_spec.rb
300
307
  - spec/integration/sinatra_spec.rb
301
- - spec/loga/sidekiq/job_logger_spec.rb
308
+ - spec/loga/sidekiq5/job_logger_spec.rb
309
+ - spec/loga/sidekiq6/job_logger_spec.rb
302
310
  - spec/loga/sidekiq_spec.rb
303
311
  - spec/spec_helper.rb
304
312
  - spec/support/gethostname_shared.rb
@@ -335,8 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
335
343
  - !ruby/object:Gem::Version
336
344
  version: '0'
337
345
  requirements: []
338
- rubyforge_project:
339
- rubygems_version: 2.7.7
346
+ rubygems_version: 3.2.32
340
347
  signing_key:
341
348
  specification_version: 4
342
349
  summary: Facilitate log aggregation via unified logging
@@ -348,13 +355,17 @@ test_files:
348
355
  - spec/fixtures/rails50.rb
349
356
  - spec/fixtures/rails52.rb
350
357
  - spec/fixtures/rails60.rb
358
+ - spec/fixtures/rails61.rb
359
+ - spec/fixtures/rails70.rb
351
360
  - spec/fixtures/random_bin
352
361
  - spec/integration/rails/action_mailer_spec.rb
353
362
  - spec/integration/rails/railtie_spec.rb
354
363
  - spec/integration/rails/request_spec.rb
355
- - spec/integration/sidekiq_spec.rb
364
+ - spec/integration/sidekiq5_spec.rb
365
+ - spec/integration/sidekiq6_spec.rb
356
366
  - spec/integration/sinatra_spec.rb
357
- - spec/loga/sidekiq/job_logger_spec.rb
367
+ - spec/loga/sidekiq5/job_logger_spec.rb
368
+ - spec/loga/sidekiq6/job_logger_spec.rb
358
369
  - spec/loga/sidekiq_spec.rb
359
370
  - spec/spec_helper.rb
360
371
  - 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