lumberjack_rails 1.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.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/continuous_integration.yml +70 -0
- data/.standard.yml +9 -0
- data/.yardopts +1 -0
- data/CHANGE_LOG.md +11 -0
- data/MIT_LICENSE.txt +20 -0
- data/README.md +329 -0
- data/VERSION +1 -0
- data/lib/lumberjack/rails/action_cable_extension.rb +19 -0
- data/lib/lumberjack/rails/action_controller_extension.rb +19 -0
- data/lib/lumberjack/rails/action_controller_log_subscriber_extension.rb +103 -0
- data/lib/lumberjack/rails/action_mailbox_extension.rb +19 -0
- data/lib/lumberjack/rails/action_mailer_extension.rb +19 -0
- data/lib/lumberjack/rails/active_job_extension.rb +19 -0
- data/lib/lumberjack/rails/apply_patches.rb +86 -0
- data/lib/lumberjack/rails/broadcast_logger_extension.rb +302 -0
- data/lib/lumberjack/rails/context_middleware.rb +23 -0
- data/lib/lumberjack/rails/log_at_level.rb +19 -0
- data/lib/lumberjack/rails/log_subscriber_extension.rb +97 -0
- data/lib/lumberjack/rails/rack_logger_extension.rb +13 -0
- data/lib/lumberjack/rails/railtie.rb +174 -0
- data/lib/lumberjack/rails/request_attributes_middleware.rb +42 -0
- data/lib/lumberjack/rails/tagged_forked_logger.rb +22 -0
- data/lib/lumberjack/rails/tagged_logging_formatter.rb +28 -0
- data/lib/lumberjack/rails.rb +106 -0
- data/lib/lumberjack_rails.rb +3 -0
- data/lumberjack_rails.gemspec +40 -0
- metadata +97 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Integration patches for Lumberjack Rails support.
|
|
4
|
+
#
|
|
5
|
+
# This file applies various patches and extensions to integrate Lumberjack
|
|
6
|
+
# with Rails framework components. It performs the following key integrations:
|
|
7
|
+
#
|
|
8
|
+
# 1. Removes deprecated Lumberjack::Logger methods that conflict with ActiveSupport
|
|
9
|
+
# 2. Adds tagged logging support to Lumberjack formatters and loggers
|
|
10
|
+
# 3. Extends ActiveSupport::BroadcastLogger with Lumberjack compatibility
|
|
11
|
+
# 4. Integrates with Rails framework components (ActiveJob, ActionCable, etc.)
|
|
12
|
+
# 5. Sets up log subscribers to use forked Lumberjack loggers
|
|
13
|
+
#
|
|
14
|
+
# These patches ensure seamless integration between Lumberjack's logging
|
|
15
|
+
# capabilities and Rails' existing logging infrastructure while maintaining
|
|
16
|
+
# backward compatibility with existing Rails logging patterns.
|
|
17
|
+
|
|
18
|
+
# Remove deprecated methods on Lumberjack::Logger that are implemented by ActiveSupport
|
|
19
|
+
Lumberjack::Logger.remove_method(:tagged) if Lumberjack::Logger.instance_methods.include?(:tagged)
|
|
20
|
+
Lumberjack::Logger.remove_method(:log_at) if Lumberjack::Logger.instance_methods.include?(:log_at)
|
|
21
|
+
Lumberjack::Logger.remove_method(:silence) if Lumberjack::Logger.instance_methods.include?(:silence)
|
|
22
|
+
|
|
23
|
+
# Add tagged logging support to the Lumberjack::EntryFormatter
|
|
24
|
+
Lumberjack::EntryFormatter.prepend(Lumberjack::Rails::TaggedLoggingFormatter)
|
|
25
|
+
Lumberjack::EntryFormatter.include(ActiveSupport::TaggedLogging::Formatter)
|
|
26
|
+
|
|
27
|
+
# Add silence method to Lumberjack::Logger
|
|
28
|
+
require "active_support/logger_silence"
|
|
29
|
+
Lumberjack::ContextLogger.include(ActiveSupport::LoggerSilence)
|
|
30
|
+
|
|
31
|
+
# Use prepend to ensure level is overridden properly
|
|
32
|
+
Lumberjack::ContextLogger.prepend(Lumberjack::Rails::LogAtLevel)
|
|
33
|
+
|
|
34
|
+
# Add tagged logging support to Lumberjack
|
|
35
|
+
Lumberjack::ContextLogger.prepend(ActiveSupport::TaggedLogging)
|
|
36
|
+
Lumberjack::ForkedLogger.include(Lumberjack::Rails::TaggedForkedLogger)
|
|
37
|
+
|
|
38
|
+
ActiveSupport::BroadcastLogger.prepend(Lumberjack::Rails::BroadcastLoggerExtension)
|
|
39
|
+
|
|
40
|
+
ActiveSupport.on_load(:active_job) do
|
|
41
|
+
ActiveJob::Base.prepend(Lumberjack::Rails::ActiveJobExtension)
|
|
42
|
+
ActiveJob::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
43
|
+
ActiveJob::LogSubscriber.logger = -> { ActiveJob::Base.logger }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
ActiveSupport.on_load(:action_cable) do
|
|
47
|
+
ActionCable::Connection::Base.prepend(Lumberjack::Rails::ActionCableExtension)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
ActiveSupport.on_load(:action_mailer) do
|
|
51
|
+
ActionMailer::Base.prepend(Lumberjack::Rails::ActionMailerExtension)
|
|
52
|
+
ActionMailer::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
53
|
+
ActionMailer::LogSubscriber.logger = -> { ActionMailer::Base.logger }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ActiveSupport.on_load(:action_mailbox) do
|
|
57
|
+
ActionMailbox::Base.prepend(Lumberjack::Rails::ActionMailboxExtension)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
ActiveSupport.on_load(:action_controller) do
|
|
61
|
+
# Add hook to allow disabling of "Started ..." log lines in Rack::Logger
|
|
62
|
+
::Rails::Rack::Logger.prepend(Lumberjack::Rails::RackLoggerExtension) if defined?(::Rails::Rack::Logger)
|
|
63
|
+
|
|
64
|
+
ActionController::Base.prepend(Lumberjack::Rails::ActionControllerExtension)
|
|
65
|
+
|
|
66
|
+
ActionController::LogSubscriber.prepend(Lumberjack::Rails::ActionControllerLogSubscriberExtension)
|
|
67
|
+
ActionController::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
68
|
+
ActionController::LogSubscriber.logger = -> { ActionController::Base.logger }
|
|
69
|
+
|
|
70
|
+
ActionDispatch::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
ActiveSupport.on_load(:action_view) do
|
|
74
|
+
ActionView::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
75
|
+
ActionView::LogSubscriber.logger = -> { ActionView::Base.logger }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
ActiveSupport.on_load(:active_record) do
|
|
79
|
+
ActiveRecord::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
80
|
+
ActiveRecord::LogSubscriber.logger = -> { ActiveRecord::Base.logger }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
ActiveSupport.on_load(:active_storage_record) do
|
|
84
|
+
ActiveStorage::LogSubscriber.prepend(Lumberjack::Rails::LogSubscriberExtension)
|
|
85
|
+
ActiveStorage::LogSubscriber.logger = -> { ActiveStorage.logger }
|
|
86
|
+
end
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension for ActiveSupport::BroadcastLogger to provide Lumberjack compatibility.
|
|
6
|
+
#
|
|
7
|
+
# This module extends ActiveSupport::BroadcastLogger to ensure proper handling
|
|
8
|
+
# of Lumberjack loggers when broadcasting to multiple loggers, including
|
|
9
|
+
# support for Lumberjack-specific features like attributes and contexts.
|
|
10
|
+
module BroadcastLoggerExtension
|
|
11
|
+
# Initialize the broadcast logger with validation for Lumberjack loggers.
|
|
12
|
+
#
|
|
13
|
+
# @param loggers [Array<Logger>] array of loggers to broadcast to
|
|
14
|
+
# @raise [ArgumentError] if more than one Lumberjack logger is provided
|
|
15
|
+
def initialize(*loggers)
|
|
16
|
+
if loggers.count { |logger| logger.is_a?(Lumberjack::ContextLogger) } > 1
|
|
17
|
+
raise ArgumentError, "Only one Lumberjack logger is allowed"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Log a debug message with optional attributes support.
|
|
24
|
+
#
|
|
25
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
26
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
27
|
+
# @yield optional block that returns the message
|
|
28
|
+
# @return [void]
|
|
29
|
+
def debug(message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
30
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
31
|
+
call_with_attributes_arg(logger, :debug, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Log an info message with optional attributes support.
|
|
36
|
+
#
|
|
37
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
38
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
39
|
+
# @yield optional block that returns the message
|
|
40
|
+
# @return [void]
|
|
41
|
+
def info(message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
42
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
43
|
+
call_with_attributes_arg(logger, :info, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Log a warning message with optional attributes support.
|
|
48
|
+
#
|
|
49
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
50
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
51
|
+
# @yield optional block that returns the message
|
|
52
|
+
# @return [void]
|
|
53
|
+
def warn(message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
54
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
55
|
+
call_with_attributes_arg(logger, :warn, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Log an error message with optional attributes support.
|
|
60
|
+
#
|
|
61
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
62
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
63
|
+
# @yield optional block that returns the message
|
|
64
|
+
# @return [void]
|
|
65
|
+
def error(message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
66
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
67
|
+
call_with_attributes_arg(logger, :error, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Log a fatal message with optional attributes support.
|
|
72
|
+
#
|
|
73
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
74
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
75
|
+
# @yield optional block that returns the message
|
|
76
|
+
# @return [void]
|
|
77
|
+
def fatal(message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
78
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
79
|
+
call_with_attributes_arg(logger, :fatal, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Log an unknown severity message with optional attributes support.
|
|
84
|
+
#
|
|
85
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
86
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
87
|
+
# @yield optional block that returns the message
|
|
88
|
+
# @return [void]
|
|
89
|
+
def unknown(message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
90
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
91
|
+
call_with_attributes_arg(logger, :unknown, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Add a log entry with the specified severity and optional attributes support.
|
|
96
|
+
#
|
|
97
|
+
# @param severity [Integer, Symbol, String] the severity for the log entry
|
|
98
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
99
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
100
|
+
# @yield optional block that returns the message
|
|
101
|
+
# @return [void]
|
|
102
|
+
def add(severity, message_or_progname_or_attributes = nil, progname_or_attributes = nil, &block)
|
|
103
|
+
severity = Logger::Severity.coerce(severity)
|
|
104
|
+
dispatch_to_each(block) do |logger, one_time_block|
|
|
105
|
+
call_add_with_attributes_arg(logger, severity, message_or_progname_or_attributes, progname_or_attributes, &one_time_block)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
alias_method :log, :add
|
|
110
|
+
|
|
111
|
+
# Override the with_level method defined on the logger gem to use Rails' log_at method instead.
|
|
112
|
+
#
|
|
113
|
+
# @param level [Symbol, Integer] the log level to set temporarily
|
|
114
|
+
# @yield the block to execute at the specified log level
|
|
115
|
+
# @return [Object] the result of the block execution
|
|
116
|
+
def with_level(level, &block)
|
|
117
|
+
log_at(level, &block)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Tag log entries with the specified attributes.
|
|
121
|
+
#
|
|
122
|
+
# @param attributes [Hash] the attributes to tag with
|
|
123
|
+
# @yield the block to execute with the tagged context
|
|
124
|
+
# @return [Object] the result of the block execution
|
|
125
|
+
def tag(attributes, &block)
|
|
126
|
+
dispatch_block_method(:tag, attributes, &block)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Execute a block within a logger context.
|
|
130
|
+
#
|
|
131
|
+
# @yield the block to execute within the context
|
|
132
|
+
# @return [Object] the result of the block execution
|
|
133
|
+
def context(&block)
|
|
134
|
+
dispatch_block_method(:context, &block)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Ensure a Lumberjack context is present for the duration of the block.
|
|
138
|
+
#
|
|
139
|
+
# @yield the block to execute within the ensured context
|
|
140
|
+
# @return [Object] the result of the block execution
|
|
141
|
+
def ensure_context(&block)
|
|
142
|
+
dispatch_block_method(:ensure_context, &block)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Append values to an existing attribute.
|
|
146
|
+
#
|
|
147
|
+
# @param attribute_name [String, Symbol] the name of the attribute
|
|
148
|
+
# @param tag [Array] the values to append
|
|
149
|
+
# @yield the block to execute with the modified attribute
|
|
150
|
+
# @return [Object] the result of the block execution
|
|
151
|
+
def append_to(attribute_name, *tag, &block)
|
|
152
|
+
dispatch_block_method(:append_to, attribute_name, *tag, &block)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Clear all current attributes.
|
|
156
|
+
#
|
|
157
|
+
# @yield the block to execute with cleared attributes
|
|
158
|
+
# @return [Object] the result of the block execution
|
|
159
|
+
def clear_attributes(&block)
|
|
160
|
+
dispatch_block_method(:clear_attributes, &block)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Execute a block without any tags.
|
|
164
|
+
#
|
|
165
|
+
# @yield the block to execute without tags
|
|
166
|
+
# @return [Object] the result of the block execution
|
|
167
|
+
def untagged(&block)
|
|
168
|
+
dispatch_block_method(:untagged, &block)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Set the progname temporarily for a block.
|
|
172
|
+
#
|
|
173
|
+
# @param value [String] the progname to set
|
|
174
|
+
# @yield the block to execute with the specified progname
|
|
175
|
+
# @return [Object] the result of the block execution
|
|
176
|
+
def with_progname(value, &block)
|
|
177
|
+
dispatch_block_method(:with_progname, value, &block)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Alias for with_progname for backward compatibility.
|
|
181
|
+
#
|
|
182
|
+
# @param value [String] the progname to set
|
|
183
|
+
# @yield the block to execute with the specified progname
|
|
184
|
+
# @return [Object] the result of the block execution
|
|
185
|
+
def set_progname(value, &block)
|
|
186
|
+
dispatch_block_method(:with_progname, value, &block)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Create a forked logger from this broadcast logger.
|
|
190
|
+
#
|
|
191
|
+
# @param level [Symbol, Integer] optional log level for the forked logger
|
|
192
|
+
# @param progname [String] optional progname for the forked logger
|
|
193
|
+
# @param attributes [Hash] optional attributes for the forked logger
|
|
194
|
+
# @return [Lumberjack::ForkedLogger] the forked logger
|
|
195
|
+
def fork(level: nil, progname: nil, attributes: nil)
|
|
196
|
+
logger = Lumberjack::ForkedLogger.new(self)
|
|
197
|
+
logger.level = level if level
|
|
198
|
+
logger.progname = progname if progname
|
|
199
|
+
logger.tag!(attributes) if attributes && !attributes.empty?
|
|
200
|
+
logger
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
private
|
|
204
|
+
|
|
205
|
+
# Lumberjack loggers support an optional attributes argument to the logging methods. This method provides
|
|
206
|
+
# compatibility with other Loggers that don't support that argument. The arguments here are funky because
|
|
207
|
+
# the methods on Logger are funky. On Logger the sole argument to a logging method can be message or
|
|
208
|
+
# the progname depending on if the message is in the block.
|
|
209
|
+
#
|
|
210
|
+
# @param logger [Logger] the logger to call the method on
|
|
211
|
+
# @param method [Symbol] the logging method to call
|
|
212
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
213
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
214
|
+
# @yield optional block that returns the message
|
|
215
|
+
# @return [void]
|
|
216
|
+
def call_with_attributes_arg(logger, method, message_or_progname_or_attributes, progname_or_attributes, &block)
|
|
217
|
+
if logger.is_a?(Lumberjack::ContextLogger)
|
|
218
|
+
logger.send(method, message_or_progname_or_attributes, progname_or_attributes, &block)
|
|
219
|
+
elsif block
|
|
220
|
+
progname = message_or_progname_or_attributes unless progname_or_attributes.is_a?(Hash)
|
|
221
|
+
logger.send(method, progname, &block)
|
|
222
|
+
else
|
|
223
|
+
logger.send(method, message_or_progname_or_attributes)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Lumberjack loggers support an optional attributes argument to the logging methods. This method provides
|
|
228
|
+
# compatibility with other Loggers that don't support that argument. The arguments here are funky because
|
|
229
|
+
# the methods on Logger#add are funky. On Logger the sole argument to a logging method can be message or
|
|
230
|
+
# the progname depending on if the message is in the block.
|
|
231
|
+
#
|
|
232
|
+
# @param logger [Logger] the logger to call the method on
|
|
233
|
+
# @param severity [Integer, Symbol, String] the severity for the log entry
|
|
234
|
+
# @param message_or_progname_or_attributes [String, Hash] the message, progname, or attributes
|
|
235
|
+
# @param progname_or_attributes [String, Hash] the progname or attributes
|
|
236
|
+
# @yield optional block that returns the message
|
|
237
|
+
# @return [void]
|
|
238
|
+
def call_add_with_attributes_arg(logger, severity, message_or_progname_or_attributes, progname_or_attributes, &block)
|
|
239
|
+
if logger.is_a?(Lumberjack::ContextLogger)
|
|
240
|
+
logger.add(severity, message_or_progname_or_attributes, progname_or_attributes, &block)
|
|
241
|
+
elsif block
|
|
242
|
+
progname = message_or_progname_or_attributes unless progname_or_attributes.is_a?(Hash)
|
|
243
|
+
logger.add(severity, progname, &block)
|
|
244
|
+
else
|
|
245
|
+
logger.add(severity, message_or_progname_or_attributes)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Guard against multiple loggers responding to the same method that takes
|
|
250
|
+
# a block. In that case we don't want to call the block multiple times.
|
|
251
|
+
# This does not include the logging methods like `info` but does include
|
|
252
|
+
# methods like `tag` that are expected to be called with a block that
|
|
253
|
+
# has business logic inside of it.
|
|
254
|
+
#
|
|
255
|
+
# This method is used for methods that modify the state of the logger. Since the block
|
|
256
|
+
# is only called once, other loggers will not have the internal state modified as expected.
|
|
257
|
+
#
|
|
258
|
+
# @param name [Symbol] the method name to dispatch
|
|
259
|
+
# @yield optional block to execute
|
|
260
|
+
# @return [Object] the result of the method execution
|
|
261
|
+
def dispatch_block_method(name, ...)
|
|
262
|
+
loggers = broadcasts.select { |logger| logger.respond_to?(name) }
|
|
263
|
+
|
|
264
|
+
if loggers.none?
|
|
265
|
+
result = yield if block_given?
|
|
266
|
+
return result
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
return loggers.first.send(name, ...) if loggers.one?
|
|
270
|
+
|
|
271
|
+
message = "BroadcastLogger cannot call #{name} on multiple loggers with a block."
|
|
272
|
+
loggers.first.warn("#{message} It was called on this logger.")
|
|
273
|
+
loggers[1..].each { |logger| logger.warn("#{message} It was not called on this logger.") }
|
|
274
|
+
loggers.first.send(name, ...)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Dispatch to each logger and the block if any. The block will only be called once.
|
|
278
|
+
#
|
|
279
|
+
# @param block [Proc] Block that will be called on the wrapped method.
|
|
280
|
+
# @yield block to execute for each logger
|
|
281
|
+
# @return [Object] the result of the first logger's block execution
|
|
282
|
+
# @yieldparam logger [Logger] the current logger
|
|
283
|
+
# @yieldparam one_time_block [Proc, nil] the block to execute, or nil if no block was given.
|
|
284
|
+
def dispatch_to_each(block)
|
|
285
|
+
if block
|
|
286
|
+
called = false
|
|
287
|
+
result = nil
|
|
288
|
+
one_time_block = lambda do
|
|
289
|
+
if called
|
|
290
|
+
result
|
|
291
|
+
else
|
|
292
|
+
called = true
|
|
293
|
+
result = block.call
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
broadcasts.map { |logger| yield(logger, one_time_block) }.first
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# This Rack middleware provides a Lumberjack context for each request.
|
|
6
|
+
class ContextMiddleware
|
|
7
|
+
# @param app [#call] The Rack application.
|
|
8
|
+
def initialize(app)
|
|
9
|
+
@app = app
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Process a request through the middleware stack with Lumberjack context.
|
|
13
|
+
#
|
|
14
|
+
# @param env [Hash] the Rack environment hash
|
|
15
|
+
# @return [Array] the Rack response array
|
|
16
|
+
def call(env)
|
|
17
|
+
Lumberjack::Rails.logger_context do
|
|
18
|
+
@app.call(env)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack
|
|
4
|
+
module Rails
|
|
5
|
+
# Extension that provides log level override functionality.
|
|
6
|
+
#
|
|
7
|
+
# This module allows temporary overriding of the logger's level using
|
|
8
|
+
# Rails' local_level mechanism while maintaining compatibility with
|
|
9
|
+
# the underlying Lumberjack logger.
|
|
10
|
+
module LogAtLevel
|
|
11
|
+
# Get the effective log level, checking for local level override first.
|
|
12
|
+
#
|
|
13
|
+
# @return [Integer] the effective log level
|
|
14
|
+
def level
|
|
15
|
+
local_level || super
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lumberjack::Rails
|
|
4
|
+
# Extension for Rails log subscribers to provide Lumberjack logger integration.
|
|
5
|
+
#
|
|
6
|
+
# This module enables Rails log subscribers (such as ActiveRecord::LogSubscriber,
|
|
7
|
+
# ActionController::LogSubscriber, etc.) to use forked Lumberjack loggers.
|
|
8
|
+
# Forked loggers provide isolation, allowing different log levels and attributes
|
|
9
|
+
# to be set for different log subscribers without affecting the main logger.
|
|
10
|
+
#
|
|
11
|
+
# When a log subscriber's logger is accessed, this extension checks if the
|
|
12
|
+
# parent logger supports forking. If it does, a ForkedLogger is created and
|
|
13
|
+
# cached for subsequent use. This ensures each log subscriber has its own
|
|
14
|
+
# isolated logger context.
|
|
15
|
+
module LogSubscriberExtension
|
|
16
|
+
extend ActiveSupport::Concern
|
|
17
|
+
|
|
18
|
+
prepended do
|
|
19
|
+
@__logger ||= nil
|
|
20
|
+
@__silenced_events ||= nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class_methods do
|
|
24
|
+
# Get the logger for this log subscriber class.
|
|
25
|
+
#
|
|
26
|
+
# This method overrides the default Rails log subscriber logger behavior
|
|
27
|
+
# to provide Lumberjack forked logger support. If the parent logger supports
|
|
28
|
+
# forking, a ForkedLogger is created and cached. Otherwise, the original
|
|
29
|
+
# logger is returned unchanged.
|
|
30
|
+
#
|
|
31
|
+
# @return [Lumberjack::ForkedLogger, Logger] the logger instance for this subscriber
|
|
32
|
+
def logger
|
|
33
|
+
class_logger = super
|
|
34
|
+
class_logger = class_logger.call if class_logger.is_a?(Proc)
|
|
35
|
+
|
|
36
|
+
if class_logger.respond_to?(:fork)
|
|
37
|
+
if !@__logger.is_a?(Lumberjack::ForkedLogger) || @__logger&.parent_logger != class_logger
|
|
38
|
+
@__logger = class_logger.fork
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
@__logger = class_logger
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@__logger
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Silence an individual event for this subscriber. The event name is the name of the public
|
|
48
|
+
# instance method to silence.
|
|
49
|
+
#
|
|
50
|
+
# @param event_name [String, Symbol] the name of the event to silence
|
|
51
|
+
# @return [void]
|
|
52
|
+
def silence_event!(event_name)
|
|
53
|
+
@__silenced_events ||= Set.new
|
|
54
|
+
@__silenced_events << event_name.to_s
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Unsilence an individual event for this subscriber.
|
|
58
|
+
#
|
|
59
|
+
# @param event_name [String, Symbol] the name of the event to unsilence
|
|
60
|
+
# @return [void]
|
|
61
|
+
def unsilence_event!(event_name)
|
|
62
|
+
@__silenced_events&.delete(event_name.to_s)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Check if a specific event is silenced for this subscriber.
|
|
66
|
+
#
|
|
67
|
+
# @param event [String] the full event name of the event to check with the namespace
|
|
68
|
+
# @return [Boolean] true if the event is silenced, false otherwise
|
|
69
|
+
# @api private
|
|
70
|
+
def silenced_event?(event)
|
|
71
|
+
return false if @__silenced_events.nil?
|
|
72
|
+
|
|
73
|
+
i = event.index(".")
|
|
74
|
+
event_name = i ? event[0, i] : event
|
|
75
|
+
@__silenced_events.include?(event_name)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Override the silenced? method to check if the event has been explicitly silenced.
|
|
80
|
+
#
|
|
81
|
+
# @param event [String] the event to check
|
|
82
|
+
# @return [Boolean] true if the event is silenced, false otherwise
|
|
83
|
+
def silenced?(event)
|
|
84
|
+
super || self.class.silenced_event?(event)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Get the logger for this log subscriber instance.
|
|
88
|
+
#
|
|
89
|
+
# Delegates to the class-level logger method to ensure consistent
|
|
90
|
+
# behavior across all instances of the log subscriber.
|
|
91
|
+
#
|
|
92
|
+
# @return [Lumberjack::ForkedLogger, Logger] the logger instance for this subscriber
|
|
93
|
+
def logger
|
|
94
|
+
self.class.logger
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|