lumberjack 1.4.2 → 2.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 +4 -4
- data/ARCHITECTURE.md +524 -176
- data/CHANGELOG.md +89 -0
- data/README.md +604 -211
- data/UPGRADE_GUIDE.md +80 -0
- data/VERSION +1 -1
- data/lib/lumberjack/attribute_formatter.rb +451 -0
- data/lib/lumberjack/attributes_helper.rb +100 -0
- data/lib/lumberjack/context.rb +120 -23
- data/lib/lumberjack/context_logger.rb +620 -0
- data/lib/lumberjack/device/buffer.rb +209 -0
- data/lib/lumberjack/device/date_rolling_log_file.rb +10 -62
- data/lib/lumberjack/device/log_file.rb +76 -29
- data/lib/lumberjack/device/logger_wrapper.rb +137 -0
- data/lib/lumberjack/device/multi.rb +92 -30
- data/lib/lumberjack/device/null.rb +26 -8
- data/lib/lumberjack/device/size_rolling_log_file.rb +13 -54
- data/lib/lumberjack/device/test.rb +337 -0
- data/lib/lumberjack/device/writer.rb +184 -176
- data/lib/lumberjack/device.rb +134 -15
- data/lib/lumberjack/device_registry.rb +90 -0
- data/lib/lumberjack/entry_formatter.rb +357 -0
- data/lib/lumberjack/fiber_locals.rb +55 -0
- data/lib/lumberjack/forked_logger.rb +143 -0
- data/lib/lumberjack/formatter/date_time_formatter.rb +14 -3
- data/lib/lumberjack/formatter/exception_formatter.rb +12 -2
- data/lib/lumberjack/formatter/id_formatter.rb +13 -1
- data/lib/lumberjack/formatter/inspect_formatter.rb +14 -1
- data/lib/lumberjack/formatter/multiply_formatter.rb +10 -0
- data/lib/lumberjack/formatter/object_formatter.rb +13 -1
- data/lib/lumberjack/formatter/pretty_print_formatter.rb +15 -2
- data/lib/lumberjack/formatter/redact_formatter.rb +18 -3
- data/lib/lumberjack/formatter/round_formatter.rb +12 -0
- data/lib/lumberjack/formatter/string_formatter.rb +9 -1
- data/lib/lumberjack/formatter/strip_formatter.rb +13 -1
- data/lib/lumberjack/formatter/structured_formatter.rb +18 -2
- data/lib/lumberjack/formatter/tagged_message.rb +10 -32
- data/lib/lumberjack/formatter/tags_formatter.rb +32 -0
- data/lib/lumberjack/formatter/truncate_formatter.rb +8 -1
- data/lib/lumberjack/formatter.rb +271 -141
- data/lib/lumberjack/formatter_registry.rb +84 -0
- data/lib/lumberjack/io_compatibility.rb +133 -0
- data/lib/lumberjack/local_log_template.rb +209 -0
- data/lib/lumberjack/log_entry.rb +154 -79
- data/lib/lumberjack/log_entry_matcher/score.rb +276 -0
- data/lib/lumberjack/log_entry_matcher.rb +126 -0
- data/lib/lumberjack/logger.rb +328 -556
- data/lib/lumberjack/message_attributes.rb +38 -0
- data/lib/lumberjack/rack/context.rb +66 -15
- data/lib/lumberjack/rack.rb +0 -2
- data/lib/lumberjack/remap_attribute.rb +24 -0
- data/lib/lumberjack/severity.rb +52 -15
- data/lib/lumberjack/tag_context.rb +8 -71
- data/lib/lumberjack/tag_formatter.rb +22 -188
- data/lib/lumberjack/tags.rb +15 -21
- data/lib/lumberjack/template.rb +252 -62
- data/lib/lumberjack/template_registry.rb +60 -0
- data/lib/lumberjack/utils.rb +198 -48
- data/lib/lumberjack.rb +167 -59
- data/lumberjack.gemspec +4 -2
- metadata +41 -15
- data/lib/lumberjack/device/rolling_log_file.rb +0 -145
- data/lib/lumberjack/rack/request_id.rb +0 -31
- data/lib/lumberjack/rack/unit_of_work.rb +0 -21
- data/lib/lumberjack/tagged_logger_support.rb +0 -81
- data/lib/lumberjack/tagged_logging.rb +0 -29
data/lib/lumberjack/logger.rb
CHANGED
@@ -1,87 +1,149 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Lumberjack
|
4
|
-
# Logger is a thread
|
5
|
-
#
|
4
|
+
# Lumberjack::Logger is a thread-safe, feature-rich logging implementation that extends Ruby's standard
|
5
|
+
# library Logger class with advanced capabilities for structured logging.
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# Key features include:
|
8
|
+
# - Structured logging with attributes (key-value pairs) attached to log entries
|
9
|
+
# - Context isolation for scoping logging behavior to specific code blocks
|
10
|
+
# - Flexible output devices supporting files, streams, and custom destinations
|
11
|
+
# - Customizable formatters for messages and attributes
|
8
12
|
#
|
9
|
-
#
|
13
|
+
# The Logger maintains full API compatibility with Ruby's standard Logger while adding
|
14
|
+
# powerful extensions for modern logging needs.
|
15
|
+
#
|
16
|
+
# @example Basic usage
|
17
|
+
# logger = Lumberjack::Logger.new(STDOUT)
|
10
18
|
# logger.info("Starting processing")
|
11
19
|
# logger.debug("Processing options #{options.inspect}")
|
12
20
|
# logger.fatal("OMG the application is on fire!")
|
13
21
|
#
|
14
|
-
#
|
22
|
+
# @example Structured logging with attributes
|
23
|
+
# logger = Lumberjack::Logger.new("/var/log/app.log")
|
24
|
+
# logger.tag(request_id: "abc123") do
|
25
|
+
# logger.info("User logged in", user_id: 123, ip: "192.168.1.1")
|
26
|
+
# logger.info("Processing request") # Will include request_id: "abc123"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Log rotation
|
30
|
+
# # Keep 10 files, rotate when each reaches 10MB
|
31
|
+
# logger = Lumberjack::Logger.new("/var/log/app.log", 10, 10 * 1024 * 1024)
|
32
|
+
#
|
33
|
+
# @example Using different devices
|
34
|
+
# logger = Lumberjack::Logger.new("logs/application.log") # Log to file
|
35
|
+
# logger = Lumberjack::Logger.new(STDOUT, template: "{{severity}} - {{message}}") # Log to a stream with a template
|
36
|
+
# logger = Lumberjack::Logger.new(:test) # Log to an in memory buffer for testing
|
37
|
+
# logger = Lumberjack::Logger.new(another_logger) # Proxy logs to another logger
|
38
|
+
# logger = Lumberjack::Logger.new(MyDevice.new) # Log to a custom Lumberjack::Device
|
15
39
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# long running sections of code since it is likely that none of the messages logged before the long
|
19
|
-
# running code will appear in the log until the entire process finishes. You can set the +:flush_seconds+
|
20
|
-
# option on the constructor to force the device to be flushed periodically. This will create a new
|
21
|
-
# monitoring thread, but its use is highly recommended.
|
40
|
+
# @example Logging to multiple devices with an array
|
41
|
+
# logger = Lumberjack::Logger.new(["/var/log/app.log", [:stdout, {template: "{{message}}"}]])
|
22
42
|
#
|
43
|
+
# Log entries are written to a logging Device if their severity meets or exceeds the log level.
|
23
44
|
# Each log entry records the log message and severity along with the time it was logged, the
|
24
|
-
# program name, process id, and an optional hash of
|
25
|
-
# otherwise, it is up to the device how these values are recorded. Messages are converted to strings
|
45
|
+
# program name, process id, and an optional hash of attributes. Messages are converted to strings
|
26
46
|
# using a Formatter associated with the logger.
|
27
|
-
|
28
|
-
|
47
|
+
#
|
48
|
+
# @see Lumberjack::ContextLogger
|
49
|
+
# @see Lumberjack::Device
|
50
|
+
# @see Lumberjack::Template
|
51
|
+
# @see Lumberjack::EntryFormatter
|
52
|
+
class Logger < ::Logger
|
53
|
+
include ContextLogger
|
29
54
|
|
30
|
-
#
|
31
|
-
|
55
|
+
# Create a new logger to log to a Device.
|
56
|
+
#
|
57
|
+
# The +device+ argument can be in any one of several formats:
|
58
|
+
# - A symbol for a device name (e.g. :null, :test). You can call +Lumberjack::DeviceRegistry.registered_devices+ for a list.
|
59
|
+
# - A stream
|
60
|
+
# - A file path string or +Pathname+
|
61
|
+
# - A +Lumberjack::Device+ object
|
62
|
+
# - An object with a +write+ method will be wrapped in a Device::Writer
|
63
|
+
# - An array of any of the above will open a Multi device that will send output to all devices.
|
64
|
+
#
|
65
|
+
# @param logdev [Lumberjack::Device, IO, Symbol, String, Pathname] The device to log to.
|
66
|
+
# If this is a symbol, the device will be looked up from the DeviceRegistry. If it is
|
67
|
+
# a string or a Pathname, the logs will be sent to the corresponding file path.
|
68
|
+
# @param shift_age [Integer, String, Symbol] If this is an integer greater than zero, then
|
69
|
+
# log files will be rolled when they get to the size specified in shift_size and the number of
|
70
|
+
# files to keep will be determined by this value. Otherwise it will be interpreted as a date
|
71
|
+
# rolling value and must be one of "daily", "weekly", or "monthly". This parameter has no
|
72
|
+
# effect unless the device parameter is a file path or file stream. This can also be
|
73
|
+
# specified with the :roll keyword argument.
|
74
|
+
# @param shift_size [Integer] The size in bytes of the log files before rolling them. This can
|
75
|
+
# be passed as a string with a unit suffix of K, M, or G (e.g. "10M" for 10 megabytes).
|
76
|
+
# This can also be specified with the :max_size keyword argument.
|
77
|
+
# @param level [Integer, Symbol, String] The logging level below which messages will be ignored.
|
78
|
+
# @param progname [String] The name of the program that will be recorded with each log entry.
|
79
|
+
# @param formatter [Lumberjack::EntryFormatter, Lumberjack::Formatter, ::Logger::Formatter, :default, #call]
|
80
|
+
# The formatter to use for outputting messages to the log. If this is a Lumberjack::EntryFormatter
|
81
|
+
# or a Lumberjack::Formatter, it will be used to format structured log entries.
|
82
|
+
# You can also pass the value +:default+ to use the default message formatter which formats
|
83
|
+
# non-primitive objects with +inspect+ and includes the backtrace in exceptions.
|
84
|
+
#
|
85
|
+
# For compatibility with the standard library Logger when writing to a stream, you can also
|
86
|
+
# pass in a +::Logger::Formatter+ object or a callable object that takes exactly 4 arguments
|
87
|
+
# (severity, time, progname, msg).
|
88
|
+
# @param datetime_format [String] The format to use for log timestamps.
|
89
|
+
# @param binmode [Boolean] Whether to open the log file in binary mode.
|
90
|
+
# @param shift_period_suffix [String] The suffix to use for the shifted log file names.
|
91
|
+
# @param kwargs [Hash] Additional device-specific options. These will be passed through when creating
|
92
|
+
# a device from the logdev argument.
|
93
|
+
# @return [Lumberjack::Logger] A new logger instance.
|
94
|
+
def initialize(logdev, shift_age = 0, shift_size = 1048576,
|
95
|
+
level: DEBUG, progname: nil, formatter: nil, datetime_format: nil,
|
96
|
+
binmode: false, shift_period_suffix: "%Y%m%d", **kwargs)
|
97
|
+
init_fiber_locals!
|
98
|
+
|
99
|
+
if shift_age.is_a?(Hash)
|
100
|
+
Lumberjack::Utils.deprecated("Logger.new(options)", "Passing a Hash as the second argument to Logger.new is deprecated and will be removed in version 2.1; use keyword arguments instead.")
|
101
|
+
options = shift_age
|
102
|
+
level = options[:level] if options.include?(:level)
|
103
|
+
progname = options[:progname] if options.include?(:progname)
|
104
|
+
formatter = options[:formatter] if options.include?(:formatter)
|
105
|
+
datetime_format = options[:datetime_format] if options.include?(:datetime_format)
|
106
|
+
kwargs = options.merge(kwargs)
|
107
|
+
end
|
32
108
|
|
33
|
-
|
34
|
-
|
109
|
+
# Include standard args that affect devices with the optional kwargs which may
|
110
|
+
# contain device specific options.
|
111
|
+
device_options = kwargs.merge(shift_age: shift_age, shift_size: size_with_units(shift_size), binmode: binmode, shift_period_suffix: shift_period_suffix)
|
112
|
+
device_options[:standard_logger_formatter] = formatter if standard_logger_formatter?(formatter)
|
35
113
|
|
36
|
-
|
37
|
-
|
114
|
+
if device_options.include?(:roll)
|
115
|
+
Utils.deprecated("Logger.options(:roll)", "Lumberjack::Logger :roll option is deprecated and will be removed in version 2.1; use the shift_age argument instead.")
|
116
|
+
device_options[:shift_age] = device_options.delete(:roll) unless shift_age != 0
|
117
|
+
end
|
38
118
|
|
39
|
-
|
40
|
-
|
119
|
+
if device_options.include?(:max_size)
|
120
|
+
Utils.deprecated("Logger.options(:max_size)", "Lumberjack::Logger :max_size option is deprecated and will be removed in version 2.1; use the shift_size argument instead.")
|
121
|
+
device_options[:shift_age] = 10 if shift_age == 0
|
122
|
+
device_options[:shift_size] = device_options.delete(:max_size)
|
123
|
+
end
|
41
124
|
|
42
|
-
|
43
|
-
|
125
|
+
message_formatter = nil
|
126
|
+
if device_options.include?(:message_formatter)
|
127
|
+
Utils.deprecated("Logger.options(:message_formatter)", "Lumberjack::Logger :message_formatter option is deprecated and will be removed in version 2.1; use the formatter argument instead to specify an EntryFormatter.")
|
128
|
+
message_formatter = device_options.delete(:message_formatter)
|
129
|
+
end
|
44
130
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# If it has a +write+ method, it will be wrapped in a Device::Writer class.
|
51
|
-
# If it is :null, it will be a Null device that won't record any output.
|
52
|
-
# Otherwise, it will be assumed to be file path and wrapped in a Device::LogFile class.
|
53
|
-
#
|
54
|
-
# All other options are passed to the device constuctor.
|
55
|
-
#
|
56
|
-
# @param [Lumberjack::Device, Object, Symbol, String] device The device to log to.
|
57
|
-
# @param [Hash] options The options for the logger.
|
58
|
-
# @option options [Integer, Symbol, String] :level The logging level below which messages will be ignored.
|
59
|
-
# @option options [Lumberjack::Formatter] :formatter The formatter to use for outputting messages to the log.
|
60
|
-
# @option options [String] :datetime_format The format to use for log timestamps.
|
61
|
-
# @option options [Lumberjack::Formatter] :message_formatter The MessageFormatter to use for formatting log messages.
|
62
|
-
# @option options [Lumberjack::TagFormatter] :tag_formatter The TagFormatter to use for formatting tags.
|
63
|
-
# @option options [String] :progname The name of the program that will be recorded with each log entry.
|
64
|
-
# @option options [Numeric] :flush_seconds The maximum number of seconds between flush calls.
|
65
|
-
# @option options [Boolean] :roll If the log device is a file path, it will be a Device::DateRollingLogFile if this is set.
|
66
|
-
# @option options [Integer] :max_size If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
|
67
|
-
def initialize(device = $stdout, options = {})
|
68
|
-
options = options.dup
|
69
|
-
self.level = options.delete(:level) || INFO
|
70
|
-
self.progname = options.delete(:progname)
|
71
|
-
max_flush_seconds = options.delete(:flush_seconds).to_f
|
72
|
-
|
73
|
-
@logdev = open_device(device, options) if device
|
74
|
-
self.formatter = (options[:formatter] || Formatter.new)
|
75
|
-
@message_formatter = options[:message_formatter] || Formatter.empty
|
76
|
-
@tag_formatter = options[:tag_formatter] || TagFormatter.new
|
77
|
-
time_format = options[:datetime_format] || options[:time_format]
|
78
|
-
self.datetime_format = time_format if time_format
|
79
|
-
@last_flushed_at = Time.now
|
80
|
-
@silencer = true
|
81
|
-
@tags = {}
|
82
|
-
@closed = false
|
131
|
+
attribute_formatter = nil
|
132
|
+
if device_options.include?(:tag_formatter)
|
133
|
+
Utils.deprecated("Logger.options(:tag_formatter)", "Lumberjack::Logger :tag_formatter option is deprecated and will be removed in version 2.1; use the formatter argument instead to specify an EntryFormatter.")
|
134
|
+
attribute_formatter = device_options.delete(:tag_formatter)
|
135
|
+
end
|
83
136
|
|
84
|
-
|
137
|
+
@logdev = Device.open_device(logdev, device_options)
|
138
|
+
|
139
|
+
@context = Context.new
|
140
|
+
self.level = level || DEBUG
|
141
|
+
self.progname = progname
|
142
|
+
|
143
|
+
self.formatter = build_entry_formatter(formatter, message_formatter, attribute_formatter)
|
144
|
+
self.datetime_format = datetime_format if datetime_format
|
145
|
+
|
146
|
+
@closed = false
|
85
147
|
end
|
86
148
|
|
87
149
|
# Get the logging device that is used to write log entries.
|
@@ -93,10 +155,19 @@ module Lumberjack
|
|
93
155
|
|
94
156
|
# Set the logging device to a new device.
|
95
157
|
#
|
96
|
-
# @param [Lumberjack::Device]
|
158
|
+
# @param device [Lumberjack::Device] The new logging device.
|
97
159
|
# @return [void]
|
98
160
|
def device=(device)
|
99
|
-
@logdev =
|
161
|
+
@logdev = Device.open_device(device, {})
|
162
|
+
end
|
163
|
+
|
164
|
+
# Set the formatter used for log entries. This can be an EntryFormatter, a standard Logger::Formatter,
|
165
|
+
# or any callable object that formats log entries.
|
166
|
+
#
|
167
|
+
# @param value [Lumberjack::EntryFormatter, ::Logger::Formatter, #call] The formatter to use.
|
168
|
+
# @return [void]
|
169
|
+
def formatter=(value)
|
170
|
+
@formatter = build_entry_formatter(value, nil, nil)
|
100
171
|
end
|
101
172
|
|
102
173
|
# Get the timestamp format on the device if it has one.
|
@@ -108,7 +179,7 @@ module Lumberjack
|
|
108
179
|
|
109
180
|
# Set the timestamp format on the device if it is supported.
|
110
181
|
#
|
111
|
-
# @param [String]
|
182
|
+
# @param format [String] The timestamp format.
|
112
183
|
# @return [void]
|
113
184
|
def datetime_format=(format)
|
114
185
|
if device.respond_to?(:datetime_format=)
|
@@ -116,156 +187,55 @@ module Lumberjack
|
|
116
187
|
end
|
117
188
|
end
|
118
189
|
|
119
|
-
# Get the
|
120
|
-
# severity level will be ignored.
|
190
|
+
# Get the message formatter used to format log messages.
|
121
191
|
#
|
122
|
-
# @return [
|
123
|
-
def
|
124
|
-
|
192
|
+
# @return [Lumberjack::Formatter] The message formatter.
|
193
|
+
def message_formatter
|
194
|
+
formatter.message_formatter
|
125
195
|
end
|
126
196
|
|
127
|
-
|
128
|
-
|
129
|
-
# Set the log level using either an integer level like Logger::INFO or a label like
|
130
|
-
# :info or "info"
|
197
|
+
# Set the message formatter used to format log messages.
|
131
198
|
#
|
132
|
-
# @param [
|
199
|
+
# @param value [Lumberjack::Formatter] The message formatter to use.
|
133
200
|
# @return [void]
|
134
|
-
def
|
135
|
-
|
201
|
+
def message_formatter=(value)
|
202
|
+
formatter.message_formatter = value
|
136
203
|
end
|
137
204
|
|
138
|
-
|
139
|
-
|
140
|
-
# Adjust the log level during the block execution for the current Fiber only.
|
205
|
+
# Get the attribute formatter used to format log entry attributes.
|
141
206
|
#
|
142
|
-
# @
|
143
|
-
|
144
|
-
|
145
|
-
push_thread_local_value(:lumberjack_logger_level, Severity.coerce(severity), &block)
|
207
|
+
# @return [Lumberjack::AttributeFormatter] The attribute formatter.
|
208
|
+
def attribute_formatter
|
209
|
+
formatter.attribute_formatter
|
146
210
|
end
|
147
211
|
|
148
|
-
# Set the
|
212
|
+
# Set the attribute formatter used to format log entry attributes.
|
149
213
|
#
|
150
|
-
# @param [Lumberjack::
|
214
|
+
# @param value [Lumberjack::AttributeFormatter] The attribute formatter to use.
|
151
215
|
# @return [void]
|
152
|
-
def
|
153
|
-
|
154
|
-
end
|
155
|
-
|
156
|
-
# Get the Lumberjack::Formatter used to format objects for logging as messages.
|
157
|
-
#
|
158
|
-
# @return [Lumberjack::Formatter] The formatter.
|
159
|
-
def formatter
|
160
|
-
if respond_to?(:tagged)
|
161
|
-
# Wrap in an object that supports ActiveSupport::TaggedLogger API
|
162
|
-
TaggedLoggerSupport::Formatter.new(logger: self, formatter: @_formatter)
|
163
|
-
else
|
164
|
-
@_formatter
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
# Enable this logger to function like an ActiveSupport::TaggedLogger. This will make the logger
|
169
|
-
# API compatible with ActiveSupport::TaggedLogger and is provided as a means of compatibility
|
170
|
-
# with other libraries that assume they can call the `tagged` method on a logger to add tags.
|
171
|
-
#
|
172
|
-
# The tags added with this method are just strings so they are stored in the logger tags
|
173
|
-
# in an array under the "tagged" tag. So calling `logger.tagged("foo", "bar")` will result
|
174
|
-
# in tags `{"tagged" => ["foo", "bar"]}`.
|
175
|
-
#
|
176
|
-
# @return [Lumberjack::Logger] self.
|
177
|
-
def tagged_logger!
|
178
|
-
extend(TaggedLoggerSupport)
|
179
|
-
self
|
216
|
+
def attribute_formatter=(value)
|
217
|
+
formatter.attribute_formatter = value
|
180
218
|
end
|
181
219
|
|
182
|
-
#
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
#
|
187
|
-
# The severity can be passed in either as one of the Severity constants,
|
188
|
-
# or as a Severity label.
|
189
|
-
#
|
190
|
-
# @param [Integer, Symbol, String] severity The severity of the message.
|
191
|
-
# @param [Object] message The message to log.
|
192
|
-
# @param [String] progname The name of the program that is logging the message.
|
193
|
-
# @param [Hash] tags The tags to add to the log entry.
|
194
|
-
# @return [void]
|
195
|
-
#
|
196
|
-
# @example
|
197
|
-
#
|
198
|
-
# logger.add_entry(Logger::ERROR, exception)
|
199
|
-
# logger.add_entry(Logger::INFO, "Request completed")
|
200
|
-
# logger.add_entry(:warn, "Request took a long time")
|
201
|
-
# logger.add_entry(Logger::DEBUG){"Start processing with options #{options.inspect}"}
|
202
|
-
def add_entry(severity, message, progname = nil, tags = nil)
|
203
|
-
severity = Severity.label_to_level(severity) unless severity.is_a?(Integer)
|
204
|
-
return true unless device && severity && severity >= level
|
205
|
-
return true if Thread.current[:lumberjack_logging]
|
206
|
-
|
207
|
-
begin
|
208
|
-
Thread.current[:lumberjack_logging] = true # Prevent circular calls to add_entry
|
209
|
-
|
210
|
-
time = Time.now
|
211
|
-
|
212
|
-
message = message.call if message.is_a?(Proc)
|
213
|
-
msg_class_formatter = message_formatter&.formatter_for(message.class)
|
214
|
-
if msg_class_formatter
|
215
|
-
message = msg_class_formatter.call(message)
|
216
|
-
elsif formatter
|
217
|
-
message = formatter.format(message)
|
218
|
-
end
|
219
|
-
message_tags = nil
|
220
|
-
if message.is_a?(Formatter::TaggedMessage)
|
221
|
-
message_tags = message.tags
|
222
|
-
message = message.message
|
223
|
-
end
|
224
|
-
|
225
|
-
progname ||= self.progname
|
226
|
-
message_tags = Utils.flatten_tags(message_tags) if message_tags
|
227
|
-
|
228
|
-
current_tags = self.tags
|
229
|
-
tags = nil unless tags.is_a?(Hash)
|
230
|
-
tags = merge_tags(current_tags, tags)
|
231
|
-
tags = merge_tags(tags, message_tags) if message_tags
|
232
|
-
tags = Tags.expand_runtime_values(tags)
|
233
|
-
tags = tag_formatter.format(tags) if tag_formatter
|
234
|
-
|
235
|
-
entry = LogEntry.new(time, severity, message, progname, Process.pid, tags)
|
236
|
-
write_to_device(entry)
|
237
|
-
ensure
|
238
|
-
Thread.current[:lumberjack_logging] = nil
|
220
|
+
# @deprecated Use {#attribute_formatter} instead.
|
221
|
+
def tag_formatter
|
222
|
+
Utils.deprecated("Logger#tag_formatter", "Lumberjack::Logger#tag_formatter is deprecated and will be removed in version 2.1; use attribute_formatter instead.") do
|
223
|
+
formatter.attributes.attribute_formatter
|
239
224
|
end
|
240
|
-
true
|
241
225
|
end
|
242
226
|
|
243
|
-
#
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
# @param [String] progname The name of the program that is logging the message.
|
248
|
-
# @return [void]
|
249
|
-
def add(severity, message = nil, progname = nil, &block)
|
250
|
-
if message.nil?
|
251
|
-
if block
|
252
|
-
message = block
|
253
|
-
else
|
254
|
-
message = progname
|
255
|
-
progname = nil
|
256
|
-
end
|
227
|
+
# @deprecated Use {#attribute_formatter=} instead.
|
228
|
+
def tag_formatter=(value)
|
229
|
+
Utils.deprecated("Logger#tag_formatter=", "Lumberjack::Logger#tag_formatter= is deprecated and will be removed in version 2.1; use attribute_formatter= instead.") do
|
230
|
+
formatter.attributes.attribute_formatter = value
|
257
231
|
end
|
258
|
-
add_entry(severity, message, progname)
|
259
232
|
end
|
260
233
|
|
261
|
-
alias_method :log, :add
|
262
|
-
|
263
234
|
# Flush the logging device. Messages are not guaranteed to be written until this method is called.
|
264
235
|
#
|
265
236
|
# @return [void]
|
266
237
|
def flush
|
267
238
|
device.flush
|
268
|
-
@last_flushed_at = Time.now
|
269
239
|
nil
|
270
240
|
end
|
271
241
|
|
@@ -282,454 +252,256 @@ module Lumberjack
|
|
282
252
|
#
|
283
253
|
# @return [Boolean] +true+ if the logging device is closed.
|
284
254
|
def closed?
|
285
|
-
@closed
|
255
|
+
return true if @closed
|
256
|
+
|
257
|
+
device.respond_to?(:closed?) && device.closed?
|
286
258
|
end
|
287
259
|
|
288
260
|
# Reopen the logging device.
|
289
261
|
#
|
290
|
-
# @param [Object]
|
262
|
+
# @param logdev [Object] passed through to the logging device.
|
263
|
+
# @return [Lumberjack::Logger] self
|
291
264
|
def reopen(logdev = nil)
|
292
265
|
@closed = false
|
293
266
|
device.reopen(logdev) if device.respond_to?(:reopen)
|
267
|
+
self
|
294
268
|
end
|
295
269
|
|
296
|
-
#
|
270
|
+
# Set the program name that is associated with log messages. If a block
|
271
|
+
# is given, the program name will be valid only within the block.
|
297
272
|
#
|
298
|
-
# @param [
|
299
|
-
# if the message is passed in a block.
|
300
|
-
# @param [String, Hash] progname_or_tags The name of the program that is logging the message or tags
|
301
|
-
# if the message is passed in a block.
|
273
|
+
# @param value [String] The program name to use.
|
302
274
|
# @return [void]
|
303
|
-
|
304
|
-
|
275
|
+
# @deprecated Use with_progname or progname= instead.
|
276
|
+
def set_progname(value, &block)
|
277
|
+
Utils.deprecated("Logger#set_progname", "Lumberjack::Logger#set_progname is deprecated and will be removed in version 2.1; use with_progname or progname= instead.") do
|
278
|
+
if block
|
279
|
+
with_progname(value, &block)
|
280
|
+
else
|
281
|
+
self.progname = value
|
282
|
+
end
|
283
|
+
end
|
305
284
|
end
|
306
285
|
|
307
|
-
#
|
286
|
+
# Alias method for #attributes to provide backward compatibility with version 1.x API. This
|
287
|
+
# method will eventually be removed.
|
308
288
|
#
|
309
|
-
# @return [
|
310
|
-
|
311
|
-
|
289
|
+
# @return [Hash]
|
290
|
+
# @deprecated Use {#attributes} instead
|
291
|
+
def tags
|
292
|
+
Utils.deprecated("Logger#tags", "Lumberjack::Logger#tags is deprecated and will be removed in version 2.1; use attributes instead.") do
|
293
|
+
attributes
|
294
|
+
end
|
312
295
|
end
|
313
296
|
|
314
|
-
#
|
297
|
+
# Alias method for #attribute_value to provide backward compatibility with version 1.x API. This
|
298
|
+
# method will eventually be removed.
|
315
299
|
#
|
316
|
-
# @return [
|
317
|
-
|
318
|
-
|
300
|
+
# @return [Hash]
|
301
|
+
# @deprecated Use {#attribute_value} instead
|
302
|
+
def tag_value(name)
|
303
|
+
Utils.deprecated("Logger#tag_value", "Lumberjack::Logger#tag_value is deprecated and will be removed in version 2.1; use attribute_value instead.") do
|
304
|
+
attribute_value(name)
|
305
|
+
end
|
319
306
|
end
|
320
307
|
|
321
|
-
#
|
308
|
+
# Use tag! instead
|
322
309
|
#
|
323
|
-
# @param [Object] message_or_progname_or_tags The message to log or progname
|
324
|
-
# if the message is passed in a block.
|
325
|
-
# @param [String, Hash] progname_or_tags The name of the program that is logging the message or tags
|
326
|
-
# if the message is passed in a block.
|
327
310
|
# @return [void]
|
328
|
-
|
329
|
-
|
311
|
+
# @deprecated Use {#tag!} instead.
|
312
|
+
def tag_globally(tags)
|
313
|
+
Utils.deprecated("Logger#tag_globally", "Lumberjack::Logger#tag_globally is deprecated and will be removed in version 2.1; use tag! instead.") do
|
314
|
+
tag!(tags)
|
315
|
+
end
|
330
316
|
end
|
331
317
|
|
332
|
-
#
|
318
|
+
# Use context? instead
|
333
319
|
#
|
334
320
|
# @return [Boolean]
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
#
|
341
|
-
# @return [void]
|
342
|
-
def error!
|
343
|
-
self.level = ERROR
|
321
|
+
# @deprecated Use {#in_context?} instead.
|
322
|
+
def in_tag_context?
|
323
|
+
Utils.deprecated("Logger#in_tag_context?", "Lumberjack::Logger#in_tag_context? is deprecated and will be removed in version 2.1; use in_context? instead.") do
|
324
|
+
context?
|
325
|
+
end
|
344
326
|
end
|
345
327
|
|
346
|
-
#
|
328
|
+
# Remove a tag from the current context block. If this is called inside a context block,
|
329
|
+
# the attributes will only be removed for the duration of that block. Otherwise they will be removed
|
330
|
+
# from the global attributes.
|
347
331
|
#
|
348
|
-
# @param [
|
349
|
-
# if the message is passed in a block.
|
350
|
-
# @param [String, Hash] progname_or_tags The name of the program that is logging the message or tags
|
351
|
-
# if the message is passed in a block.
|
332
|
+
# @param tag_names [Array<String, Symbol>] The attributes to remove.
|
352
333
|
# @return [void]
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
# @return [Boolean]
|
360
|
-
def warn?
|
361
|
-
level <= WARN
|
334
|
+
# @deprecated Use untag or untag! instead.
|
335
|
+
def remove_tag(*tag_names)
|
336
|
+
Utils.deprecated("Logger#remove_tag", "Lumberjack::Logger#remove_tag is deprecated and will be removed in version 2.1; use untag or untag! instead.") do
|
337
|
+
attributes = current_context&.attributes
|
338
|
+
AttributesHelper.new(attributes).delete(*tag_names) if attributes
|
339
|
+
end
|
362
340
|
end
|
363
341
|
|
364
|
-
#
|
342
|
+
# Alias for append_to(:tagged) for compatibility with ActiveSupport support in Lumberjack 1.x.
|
343
|
+
# This functionality has been moved to the lumberjack_rails gem. Note that in that gem the
|
344
|
+
# tags are added to the :tags attribute instead of the :tagged attribute.
|
365
345
|
#
|
366
|
-
# @
|
367
|
-
|
368
|
-
|
346
|
+
# @see append_to
|
347
|
+
# @deprecated This implementation is deprecated. Install the lumberjack_rails gem for full support.
|
348
|
+
def tagged(*tags, &block)
|
349
|
+
deprecation_message = "Install the lumberjack_rails gem for full support of the tagged method."
|
350
|
+
Utils.deprecated("Logger#tagged", deprecation_message) do
|
351
|
+
append_to(:tagged, *tags, &block)
|
352
|
+
end
|
369
353
|
end
|
370
354
|
|
371
|
-
#
|
355
|
+
# Alias for clear_attributes.
|
372
356
|
#
|
373
|
-
# @
|
374
|
-
#
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
call_add_entry(INFO, message_or_progname_or_tags, progname_or_tags, &block)
|
357
|
+
# @see clear_attributes
|
358
|
+
# @deprecated Use clear_attributes instead.
|
359
|
+
def untagged(&block)
|
360
|
+
Utils.deprecated("Logger#untagged", "Lumberjack::Logger#untagged is deprecated and will be removed in version 2.1; use clear_attributes instead.") do
|
361
|
+
clear_attributes(&block)
|
362
|
+
end
|
380
363
|
end
|
381
364
|
|
382
|
-
#
|
365
|
+
# Alias for with_level for compatibility with ActiveSupport loggers. This functionality
|
366
|
+
# has been moved to the lumberjack_rails gem.
|
383
367
|
#
|
384
|
-
# @
|
385
|
-
|
386
|
-
|
368
|
+
# @see with_level
|
369
|
+
# @deprecated This implementation is deprecated. Install the lumberjack_rails gem for full support.
|
370
|
+
def log_at(level, &block)
|
371
|
+
deprecation_message = "Install the lumberjack_rails gem for full support of the log_at method."
|
372
|
+
Utils.deprecated("Logger#log_at", deprecation_message) do
|
373
|
+
with_level(level, &block)
|
374
|
+
end
|
387
375
|
end
|
388
376
|
|
389
|
-
#
|
377
|
+
# Alias for with_level for compatibilty with ActiveSupport loggers. This functionality
|
378
|
+
# has been moved to the lumberjack_rails gem.
|
390
379
|
#
|
391
|
-
# @
|
392
|
-
|
393
|
-
|
380
|
+
# @see with_level
|
381
|
+
# @deprecated This implementation is deprecated. Install the lumberjack_rails gem for full support.
|
382
|
+
def silence(level = Logger::ERROR, &block)
|
383
|
+
deprecation_message = "Install the lumberjack_rails gem for full support of the silence method."
|
384
|
+
Utils.deprecated("Logger#silence", deprecation_message) do
|
385
|
+
with_level(level, &block)
|
386
|
+
end
|
394
387
|
end
|
395
388
|
|
396
|
-
#
|
389
|
+
# Add an entry to the log.
|
397
390
|
#
|
398
|
-
# @param [
|
399
|
-
#
|
400
|
-
# @param [String
|
401
|
-
#
|
391
|
+
# @param severity [Integer, Symbol, String] The severity of the message.
|
392
|
+
# @param message [Object] The message to log.
|
393
|
+
# @param progname [String] The name of the program that is logging the message.
|
394
|
+
# @param attributes [Hash] The attributes to add to the log entry.
|
402
395
|
# @return [void]
|
403
|
-
|
404
|
-
|
405
|
-
|
396
|
+
# @api private
|
397
|
+
def add_entry(severity, message, progname = nil, attributes = nil)
|
398
|
+
return false unless device
|
399
|
+
return false if fiber_local&.logging
|
406
400
|
|
407
|
-
|
408
|
-
#
|
409
|
-
# @return [Boolean]
|
410
|
-
def debug?
|
411
|
-
level <= DEBUG
|
412
|
-
end
|
401
|
+
severity = Severity.label_to_level(severity) unless severity.is_a?(Integer)
|
413
402
|
|
414
|
-
|
415
|
-
|
416
|
-
# @return [void]
|
417
|
-
def debug!
|
418
|
-
self.level = DEBUG
|
419
|
-
end
|
403
|
+
fiber_locals do |locals|
|
404
|
+
locals.logging = true # protection from infinite loops
|
420
405
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
# @param [String, Hash] progname_or_tags The name of the program that is logging the message or tags
|
427
|
-
# if the message is passed in a block.
|
428
|
-
# @return [void]
|
429
|
-
def unknown(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
|
430
|
-
call_add_entry(UNKNOWN, message_or_progname_or_tags, progname_or_tags, &block)
|
431
|
-
end
|
406
|
+
time = Time.now
|
407
|
+
progname ||= self.progname
|
408
|
+
attributes = nil unless attributes.is_a?(Hash)
|
409
|
+
attributes = merge_attributes(merge_all_attributes, attributes)
|
410
|
+
message, attributes = formatter.format(message, attributes) if formatter
|
432
411
|
|
433
|
-
|
434
|
-
#
|
435
|
-
# @param [Object] msg The message to log.
|
436
|
-
# @return [void]
|
437
|
-
def <<(msg)
|
438
|
-
add_entry(UNKNOWN, msg)
|
439
|
-
end
|
412
|
+
entry = Lumberjack::LogEntry.new(time, severity, message, progname, Process.pid, attributes)
|
440
413
|
|
441
|
-
|
442
|
-
# messages will be logged.
|
443
|
-
#
|
444
|
-
# @param [Integer, String, Symbol] temporary_level The log level to use inside the block.
|
445
|
-
# @return [Object] The result of the block.
|
446
|
-
#
|
447
|
-
# @example
|
448
|
-
#
|
449
|
-
# logger.level = Logger::INFO
|
450
|
-
# logger.silence do
|
451
|
-
# do_something # Log level inside the block is +ERROR+
|
452
|
-
# end
|
453
|
-
def silence(temporary_level = ERROR, &block)
|
454
|
-
if silencer
|
455
|
-
unless temporary_level.is_a?(Integer)
|
456
|
-
temporary_level = Severity.label_to_level(temporary_level)
|
457
|
-
end
|
458
|
-
push_thread_local_value(:lumberjack_logger_level, temporary_level, &block)
|
459
|
-
else
|
460
|
-
yield
|
414
|
+
write_to_device(entry)
|
461
415
|
end
|
462
|
-
end
|
463
416
|
|
464
|
-
|
465
|
-
#
|
466
|
-
# @param [Integer, String, Symbol] level The log level to use inside the block.
|
467
|
-
# @return [Object] The result of the block.
|
468
|
-
def log_at(level, &block)
|
469
|
-
with_level(level, &block)
|
417
|
+
true
|
470
418
|
end
|
471
419
|
|
472
|
-
#
|
473
|
-
# is given, the program name will be valid only within the block.
|
420
|
+
# Return a human-readable representation of the logger showing its key configuration.
|
474
421
|
#
|
475
|
-
# @
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
push_thread_local_value(:lumberjack_logger_progname, value, &block)
|
480
|
-
else
|
481
|
-
self.progname = value
|
482
|
-
end
|
422
|
+
# @return [String] A string representation of the logger.
|
423
|
+
def inspect
|
424
|
+
formatted_object_id = object_id.to_s(16).rjust(16, "0")
|
425
|
+
"#<Lumberjack::Logger:0x#{formatted_object_id} level:#{Severity.level_to_label(level)} device:#{device.class.name} progname:#{progname.inspect} attributes:#{attributes.inspect}>"
|
483
426
|
end
|
484
427
|
|
485
|
-
|
486
|
-
#
|
487
|
-
# @yield [Object] The block to execute with the program name set.
|
488
|
-
# @param [String] value The program name to use.
|
489
|
-
# @return [Object] The result of the block.
|
490
|
-
def with_progname(value, &block)
|
491
|
-
set_progname(value, &block)
|
492
|
-
end
|
428
|
+
private
|
493
429
|
|
494
|
-
|
495
|
-
|
496
|
-
# @return [String]
|
497
|
-
def progname
|
498
|
-
thread_local_value(:lumberjack_logger_progname) || @progname
|
430
|
+
def default_context
|
431
|
+
@context
|
499
432
|
end
|
500
433
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
def tag(tags, &block)
|
511
|
-
thread_tags = thread_local_value(:lumberjack_logger_tags)
|
512
|
-
if block
|
513
|
-
merged_tags = (thread_tags ? thread_tags.dup : {})
|
514
|
-
TagContext.new(merged_tags).tag(tags)
|
515
|
-
push_thread_local_value(:lumberjack_logger_tags, merged_tags, &block)
|
516
|
-
elsif thread_tags
|
517
|
-
TagContext.new(thread_tags).tag(tags)
|
518
|
-
nil
|
519
|
-
else
|
520
|
-
Utils.deprecated("Lumberjack::Logger#tag", "Lumberjack::Logger#tag must be called with a block or inside a context block. In version 2.0 it will no longer be used for setting global tags. Use Lumberjack::Logger#tag_globally instead.") do
|
521
|
-
tag_globally(tags)
|
522
|
-
end
|
523
|
-
end
|
434
|
+
def write_to_device(entry) # :nodoc:
|
435
|
+
device.write(entry)
|
436
|
+
rescue => e
|
437
|
+
err = e.class.name.dup
|
438
|
+
err << ": #{e.message}" unless e.message.to_s.empty?
|
439
|
+
err << " at #{e.backtrace.first}" if e.backtrace
|
440
|
+
$stderr.write("#{err}#{Lumberjack::LINE_SEPARATOR}#{entry}#{Lumberjack::LINE_SEPARATOR}") # rubocop:disable Style/StderrPuts
|
441
|
+
|
442
|
+
raise e if Lumberjack.raise_logger_errors?
|
524
443
|
end
|
525
444
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
# @yield [TagContext] If a block is passed, it will be yielded a TagContext object that can be used to
|
533
|
-
# add or remove tags within the context.
|
534
|
-
def context(&block)
|
535
|
-
if block
|
536
|
-
thread_tags = thread_local_value(:lumberjack_logger_tags)&.dup
|
537
|
-
thread_tags ||= {}
|
538
|
-
push_thread_local_value(:lumberjack_logger_tags, thread_tags) do
|
539
|
-
block.call(TagContext.new(thread_tags))
|
540
|
-
end
|
541
|
-
else
|
542
|
-
TagContext.new(thread_local_value(:lumberjack_logger_tags) || {})
|
445
|
+
def build_entry_formatter(formatter, message_formatter, attribute_formatter) # :nodoc:
|
446
|
+
entry_formatter = formatter if formatter.is_a?(Lumberjack::EntryFormatter)
|
447
|
+
|
448
|
+
unless entry_formatter
|
449
|
+
message_formatter ||= formatter if formatter.is_a?(Lumberjack::Formatter) || formatter == :default
|
450
|
+
entry_formatter = Lumberjack::EntryFormatter.new
|
543
451
|
end
|
544
|
-
end
|
545
452
|
|
546
|
-
|
547
|
-
#
|
548
|
-
# @param [Hash] tags The tags to set.
|
549
|
-
# @return [void]
|
550
|
-
def tag_globally(tags)
|
551
|
-
TagContext.new(@tags).tag(tags)
|
552
|
-
nil
|
553
|
-
end
|
453
|
+
message_formatter = Lumberjack::Formatter.default if message_formatter == :default
|
554
454
|
|
555
|
-
|
556
|
-
|
557
|
-
# from the global tags.
|
558
|
-
#
|
559
|
-
# @param [Array<String, Symbol>] tag_names The tags to remove.
|
560
|
-
# @return [void]
|
561
|
-
def remove_tag(*tag_names)
|
562
|
-
tags = thread_local_value(:lumberjack_logger_tags) || @tags
|
563
|
-
TagContext.new(tags).delete(*tag_names)
|
564
|
-
end
|
455
|
+
entry_formatter.message_formatter = message_formatter if message_formatter
|
456
|
+
entry_formatter.attribute_formatter = attribute_formatter if attribute_formatter
|
565
457
|
|
566
|
-
|
567
|
-
# context, tags set on the logger, and tags set on the current block for the logger.
|
568
|
-
#
|
569
|
-
# @return [Hash]
|
570
|
-
def tags
|
571
|
-
tags = {}
|
572
|
-
context_tags = Lumberjack.context_tags
|
573
|
-
tags.merge!(context_tags) if context_tags && !context_tags.empty?
|
574
|
-
tags.merge!(@tags) if !@tags.empty? && !thread_local_value(:lumberjack_logger_untagged)
|
575
|
-
scope_tags = thread_local_value(:lumberjack_logger_tags)
|
576
|
-
tags.merge!(scope_tags) if scope_tags && !scope_tags.empty?
|
577
|
-
tags
|
458
|
+
entry_formatter
|
578
459
|
end
|
579
460
|
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
def tag_value(name)
|
585
|
-
name = name.join(".") if name.is_a?(Array)
|
586
|
-
TagContext.new(tags)[name]
|
587
|
-
end
|
461
|
+
def standard_logger_formatter?(formatter)
|
462
|
+
return false if formatter.is_a?(Lumberjack::EntryFormatter)
|
463
|
+
return false if formatter.is_a?(Lumberjack::Formatter)
|
464
|
+
return true if formatter.is_a?(::Logger::Formatter)
|
588
465
|
|
589
|
-
|
590
|
-
# You can still set new block scoped tags within theuntagged block and provide
|
591
|
-
# tags on individual log methods.
|
592
|
-
#
|
593
|
-
# @return [void]
|
594
|
-
def untagged(&block)
|
595
|
-
Lumberjack.use_context(nil) do
|
596
|
-
scope_tags = thread_local_value(:lumberjack_logger_tags)
|
597
|
-
untagged = thread_local_value(:lumberjack_logger_untagged)
|
598
|
-
begin
|
599
|
-
set_thread_local_value(:lumberjack_logger_untagged, true)
|
600
|
-
set_thread_local_value(:lumberjack_logger_tags, nil)
|
601
|
-
tag({}, &block)
|
602
|
-
ensure
|
603
|
-
set_thread_local_value(:lumberjack_logger_untagged, untagged)
|
604
|
-
set_thread_local_value(:lumberjack_logger_tags, scope_tags)
|
605
|
-
end
|
606
|
-
end
|
466
|
+
takes_exactly_n_call_args?(formatter, 4)
|
607
467
|
end
|
608
468
|
|
609
|
-
#
|
610
|
-
#
|
469
|
+
# Convert a size string with optional unit suffix to an integer size in bytes.
|
470
|
+
# Allowed suffixes are K, M, and G (case insensitive) for kilobytes, megabytes, and gigabytes.
|
611
471
|
#
|
612
|
-
# @
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
private
|
472
|
+
# @param size [String, Integer] The size string to convert.
|
473
|
+
# @return [Integer] The size in bytes.
|
474
|
+
def size_with_units(size)
|
475
|
+
return size unless size.is_a?(String) && size.match?(/\A\d+(\.\d+)?[KMG]?\z/i)
|
618
476
|
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
if block
|
625
|
-
message = block
|
626
|
-
if message_or_progname_or_tags.is_a?(Hash)
|
627
|
-
tags = message_or_progname_or_tags
|
628
|
-
progname = progname_or_tags
|
629
|
-
else
|
630
|
-
progname = message_or_progname_or_tags
|
631
|
-
tags = progname_or_tags if progname_or_tags.is_a?(Hash)
|
632
|
-
end
|
633
|
-
else
|
634
|
-
message = message_or_progname_or_tags
|
635
|
-
if progname_or_tags.is_a?(Hash)
|
636
|
-
tags = progname_or_tags
|
637
|
-
else
|
638
|
-
progname = progname_or_tags
|
639
|
-
end
|
477
|
+
multiplier = case size[-1].upcase
|
478
|
+
when "K" then 1024
|
479
|
+
when "M" then 1024 * 1024
|
480
|
+
when "G" then 1024 * 1024 * 1024
|
481
|
+
else 1
|
640
482
|
end
|
641
|
-
add_entry(severity, message, progname, tags)
|
642
|
-
end
|
643
483
|
|
644
|
-
|
645
|
-
def merge_tags(current_tags, tags)
|
646
|
-
if current_tags.nil? || current_tags.empty?
|
647
|
-
tags
|
648
|
-
elsif tags.nil?
|
649
|
-
current_tags
|
650
|
-
else
|
651
|
-
current_tags.merge(tags)
|
652
|
-
end
|
484
|
+
(size.to_f * multiplier).round
|
653
485
|
end
|
654
486
|
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
Thread.current[name] = values
|
487
|
+
def takes_exactly_n_call_args?(callable, count)
|
488
|
+
params = if callable.is_a?(Proc)
|
489
|
+
callable.parameters
|
490
|
+
elsif callable.respond_to?(:call)
|
491
|
+
callable.method(:call).parameters
|
661
492
|
end
|
662
|
-
if value.nil?
|
663
|
-
values.delete(self)
|
664
|
-
Thread.current[name] = nil if values.empty?
|
665
|
-
else
|
666
|
-
values[self] = value
|
667
|
-
end
|
668
|
-
end
|
669
493
|
|
670
|
-
|
671
|
-
def thread_local_value(name) # :nodoc:
|
672
|
-
values = Thread.current[name]
|
673
|
-
values[self] if values
|
674
|
-
end
|
494
|
+
return false unless params
|
675
495
|
|
676
|
-
|
677
|
-
|
678
|
-
save_val = thread_local_value(name)
|
679
|
-
set_thread_local_value(name, value)
|
680
|
-
begin
|
681
|
-
yield
|
682
|
-
ensure
|
683
|
-
set_thread_local_value(name, save_val)
|
496
|
+
positional_arg_count = params.count do |type, _name|
|
497
|
+
type == :req || type == :opt
|
684
498
|
end
|
685
|
-
end
|
686
499
|
|
687
|
-
|
688
|
-
|
689
|
-
if device.nil?
|
690
|
-
nil
|
691
|
-
elsif device.is_a?(Device)
|
692
|
-
device
|
693
|
-
elsif device.respond_to?(:write) && device.respond_to?(:flush)
|
694
|
-
Device::Writer.new(device, options)
|
695
|
-
elsif device == :null
|
696
|
-
Device::Null.new
|
697
|
-
else
|
698
|
-
device = device.to_s
|
699
|
-
if options[:roll]
|
700
|
-
Device::DateRollingLogFile.new(device, options)
|
701
|
-
elsif options[:max_size]
|
702
|
-
Device::SizeRollingLogFile.new(device, options)
|
703
|
-
else
|
704
|
-
Device::LogFile.new(device, options)
|
705
|
-
end
|
500
|
+
has_forbidden_args = params.any? do |type, _name|
|
501
|
+
[:rest, :keyreq, :key, :keyrest].include?(type)
|
706
502
|
end
|
707
|
-
end
|
708
503
|
|
709
|
-
|
710
|
-
device.write(entry)
|
711
|
-
rescue => e
|
712
|
-
# rubocop:disable Style/StderrPuts
|
713
|
-
$stderr.puts("#{e.class.name}: #{e.message}#{" at " + e.backtrace.first if e.backtrace}")
|
714
|
-
$stderr.puts(entry.to_s)
|
715
|
-
# rubocop:enable Style/StderrPuts
|
716
|
-
end
|
717
|
-
|
718
|
-
# Create a thread that will periodically call flush.
|
719
|
-
def create_flusher_thread(flush_seconds) # :nodoc:
|
720
|
-
if flush_seconds > 0
|
721
|
-
logger = self
|
722
|
-
Thread.new do
|
723
|
-
until closed?
|
724
|
-
begin
|
725
|
-
sleep(flush_seconds)
|
726
|
-
logger.flush if Time.now - logger.last_flushed_at >= flush_seconds
|
727
|
-
rescue => e
|
728
|
-
warn("Error flushing log: #{e.inspect}")
|
729
|
-
end
|
730
|
-
end
|
731
|
-
end
|
732
|
-
end
|
504
|
+
positional_arg_count == 4 && !has_forbidden_args
|
733
505
|
end
|
734
506
|
end
|
735
507
|
end
|