rails_semantic_logger 4.19.0 → 5.0.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 +5 -2
  4. data/lib/rails_semantic_logger/action_controller/log_subscriber.rb +86 -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 +74 -40
  7. data/lib/rails_semantic_logger/active_job/log_subscriber.rb +218 -7
  8. data/lib/rails_semantic_logger/active_record/log_subscriber.rb +62 -164
  9. data/lib/rails_semantic_logger/appenders.rb +91 -0
  10. data/lib/rails_semantic_logger/engine.rb +51 -38
  11. data/lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb +44 -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/extensions/sidekiq/sidekiq.rb +33 -16
  18. data/lib/rails_semantic_logger/options.rb +175 -18
  19. data/lib/rails_semantic_logger/rack/logger.rb +6 -13
  20. data/lib/rails_semantic_logger/sidekiq/defaults.rb +4 -2
  21. data/lib/rails_semantic_logger/sidekiq/job_logger.rb +41 -15
  22. data/lib/rails_semantic_logger/solid_queue/log_subscriber.rb +179 -0
  23. data/lib/rails_semantic_logger/version.rb +1 -1
  24. data/lib/rails_semantic_logger.rb +81 -26
  25. metadata +15 -16
  26. data/lib/rails_semantic_logger/delayed_job/plugin.rb +0 -11
  27. data/lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb +0 -13
  28. data/lib/rails_semantic_logger/extensions/rack/server.rb +0 -12
  29. data/lib/rails_semantic_logger/extensions/rackup/server.rb +0 -12
@@ -0,0 +1,179 @@
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 = event.payload[:skipped].present? ? "Skipped recurring task – already dispatched" : "Enqueued recurring task"
58
+ log_event(event, :debug, action, **attributes)
59
+ end
60
+ end
61
+
62
+ def start_process(event)
63
+ process = event.payload[:process]
64
+ attributes = process_attributes(process).merge(process.metadata)
65
+
66
+ log_event(event, :info, "Started #{process.kind}", **attributes)
67
+ end
68
+
69
+ def shutdown_process(event)
70
+ process = event.payload[:process]
71
+ attributes = process_attributes(process).merge(process.metadata)
72
+
73
+ log_event(event, :info, "Shutdown #{process.kind}", **attributes)
74
+ end
75
+
76
+ def register_process(event)
77
+ process_kind = event.payload[:kind]
78
+ attributes = event.payload.slice(:pid, :hostname, :process_id, :name)
79
+
80
+ if (error = event.payload[:error])
81
+ log_event(event, :warn, "Error registering #{process_kind}", exception: error, **attributes)
82
+ else
83
+ log_event(event, :debug, "Register #{process_kind}", **attributes)
84
+ end
85
+ end
86
+
87
+ def deregister_process(event)
88
+ process = event.payload[:process]
89
+ attributes = {
90
+ process_id: process.id,
91
+ pid: process.pid,
92
+ hostname: process.hostname,
93
+ name: process.name,
94
+ last_heartbeat_at: process.last_heartbeat_at.iso8601,
95
+ claimed_size: event.payload[:claimed_size],
96
+ pruned: event.payload[:pruned]
97
+ }
98
+
99
+ if (error = event.payload[:error])
100
+ log_event(event, :warn, "Error deregistering #{process.kind}", exception: error, **attributes)
101
+ else
102
+ log_event(event, :debug, "Deregister #{process.kind}", **attributes)
103
+ end
104
+ end
105
+
106
+ def prune_processes(event)
107
+ log_event(event, :debug, "Prune dead processes", **event.payload.slice(:size))
108
+ end
109
+
110
+ def thread_error(event)
111
+ log_event(event, :error, "Error in thread", exception: event.payload[:error])
112
+ end
113
+
114
+ def graceful_termination(event)
115
+ attributes = event.payload.slice(:process_id, :supervisor_pid, :supervised_processes)
116
+
117
+ if event.payload[:shutdown_timeout_exceeded]
118
+ log_event(event, :warn, "Supervisor wasn't terminated gracefully - shutdown timeout exceeded", **attributes)
119
+ else
120
+ log_event(event, :info, "Supervisor terminated gracefully", **attributes)
121
+ end
122
+ end
123
+
124
+ def immediate_termination(event)
125
+ log_event(event, :info, "Supervisor terminated immediately",
126
+ **event.payload.slice(:process_id, :supervisor_pid, :supervised_processes))
127
+ end
128
+
129
+ def unhandled_signal_error(event)
130
+ log_event(event, :error, "Received unhandled signal", **event.payload.slice(:signal))
131
+ end
132
+
133
+ def replace_fork(event)
134
+ supervisor_pid = event.payload[:supervisor_pid]
135
+ status = event.payload[:status]
136
+ attributes = event.payload.slice(:pid).merge(
137
+ status: status.exitstatus || "no exit status set",
138
+ pid_from_status: status.pid,
139
+ signaled: status.signaled?,
140
+ stopsig: status.stopsig,
141
+ termsig: status.termsig
142
+ )
143
+
144
+ if (replaced_fork = event.payload[:fork])
145
+ log_event(event, :info, "Replaced terminated #{replaced_fork.kind}",
146
+ **attributes, hostname: replaced_fork.hostname, name: replaced_fork.name)
147
+ elsif supervisor_pid != 1 # Running Docker, possibly having some processes that have been reparented
148
+ log_event(event, :warn, "Tried to replace forked process but it had already died", **attributes)
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ def process_attributes(process)
155
+ {
156
+ pid: process.pid,
157
+ hostname: process.hostname,
158
+ process_id: process.process_id,
159
+ name: process.name
160
+ }
161
+ end
162
+
163
+ def log_event(event, level, action, exception: nil, **attributes)
164
+ logger.public_send(level) do
165
+ msg = {message: action, payload: attributes, duration: event.duration}
166
+ msg[:exception] = exception if exception
167
+ # Emit a metric for every info/warn/error entry, named after the notification
168
+ # (e.g. "start_process.solid_queue" -> "rails.solid_queue.start_process"). Debug entries are excluded.
169
+ msg[:metric] = "rails.solid_queue.#{event.name.split('.').first}" unless level == :debug
170
+ msg
171
+ end
172
+ end
173
+
174
+ def logger
175
+ @logger ||= SemanticLogger[::SolidQueue]
176
+ end
177
+ end
178
+ end
179
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsSemanticLogger
2
- VERSION = "4.19.0".freeze
2
+ VERSION = "5.0.0".freeze
3
3
  end
@@ -27,18 +27,93 @@ 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
119
  subscribers = ActiveSupport::LogSubscriber.subscribers.select { |s| s.is_a?(old_class) }
@@ -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,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.19.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-12-09 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rack
@@ -29,28 +29,28 @@ dependencies:
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '5.1'
32
+ version: '7.2'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '5.1'
39
+ version: '7.2'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: semantic_logger
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '4.16'
46
+ version: '5.0'
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: '4.16'
53
+ version: '5.0'
54
54
  executables: []
55
55
  extensions: []
56
56
  extra_rdoc_files: []
@@ -64,7 +64,7 @@ files:
64
64
  - lib/rails_semantic_logger/action_view/log_subscriber.rb
65
65
  - lib/rails_semantic_logger/active_job/log_subscriber.rb
66
66
  - lib/rails_semantic_logger/active_record/log_subscriber.rb
67
- - lib/rails_semantic_logger/delayed_job/plugin.rb
67
+ - lib/rails_semantic_logger/appenders.rb
68
68
  - lib/rails_semantic_logger/engine.rb
69
69
  - lib/rails_semantic_logger/extensions/action_cable/tagged_logger_proxy.rb
70
70
  - lib/rails_semantic_logger/extensions/action_controller/live.rb
@@ -72,12 +72,9 @@ files:
72
72
  - lib/rails_semantic_logger/extensions/action_view/streaming_template_renderer.rb
73
73
  - lib/rails_semantic_logger/extensions/active_job/logging.rb
74
74
  - lib/rails_semantic_logger/extensions/active_model_serializers/logging.rb
75
- - lib/rails_semantic_logger/extensions/active_support/log_subscriber.rb
76
75
  - lib/rails_semantic_logger/extensions/active_support/logger.rb
77
76
  - lib/rails_semantic_logger/extensions/active_support/tagged_logging.rb
78
77
  - lib/rails_semantic_logger/extensions/mongoid/config.rb
79
- - lib/rails_semantic_logger/extensions/rack/server.rb
80
- - lib/rails_semantic_logger/extensions/rackup/server.rb
81
78
  - lib/rails_semantic_logger/extensions/rails/server.rb
82
79
  - lib/rails_semantic_logger/extensions/sidekiq/sidekiq.rb
83
80
  - lib/rails_semantic_logger/options.rb
@@ -85,6 +82,7 @@ files:
85
82
  - lib/rails_semantic_logger/sidekiq/defaults.rb
86
83
  - lib/rails_semantic_logger/sidekiq/job_logger.rb
87
84
  - lib/rails_semantic_logger/sidekiq/loggable.rb
85
+ - lib/rails_semantic_logger/solid_queue/log_subscriber.rb
88
86
  - lib/rails_semantic_logger/version.rb
89
87
  homepage: https://logger.rocketjob.io
90
88
  licenses:
@@ -92,7 +90,7 @@ licenses:
92
90
  metadata:
93
91
  bug_tracker_uri: https://github.com/reidmorrison/rails_semantic_logger/issues
94
92
  documentation_uri: https://logger.rocketjob.io
95
- source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/v4.19.0
93
+ source_code_uri: https://github.com/reidmorrison/rails_semantic_logger/tree/v5.0.0
96
94
  rubygems_mfa_required: 'true'
97
95
  rdoc_options: []
98
96
  require_paths:
@@ -101,14 +99,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
99
  requirements:
102
100
  - - ">="
103
101
  - !ruby/object:Gem::Version
104
- version: '2.5'
102
+ version: '3.2'
105
103
  required_rubygems_version: !ruby/object:Gem::Requirement
106
104
  requirements:
107
105
  - - ">="
108
106
  - !ruby/object:Gem::Version
109
107
  version: '0'
110
108
  requirements: []
111
- rubygems_version: 3.6.2
109
+ rubygems_version: 3.6.9
112
110
  specification_version: 4
113
- summary: Feature rich logging framework that replaces the Rails logger.
111
+ summary: High-performance, asynchronous structured logging that replaces the Rails
112
+ logger.
114
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)