rails_semantic_logger 5.0.0 → 5.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 213d85a11e285b1353549f41b8a8c28068a33d3913e270d72eed94f6ee1d861c
4
- data.tar.gz: 8233c4128fdc790e3cefedd3efc8d8c6b274393604527cc162dff97842227fea
3
+ metadata.gz: '08056406dee88f7c5eb0d29107d9d82b95487cf913ace9a6dd292c49641f58c4'
4
+ data.tar.gz: 5dfdb7970f4baf88676218aa9a0778245957c094dc1ee7103e7940c456a54e06
5
5
  SHA512:
6
- metadata.gz: 52330aaea8cf48aa21a62b8c5654163ce481382fa67bd6935c02d3deecfcef3a83a32b30c563941eb49404d86063ff2056778692781bd14a96174b55d2372f9f
7
- data.tar.gz: 5da348c363745f1e3b7a2fc73c36221658f86dafcad53d5078990d9d204fe5bf2224a319a156395597a7916bb2a950b1c27974114bbee37662f388295999758a
6
+ metadata.gz: e138fdae60edf8a40b1e0b57d4b351bc0069b48550f0ecd0ee443ef8bbb154984c8923a07632d441cf154b39f7777e266073254f6cd57bd6bf83c26dd59c5b63
7
+ data.tar.gz: 5e7e1e27aded0d3a1731cab0f756dfada2d11dcf1f2a756bd41ecfa912c44f9931649df0a2e56f32d21328a64f22db1a9f97c02c6ac939f17974342f4805c7d8
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Rails Semantic Logger
2
2
  [![Gem Version](https://img.shields.io/gem/v/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![Build Status](https://github.com/reidmorrison/rails_semantic_logger/workflows/build/badge.svg)](https://github.com/reidmorrison/rails_semantic_logger/actions?query=workflow%3Abuild) [![Downloads](https://img.shields.io/gem/dt/rails_semantic_logger.svg)](https://rubygems.org/gems/rails_semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg)
3
3
 
4
- Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](https://logger.rocketjob.io/), so that Rails, your application code, and many common gems all log through structured logging instead of plain text.
4
+ Rails Semantic Logger replaces the Rails default logger with [Semantic Logger](https://logger.reidmorrison.com/), so that Rails, your application code, and many common gems all log through structured logging instead of plain text.
5
5
 
6
6
  When any large Rails application is deployed to production one of the first steps is to move to centralized logging, so that logs can be viewed and searched from a central location. That quickly falls apart when consuming human readable text logs:
7
7
 
@@ -67,17 +67,17 @@ end
67
67
 
68
68
  Because declaring an appender replaces the default file appender, JSON to stdout becomes the only destination, exactly what a container platform wants. Once logs are emitted as structured JSON, a centralized logging system can parse each field, including the nested `payload` and any `metric` data, into a searchable hierarchy, so you can build searches, alerts, and dashboards against well-defined fields instead of brittle text matching.
69
69
 
70
- See [Configuring appenders](https://logger.rocketjob.io/rails#configuring-where-logs-go-the-appenders-block) for the full guide, including formatters, third-party destinations, the [container platform recipe](https://logger.rocketjob.io/rails#production-on-a-container-platform-docker-kubernetes-heroku), tuning what Rails logs, and worked examples of querying the JSON.
70
+ See [Configuring appenders](https://logger.reidmorrison.com/rails#configuring-where-logs-go-the-appenders-block) for the full guide, including formatters, third-party destinations, the [container platform recipe](https://logger.reidmorrison.com/rails#production-on-a-container-platform-docker-kubernetes-heroku), tuning what Rails logs, and worked examples of querying the JSON.
71
71
 
72
72
  ## Documentation
73
73
 
74
- For complete documentation see: https://logger.rocketjob.io/rails
74
+ For complete documentation see: https://logger.reidmorrison.com/rails
75
75
 
76
76
  ## Upgrading
77
77
 
78
78
  The way appenders (log destinations) are configured changed in v5. See the
79
- [v4 to v5 migration guide](https://logger.rocketjob.io/rails#migrating-from-v4-to-v5) for the
80
- before/after mapping, and [Migrating from earlier versions](https://logger.rocketjob.io/rails#migrating-from-earlier-versions)
79
+ [v4 to v5 migration guide](https://logger.reidmorrison.com/rails#migrating-from-v4-to-v5) for the
80
+ before/after mapping, and [Migrating from earlier versions](https://logger.reidmorrison.com/rails#migrating-from-earlier-versions)
81
81
  for older releases.
82
82
 
83
83
  ## New Versions of Rails, etc.
data/Rakefile CHANGED
@@ -5,10 +5,12 @@ require "bundler/setup"
5
5
  require "rake/testtask"
6
6
  require_relative "lib/rails_semantic_logger/version"
7
7
 
8
+ desc "Build the gem"
8
9
  task :gem do
9
10
  system "gem build rails_semantic_logger.gemspec"
10
11
  end
11
12
 
13
+ desc "Build and publish the gem, and tag the release"
12
14
  task publish: :gem do
13
15
  system "git tag -a v#{RailsSemanticLogger::VERSION} -m 'Tagging #{RailsSemanticLogger::VERSION}'"
14
16
  system "git push --tags"
@@ -137,7 +137,8 @@ module RailsSemanticLogger
137
137
  payload[:source] = source if source
138
138
  end
139
139
 
140
- controller_logger(event).info(message: "Redirected to", payload: payload, metric: "rails.controller.redirect_to")
140
+ controller_logger(event).info(message: "Redirected to", payload: payload,
141
+ metric: "rails.controller.redirect_to")
141
142
  end
142
143
 
143
144
  def send_data(event)
@@ -142,7 +142,7 @@ module RailsSemanticLogger
142
142
  end
143
143
 
144
144
  def rails_root
145
- @root ||= "#{Rails.root}/"
145
+ @rails_root ||= "#{Rails.root}/"
146
146
  end
147
147
 
148
148
  def logger
@@ -161,12 +161,12 @@ module RailsSemanticLogger
161
161
  super
162
162
  end
163
163
 
164
- private
164
+ EMPTY = "".freeze
165
165
 
166
166
  @logger = ::ActionView::Base.logger
167
167
  @rendered_log_level = :debug
168
168
 
169
- EMPTY = "".freeze
169
+ private
170
170
 
171
171
  def should_log?
172
172
  logger.send("#{self.class.rendered_log_level}?")
@@ -16,8 +16,8 @@ module RailsSemanticLogger
16
16
  # destination and formatting are ordinary `SemanticLogger.add_appender` arguments:
17
17
  #
18
18
  # #add - always created, during Rails initialization.
19
- # #add_server - created only when serving requests (`rails server`, a rack
20
- # server, Sidekiq in server mode). Defaults to `$stdout`.
19
+ # #add_server - created only when serving requests (`rails server`, Sidekiq
20
+ # in server mode). Defaults to `$stdout`.
21
21
  # #add_console - created only inside a `rails console` session. Defaults to
22
22
  # `$stderr` so log output does not tangle with command results.
23
23
  #
@@ -44,9 +44,10 @@ module RailsSemanticLogger
44
44
  end
45
45
 
46
46
  # Declare an appender that is only created when the application is serving
47
- # requests: `rails server`, a rack server started directly (puma, etc.), or
48
- # Sidekiq in server mode. It is never created during a non-serving boot (rake
49
- # tasks, runners, generators), so it only appears where it is useful.
47
+ # requests: `rails server`, Sidekiq in server mode, or when the app calls
48
+ # RailsSemanticLogger.add_server_appenders from its own server's boot hook.
49
+ # It is never created during a non-serving boot (rake tasks, runners,
50
+ # generators), so it only appears where it is useful.
50
51
  #
51
52
  # Accepts the same arguments (and optional block) as SemanticLogger.add_appender.
52
53
  # When no destination is given it defaults to `$stdout`; the formatter defaults
@@ -25,6 +25,27 @@ module RailsSemanticLogger
25
25
  # insert itself above the configured rails logger to add support for its
26
26
  # additional features
27
27
 
28
+ # Register this gem's deprecator with the application so that the standard Rails
29
+ # deprecation settings govern it: `config.active_support.report_deprecations`,
30
+ # `config.active_support.deprecation`, and
31
+ # `Rails.application.deprecators[:rails_semantic_logger]`. Rails' own
32
+ # `active_support.deprecation_behavior` initializer only reaches deprecators in
33
+ # that collection.
34
+ #
35
+ # Runs before the environment file is read so that an application can also reach
36
+ # the deprecator by name from `config/environments/*.rb`.
37
+ initializer "rails_semantic_logger.deprecator", before: :load_environment_config do |app|
38
+ app.deprecators[:rails_semantic_logger] = RailsSemanticLogger.deprecator
39
+ end
40
+
41
+ # The deprecated appender options are set from `config/application.rb` and
42
+ # `config/environments/*.rb`, which Rails reads before it applies the deprecation
43
+ # settings above, so their warnings are recorded rather than emitted. Now that
44
+ # the settings are in place, emit them.
45
+ initializer "rails_semantic_logger.flush_deprecations", after: "active_support.deprecation_behavior" do |app|
46
+ app.config.rails_semantic_logger.flush_deprecations!
47
+ end
48
+
28
49
  # Replace Rails logger initializer
29
50
  Rails::Application::Bootstrap.initializers.delete_if { |i| i.name == :initialize_logger }
30
51
 
@@ -48,7 +69,7 @@ module RailsSemanticLogger
48
69
  elsif config.rails_semantic_logger.add_file_appender
49
70
  # DEPRECATED: This option is deprecated and will be removed in a future version.
50
71
  path = config.paths["log"].first
51
- FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(File.dirname(path))
72
+ FileUtils.mkdir_p(File.dirname(path))
52
73
 
53
74
  # Add the log file to the list of appenders
54
75
  # Use the colorized formatter if Rails colorized logs are enabled
@@ -67,21 +88,28 @@ module RailsSemanticLogger
67
88
 
68
89
  app.formatter = formatter
69
90
  end
70
- SemanticLogger.add_appender(file_name: path, formatter: formatter, filter: config.rails_semantic_logger.filter)
91
+ SemanticLogger.add_appender(file_name: path, formatter: formatter,
92
+ filter: config.rails_semantic_logger.filter)
71
93
  end
72
94
 
73
95
  SemanticLogger[Rails]
74
96
  rescue StandardError => e
75
- # If not able to log to file, log to standard error with warning level only
97
+ # If unable to create the appenders, log to standard error with warning level only
76
98
  SemanticLogger.default_level = :warn
77
99
 
78
100
  SemanticLogger::Processor.logger = SemanticLogger::Appender::IO.new($stderr)
79
101
  SemanticLogger.add_appender(io: $stderr)
80
102
 
103
+ message =
104
+ if path
105
+ "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666."
106
+ else
107
+ "Rails Error: Unable to create the configured appenders."
108
+ end
81
109
  logger = SemanticLogger[Rails]
82
110
  logger.warn(
83
- "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " \
84
- "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.",
111
+ "#{message} The log level has been raised to WARN and the output directed to STDERR " \
112
+ "until the problem is fixed.",
85
113
  e
86
114
  )
87
115
  logger
@@ -122,12 +150,8 @@ module RailsSemanticLogger
122
150
  end
123
151
 
124
152
  ::Sidekiq.configure_server do |config|
125
- config.logger = ::SemanticLogger[::Sidekiq]
126
- if ::Sidekiq::VERSION.to_i < 6 || (::Sidekiq::VERSION.to_i == 6 && ::Sidekiq::VERSION.to_f < 6.5)
127
- config.options[:job_logger] = RailsSemanticLogger::Sidekiq::JobLogger
128
- else
129
- config[:job_logger] = RailsSemanticLogger::Sidekiq::JobLogger
130
- end
153
+ config.logger = ::SemanticLogger[::Sidekiq]
154
+ config[:job_logger] = RailsSemanticLogger::Sidekiq::JobLogger
131
155
 
132
156
  # Add back the default console logger (unless the app declared its own appenders, or one exists)
133
157
  RailsSemanticLogger.add_server_appenders
@@ -137,15 +161,12 @@ module RailsSemanticLogger
137
161
  config.error_handlers << RailsSemanticLogger::Sidekiq::Defaults::ERROR_HANDLER if existing
138
162
  end
139
163
 
140
- if defined?(::Sidekiq::Job) && (::Sidekiq::VERSION.to_i != 5)
141
- ::Sidekiq::Job.singleton_class.prepend(RailsSemanticLogger::Sidekiq::Loggable)
142
- else
143
- ::Sidekiq::Worker.singleton_class.prepend(RailsSemanticLogger::Sidekiq::Loggable)
144
- end
164
+ ::Sidekiq::Job.singleton_class.prepend(RailsSemanticLogger::Sidekiq::Loggable)
145
165
  end
146
166
 
147
167
  # Replace the SolidQueue logger
148
- if config.rails_semantic_logger.replace_solid_queue_logger && defined?(::SolidQueue) && ::SolidQueue.respond_to?(:logger=)
168
+ if config.rails_semantic_logger.replace_solid_queue_logger &&
169
+ defined?(::SolidQueue) && ::SolidQueue.respond_to?(:logger=)
149
170
  ::SolidQueue.logger = SemanticLogger[::SolidQueue]
150
171
  end
151
172
 
@@ -224,14 +245,18 @@ module RailsSemanticLogger
224
245
  if config.rails_semantic_logger.quiet_assets && config.respond_to?(:assets) && config.assets.prefix
225
246
  assets_root = config.relative_url_root.to_s + config.assets.prefix
226
247
  assets_regex = %r(\A/{0,2}#{assets_root})
227
- RailsSemanticLogger::Rack::Logger.logger.filter = ->(log) { log.payload[:path] !~ assets_regex if log.payload }
248
+ RailsSemanticLogger::Rack::Logger.logger.filter = lambda do |log|
249
+ log.payload[:path] !~ assets_regex if log.payload
250
+ end
228
251
  end
229
252
 
230
253
  # Action View
231
254
  if defined?(::ActionView)
232
255
  require "action_view/log_subscriber"
233
256
 
234
- RailsSemanticLogger::ActionView::LogSubscriber.rendered_log_level = :info if config.rails_semantic_logger.rendered
257
+ if config.rails_semantic_logger.rendered
258
+ RailsSemanticLogger::ActionView::LogSubscriber.rendered_log_level = :info
259
+ end
235
260
  RailsSemanticLogger.swap_subscriber(
236
261
  ::ActionView::LogSubscriber,
237
262
  RailsSemanticLogger::ActionView::LogSubscriber,
@@ -264,10 +289,6 @@ module RailsSemanticLogger
264
289
  )
265
290
  end
266
291
 
267
- if config.rails_semantic_logger.replace_sidekiq_logger && defined?(::Sidekiq)
268
- require("rails_semantic_logger/extensions/sidekiq/sidekiq")
269
- end
270
-
271
292
  # SolidQueue
272
293
  if config.rails_semantic_logger.replace_solid_queue_logger && defined?(::SolidQueue::LogSubscriber)
273
294
  RailsSemanticLogger.swap_subscriber(
@@ -1,53 +1,81 @@
1
- require "action_cable/connection/tagged_logger_proxy"
2
-
3
- # Upstream source (identical across supported versions):
1
+ # Upstream source (identical across supported versions, only the namespace differs):
4
2
  # https://github.com/rails/rails/blob/v7.2.2/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb
5
3
  # https://github.com/rails/rails/blob/v8.0.2/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb
6
4
  # https://github.com/rails/rails/blob/v8.1.3/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb
7
- module ActionCable
8
- module Connection
9
- class TaggedLoggerProxy
10
- # Mirrors upstream #tag, including the `respond_to?(:tagged)` guard so a
11
- # target logger without tagging support (e.g. when handed a non-tagged
12
- # ActiveRecord::Base.logger by the worker pool) simply yields. Diverges in
13
- # one place: upstream reads the already-applied tags via
14
- # `logger.formatter.current_tags` (ActiveSupport::TaggedLogging), but
15
- # Semantic Logger exposes them via `#tags`, so resolve from whichever the
16
- # target logger supports. See #220.
17
- def tag(logger, &)
18
- if logger.respond_to?(:tagged)
19
- current_tags = tags - applied_tags_for(logger)
20
- logger.tagged(*current_tags, &)
21
- else
22
- yield
23
- end
5
+ # https://github.com/rails/rails/blob/main/actioncable/lib/action_cable/server/tagged_logger_proxy.rb
6
+ module RailsSemanticLogger
7
+ module ActionCable
8
+ # Rails 8.2 moved the proxy from ActionCable::Connection to ActionCable::Server, as part of
9
+ # the ActionCable::Server::Socket refactor, without leaving a back-compat alias behind.
10
+ # Resolve whichever constant this version of ActionCable ships rather than hard-coding a
11
+ # namespace, so that a `require` of the old path cannot fail the app's boot. See #326.
12
+ TaggedLoggerProxy =
13
+ if defined?(::ActionCable::Server::TaggedLoggerProxy)
14
+ ::ActionCable::Server::TaggedLoggerProxy
15
+ else
16
+ require "action_cable/connection/tagged_logger_proxy"
17
+ ::ActionCable::Connection::TaggedLoggerProxy
24
18
  end
19
+ end
20
+ end
25
21
 
26
- # Upstream defines the severity methods with a single-arg signature
27
- # (`message = nil`), which discards Semantic Logger's richer payload and
28
- # exception arguments and raises ArgumentError when they are supplied.
29
- # Redefine them to forward the full Semantic Logger signature down to the
30
- # wrapped logger, while still applying the connection's tags. See #220.
31
- %i[debug info warn error fatal unknown].each do |severity|
32
- define_method(severity) do |message = nil, payload = nil, exception = nil, &block|
33
- tag(@logger) { @logger.public_send(severity, message, payload, exception, &block) }
34
- end
35
- end
22
+ RailsSemanticLogger::ActionCable::TaggedLoggerProxy.class_eval do
23
+ # Mirrors upstream #tag, including the `respond_to?(:tagged)` guard so a
24
+ # target logger without tagging support (e.g. when handed a non-tagged
25
+ # ActiveRecord::Base.logger by the worker pool) simply yields. Diverges in
26
+ # one place: upstream reads the already-applied tags via
27
+ # `logger.formatter.current_tags` (ActiveSupport::TaggedLogging), but
28
+ # Semantic Logger exposes them via `#tags`, so resolve from whichever the
29
+ # target logger supports. See #220.
30
+ def tag(logger, &)
31
+ if logger.respond_to?(:tagged)
32
+ current_tags = tags - applied_tags_for(logger)
33
+ logger.tagged(*current_tags, &)
34
+ else
35
+ yield
36
+ end
37
+ end
36
38
 
37
- private
39
+ # Upstream defines the severity methods with a single-arg signature
40
+ # (`message = nil`), which discards Semantic Logger's richer payload and
41
+ # exception arguments and raises ArgumentError when they are supplied.
42
+ # Redefine them to forward the full Semantic Logger signature down to the
43
+ # wrapped logger, while still applying the connection's tags. See #220.
44
+ %i[debug info warn error fatal unknown].each do |severity|
45
+ define_method(severity) do |message = nil, payload = nil, exception = nil, &block|
46
+ tag(@logger) { forward(severity, message, payload, exception, &block) }
47
+ end
48
+ end
38
49
 
39
- # Tags already applied to the target logger, so they are not duplicated.
40
- # Semantic Logger exposes them via `#tags`; ActiveSupport::TaggedLogging
41
- # via `formatter.current_tags`. Fall back to none when neither is present.
42
- def applied_tags_for(logger)
43
- if logger.respond_to?(:tags)
44
- Array(logger.tags)
45
- elsif logger.respond_to?(:formatter) && logger.formatter.respond_to?(:current_tags)
46
- logger.formatter.current_tags
47
- else
48
- []
49
- end
50
- end
50
+ private
51
+
52
+ # Only forward the extra payload/exception arguments when the wrapped logger's
53
+ # method can accept them. A standard Ruby Logger (e.g. the one wrapped by
54
+ # ActionCable::Connection::TestCase) only accepts a single `progname` argument
55
+ # and raises ArgumentError given more, so fall back to the single-arg call. See #317.
56
+ def forward(severity, message, payload, exception, &)
57
+ if extended_signature?(@logger, severity)
58
+ @logger.public_send(severity, message, payload, exception, &)
59
+ else
60
+ @logger.public_send(severity, message, &)
61
+ end
62
+ end
63
+
64
+ def extended_signature?(logger, severity)
65
+ params = logger.method(severity).parameters
66
+ params.any? { |type, _| type == :rest } || params.count { |type, _| %i[req opt].include?(type) } >= 3
67
+ end
68
+
69
+ # Tags already applied to the target logger, so they are not duplicated.
70
+ # Semantic Logger exposes them via `#tags`; ActiveSupport::TaggedLogging
71
+ # via `formatter.current_tags`. Fall back to none when neither is present.
72
+ def applied_tags_for(logger)
73
+ if logger.respond_to?(:tags)
74
+ Array(logger.tags)
75
+ elsif logger.respond_to?(:formatter) && logger.formatter.respond_to?(:current_tags)
76
+ logger.formatter.current_tags
77
+ else
78
+ []
51
79
  end
52
80
  end
53
81
  end
@@ -181,7 +181,7 @@ module RailsSemanticLogger
181
181
  # The method names the context in which the appender is created; the destination
182
182
  # is an ordinary `SemanticLogger.add_appender` argument. Use `add` for an
183
183
  # appender that is always created, `add_server` for one created only when serving
184
- # requests (`rails server`, a rack server, Sidekiq in server mode; defaults to
184
+ # requests (`rails server`, Sidekiq in server mode; defaults to
185
185
  # `$stdout`), and `add_console` for one created only inside a `rails console`
186
186
  # session (defaults to `$stderr`). Any appender works in any context, so a
187
187
  # context may declare several (e.g. a server-only stdout and file appender).
@@ -256,14 +256,56 @@ module RailsSemanticLogger
256
256
  @add_file_appender = value
257
257
  end
258
258
 
259
+ # Emit the deprecation warnings recorded by the deprecated appender option
260
+ # setters, and warn immediately from any later call. Called by the engine once
261
+ # Rails has applied the application's deprecation configuration.
262
+ #
263
+ # The deprecated options are documented to be set in `config/application.rb` or
264
+ # `config/environments/*.rb`, which Rails reads in `load_environment_config`,
265
+ # long before `active_support.deprecation_behavior` applies
266
+ # `config.active_support.report_deprecations`, `config.active_support.deprecation`,
267
+ # and any per-deprecator settings. Warning from the setter itself would therefore
268
+ # land in a window where nothing the application configures can reach it. The
269
+ # setters record instead, and this flushes once the settings are in place.
270
+ #
271
+ # Each option is reported once, attributed to the first place it was set, so an
272
+ # application setting several deprecated options gets one warning per option
273
+ # rather than one per assignment.
274
+ def flush_deprecations!
275
+ @deprecations_flushed = true
276
+ pending = pending_deprecations
277
+ @pending_deprecations = {}
278
+ pending.each_value { |message, callstack| RailsSemanticLogger.deprecator.warn(message, callstack) }
279
+ nil
280
+ end
281
+
259
282
  private
260
283
 
261
284
  def deprecate_appender_option(option, via: "appenders.add(...)")
262
- RailsSemanticLogger.deprecator.warn(
285
+ message =
263
286
  "`config.rails_semantic_logger.#{option}=` is deprecated and will be removed in a future release. " \
264
287
  "Declare the destination and formatting directly instead, via " \
265
288
  "`config.rails_semantic_logger.appenders { |appenders| #{via} }`."
266
- )
289
+
290
+ # Skip this method and the setter that called it, so the warning is attributed
291
+ # to the application code that set the option, whether it is emitted now or
292
+ # flushed later by #flush_deprecations!.
293
+ callstack = caller_locations(2)
294
+
295
+ return RailsSemanticLogger.deprecator.warn(message, callstack) if deprecations_flushed?
296
+
297
+ pending_deprecations[option] ||= [message, callstack]
298
+ nil
299
+ end
300
+
301
+ # Deprecations recorded before Rails applied its deprecation configuration,
302
+ # keyed by option so that each is reported only once. See #flush_deprecations!.
303
+ def pending_deprecations
304
+ @pending_deprecations ||= {}
305
+ end
306
+
307
+ def deprecations_flushed?
308
+ defined?(@deprecations_flushed) && @deprecations_flushed
267
309
  end
268
310
 
269
311
  # Warn when an init-time setting is changed after the logger and its
@@ -4,38 +4,21 @@ module RailsSemanticLogger
4
4
  # Prevent exception logging during standard error handling since the Job Logger below already logs the exception.
5
5
  # Logs the remaining Sidekiq context at :info (matching upstream Sidekiq's default handler) rather than :warn,
6
6
  # since the exception itself is already logged at :error by the Job Logger.
7
+ # Sidekiq 7.1.6+ calls error handlers with a third config argument; earlier 7.x versions pass only two.
7
8
  ERROR_HANDLER =
8
- if ::Sidekiq::VERSION.to_f < 7.1 ||
9
- (::Sidekiq::VERSION.to_f == 7.1 && ::Sidekiq::VERSION.split(".").last.to_i < 6)
10
- lambda do |_ex, ctx|
11
- unless ctx.empty?
12
- job_hash = ctx[:job] || {}
13
- klass = job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
14
- logger = klass ? SemanticLogger[klass] : ::Sidekiq.logger
15
- ctx[:context] ? logger.info(ctx[:context], ctx) : logger.info(ctx)
16
- end
17
- end
18
- else
19
- lambda do |_ex, ctx, _default_configuration|
20
- unless ctx.empty?
21
- job_hash = ctx[:job] || {}
22
- klass = job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
23
- logger = klass ? SemanticLogger[klass] : ::Sidekiq.logger
24
- ctx[:context] ? logger.info(ctx[:context], ctx) : logger.info(ctx)
25
- end
9
+ lambda do |_ex, ctx, _config = nil|
10
+ unless ctx.empty?
11
+ job_hash = ctx[:job] || {}
12
+ klass = job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
13
+ logger = klass ? SemanticLogger[klass] : ::Sidekiq.logger
14
+ ctx[:context] ? logger.info(ctx[:context], ctx) : logger.info(ctx)
26
15
  end
27
16
  end
28
17
 
29
- # Returns the default logger after removing from the supplied list.
30
- # Returns [nil] when the default logger was not present.
18
+ # Returns the default error handler after removing it from the supplied list.
19
+ # Returns [nil] when the default handler was not present.
31
20
  def self.delete_default_error_handler(error_handlers)
32
- return error_handlers.delete(::Sidekiq::Config::ERROR_HANDLER) if defined?(::Sidekiq::Config::ERROR_HANDLER)
33
- return error_handlers.delete(::Sidekiq::DEFAULT_ERROR_HANDLER) if defined?(::Sidekiq::DEFAULT_ERROR_HANDLER)
34
-
35
- return unless defined?(::Sidekiq::ExceptionHandler)
36
-
37
- existing = error_handlers.find { |handler| handler.is_a?(::Sidekiq::ExceptionHandler::Logger) }
38
- error_handlers.delete(existing) if existing
21
+ error_handlers.delete(::Sidekiq::Config::ERROR_HANDLER)
39
22
  end
40
23
  end
41
24
  end
@@ -1,6 +1,10 @@
1
1
  module RailsSemanticLogger
2
2
  module Sidekiq
3
3
  class JobLogger
4
+ # Job attributes copied into the logging context, matching Sidekiq's own defaults.
5
+ # Sidekiq 8 makes this configurable via `config[:logged_job_attributes]`.
6
+ DEFAULT_LOGGED_JOB_ATTRIBUTES = %w[bid tags].freeze
7
+
4
8
  class << self
5
9
  attr_writer :perform_messages
6
10
 
@@ -9,8 +13,9 @@ module RailsSemanticLogger
9
13
  end
10
14
  end
11
15
 
12
- # Sidekiq 6.5 does not take any arguments, whereas v7 is given a logger
13
- def initialize(*_args)
16
+ # Sidekiq 7 passes its logger, whereas Sidekiq 8 passes its config.
17
+ def initialize(arg = nil)
18
+ @config = arg if arg.respond_to?(:[])
14
19
  end
15
20
 
16
21
  def call(item, queue, &block)
@@ -56,17 +61,24 @@ module RailsSemanticLogger
56
61
  private
57
62
 
58
63
  def perform_messages_enabled?
64
+ return false if @config && @config[:skip_default_job_logging]
65
+
59
66
  self.class.perform_messages != false
60
67
  end
61
68
 
62
69
  def job_hash_context(job_hash)
63
- h = {jid: job_hash["jid"], class: job_hash["wrapped"] || job_hash["class"]}
64
- h[:bid] = job_hash["bid"] if job_hash["bid"]
65
- h[:tags] = job_hash["tags"] if job_hash["tags"]
70
+ h = {jid: job_hash["jid"], class: job_hash["wrapped"] || job_hash["class"]}
71
+ logged_job_attributes.each do |attr|
72
+ h[attr.to_sym] = job_hash[attr] if job_hash.key?(attr)
73
+ end
66
74
  h[:queue] = job_hash["queue"] if job_hash["queue"]
67
75
  h
68
76
  end
69
77
 
78
+ def logged_job_attributes
79
+ (@config && @config[:logged_job_attributes]) || DEFAULT_LOGGED_JOB_ATTRIBUTES
80
+ end
81
+
70
82
  def job_latency_ms(job)
71
83
  return unless job && job["enqueued_at"]
72
84
 
@@ -54,7 +54,11 @@ module RailsSemanticLogger
54
54
  elsif event.payload[:other_adapter]
55
55
  log_event(event, :debug, "Enqueued recurring task outside Solid Queue", **attributes)
56
56
  else
57
- action = event.payload[:skipped].present? ? "Skipped recurring task – already dispatched" : "Enqueued recurring task"
57
+ action = if event.payload[:skipped].present?
58
+ "Skipped recurring task – already dispatched"
59
+ else
60
+ "Enqueued recurring task"
61
+ end
58
62
  log_event(event, :debug, action, **attributes)
59
63
  end
60
64
  end
@@ -1,3 +1,3 @@
1
1
  module RailsSemanticLogger
2
- VERSION = "5.0.0".freeze
2
+ VERSION = "5.2.0".freeze
3
3
  end
@@ -116,7 +116,7 @@ module RailsSemanticLogger
116
116
 
117
117
  # Swap an existing subscriber with a new one
118
118
  def self.swap_subscriber(old_class, new_class, notifier)
119
- subscribers = ActiveSupport::LogSubscriber.subscribers.select { |s| s.is_a?(old_class) }
119
+ subscribers = ActiveSupport::LogSubscriber.subscribers.grep(old_class)
120
120
  subscribers.each { |subscriber| unattach(subscriber) }
121
121
 
122
122
  new_class.attach_to(notifier)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '5.0'
46
+ version: '5.1'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '5.0'
53
+ version: '5.1'
54
54
  executables: []
55
55
  extensions: []
56
56
  extra_rdoc_files: []
@@ -76,7 +76,6 @@ files:
76
76
  - lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb
77
77
  - lib/rails_semantic_logger/extensions/mongoid/config.rb
78
78
  - lib/rails_semantic_logger/extensions/rails/server.rb
79
- - lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb
80
79
  - lib/rails_semantic_logger/options.rb
81
80
  - lib/rails_semantic_logger/rack/logger.rb
82
81
  - lib/rails_semantic_logger/sidekiq/defaults.rb
@@ -84,13 +83,14 @@ files:
84
83
  - lib/rails_semantic_logger/sidekiq/loggable.rb
85
84
  - lib/rails_semantic_logger/solid_queue/log_subscriber.rb
86
85
  - lib/rails_semantic_logger/version.rb
87
- homepage: https://logger.rocketjob.io
86
+ homepage: https://logger.reidmorrison.com
88
87
  licenses:
89
88
  - Apache-2.0
90
89
  metadata:
91
90
  bug_tracker_uri: https://github.com/reidmorrison/rails_semantic_logger/issues
92
- documentation_uri: https://logger.rocketjob.io
93
- source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/v5.0.0
91
+ documentation_uri: https://logger.reidmorrison.com
92
+ source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/v5.2.0
93
+ changelog_uri: https://github.com/reidmorrison/rails_semantic_logger/blob/main/CHANGELOG.md
94
94
  rubygems_mfa_required: 'true'
95
95
  rdoc_options: []
96
96
  require_paths:
@@ -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, &)
16
- SemanticLogger.tagged(msg, &)
17
- end
18
-
19
- def self.job_hash_context(job_hash)
20
- h = {jid: job_hash["jid"], class: job_hash["wrapped"] || job_hash["class"]}
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"], class: job_hash["wrapped"] || job_hash["class"]}
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