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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +17 -56
- data/Appraisals +26 -10
- data/CHANGELOG.md +20 -0
- data/Gemfile +1 -1
- data/Guardfile +1 -1
- data/README.md +1 -1
- data/gemfiles/rails60.gemfile +1 -1
- data/gemfiles/rails61.gemfile +11 -0
- data/gemfiles/rails70.gemfile +11 -0
- data/gemfiles/sidekiq51.gemfile +1 -1
- data/gemfiles/sidekiq6.gemfile +11 -0
- data/gemfiles/sinatra14.gemfile +1 -1
- data/gemfiles/unit.gemfile +1 -1
- data/lib/loga/configuration.rb +1 -0
- data/lib/loga/formatters/gelf_formatter.rb +16 -1
- data/lib/loga/rack/logger.rb +31 -44
- data/lib/loga/railtie.rb +1 -1
- data/lib/loga/sidekiq.rb +13 -5
- data/lib/loga/{sidekiq → sidekiq5}/job_logger.rb +1 -3
- data/lib/loga/sidekiq6/job_logger.rb +50 -0
- data/lib/loga/version.rb +1 -1
- data/loga.gemspec +4 -4
- data/spec/fixtures/rails61.rb +80 -0
- data/spec/fixtures/rails70.rb +80 -0
- data/spec/integration/sidekiq5_spec.rb +143 -0
- data/spec/integration/sidekiq6_spec.rb +164 -0
- data/spec/integration/sinatra_spec.rb +1 -1
- data/spec/loga/{sidekiq → sidekiq5}/job_logger_spec.rb +2 -1
- data/spec/loga/sidekiq6/job_logger_spec.rb +121 -0
- data/spec/loga/sidekiq_spec.rb +10 -3
- data/spec/spec_helper.rb +17 -8
- data/spec/unit/loga/formatters/gelf_formatter_spec.rb +43 -0
- data/spec/unit/loga/rack/logger_spec.rb +56 -36
- metadata +28 -17
- data/spec/integration/sidekiq_spec.rb +0 -147
@@ -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/
|
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
|
-
|
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
|
-
|
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' =>
|
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:
|
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
|
-
|
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
|
-
|
74
|
-
|
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) {
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
127
|
-
|
150
|
+
it 'calls the tags and computes them' do
|
151
|
+
middleware.call(env)
|
128
152
|
|
129
|
-
|
130
|
-
|
131
|
-
|
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/
|
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
|
+
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:
|
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.
|
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.
|
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
|
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
|
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
|
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
|
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/
|
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/
|
305
|
+
- spec/integration/sidekiq5_spec.rb
|
306
|
+
- spec/integration/sidekiq6_spec.rb
|
300
307
|
- spec/integration/sinatra_spec.rb
|
301
|
-
- spec/loga/
|
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
|
-
|
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/
|
364
|
+
- spec/integration/sidekiq5_spec.rb
|
365
|
+
- spec/integration/sidekiq6_spec.rb
|
356
366
|
- spec/integration/sinatra_spec.rb
|
357
|
-
- spec/loga/
|
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
|