rails_semantic_logger 4.20.0 → 5.1.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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -98
  3. data/Rakefile +9 -4
  4. data/lib/rails_semantic_logger/action_controller/log_subscriber.rb +87 -16
  5. data/lib/rails_semantic_logger/action_mailer/log_subscriber.rb +36 -22
  6. data/lib/rails_semantic_logger/action_view/log_subscriber.rb +76 -42
  7. data/lib/rails_semantic_logger/active_job/log_subscriber.rb +216 -7
  8. data/lib/rails_semantic_logger/active_record/log_subscriber.rb +62 -160
  9. data/lib/rails_semantic_logger/appenders.rb +92 -0
  10. data/lib/rails_semantic_logger/engine.rb +68 -57
  11. data/lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb +61 -3
  12. data/lib/rails_semantic_logger/extensions/action_dispatch/debug_exceptions.rb +5 -14
  13. data/lib/rails_semantic_logger/extensions/active_job/logging.rb +2 -2
  14. data/lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb +2 -2
  15. data/lib/rails_semantic_logger/extensions/active_support/logger.rb +24 -15
  16. data/lib/rails_semantic_logger/extensions/rails/server.rb +1 -1
  17. data/lib/rails_semantic_logger/options.rb +171 -20
  18. data/lib/rails_semantic_logger/rack/logger.rb +6 -13
  19. data/lib/rails_semantic_logger/sidekiq/defaults.rb +12 -27
  20. data/lib/rails_semantic_logger/sidekiq/job_logger.rb +29 -9
  21. data/lib/rails_semantic_logger/solid_queue/log_subscriber.rb +183 -0
  22. data/lib/rails_semantic_logger/version.rb +1 -1
  23. data/lib/rails_semantic_logger.rb +82 -27
  24. metadata +16 -22
  25. data/lib/rails_semantic_logger/delayed_job/plugin.rb +0 -11
  26. data/lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb +0 -13
  27. data/lib/rails_semantic_logger/extensions/rack/server.rb +0 -12
  28. data/lib/rails_semantic_logger/extensions/rackup/server.rb +0 -12
  29. data/lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb +0 -87
@@ -0,0 +1,183 @@
1
+ module RailsSemanticLogger
2
+ module SolidQueue
3
+ class LogSubscriber < ::ActiveSupport::LogSubscriber
4
+ def dispatch_scheduled(event)
5
+ log_event(event, :debug, "Dispatch scheduled jobs", **event.payload.slice(:batch_size, :size))
6
+ end
7
+
8
+ def claim(event)
9
+ log_event(event, :debug, "Claim jobs", **event.payload.slice(:process_id, :job_ids, :claimed_job_ids, :size))
10
+ end
11
+
12
+ def release_many_claimed(event)
13
+ log_event(event, :info, "Release claimed jobs", **event.payload.slice(:size))
14
+ end
15
+
16
+ def fail_many_claimed(event)
17
+ log_event(event, :warn, "Fail claimed jobs", **event.payload.slice(:job_ids, :process_ids))
18
+ end
19
+
20
+ def release_claimed(event)
21
+ log_event(event, :info, "Release claimed job", **event.payload.slice(:job_id, :process_id))
22
+ end
23
+
24
+ def retry_all(event)
25
+ log_event(event, :debug, "Retry failed jobs", **event.payload.slice(:jobs_size, :size))
26
+ end
27
+
28
+ def retry(event)
29
+ log_event(event, :debug, "Retry failed job", **event.payload.slice(:job_id))
30
+ end
31
+
32
+ def discard_all(event)
33
+ log_event(event, :debug, "Discard jobs", **event.payload.slice(:jobs_size, :size, :status))
34
+ end
35
+
36
+ def discard(event)
37
+ log_event(event, :debug, "Discard job", **event.payload.slice(:job_id, :status))
38
+ end
39
+
40
+ def release_many_blocked(event)
41
+ log_event(event, :debug, "Unblock jobs", **event.payload.slice(:limit, :size))
42
+ end
43
+
44
+ def release_blocked(event)
45
+ log_event(event, :debug, "Release blocked job", **event.payload.slice(:job_id, :concurrency_key, :released))
46
+ end
47
+
48
+ def enqueue_recurring_task(event)
49
+ attributes = event.payload.slice(:task, :active_job_id, :enqueue_error)
50
+ attributes[:at] = event.payload[:at]&.iso8601
51
+
52
+ if attributes[:active_job_id].nil? && event.payload[:skipped].nil?
53
+ log_event(event, :error, "Error enqueuing recurring task", **attributes)
54
+ elsif event.payload[:other_adapter]
55
+ log_event(event, :debug, "Enqueued recurring task outside Solid Queue", **attributes)
56
+ else
57
+ action = if event.payload[:skipped].present?
58
+ "Skipped recurring task – already dispatched"
59
+ else
60
+ "Enqueued recurring task"
61
+ end
62
+ log_event(event, :debug, action, **attributes)
63
+ end
64
+ end
65
+
66
+ def start_process(event)
67
+ process = event.payload[:process]
68
+ attributes = process_attributes(process).merge(process.metadata)
69
+
70
+ log_event(event, :info, "Started #{process.kind}", **attributes)
71
+ end
72
+
73
+ def shutdown_process(event)
74
+ process = event.payload[:process]
75
+ attributes = process_attributes(process).merge(process.metadata)
76
+
77
+ log_event(event, :info, "Shutdown #{process.kind}", **attributes)
78
+ end
79
+
80
+ def register_process(event)
81
+ process_kind = event.payload[:kind]
82
+ attributes = event.payload.slice(:pid, :hostname, :process_id, :name)
83
+
84
+ if (error = event.payload[:error])
85
+ log_event(event, :warn, "Error registering #{process_kind}", exception: error, **attributes)
86
+ else
87
+ log_event(event, :debug, "Register #{process_kind}", **attributes)
88
+ end
89
+ end
90
+
91
+ def deregister_process(event)
92
+ process = event.payload[:process]
93
+ attributes = {
94
+ process_id: process.id,
95
+ pid: process.pid,
96
+ hostname: process.hostname,
97
+ name: process.name,
98
+ last_heartbeat_at: process.last_heartbeat_at.iso8601,
99
+ claimed_size: event.payload[:claimed_size],
100
+ pruned: event.payload[:pruned]
101
+ }
102
+
103
+ if (error = event.payload[:error])
104
+ log_event(event, :warn, "Error deregistering #{process.kind}", exception: error, **attributes)
105
+ else
106
+ log_event(event, :debug, "Deregister #{process.kind}", **attributes)
107
+ end
108
+ end
109
+
110
+ def prune_processes(event)
111
+ log_event(event, :debug, "Prune dead processes", **event.payload.slice(:size))
112
+ end
113
+
114
+ def thread_error(event)
115
+ log_event(event, :error, "Error in thread", exception: event.payload[:error])
116
+ end
117
+
118
+ def graceful_termination(event)
119
+ attributes = event.payload.slice(:process_id, :supervisor_pid, :supervised_processes)
120
+
121
+ if event.payload[:shutdown_timeout_exceeded]
122
+ log_event(event, :warn, "Supervisor wasn't terminated gracefully - shutdown timeout exceeded", **attributes)
123
+ else
124
+ log_event(event, :info, "Supervisor terminated gracefully", **attributes)
125
+ end
126
+ end
127
+
128
+ def immediate_termination(event)
129
+ log_event(event, :info, "Supervisor terminated immediately",
130
+ **event.payload.slice(:process_id, :supervisor_pid, :supervised_processes))
131
+ end
132
+
133
+ def unhandled_signal_error(event)
134
+ log_event(event, :error, "Received unhandled signal", **event.payload.slice(:signal))
135
+ end
136
+
137
+ def replace_fork(event)
138
+ supervisor_pid = event.payload[:supervisor_pid]
139
+ status = event.payload[:status]
140
+ attributes = event.payload.slice(:pid).merge(
141
+ status: status.exitstatus || "no exit status set",
142
+ pid_from_status: status.pid,
143
+ signaled: status.signaled?,
144
+ stopsig: status.stopsig,
145
+ termsig: status.termsig
146
+ )
147
+
148
+ if (replaced_fork = event.payload[:fork])
149
+ log_event(event, :info, "Replaced terminated #{replaced_fork.kind}",
150
+ **attributes, hostname: replaced_fork.hostname, name: replaced_fork.name)
151
+ elsif supervisor_pid != 1 # Running Docker, possibly having some processes that have been reparented
152
+ log_event(event, :warn, "Tried to replace forked process but it had already died", **attributes)
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def process_attributes(process)
159
+ {
160
+ pid: process.pid,
161
+ hostname: process.hostname,
162
+ process_id: process.process_id,
163
+ name: process.name
164
+ }
165
+ end
166
+
167
+ def log_event(event, level, action, exception: nil, **attributes)
168
+ logger.public_send(level) do
169
+ msg = {message: action, payload: attributes, duration: event.duration}
170
+ msg[:exception] = exception if exception
171
+ # Emit a metric for every info/warn/error entry, named after the notification
172
+ # (e.g. "start_process.solid_queue" -> "rails.solid_queue.start_process"). Debug entries are excluded.
173
+ msg[:metric] = "rails.solid_queue.#{event.name.split('.').first}" unless level == :debug
174
+ msg
175
+ end
176
+ end
177
+
178
+ def logger
179
+ @logger ||= SemanticLogger[::SolidQueue]
180
+ end
181
+ end
182
+ end
183
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsSemanticLogger
2
- VERSION = "4.20.0".freeze
2
+ VERSION = "5.1.0".freeze
3
3
  end
@@ -27,21 +27,96 @@ module RailsSemanticLogger
27
27
  autoload :Logger, "rails_semantic_logger/rack/logger"
28
28
  end
29
29
 
30
- module DelayedJob
31
- autoload :Plugin, "rails_semantic_logger/delayed_job/plugin"
32
- end
33
-
34
30
  module Sidekiq
35
31
  autoload :Defaults, "rails_semantic_logger/sidekiq/defaults"
36
32
  autoload :JobLogger, "rails_semantic_logger/sidekiq/job_logger"
37
33
  autoload :Loggable, "rails_semantic_logger/sidekiq/loggable"
38
34
  end
39
35
 
36
+ module SolidQueue
37
+ autoload :LogSubscriber, "rails_semantic_logger/solid_queue/log_subscriber"
38
+ end
39
+
40
+ autoload :Appenders, "rails_semantic_logger/appenders"
40
41
  autoload :Options, "rails_semantic_logger/options"
41
42
 
43
+ # Deprecator used for options that are being phased out in favor of declaring
44
+ # appenders directly (see RailsSemanticLogger::Appenders).
45
+ def self.deprecator
46
+ @deprecator ||= ActiveSupport::Deprecation.new("6.0", "rails_semantic_logger")
47
+ end
48
+
49
+ # Warn that a setting was changed too late to take effect, so the change has no
50
+ # effect. When `config_initializers_too_late` is true (the default), the setting
51
+ # is consumed while the logger is built, *before* `config/initializers/*` is
52
+ # loaded, so that location is called out as too late. When false, the setting is
53
+ # consumed at the end of initialization (`config/initializers/*` still works) and
54
+ # only a change after the application has booted is too late.
55
+ def self.warn_initialized_too_late(setting, config_initializers_too_late: true)
56
+ env = defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : "<env>"
57
+ locations = "`config/application.rb` or `config/environments/#{env}.rb`"
58
+ locations += " (or a `config/initializers/*` file)" unless config_initializers_too_late
59
+ suffix = config_initializers_too_late ? "; `config/initializers/*` is loaded too late." : "."
60
+ warn(
61
+ "[rails_semantic_logger] `config.rails_semantic_logger.#{setting}` was set too late to take " \
62
+ "effect, so it has no effect. Set it in #{locations}#{suffix}"
63
+ )
64
+ end
65
+
66
+ # Create the appenders declared via `config.rails_semantic_logger.appenders` with
67
+ # `add_server` (or the default console appender when the application declared no
68
+ # appenders of its own).
69
+ #
70
+ # Called automatically for the server contexts that have a first-party hook
71
+ # (`rails server`, Sidekiq in server mode). App servers without such a hook (bare
72
+ # puma, rackup, Passenger, Unicorn) cannot be detected reliably, so call this from
73
+ # the server's own definitive boot hook instead of relying on a guess. Example,
74
+ # in `config/puma.rb`:
75
+ #
76
+ # on_booted { RailsSemanticLogger.add_server_appenders }
77
+ def self.add_server_appenders
78
+ options = Rails.application.config.rails_semantic_logger
79
+ # Backward compatibility
80
+ if !options.appenders? && options.console_logger && !SemanticLogger.appenders.console_output?
81
+ SemanticLogger.add_appender(io: $stdout, formatter: :color)
82
+ end
83
+
84
+ options.appenders.server.each do |args, block|
85
+ SemanticLogger.add_appender(**args, &block)
86
+ end
87
+ end
88
+
89
+ # Console (REPL) counterpart of .add_server_appenders, used by the `rails console`
90
+ # hook. When the application declared its own appenders, its `add_console`
91
+ # declarations apply; otherwise the deprecated `console_logger` toggle decides
92
+ # whether the default stderr console appender is added.
93
+ def self.add_console_appenders
94
+ options = Rails.application.config.rails_semantic_logger
95
+ # Backward compatibility: honor the deprecated console_logger toggle.
96
+ if !options.appenders? && options.console_logger && !SemanticLogger.appenders.console_output?
97
+ SemanticLogger.add_appender(io: $stderr, formatter: :color)
98
+ end
99
+
100
+ options.appenders.console.each do |args, block|
101
+ SemanticLogger.add_appender(**args, &block)
102
+ end
103
+ end
104
+
105
+ # Create each appender declared via `config.rails_semantic_logger.appenders`.
106
+ # The first file appender (if any) becomes the internal logger, so that any
107
+ # failures writing to other appenders are still recorded somewhere durable.
108
+ def self.add_appenders(appenders)
109
+ internal_logger = nil
110
+ appenders.each do |args, block|
111
+ appender = SemanticLogger.add_appender(**args, &block)
112
+ internal_logger ||= appender if appender.is_a?(SemanticLogger::Appender::File)
113
+ end
114
+ SemanticLogger::Processor.logger = internal_logger if internal_logger
115
+ end
116
+
42
117
  # Swap an existing subscriber with a new one
43
118
  def self.swap_subscriber(old_class, new_class, notifier)
44
- subscribers = ActiveSupport::LogSubscriber.subscribers.select { |s| s.is_a?(old_class) }
119
+ subscribers = ActiveSupport::LogSubscriber.subscribers.grep(old_class)
45
120
  subscribers.each { |subscriber| unattach(subscriber) }
46
121
 
47
122
  new_class.attach_to(notifier)
@@ -60,19 +135,11 @@ module RailsSemanticLogger
60
135
  end
61
136
 
62
137
  def self.subscriber_patterns(subscriber)
63
- if subscriber.patterns.respond_to?(:keys)
64
- subscriber.patterns.keys
65
- else
66
- subscriber.patterns
67
- end
138
+ subscriber.patterns.keys
68
139
  end
69
140
 
70
141
  def self.listeners_for(notifier, pattern)
71
- if notifier.respond_to?(:all_listeners_for) # Rails >= 7.1
72
- notifier.all_listeners_for(pattern)
73
- else
74
- notifier.listeners_for(pattern)
75
- end
142
+ notifier.all_listeners_for(pattern)
76
143
  end
77
144
 
78
145
  private_class_method :listeners_for, :subscriber_patterns, :unattach
@@ -80,15 +147,3 @@ end
80
147
 
81
148
  require("rails_semantic_logger/extensions/mongoid/config") if defined?(Mongoid)
82
149
  require("rails_semantic_logger/extensions/active_support/logger") if defined?(ActiveSupport::Logger)
83
- require("rails_semantic_logger/extensions/active_support/log_subscriber") if defined?(ActiveSupport::LogSubscriber)
84
-
85
- begin
86
- require "rackup"
87
- rescue LoadError
88
- # No need to do anything, will fall back to Rack
89
- end
90
- if defined?(Rackup::Server)
91
- require("rails_semantic_logger/extensions/rackup/server")
92
- elsif defined?(Rack::Server)
93
- require("rails_semantic_logger/extensions/rack/server")
94
- end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.20.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-04-10 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rack
@@ -30,30 +29,28 @@ dependencies:
30
29
  requirements:
31
30
  - - ">="
32
31
  - !ruby/object:Gem::Version
33
- version: '5.1'
32
+ version: '7.2'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - ">="
39
38
  - !ruby/object:Gem::Version
40
- version: '5.1'
39
+ version: '7.2'
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: semantic_logger
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
- - - "~>"
44
+ - - ">="
46
45
  - !ruby/object:Gem::Version
47
- version: '4.16'
46
+ version: '5.1'
48
47
  type: :runtime
49
48
  prerelease: false
50
49
  version_requirements: !ruby/object:Gem::Requirement
51
50
  requirements:
52
- - - "~>"
51
+ - - ">="
53
52
  - !ruby/object:Gem::Version
54
- version: '4.16'
55
- description:
56
- email:
53
+ version: '5.1'
57
54
  executables: []
58
55
  extensions: []
59
56
  extra_rdoc_files: []
@@ -67,7 +64,7 @@ files:
67
64
  - lib/rails_semantic_logger/action_view/log_subscriber.rb
68
65
  - lib/rails_semantic_logger/active_job/log_subscriber.rb
69
66
  - lib/rails_semantic_logger/active_record/log_subscriber.rb
70
- - lib/rails_semantic_logger/delayed_job/plugin.rb
67
+ - lib/rails_semantic_logger/appenders.rb
71
68
  - lib/rails_semantic_logger/engine.rb
72
69
  - lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb
73
70
  - lib/rails_semantic_logger/extensions/action_controller/live.rb
@@ -75,19 +72,16 @@ files:
75
72
  - lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb
76
73
  - lib/rails_semantic_logger/extensions/active_job/logging.rb
77
74
  - lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb
78
- - lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb
79
75
  - lib/rails_semantic_logger/extensions/active_support/logger.rb
80
76
  - lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb
81
77
  - lib/rails_semantic_logger/extensions/mongoid/config.rb
82
- - lib/rails_semantic_logger/extensions/rack/server.rb
83
- - lib/rails_semantic_logger/extensions/rackup/server.rb
84
78
  - lib/rails_semantic_logger/extensions/rails/server.rb
85
- - lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb
86
79
  - lib/rails_semantic_logger/options.rb
87
80
  - lib/rails_semantic_logger/rack/logger.rb
88
81
  - lib/rails_semantic_logger/sidekiq/defaults.rb
89
82
  - lib/rails_semantic_logger/sidekiq/job_logger.rb
90
83
  - lib/rails_semantic_logger/sidekiq/loggable.rb
84
+ - lib/rails_semantic_logger/solid_queue/log_subscriber.rb
91
85
  - lib/rails_semantic_logger/version.rb
92
86
  homepage: https://logger.rocketjob.io
93
87
  licenses:
@@ -95,9 +89,9 @@ licenses:
95
89
  metadata:
96
90
  bug_tracker_uri: https://github.com/reidmorrison/rails_semantic_logger/issues
97
91
  documentation_uri: https://logger.rocketjob.io
98
- source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/v4.20.0
92
+ source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/v5.1.0
93
+ changelog_uri: https://github.com/reidmorrison/rails_semantic_logger/blob/main/CHANGELOG.md
99
94
  rubygems_mfa_required: 'true'
100
- post_install_message:
101
95
  rdoc_options: []
102
96
  require_paths:
103
97
  - lib
@@ -105,15 +99,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
99
  requirements:
106
100
  - - ">="
107
101
  - !ruby/object:Gem::Version
108
- version: '2.5'
102
+ version: '3.2'
109
103
  required_rubygems_version: !ruby/object:Gem::Requirement
110
104
  requirements:
111
105
  - - ">="
112
106
  - !ruby/object:Gem::Version
113
107
  version: '0'
114
108
  requirements: []
115
- rubygems_version: 3.4.19
116
- signing_key:
109
+ rubygems_version: 3.6.9
117
110
  specification_version: 4
118
- summary: Feature rich logging framework that replaces the Rails logger.
111
+ summary: High-performance, asynchronous structured logging that replaces the Rails
112
+ logger.
119
113
  test_files: []
@@ -1,11 +0,0 @@
1
- module RailsSemanticLogger
2
- module DelayedJob
3
- class Plugin < Delayed::Plugin
4
- callbacks do |lifecycle|
5
- lifecycle.before(:execute) do |_job|
6
- ::SemanticLogger.reopen
7
- end
8
- end
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- if ActiveSupport::VERSION::STRING == "7.1.1"
2
- require "active_support/log_subscriber"
3
-
4
- module ActiveSupport
5
- class LogSubscriber
6
- # @override Rails 7.1
7
- def silenced?(event)
8
- native_log_level = @event_levels.fetch(event, ::Logger::Severity::FATAL)
9
- logger.nil? || SemanticLogger::Levels.index(logger.level) > SemanticLogger::Levels.index(native_log_level)
10
- end
11
- end
12
- end
13
- end
@@ -1,12 +0,0 @@
1
- module RailsSemanticLogger
2
- module Rack
3
- module Server
4
- def daemonize_app
5
- super
6
- SemanticLogger.reopen
7
- end
8
- end
9
- end
10
- end
11
-
12
- Rack::Server.prepend(RailsSemanticLogger::Rack::Server)
@@ -1,12 +0,0 @@
1
- module RailsSemanticLogger
2
- module Rackup
3
- module Server
4
- def daemonize_app
5
- super
6
- SemanticLogger.reopen
7
- end
8
- end
9
- end
10
- end
11
-
12
- Rackup::Server.prepend(RailsSemanticLogger::Rackup::Server)
@@ -1,87 +0,0 @@
1
- # Sidekiq patches
2
- if Sidekiq::VERSION.to_i == 4
3
- require "sidekiq/logging"
4
- require "sidekiq/middleware/server/logging"
5
- require "sidekiq/processor"
6
- elsif Sidekiq::VERSION.to_i == 5
7
- require "sidekiq/logging"
8
- end
9
-
10
- module Sidekiq
11
- # Sidekiq v4 & v5
12
- if defined?(::Sidekiq::Logging)
13
- # Replace Sidekiq logging context
14
- module Logging
15
- def self.with_context(msg, &block)
16
- SemanticLogger.tagged(msg, &block)
17
- end
18
-
19
- def self.job_hash_context(job_hash)
20
- h = {jid: job_hash["jid"]}
21
- h[:bid] = job_hash["bid"] if job_hash["bid"]
22
- h[:queue] = job_hash["queue"] if job_hash["queue"]
23
- h
24
- end
25
- end
26
- end
27
-
28
- # Sidekiq v4
29
- if defined?(::Sidekiq::Middleware::Server::Logging)
30
- # Convert string to machine readable format
31
- class Processor
32
- def log_context(job_hash)
33
- h = {jid: job_hash["jid"]}
34
- h[:bid] = job_hash["bid"] if job_hash["bid"]
35
- h[:queue] = job_hash["queue"] if job_hash["queue"]
36
- h
37
- end
38
- end
39
-
40
- # Let Semantic Logger handle duration logging
41
- module Middleware
42
- module Server
43
- class Logging
44
- # rubocop:disable Style/ExplicitBlockArgument
45
- def call(worker, item, queue)
46
- SemanticLogger.tagged(queue: queue) do
47
- if perform_messages_enabled?
48
- worker.logger.info(
49
- "Start #perform",
50
- metric: "sidekiq.queue.latency",
51
- metric_amount: job_latency_ms(item)
52
- )
53
-
54
- worker.logger.measure_info(
55
- "Completed #perform",
56
- on_exception_level: :error,
57
- log_exception: :full,
58
- metric: "sidekiq.job.perform"
59
- ) { yield }
60
- else
61
- yield
62
- end
63
- end
64
- end
65
-
66
- def perform_messages_enabled?
67
- RailsSemanticLogger::Sidekiq::JobLogger.perform_messages != false
68
- end
69
-
70
- def job_latency_ms(job)
71
- return unless job && job["enqueued_at"]
72
-
73
- enqueued_at = job["enqueued_at"]
74
- if enqueued_at.is_a?(Float)
75
- # Sidekiq <= 7: seconds since epoch
76
- (Time.now.to_f - enqueued_at) * 1000
77
- else
78
- # Sidekiq 8+: milliseconds since epoch
79
- now = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
80
- now - enqueued_at
81
- end
82
- end
83
- end
84
- end
85
- end
86
- end
87
- end