loga 2.6.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c431f4c2be4360f29975cc8434c86647c77cf8a375bcd8fa6e6a0b47bb8a2e8
4
- data.tar.gz: 2ec1e76ed48281e99acca8bdc3dd55b3fb6068dee599dd5c4bf92008e1af6eb0
3
+ metadata.gz: dc1346e981871beb7504038280a989df0b08f8758de0aafbc2ad6353bf15b37b
4
+ data.tar.gz: 7cca9a16fd0d79616445d8b497d28064b4e62c5b9ec075594787e069020d031c
5
5
  SHA512:
6
- metadata.gz: 5c09402cb2b8f7e90bb53ccba07df43c759a9d4cea9cd5a19f8fbfcf332b0ce7914dca1d3c085cd43d9d081e40cc2c4d18452bd5c6b44d10e1df2771c7a88146
7
- data.tar.gz: f9f937d8e0a600c05ca50e60c05b084d6756b76158f2b4dcfc7a070ee30ad535ef2df6f0c10d6f61a99152ec2fa2cdb1815b450ce600e4be72e51e797d1165b6
6
+ metadata.gz: 9b644025cbf6f8ff20b5980d8c261146a3832b2ea0e18eec3efabd1c8d7fbb75b540591fe5eb480a3475c8e646a85fd274a2352c9ed95baebf84ec01c29c8a8b
7
+ data.tar.gz: 5b5b9ae15e5383bb6b8b48e2a990b340134c2e77391fef261a275ae47e41b95538a9ba95553820d335634bdd8cbd1530f839bae8dade08b8bfd57af18dfd15aa
data/.circleci/config.yml CHANGED
@@ -30,10 +30,6 @@ test_build: &test_build
30
30
 
31
31
  version: 2
32
32
  jobs:
33
- ruby-2.4:
34
- docker:
35
- - image: circleci/ruby:2.4
36
- <<: *test_build
37
33
  ruby-2.5:
38
34
  docker:
39
35
  - image: circleci/ruby:2.5
@@ -45,10 +41,12 @@ jobs:
45
41
  ruby-2.7:
46
42
  docker:
47
43
  - image: cimg/ruby:2.7
44
+ - image: redis:7
48
45
  <<: *test_build
49
46
  ruby-3.0:
50
47
  docker:
51
48
  - image: cimg/ruby:3.0
49
+ - image: redis:7
52
50
  <<: *test_build
53
51
  rubocop:
54
52
  <<: *basic_build
@@ -83,10 +81,6 @@ workflows:
83
81
  filters:
84
82
  tags:
85
83
  only: /.*/
86
- - ruby-2.4:
87
- filters:
88
- tags:
89
- only: /.*/
90
84
  - ruby-2.5:
91
85
  filters:
92
86
  tags:
@@ -112,7 +106,6 @@ workflows:
112
106
  ignore: /.*/
113
107
  requires:
114
108
  - rubocop
115
- - ruby-2.4
116
109
  - ruby-2.5
117
110
  - ruby-2.6
118
111
  - ruby-2.7
data/Appraisals CHANGED
@@ -1,13 +1,3 @@
1
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
2
- appraise 'rails32' do
3
- gem 'rails', '~> 3.2.0'
4
- end
5
-
6
- appraise 'rails40' do
7
- gem 'rails', '~> 4.0.0'
8
- end
9
- end
10
-
11
1
  if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7.0')
12
2
  appraise 'rails42' do
13
3
  gem 'rails', '~> 4.2.0'
@@ -31,13 +21,29 @@ if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('2.5.0')
31
21
  gem 'rails', '~> 6.0.0'
32
22
  end
33
23
 
34
- appraise 'sidekiq6' do
35
- gem 'sidekiq', '~> 6.0'
24
+ appraise 'sidekiq60' do
25
+ gem 'sidekiq', '~> 6.0.0'
36
26
  end
37
27
 
38
28
  appraise 'sidekiq61' do
39
29
  gem 'sidekiq', '~> 6.1.0'
40
30
  end
31
+
32
+ appraise 'sidekiq62' do
33
+ gem 'sidekiq', '~> 6.2.0'
34
+ end
35
+
36
+ appraise 'sidekiq63' do
37
+ gem 'sidekiq', '~> 6.3.0'
38
+ end
39
+
40
+ appraise 'sidekiq64' do
41
+ gem 'sidekiq', '~> 6.4.0'
42
+ end
43
+
44
+ appraise 'sidekiq65' do
45
+ gem 'sidekiq', '~> 6.5.0'
46
+ end
41
47
  end
42
48
 
43
49
  if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('2.7.0')
@@ -48,6 +54,18 @@ if Gem::Version.new(RUBY_VERSION) > Gem::Version.new('2.7.0')
48
54
  appraise 'rails70' do
49
55
  gem 'rails', '~> 7.0.0'
50
56
  end
57
+
58
+ appraise 'sidekiq7' do
59
+ gem 'sidekiq', '~> 7.0'
60
+ end
61
+
62
+ appraise 'sidekiq70' do
63
+ gem 'sidekiq', '~> 7.0.0'
64
+ end
65
+
66
+ appraise 'sidekiq71' do
67
+ gem 'sidekiq', '~> 7.1.0'
68
+ end
51
69
  end
52
70
 
53
71
  appraise 'sidekiq51' do
data/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [2.8.0] - 2023-11-14
8
+ ### Added
9
+ - Support open-telemetry and add trace_id and span_id to logs events
10
+
11
+ ## [2.7.0] - 2023-03-28
12
+ ### Added
13
+ - Support for sidekiq 7
14
+
7
15
  ## [2.6.1] - 2022-02-22
8
16
  ### Fixed
9
17
  - Fix compatibility with sidekiq 6.4.1
data/README.md CHANGED
@@ -150,7 +150,7 @@ LOGA_FORMAT=simple rackup
150
150
 
151
151
  ### Sidekiq
152
152
 
153
- Loga `2.3` provides an out-of-the-box support for `Sidekiq ~> 5.0`.
153
+ Loga `2.7` provides an out-of-the-box support for `Sidekiq ~> 7.0`.
154
154
 
155
155
  ## Output Example
156
156
 
@@ -2,10 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 3.2.0"
5
+ gem "sidekiq", "~> 6.0.0"
6
6
 
7
7
  group :test do
8
- gem "simplecov"
8
+ gem "simplecov", "~> 0.17.0"
9
9
  end
10
10
 
11
11
  gemspec path: "../"
@@ -2,10 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 4.0.0"
5
+ gem "sidekiq", "~> 6.2.0"
6
6
 
7
7
  group :test do
8
- gem "simplecov"
8
+ gem "simplecov", "~> 0.17.0"
9
9
  end
10
10
 
11
11
  gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 6.3.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 6.4.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 6.5.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sidekiq", "~> 6.0"
5
+ gem "sidekiq", "~> 7.0"
6
6
 
7
7
  group :test do
8
8
  gem "simplecov", "~> 0.17.0"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 7.0.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -0,0 +1,11 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "sidekiq", "~> 7.1.0"
6
+
7
+ group :test do
8
+ gem "simplecov", "~> 0.17.0"
9
+ end
10
+
11
+ gemspec path: "../"
@@ -39,12 +39,7 @@ module Loga
39
39
  private
40
40
 
41
41
  def build_event(time, message)
42
- event = case message
43
- when Loga::Event
44
- message
45
- else
46
- Loga::Event.new(message: message)
47
- end
42
+ event = message.is_a?(Loga::Event) ? message : Loga::Event.new(message: message)
48
43
 
49
44
  event.timestamp ||= time
50
45
  # Overwrite sidekiq_context data anything manually specified
@@ -54,6 +49,7 @@ module Loga
54
49
  hash.merge! compute_type(event.type)
55
50
  # Overwrite hash with Loga's additional fields
56
51
  hash.merge! loga_additional_fields
52
+ hash.merge! open_telemetry_fields
57
53
  end
58
54
  event
59
55
  end
@@ -103,6 +99,17 @@ module Loga
103
99
  }
104
100
  end
105
101
 
102
+ def open_telemetry_fields
103
+ return {} unless defined?(::OpenTelemetry::Trace)
104
+
105
+ span = ::OpenTelemetry::Trace.current_span
106
+
107
+ {
108
+ trace_id: span.context.hex_trace_id,
109
+ span_id: span.context.hex_span_id,
110
+ }
111
+ end
112
+
106
113
  def sidekiq_context
107
114
  return {} unless defined?(::Sidekiq::Context)
108
115
 
data/lib/loga/sidekiq.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Loga
2
4
  module Sidekiq
3
5
  def self.configure_logging
@@ -5,20 +7,41 @@ module Loga
5
7
  return if Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('5.0')
6
8
 
7
9
  if Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('6.0')
8
- require 'loga/sidekiq5/job_logger'
9
-
10
- ::Sidekiq.configure_server do |config|
11
- config.options[:job_logger] = Loga::Sidekiq5::JobLogger
12
- end
10
+ configure_for_sidekiq5
13
11
  elsif Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('7.0')
14
- require 'loga/sidekiq6/job_logger'
12
+ configure_for_sidekiq6
13
+ elsif Gem::Version.new(::Sidekiq::VERSION) < Gem::Version.new('8.0')
14
+ configure_for_sidekiq7
15
+ end
16
+ end
15
17
 
16
- ::Sidekiq.configure_server do |config|
17
- config.options[:job_logger] = Loga::Sidekiq6::JobLogger
18
- end
18
+ def self.configure_for_sidekiq5
19
+ require 'loga/sidekiq5/job_logger'
20
+
21
+ ::Sidekiq.configure_server do |config|
22
+ config.options[:job_logger] = Loga::Sidekiq5::JobLogger
19
23
  end
20
24
 
21
25
  ::Sidekiq.logger = Loga.configuration.logger
22
26
  end
27
+
28
+ def self.configure_for_sidekiq6
29
+ require 'loga/sidekiq6/job_logger'
30
+
31
+ ::Sidekiq.configure_server do |config|
32
+ config.options[:job_logger] = Loga::Sidekiq6::JobLogger
33
+ end
34
+
35
+ ::Sidekiq.logger = Loga.configuration.logger
36
+ end
37
+
38
+ def self.configure_for_sidekiq7
39
+ require 'loga/sidekiq7/job_logger'
40
+
41
+ ::Sidekiq.configure_server do |config|
42
+ config[:job_logger] = Loga::Sidekiq7::JobLogger
43
+ config.logger = Loga.configuration.logger
44
+ end
45
+ end
23
46
  end
24
47
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sidekiq/job_logger'
4
+
5
+ module Loga
6
+ module Sidekiq7
7
+ class JobLogger < ::Sidekiq::JobLogger
8
+ EVENT_TYPE = 'sidekiq'.freeze
9
+
10
+ def call(item, _queue)
11
+ start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
12
+
13
+ yield
14
+
15
+ ::Sidekiq::Context.add(:elapsed, elapsed(start))
16
+
17
+ loga_log(message: "#{item['class']} with jid: '#{item['jid']}' done", item: item)
18
+ rescue Exception => e # rubocop:disable Lint/RescueException
19
+ ::Sidekiq::Context.add(:elapsed, elapsed(start))
20
+
21
+ loga_log(
22
+ message: "#{item['class']} with jid: '#{item['jid']}' fail", item: item,
23
+ exception: e
24
+ )
25
+
26
+ raise
27
+ end
28
+
29
+ private
30
+
31
+ def loga_log(message:, item:, exception: nil)
32
+ data = item.select do |k, _v|
33
+ %w[created_at enqueued_at jid queue retry
34
+ class].include? k
35
+ end
36
+
37
+ data['params'] = item['args']
38
+
39
+ data['exception'] = exception if exception
40
+
41
+ event = Event.new(type: EVENT_TYPE, message: message, data: data)
42
+
43
+ if exception
44
+ @logger.warn(event)
45
+ else
46
+ @logger.info(event)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
data/lib/loga/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Loga
2
- VERSION = '2.6.1'.freeze
2
+ VERSION = '2.8.0'.freeze
3
3
  end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'timecop'
5
+ require 'fakeredis'
6
+
7
+ dummy_redis_config = ConnectionPool.new(size: 5) { Redis.new }
8
+
9
+ Sidekiq.configure_client do |config|
10
+ config.redis = dummy_redis_config
11
+ end
12
+
13
+ Sidekiq.configure_server do |config|
14
+ config.redis = dummy_redis_config
15
+ end
16
+
17
+ class MySidekiqWorker
18
+ include Sidekiq::Worker
19
+
20
+ def perform(_name)
21
+ logger.info('Hello from MySidekiqWorker')
22
+ end
23
+ end
24
+
25
+ describe 'Sidekiq client logger' do
26
+ let(:mgr) do
27
+ # https://github.com/mperham/sidekiq/blob/v6.0.0/test/test_actors.rb#L57:79
28
+ Class.new do
29
+ attr_reader :latest_error
30
+ attr_reader :mutex
31
+ attr_reader :cond
32
+
33
+ def initialize
34
+ @mutex = ::Mutex.new
35
+ @cond = ::ConditionVariable.new
36
+ end
37
+
38
+ def processor_died(_inst, err)
39
+ @latest_error = err
40
+ @mutex.synchronize do
41
+ @cond.signal
42
+ end
43
+ end
44
+
45
+ def processor_stopped(_inst)
46
+ @mutex.synchronize do
47
+ @cond.signal
48
+ end
49
+ end
50
+
51
+ def options
52
+ {
53
+ concurrency: 3,
54
+ job_logger: Loga::Sidekiq6::JobLogger,
55
+ queues: ['default'],
56
+ }
57
+ end
58
+ end
59
+ end
60
+
61
+ let(:target) { StringIO.new }
62
+
63
+ def read_json_log(line:)
64
+ target.rewind
65
+ JSON.parse(target.each_line.drop(line - 1).first)
66
+ end
67
+
68
+ def dump_log
69
+ offset = target.pos
70
+
71
+ target.rewind
72
+ target.each_line { puts _1 }
73
+
74
+ target.pos = offset
75
+ end
76
+
77
+ before do
78
+ Redis.current.flushall
79
+
80
+ Loga.reset
81
+
82
+ Loga.configure(
83
+ service_name: 'hello_world_app',
84
+ service_version: '1.0',
85
+ device: target,
86
+ format: :gelf,
87
+ )
88
+ end
89
+
90
+ it 'has the proper job logger' do
91
+ expect(Sidekiq.options[:job_logger]).to eq Loga::Sidekiq6::JobLogger
92
+ end
93
+
94
+ it 'has the proper logger for Sidekiq.logger' do
95
+ expect(Sidekiq.logger).to eq Loga.logger
96
+ end
97
+
98
+ it 'pushes a new element in the default queue' do
99
+ MySidekiqWorker.perform_async('Bob')
100
+
101
+ last_element = JSON.parse(Redis.current.lpop('queue:default'))
102
+
103
+ aggregate_failures do
104
+ expect(last_element['class']).to eq 'MySidekiqWorker'
105
+ expect(last_element['args']).to eq ['Bob']
106
+ expect(last_element['retry']).to eq true
107
+ expect(last_element['queue']).to eq 'default'
108
+ end
109
+ end
110
+
111
+ def test_log_from_worker(json_line)
112
+ aggregate_failures do
113
+ expect(json_line).to include(
114
+ '_class' => 'MySidekiqWorker',
115
+ '_service.name' => 'hello_world_app',
116
+ '_service.version' => '1.0',
117
+ '_tags' => '',
118
+ 'level' => 6,
119
+ 'version' => '1.1',
120
+ 'short_message' => 'Hello from MySidekiqWorker',
121
+ )
122
+
123
+ %w[_jid timestamp host].each do |key|
124
+ expect(json_line).to have_key(key)
125
+ end
126
+
127
+ expect(json_line).not_to include('_duration')
128
+ end
129
+ end
130
+
131
+ def test_job_end_log(json_line) # rubocop:disable Metrics/MethodLength
132
+ aggregate_failures do
133
+ expect(json_line).to include(
134
+ '_queue' => 'default',
135
+ '_retry' => true,
136
+ '_params' => ['Bob'],
137
+ '_class' => 'MySidekiqWorker',
138
+ '_type' => 'sidekiq',
139
+ '_service.name' => 'hello_world_app',
140
+ '_service.version' => '1.0',
141
+ '_tags' => '',
142
+ 'level' => 6,
143
+ 'version' => '1.1',
144
+ )
145
+
146
+ %w[_created_at _enqueued_at _jid _duration timestamp host].each do |key|
147
+ expect(json_line).to have_key(key)
148
+ end
149
+
150
+ expect(json_line['_duration']).to be < 500
151
+ expect(json_line['short_message']).to match(/MySidekiqWorker with jid:*/)
152
+ end
153
+ end
154
+
155
+ it 'logs the job processing event' do
156
+ MySidekiqWorker.perform_async('Bob')
157
+
158
+ require 'sidekiq/processor'
159
+
160
+ Sidekiq::Processor.new(mgr.new).start
161
+
162
+ sleep 0.5
163
+
164
+ test_log_from_worker(read_json_log(line: 1))
165
+ test_job_end_log(read_json_log(line: 2))
166
+
167
+ # This was a bug - the duration was constantly incresing based on when
168
+ # the logger was created. https://github.com/FundingCircle/loga/pull/117
169
+ #
170
+ # Test that after sleeping for few seconds the duration is still under 500ms
171
+ sleep 1
172
+
173
+ MySidekiqWorker.perform_async('Bob')
174
+
175
+ sleep 1
176
+
177
+ test_log_from_worker(read_json_log(line: 3))
178
+ test_job_end_log(read_json_log(line: 4))
179
+ end
180
+ end