logger 1.5.1 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55dfc9db8783f8e0bce997c8f6c162b10e4602bcbe968354bb8f4a0f3a6c1764
4
- data.tar.gz: '08e336951520fc4cc5ab2553ec563509a769a20fb461f47d4e0f2b561745783e'
3
+ metadata.gz: b70d947261ec2e9d94145b13c4831a54fa6c49864aa208e63d4151fd494de443
4
+ data.tar.gz: cda09e37794e00a0c56e66e7ade628f2acdf10312af790d0e2fd1d5c32bf30f1
5
5
  SHA512:
6
- metadata.gz: 001ea8a77429868cfe3e438b41a1d100ee0d5c1bba2d74685fd031add97efae2bb0f31b4d889a84a954f01dfcc96624512e488bb08da4703e33bc38432c3e606
7
- data.tar.gz: 747d62f6bf313cb3a120afcae4179feb47bbe816d40895793ccc719ca87bb4c1798c0cb72ac39862dbcbacc6468e59606d2d5600e395607562f0c0a58bbf3f6f
6
+ metadata.gz: b26008735ad28617a11e8db99db0c5aa5abd5253f3950182da45d342d2bf360d6ef48da6cf1a87c11282ff242f59ee4b731093cb6e738b0464f2a78ceb4df7d1
7
+ data.tar.gz: 5aba8135b1e8322f1038b5bdff1d5ff7472edc3aa71a88f8798e944ea0fb1fad4884c2e6281c9e0691ded78fc9cf0ae75cf6a1d56b3fa23c33fc5e90b30aaa4e
data/lib/logger/errors.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # not used after 1.2.7. just for compat.
4
3
  class Logger
4
+ # not used after 1.2.7. just for compat.
5
5
  class Error < RuntimeError # :nodoc:
6
6
  end
7
7
  class ShiftingError < Error # :nodoc:
@@ -13,7 +13,7 @@ class Logger
13
13
  end
14
14
 
15
15
  def call(severity, time, progname, msg)
16
- Format % [severity[0..0], format_datetime(time), Process.pid, severity, progname,
16
+ Format % [severity[0, 1], format_datetime(time), Process.pid, severity, progname,
17
17
  msg2str(msg)]
18
18
  end
19
19
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Logger
4
- VERSION = "1.5.1"
4
+ VERSION = "1.5.2"
5
5
  end
data/lib/logger.rb CHANGED
@@ -19,216 +19,353 @@ require_relative 'logger/log_device'
19
19
  require_relative 'logger/severity'
20
20
  require_relative 'logger/errors'
21
21
 
22
- # == Description
22
+ # \Class \Logger provides a simple but sophisticated logging utility that
23
+ # you can use to create one or more
24
+ # {event logs}[https://en.wikipedia.org/wiki/Logging_(software)#Event_logs]
25
+ # for your program.
26
+ # Each such log contains a chronological sequence of entries
27
+ # that provides a record of the program's activities.
23
28
  #
24
- # The Logger class provides a simple but sophisticated logging utility that
25
- # you can use to output messages.
29
+ # == About the Examples
26
30
  #
27
- # The messages have associated levels, such as +INFO+ or +ERROR+ that indicate
28
- # their importance. You can then give the Logger a level, and only messages
29
- # at that level or higher will be printed.
31
+ # All examples on this page assume that \Logger has been required:
30
32
  #
31
- # The levels are:
33
+ # require 'logger'
32
34
  #
33
- # +UNKNOWN+:: An unknown message that should always be logged.
34
- # +FATAL+:: An unhandleable error that results in a program crash.
35
- # +ERROR+:: A handleable error condition.
36
- # +WARN+:: A warning.
37
- # +INFO+:: Generic (useful) information about system operation.
38
- # +DEBUG+:: Low-level information for developers.
35
+ # == Synopsis
39
36
  #
40
- # For instance, in a production system, you may have your Logger set to
41
- # +INFO+ or even +WARN+.
42
- # When you are developing the system, however, you probably
43
- # want to know about the program's internal state, and would set the Logger to
44
- # +DEBUG+.
37
+ # Create a log with Logger.new:
45
38
  #
46
- # *Note*: Logger does not escape or sanitize any messages passed to it.
47
- # Developers should be aware of when potentially malicious data (user-input)
48
- # is passed to Logger, and manually escape the untrusted data:
39
+ # # Single log file.
40
+ # logger = Logger.new('t.log')
41
+ # # Size-based rotated logging: 3 10-megabyte files.
42
+ # logger = Logger.new('t.log', 3, 10485760)
43
+ # # Period-based rotated logging: daily (also allowed: 'weekly', 'monthly').
44
+ # logger = Logger.new('t.log', 'daily')
45
+ # # Log to an IO stream.
46
+ # logger = Logger.new($stdout)
49
47
  #
50
- # logger.info("User-input: #{input.dump}")
51
- # logger.info("User-input: %p" % input)
48
+ # Add entries (level, message) with Logger#add:
52
49
  #
53
- # You can use #formatter= for escaping all data.
50
+ # logger.add(Logger::DEBUG, 'Maximal debugging info')
51
+ # logger.add(Logger::INFO, 'Non-error information')
52
+ # logger.add(Logger::WARN, 'Non-error warning')
53
+ # logger.add(Logger::ERROR, 'Non-fatal error')
54
+ # logger.add(Logger::FATAL, 'Fatal error')
55
+ # logger.add(Logger::UNKNOWN, 'Most severe')
54
56
  #
55
- # original_formatter = Logger::Formatter.new
56
- # logger.formatter = proc { |severity, datetime, progname, msg|
57
- # original_formatter.call(severity, datetime, progname, msg.dump)
58
- # }
59
- # logger.info(input)
57
+ # Close the log with Logger#close:
60
58
  #
61
- # === Example
59
+ # logger.close
62
60
  #
63
- # This creates a Logger that outputs to the standard output stream, with a
64
- # level of +WARN+:
61
+ # == Entries
65
62
  #
66
- # require 'logger'
63
+ # You can add entries with method Logger#add:
64
+ #
65
+ # logger.add(Logger::DEBUG, 'Maximal debugging info')
66
+ # logger.add(Logger::INFO, 'Non-error information')
67
+ # logger.add(Logger::WARN, 'Non-error warning')
68
+ # logger.add(Logger::ERROR, 'Non-fatal error')
69
+ # logger.add(Logger::FATAL, 'Fatal error')
70
+ # logger.add(Logger::UNKNOWN, 'Most severe')
71
+ #
72
+ # These shorthand methods also add entries:
73
+ #
74
+ # logger.debug('Maximal debugging info')
75
+ # logger.info('Non-error information')
76
+ # logger.warn('Non-error warning')
77
+ # logger.error('Non-fatal error')
78
+ # logger.fatal('Fatal error')
79
+ # logger.unknown('Most severe')
80
+ #
81
+ # When you call any of these methods,
82
+ # the entry may or may not be written to the log,
83
+ # depending on the entry's severity and on the log level;
84
+ # see {Log Level}[rdoc-ref:Logger@Log+Level]
85
+ #
86
+ # An entry always has:
87
+ #
88
+ # - A severity (the required argument to #add).
89
+ # - An automatically created timestamp.
90
+ #
91
+ # And may also have:
92
+ #
93
+ # - A message.
94
+ # - A program name.
95
+ #
96
+ # Example:
97
+ #
98
+ # logger = Logger.new($stdout)
99
+ # logger.add(Logger::INFO, 'My message.', 'mung')
100
+ # # => I, [2022-05-07T17:21:46.536234 #20536] INFO -- mung: My message.
101
+ #
102
+ # The default format for an entry is:
103
+ #
104
+ # "%s, [%s #%d] %5s -- %s: %s\n"
105
+ #
106
+ # where the values to be formatted are:
107
+ #
108
+ # - \Severity (one letter).
109
+ # - Timestamp.
110
+ # - Process id.
111
+ # - \Severity (word).
112
+ # - Program name.
113
+ # - Message.
114
+ #
115
+ # You can use a different entry format by:
116
+ #
117
+ # - Setting a custom format proc (affects following entries);
118
+ # see {formatter=}[Logger.html#attribute-i-formatter].
119
+ # - Calling any of the methods above with a block
120
+ # (affects only the one entry).
121
+ # Doing so can have two benefits:
122
+ #
123
+ # - Context: the block can evaluate the entire program context
124
+ # and create a context-dependent message.
125
+ # - Performance: the block is not evaluated unless the log level
126
+ # permits the entry actually to be written:
127
+ #
128
+ # logger.error { my_slow_message_generator }
129
+ #
130
+ # Contrast this with the string form, where the string is
131
+ # always evaluated, regardless of the log level:
132
+ #
133
+ # logger.error("#{my_slow_message_generator}")
134
+ #
135
+ # === \Severity
136
+ #
137
+ # The severity of a log entry has two effects:
138
+ #
139
+ # - Determines whether the entry is selected for inclusion in the log;
140
+ # see {Log Level}[rdoc-ref:Logger@Log+Level].
141
+ # - Indicates to any log reader (whether a person or a program)
142
+ # the relative importance of the entry.
143
+ #
144
+ # === Timestamp
67
145
  #
68
- # logger = Logger.new(STDOUT)
69
- # logger.level = Logger::WARN
146
+ # The timestamp for a log entry is generated automatically
147
+ # when the entry is created.
70
148
  #
71
- # logger.debug("Created logger")
72
- # logger.info("Program started")
73
- # logger.warn("Nothing to do!")
149
+ # The logged timestamp is formatted by method
150
+ # {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime]
151
+ # using this format string:
74
152
  #
75
- # path = "a_non_existent_file"
153
+ # '%Y-%m-%dT%H:%M:%S.%6N'
76
154
  #
77
- # begin
78
- # File.foreach(path) do |line|
79
- # unless line =~ /^(\w+) = (.*)$/
80
- # logger.error("Line in wrong format: #{line.chomp}")
81
- # end
82
- # end
83
- # rescue => err
84
- # logger.fatal("Caught exception; exiting")
85
- # logger.fatal(err)
86
- # end
155
+ # Example:
87
156
  #
88
- # Because the Logger's level is set to +WARN+, only the warning, error, and
89
- # fatal messages are recorded. The debug and info messages are silently
90
- # discarded.
157
+ # logger = Logger.new($stdout)
158
+ # logger.add(Logger::INFO)
159
+ # # => I, [2022-05-07T17:04:32.318331 #20536] INFO -- : nil
91
160
  #
92
- # === Features
161
+ # You can set a different format using method #datetime_format=.
93
162
  #
94
- # There are several interesting features that Logger provides, like
95
- # auto-rolling of log files, setting the format of log messages, and
96
- # specifying a program name in conjunction with the message. The next section
97
- # shows you how to achieve these things.
163
+ # === Message
98
164
  #
165
+ # The message is an optional argument to an entry method:
99
166
  #
100
- # == HOWTOs
167
+ # logger = Logger.new($stdout)
168
+ # logger.add(Logger::INFO, 'My message')
169
+ # # => I, [2022-05-07T18:15:37.647581 #20536] INFO -- : My message
101
170
  #
102
- # === How to create a logger
171
+ # For the default entry formatter, <tt>Logger::Formatter</tt>,
172
+ # the message object may be:
103
173
  #
104
- # The options below give you various choices, in more or less increasing
105
- # complexity.
174
+ # - A string: used as-is.
175
+ # - An Exception: <tt>message.message</tt> is used.
176
+ # - Anything else: <tt>message.inspect</tt> is used.
106
177
  #
107
- # 1. Create a logger which logs messages to STDERR/STDOUT.
178
+ # *Note*: Logger::Formatter does not escape or sanitize
179
+ # the message passed to it.
180
+ # Developers should be aware that malicious data (user input)
181
+ # may be in the message, and should explicitly escape untrusted data.
108
182
  #
109
- # logger = Logger.new(STDERR)
110
- # logger = Logger.new(STDOUT)
183
+ # You can use a custom formatter to escape message data;
184
+ # see the example at {formatter=}[Logger.html#attribute-i-formatter].
111
185
  #
112
- # 2. Create a logger for the file which has the specified name.
186
+ # === Program Name
113
187
  #
114
- # logger = Logger.new('logfile.log')
188
+ # The program name is an optional argument to an entry method:
115
189
  #
116
- # 3. Create a logger for the specified file.
190
+ # logger = Logger.new($stdout)
191
+ # logger.add(Logger::INFO, 'My message', 'mung')
192
+ # # => I, [2022-05-07T18:17:38.084716 #20536] INFO -- mung: My message
117
193
  #
118
- # file = File.open('foo.log', File::WRONLY | File::APPEND)
119
- # # To create new logfile, add File::CREAT like:
120
- # # file = File.open('foo.log', File::WRONLY | File::APPEND | File::CREAT)
121
- # logger = Logger.new(file)
194
+ # The default program name for a new logger may be set in the call to
195
+ # Logger.new via optional keyword argument +progname+:
122
196
  #
123
- # 4. Create a logger which ages the logfile once it reaches a certain size.
124
- # Leave 10 "old" log files where each file is about 1,024,000 bytes.
197
+ # logger = Logger.new('t.log', progname: 'mung')
125
198
  #
126
- # logger = Logger.new('foo.log', 10, 1024000)
199
+ # The default program name for an existing logger may be set
200
+ # by a call to method #progname=:
127
201
  #
128
- # 5. Create a logger which ages the logfile daily/weekly/monthly.
202
+ # logger.progname = 'mung'
129
203
  #
130
- # logger = Logger.new('foo.log', 'daily')
131
- # logger = Logger.new('foo.log', 'weekly')
132
- # logger = Logger.new('foo.log', 'monthly')
204
+ # The current program name may be retrieved with method
205
+ # {progname}[Logger.html#attribute-i-progname]:
133
206
  #
134
- # === How to log a message
207
+ # logger.progname # => "mung"
135
208
  #
136
- # Notice the different methods (+fatal+, +error+, +info+) being used to log
137
- # messages of various levels? Other methods in this family are +warn+ and
138
- # +debug+. +add+ is used below to log a message of an arbitrary (perhaps
139
- # dynamic) level.
209
+ # == Log Level
140
210
  #
141
- # 1. Message in a block.
211
+ # The log level setting determines whether an entry is actually
212
+ # written to the log, based on the entry's severity.
142
213
  #
143
- # logger.fatal { "Argument 'foo' not given." }
214
+ # These are the defined severities (least severe to most severe):
144
215
  #
145
- # 2. Message as a string.
216
+ # logger = Logger.new($stdout)
217
+ # logger.add(Logger::DEBUG, 'Maximal debugging info')
218
+ # # => D, [2022-05-07T17:57:41.776220 #20536] DEBUG -- : Maximal debugging info
219
+ # logger.add(Logger::INFO, 'Non-error information')
220
+ # # => I, [2022-05-07T17:59:14.349167 #20536] INFO -- : Non-error information
221
+ # logger.add(Logger::WARN, 'Non-error warning')
222
+ # # => W, [2022-05-07T18:00:45.337538 #20536] WARN -- : Non-error warning
223
+ # logger.add(Logger::ERROR, 'Non-fatal error')
224
+ # # => E, [2022-05-07T18:02:41.592912 #20536] ERROR -- : Non-fatal error
225
+ # logger.add(Logger::FATAL, 'Fatal error')
226
+ # # => F, [2022-05-07T18:05:24.703931 #20536] FATAL -- : Fatal error
227
+ # logger.add(Logger::UNKNOWN, 'Most severe')
228
+ # # => A, [2022-05-07T18:07:54.657491 #20536] ANY -- : Most severe
146
229
  #
147
- # logger.error "Argument #{@foo} mismatch."
230
+ # The default initial level setting is Logger::DEBUG, the lowest level,
231
+ # which means that all entries are to be written, regardless of severity:
148
232
  #
149
- # 3. With progname.
233
+ # logger = Logger.new($stdout)
234
+ # logger.level # => 0
235
+ # logger.add(0, "My message")
236
+ # # => D, [2022-05-11T15:10:59.773668 #20536] DEBUG -- : My message
150
237
  #
151
- # logger.info('initialize') { "Initializing..." }
238
+ # You can specify a different setting in a new logger
239
+ # using keyword argument +level+ with an appropriate value:
152
240
  #
153
- # 4. With severity.
241
+ # logger = Logger.new($stdout, level: Logger::ERROR)
242
+ # logger = Logger.new($stdout, level: 'error')
243
+ # logger = Logger.new($stdout, level: :error)
244
+ # logger.level # => 3
154
245
  #
155
- # logger.add(Logger::FATAL) { 'Fatal error!' }
246
+ # With this level, entries with severity Logger::ERROR and higher
247
+ # are written, while those with lower severities are not written:
156
248
  #
157
- # The block form allows you to create potentially complex log messages,
158
- # but to delay their evaluation until and unless the message is
159
- # logged. For example, if we have the following:
249
+ # logger = Logger.new($stdout, level: Logger::ERROR)
250
+ # logger.add(3)
251
+ # # => E, [2022-05-11T15:17:20.933362 #20536] ERROR -- : nil
252
+ # logger.add(2) # Silent.
160
253
  #
161
- # logger.debug { "This is a " + potentially + " expensive operation" }
254
+ # You can set the log level for an existing logger
255
+ # with method #level=:
162
256
  #
163
- # If the logger's level is +INFO+ or higher, no debug messages will be logged,
164
- # and the entire block will not even be evaluated. Compare to this:
257
+ # logger.level = Logger::ERROR
165
258
  #
166
- # logger.debug("This is a " + potentially + " expensive operation")
259
+ # These shorthand methods also set the level:
167
260
  #
168
- # Here, the string concatenation is done every time, even if the log
169
- # level is not set to show the debug message.
261
+ # logger.debug! # => 0
262
+ # logger.info! # => 1
263
+ # logger.warn! # => 2
264
+ # logger.error! # => 3
265
+ # logger.fatal! # => 4
170
266
  #
171
- # === How to close a logger
267
+ # You can retrieve the log level with method
268
+ # {level}[Logger.html#attribute-i-level]:
172
269
  #
173
- # logger.close
270
+ # logger.level = Logger::ERROR
271
+ # logger.level # => 3
174
272
  #
175
- # === Setting severity threshold
273
+ # These methods return whether a given
274
+ # level is to be written:
176
275
  #
177
- # 1. Original interface.
276
+ # logger.level = Logger::ERROR
277
+ # logger.debug? # => false
278
+ # logger.info? # => false
279
+ # logger.warn? # => false
280
+ # logger.error? # => true
281
+ # logger.fatal? # => true
178
282
  #
179
- # logger.sev_threshold = Logger::WARN
283
+ # == Log File Rotation
180
284
  #
181
- # 2. Log4r (somewhat) compatible interface.
285
+ # By default, a log file is a single file that grows indefinitely
286
+ # (until explicitly closed); there is no file rotation.
182
287
  #
183
- # logger.level = Logger::INFO
288
+ # To keep log files to a manageable size,
289
+ # you can use _log_ _file_ _rotation_, which uses multiple log files:
184
290
  #
185
- # # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
291
+ # - Each log file has entries for a non-overlapping
292
+ # time interval.
293
+ # - Only the most recent log file is open and active;
294
+ # the others are closed and inactive.
186
295
  #
187
- # 3. Symbol or String (case insensitive)
296
+ # === Size-Based Rotation
188
297
  #
189
- # logger.level = :info
190
- # logger.level = 'INFO'
298
+ # For size-based log file rotation, call Logger.new with:
191
299
  #
192
- # # :debug < :info < :warn < :error < :fatal < :unknown
300
+ # - Argument +logdev+ as a file path.
301
+ # - Argument +shift_age+ with a positive integer:
302
+ # the number of log files to be in the rotation.
303
+ # - Argument +shift_size+ as a positive integer:
304
+ # the maximum size (in bytes) of each log file;
305
+ # defaults to 1048576 (1 megabyte).
193
306
  #
194
- # 4. Constructor
307
+ # Examples:
195
308
  #
196
- # Logger.new(logdev, level: Logger::INFO)
197
- # Logger.new(logdev, level: :info)
198
- # Logger.new(logdev, level: 'INFO')
309
+ # logger = Logger.new('t.log', 3) # Three 1-megabyte files.
310
+ # logger = Logger.new('t.log', 5, 10485760) # Five 10-megabyte files.
199
311
  #
200
- # == Format
312
+ # For these examples, suppose:
201
313
  #
202
- # Log messages are rendered in the output stream in a certain format by
203
- # default. The default format and a sample are shown below:
314
+ # logger = Logger.new('t.log', 3)
204
315
  #
205
- # Log format:
206
- # SeverityID, [DateTime #pid] SeverityLabel -- ProgName: message
316
+ # Logging begins in the new log file, +t.log+;
317
+ # the log file is "full" and ready for rotation
318
+ # when a new entry would cause its size to exceed +shift_size+.
207
319
  #
208
- # Log sample:
209
- # I, [1999-03-03T02:34:24.895701 #19074] INFO -- Main: info.
320
+ # The first time +t.log+ is full:
210
321
  #
211
- # You may change the date and time format via #datetime_format=.
322
+ # - +t.log+ is closed and renamed to +t.log.0+.
323
+ # - A new file +t.log+ is opened.
212
324
  #
213
- # logger.datetime_format = '%Y-%m-%d %H:%M:%S'
214
- # # e.g. "2004-01-03 00:54:26"
325
+ # The second time +t.log+ is full:
215
326
  #
216
- # or via the constructor.
327
+ # - +t.log.0 is renamed as +t.log.1+.
328
+ # - +t.log+ is closed and renamed to +t.log.0+.
329
+ # - A new file +t.log+ is opened.
217
330
  #
218
- # Logger.new(logdev, datetime_format: '%Y-%m-%d %H:%M:%S')
331
+ # Each subsequent time that +t.log+ is full,
332
+ # the log files are rotated:
219
333
  #
220
- # Or, you may change the overall format via the #formatter= method.
334
+ # - +t.log.1+ is removed.
335
+ # - +t.log.0 is renamed as +t.log.1+.
336
+ # - +t.log+ is closed and renamed to +t.log.0+.
337
+ # - A new file +t.log+ is opened.
221
338
  #
222
- # logger.formatter = proc do |severity, datetime, progname, msg|
223
- # "#{datetime}: #{msg}\n"
224
- # end
225
- # # e.g. "2005-09-22 08:51:08 +0900: hello world"
339
+ # === Periodic Rotation
226
340
  #
227
- # or via the constructor.
341
+ # For periodic rotation, call Logger.new with:
228
342
  #
229
- # Logger.new(logdev, formatter: proc {|severity, datetime, progname, msg|
230
- # "#{datetime}: #{msg}\n"
231
- # })
343
+ # - Argument +logdev+ as a file path.
344
+ # - Argument +shift_age+ as a string period indicator.
345
+ #
346
+ # Examples:
347
+ #
348
+ # logger = Logger.new('t.log', 'daily') # Rotate log files daily.
349
+ # logger = Logger.new('t.log', 'weekly') # Rotate log files weekly.
350
+ # logger = Logger.new('t.log', 'monthly') # Rotate log files monthly.
351
+ #
352
+ # Example:
353
+ #
354
+ # logger = Logger.new('t.log', 'daily')
355
+ #
356
+ # When the given period expires:
357
+ #
358
+ # - The base log file, +t.log+ is closed and renamed
359
+ # with a date-based suffix such as +t.log.20220509+.
360
+ # - A new log file +t.log+ is opened.
361
+ # - Nothing is removed.
362
+ #
363
+ # The default format for the suffix is <tt>'%Y%m%d'</tt>,
364
+ # which produces a suffix similar to the one above.
365
+ # You can set a different format using create-time option
366
+ # +shift_period_suffix+;
367
+ # see details and suggestions at
368
+ # {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime].
232
369
  #
233
370
  class Logger
234
371
  _, name, rev = %w$Id$
@@ -245,9 +382,18 @@ class Logger
245
382
  # Logging severity threshold (e.g. <tt>Logger::INFO</tt>).
246
383
  attr_reader :level
247
384
 
248
- # Set logging severity threshold.
385
+ # Sets the log level; returns +severity+.
386
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
387
+ #
388
+ # Argument +severity+ may be an integer, a string, or a symbol:
389
+ #
390
+ # logger.level = Logger::ERROR # => 3
391
+ # logger.level = 3 # => 3
392
+ # logger.level = 'error' # => "error"
393
+ # logger.level = :error # => :error
394
+ #
395
+ # Logger#sev_threshold= is an alias for Logger#level=.
249
396
  #
250
- # +severity+:: The Severity of the log message.
251
397
  def level=(severity)
252
398
  if severity.is_a?(Integer)
253
399
  @level = severity
@@ -274,109 +420,159 @@ class Logger
274
420
  # Program name to include in log messages.
275
421
  attr_accessor :progname
276
422
 
277
- # Set date-time format.
423
+ # Sets the date-time format.
424
+ #
425
+ # Argument +datetime_format+ should be either of these:
426
+ #
427
+ # - A string suitable for use as a format for method
428
+ # {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime].
429
+ # - +nil+: the logger uses <tt>'%Y-%m-%dT%H:%M:%S.%6N'</tt>.
278
430
  #
279
- # +datetime_format+:: A string suitable for passing to +strftime+.
280
431
  def datetime_format=(datetime_format)
281
432
  @default_formatter.datetime_format = datetime_format
282
433
  end
283
434
 
284
- # Returns the date format being used. See #datetime_format=
435
+ # Returns the date-time format; see #datetime_format=.
436
+ #
285
437
  def datetime_format
286
438
  @default_formatter.datetime_format
287
439
  end
288
440
 
289
- # Logging formatter, as a +Proc+ that will take four arguments and
290
- # return the formatted message. The arguments are:
441
+ # Sets or retrieves the logger entry formatter proc.
291
442
  #
292
- # +severity+:: The Severity of the log message.
293
- # +time+:: A Time instance representing when the message was logged.
294
- # +progname+:: The #progname configured, or passed to the logger method.
295
- # +msg+:: The _Object_ the user passed to the log message; not necessarily a
296
- # String.
443
+ # When +formatter+ is +nil+, the logger uses Logger::Formatter.
444
+ #
445
+ # When +formatter+ is a proc, a new entry is formatted by the proc,
446
+ # which is called with four arguments:
447
+ #
448
+ # - +severity+: The severity of the entry.
449
+ # - +time+: A Time object representing the entry's timestamp.
450
+ # - +progname+: The program name for the entry.
451
+ # - +msg+: The message for the entry (string or string-convertible object).
452
+ #
453
+ # The proc should return a string containing the formatted entry.
454
+ #
455
+ # This custom formatter uses
456
+ # {String#dump}[https://docs.ruby-lang.org/en/master/String.html#method-i-dump]
457
+ # to escape the message string:
458
+ #
459
+ # logger = Logger.new($stdout, progname: 'mung')
460
+ # original_formatter = logger.formatter || Logger::Formatter.new
461
+ # logger.formatter = proc { |severity, time, progname, msg|
462
+ # original_formatter.call(severity, time, progname, msg.dump)
463
+ # }
464
+ # logger.add(Logger::INFO, "hello \n ''")
465
+ # logger.add(Logger::INFO, "\f\x00\xff\\\"")
466
+ #
467
+ # Output:
468
+ #
469
+ # I, [2022-05-13T13:16:29.637488 #8492] INFO -- mung: "hello \n ''"
470
+ # I, [2022-05-13T13:16:29.637610 #8492] INFO -- mung: "\f\x00\xFF\\\""
297
471
  #
298
- # The block should return an Object that can be written to the logging
299
- # device via +write+. The default formatter is used when no formatter is
300
- # set.
301
472
  attr_accessor :formatter
302
473
 
303
474
  alias sev_threshold level
304
475
  alias sev_threshold= level=
305
476
 
306
- # Returns +true+ if and only if the current severity level allows for the printing of
307
- # +DEBUG+ messages.
477
+ # Returns +true+ if the log level allows entries with severity
478
+ # Logger::DEBUG to be written, +false+ otherwise.
479
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
480
+ #
308
481
  def debug?; level <= DEBUG; end
309
482
 
310
- # Sets the severity to DEBUG.
483
+ # Sets the log level to Logger::DEBUG.
484
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
485
+ #
311
486
  def debug!; self.level = DEBUG; end
312
487
 
313
- # Returns +true+ if and only if the current severity level allows for the printing of
314
- # +INFO+ messages.
488
+ # Returns +true+ if the log level allows entries with severity
489
+ # Logger::INFO to be written, +false+ otherwise.
490
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
491
+ #
315
492
  def info?; level <= INFO; end
316
493
 
317
- # Sets the severity to INFO.
494
+ # Sets the log level to Logger::INFO.
495
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
496
+ #
318
497
  def info!; self.level = INFO; end
319
498
 
320
- # Returns +true+ if and only if the current severity level allows for the printing of
321
- # +WARN+ messages.
499
+ # Returns +true+ if the log level allows entries with severity
500
+ # Logger::WARN to be written, +false+ otherwise.
501
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
502
+ #
322
503
  def warn?; level <= WARN; end
323
504
 
324
- # Sets the severity to WARN.
505
+ # Sets the log level to Logger::WARN.
506
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
507
+ #
325
508
  def warn!; self.level = WARN; end
326
509
 
327
- # Returns +true+ if and only if the current severity level allows for the printing of
328
- # +ERROR+ messages.
510
+ # Returns +true+ if the log level allows entries with severity
511
+ # Logger::ERROR to be written, +false+ otherwise.
512
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
513
+ #
329
514
  def error?; level <= ERROR; end
330
515
 
331
- # Sets the severity to ERROR.
516
+ # Sets the log level to Logger::ERROR.
517
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
518
+ #
332
519
  def error!; self.level = ERROR; end
333
520
 
334
- # Returns +true+ if and only if the current severity level allows for the printing of
335
- # +FATAL+ messages.
521
+ # Returns +true+ if the log level allows entries with severity
522
+ # Logger::FATAL to be written, +false+ otherwise.
523
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
524
+ #
336
525
  def fatal?; level <= FATAL; end
337
526
 
338
- # Sets the severity to FATAL.
527
+ # Sets the log level to Logger::FATAL.
528
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
529
+ #
339
530
  def fatal!; self.level = FATAL; end
340
531
 
341
- #
342
532
  # :call-seq:
343
- # Logger.new(logdev, shift_age = 0, shift_size = 1048576)
344
- # Logger.new(logdev, shift_age = 'weekly')
345
- # Logger.new(logdev, level: :info)
346
- # Logger.new(logdev, progname: 'progname')
347
- # Logger.new(logdev, formatter: formatter)
348
- # Logger.new(logdev, datetime_format: '%Y-%m-%d %H:%M:%S')
349
- #
350
- # === Args
351
- #
352
- # +logdev+::
353
- # The log device. This is a filename (String), IO object (typically
354
- # +STDOUT+, +STDERR+, or an open file), +nil+ (it writes nothing) or
355
- # +File::NULL+ (same as +nil+).
356
- # +shift_age+::
357
- # Number of old log files to keep, *or* frequency of rotation (+daily+,
358
- # +weekly+ or +monthly+). Default value is 0, which disables log file
359
- # rotation.
360
- # +shift_size+::
361
- # Maximum logfile size in bytes (only applies when +shift_age+ is a positive
362
- # Integer). Defaults to +1048576+ (1MB).
363
- # +level+::
364
- # Logging severity threshold. Default values is Logger::DEBUG.
365
- # +progname+::
366
- # Program name to include in log messages. Default value is nil.
367
- # +formatter+::
368
- # Logging formatter. Default values is an instance of Logger::Formatter.
369
- # +datetime_format+::
370
- # Date and time format. Default value is '%Y-%m-%d %H:%M:%S'.
371
- # +binmode+::
372
- # Use binary mode on the log device. Default value is false.
373
- # +shift_period_suffix+::
374
- # The log file suffix format for +daily+, +weekly+ or +monthly+ rotation.
375
- # Default is '%Y%m%d'.
376
- #
377
- # === Description
378
- #
379
- # Create an instance.
533
+ # Logger.new(logdev, shift_age = 0, shift_size = 1048576, **options)
534
+ #
535
+ # With the single argument +logdev+,
536
+ # returns a new logger with all default options:
537
+ #
538
+ # Logger.new('t.log') # => #<Logger:0x000001e685dc6ac8>
539
+ #
540
+ # Argument +logdev+ must be one of:
541
+ #
542
+ # - A string filepath: entries are to be written
543
+ # to the file at that path; if the file at that path exists,
544
+ # new entries are appended.
545
+ # - An IO stream (typically +$stdout+, +$stderr+. or an open file):
546
+ # entries are to be written to the given stream.
547
+ # - +nil+ or +File::NULL+: no entries are to be written.
548
+ #
549
+ # Examples:
550
+ #
551
+ # Logger.new('t.log')
552
+ # Logger.new($stdout)
553
+ #
554
+ # The keyword options are:
555
+ #
556
+ # - +level+: sets the log level; default value is Logger::DEBUG.
557
+ # See {Log Level}[rdoc-ref:Logger@Log+Level]:
558
+ #
559
+ # Logger.new('t.log', level: Logger::ERROR)
560
+ #
561
+ # - +progname+: sets the default program name; default is +nil+.
562
+ # See {Program Name}[rdoc-ref:Logger@Program+Name]:
563
+ #
564
+ # Logger.new('t.log', progname: 'mung')
565
+ #
566
+ # - +formatter+: sets the entry formatter; default is +nil+.
567
+ # See {formatter=}[Logger.html#attribute-i-formatter].
568
+ # - +datetime_format+: sets the format for entry timestamp;
569
+ # default is +nil+.
570
+ # See #datetime_format=.
571
+ # - +binmode+: sets whether the logger writes in binary mode;
572
+ # default is +false+.
573
+ # - +shift_period_suffix+: sets the format for the filename suffix
574
+ # for periodic log file rotation; default is <tt>'%Y%m%d'</tt>.
575
+ # See {Periodic Rotation}[rdoc-ref:Logger@Periodic+Rotation].
380
576
  #
381
577
  def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
382
578
  progname: nil, formatter: nil, datetime_format: nil,
@@ -395,67 +591,60 @@ class Logger
395
591
  end
396
592
  end
397
593
 
398
- #
399
- # :call-seq:
400
- # Logger#reopen
401
- # Logger#reopen(logdev)
402
- #
403
- # === Args
404
- #
405
- # +logdev+::
406
- # The log device. This is a filename (String) or IO object (typically
407
- # +STDOUT+, +STDERR+, or an open file). reopen the same filename if
408
- # it is +nil+, do nothing for IO. Default is +nil+.
409
- #
410
- # === Description
411
- #
412
- # Reopen a log device.
594
+ # Sets the logger's output stream:
595
+ #
596
+ # - If +logdev+ is +nil+, reopens the current output stream.
597
+ # - If +logdev+ is a filepath, opens the indicated file for append.
598
+ # - If +logdev+ is an IO stream
599
+ # (usually <tt>$stdout</tt>, <tt>$stderr</tt>, or an open File object),
600
+ # opens the stream for append.
601
+ #
602
+ # Example:
603
+ #
604
+ # logger = Logger.new('t.log')
605
+ # logger.add(Logger::ERROR, 'one')
606
+ # logger.close
607
+ # logger.add(Logger::ERROR, 'two') # Prints 'log writing failed. closed stream'
608
+ # logger.reopen
609
+ # logger.add(Logger::ERROR, 'three')
610
+ # logger.close
611
+ # File.readlines('t.log')
612
+ # # =>
613
+ # # ["# Logfile created on 2022-05-12 14:21:19 -0500 by logger.rb/v1.5.0\n",
614
+ # # "E, [2022-05-12T14:21:27.596726 #22428] ERROR -- : one\n",
615
+ # # "E, [2022-05-12T14:23:05.847241 #22428] ERROR -- : three\n"]
413
616
  #
414
617
  def reopen(logdev = nil)
415
618
  @logdev&.reopen(logdev)
416
619
  self
417
620
  end
418
621
 
622
+ # Creates a log entry, which may or may not be written to the log,
623
+ # depending on the entry's severity and on the log level.
624
+ # See {Log Level}[rdoc-ref:Logger@Log+Level]
625
+ # and {Entries}[rdoc-ref:Logger@Entries] for details.
419
626
  #
420
- # :call-seq:
421
- # Logger#add(severity, message = nil, progname = nil) { ... }
422
- #
423
- # === Args
424
- #
425
- # +severity+::
426
- # Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+,
427
- # +WARN+, +ERROR+, +FATAL+, or +UNKNOWN+.
428
- # +message+::
429
- # The log message. A String or Exception.
430
- # +progname+::
431
- # Program name string. Can be omitted. Treated as a message if no
432
- # +message+ and +block+ are given.
433
- # +block+::
434
- # Can be omitted. Called to get a message string if +message+ is nil.
435
- #
436
- # === Return
437
- #
438
- # When the given severity is not high enough (for this particular logger),
439
- # log no message, and return +true+.
627
+ # Examples:
440
628
  #
441
- # === Description
629
+ # logger = Logger.new($stdout, progname: 'mung')
630
+ # logger.add(Logger::INFO)
631
+ # logger.add(Logger::ERROR, 'No good')
632
+ # logger.add(Logger::ERROR, 'No good', 'gnum')
442
633
  #
443
- # Log a message if the given severity is high enough. This is the generic
444
- # logging method. Users will be more inclined to use #debug, #info, #warn,
445
- # #error, and #fatal.
634
+ # Output:
446
635
  #
447
- # <b>Message format</b>: +message+ can be any object, but it has to be
448
- # converted to a String in order to log it. Generally, +inspect+ is used
449
- # if the given object is not a String.
450
- # A special case is an +Exception+ object, which will be printed in detail,
451
- # including message, class, and backtrace. See #msg2str for the
452
- # implementation if required.
636
+ # I, [2022-05-12T16:25:31.469726 #36328] INFO -- mung: mung
637
+ # E, [2022-05-12T16:25:55.349414 #36328] ERROR -- mung: No good
638
+ # E, [2022-05-12T16:26:35.841134 #36328] ERROR -- gnum: No good
453
639
  #
454
- # === Bugs
640
+ # These convenience methods have implicit severity:
455
641
  #
456
- # * Logfile is not locked.
457
- # * Append open does not need to lock file.
458
- # * If the OS supports multi I/O, records possibly may be mixed.
642
+ # - #debug.
643
+ # - #info.
644
+ # - #warn.
645
+ # - #error.
646
+ # - #fatal.
647
+ # - #unknown.
459
648
  #
460
649
  def add(severity, message = nil, progname = nil)
461
650
  severity ||= UNKNOWN
@@ -479,104 +668,71 @@ class Logger
479
668
  end
480
669
  alias log add
481
670
 
671
+ # Writes the given +msg+ to the log with no formatting;
672
+ # returns the number of characters written,
673
+ # or +nil+ if no log device exists:
482
674
  #
483
- # Dump given message to the log device without any formatting. If no log
484
- # device exists, return +nil+.
675
+ # logger = Logger.new($stdout)
676
+ # logger << 'My message.' # => 10
677
+ #
678
+ # Output:
679
+ #
680
+ # My message.
485
681
  #
486
682
  def <<(msg)
487
683
  @logdev&.write(msg)
488
684
  end
489
685
 
490
- #
491
- # Log a +DEBUG+ message.
492
- #
493
- # See #info for more information.
686
+ # Equivalent to calling #add with severity <tt>Logger::DEBUG</tt>.
494
687
  #
495
688
  def debug(progname = nil, &block)
496
689
  add(DEBUG, nil, progname, &block)
497
690
  end
498
691
 
499
- #
500
- # :call-seq:
501
- # info(message)
502
- # info(progname, &block)
503
- #
504
- # Log an +INFO+ message.
505
- #
506
- # +message+:: The message to log; does not need to be a String.
507
- # +progname+:: In the block form, this is the #progname to use in the
508
- # log message. The default can be set with #progname=.
509
- # +block+:: Evaluates to the message to log. This is not evaluated unless
510
- # the logger's level is sufficient to log the message. This
511
- # allows you to create potentially expensive logging messages that
512
- # are only called when the logger is configured to show them.
513
- #
514
- # === Examples
515
- #
516
- # logger.info("MainApp") { "Received connection from #{ip}" }
517
- # # ...
518
- # logger.info "Waiting for input from user"
519
- # # ...
520
- # logger.info { "User typed #{input}" }
521
- #
522
- # You'll probably stick to the second form above, unless you want to provide a
523
- # program name (which you can do with #progname= as well).
524
- #
525
- # === Return
526
- #
527
- # See #add.
692
+ # Equivalent to calling #add with severity <tt>Logger::INFO</tt>.
528
693
  #
529
694
  def info(progname = nil, &block)
530
695
  add(INFO, nil, progname, &block)
531
696
  end
532
697
 
533
- #
534
- # Log a +WARN+ message.
535
- #
536
- # See #info for more information.
698
+ # Equivalent to calling #add with severity <tt>Logger::WARN</tt>.
537
699
  #
538
700
  def warn(progname = nil, &block)
539
701
  add(WARN, nil, progname, &block)
540
702
  end
541
703
 
542
- #
543
- # Log an +ERROR+ message.
544
- #
545
- # See #info for more information.
704
+ # Equivalent to calling #add with severity <tt>Logger::ERROR</tt>.
546
705
  #
547
706
  def error(progname = nil, &block)
548
707
  add(ERROR, nil, progname, &block)
549
708
  end
550
709
 
551
- #
552
- # Log a +FATAL+ message.
553
- #
554
- # See #info for more information.
710
+ # Equivalent to calling #add with severity <tt>Logger::FATAL</tt>.
555
711
  #
556
712
  def fatal(progname = nil, &block)
557
713
  add(FATAL, nil, progname, &block)
558
714
  end
559
715
 
560
- #
561
- # Log an +UNKNOWN+ message. This will be printed no matter what the logger's
562
- # level is.
563
- #
564
- # See #info for more information.
716
+ # Equivalent to calling #add with severity <tt>Logger::UNKNOWN</tt>.
565
717
  #
566
718
  def unknown(progname = nil, &block)
567
719
  add(UNKNOWN, nil, progname, &block)
568
720
  end
569
721
 
722
+ # Closes the logger; returns +nil+:
570
723
  #
571
- # Close the logging device.
724
+ # logger = Logger.new('t.log')
725
+ # logger.close # => nil
726
+ # logger.info('foo') # Prints "log writing failed. closed stream"
572
727
  #
728
+ # Related: Logger#reopen.
573
729
  def close
574
730
  @logdev&.close
575
731
  end
576
732
 
577
733
  private
578
734
 
579
- # Severity label for logging (max 5 chars).
735
+ # \Severity label for logging (max 5 chars).
580
736
  SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY).freeze
581
737
 
582
738
  def format_severity(severity)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-03-17 00:00:00.000000000 Z
12
+ date: 2022-12-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler