logger 1.5.0 → 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: fdee784517977e63d746c2ea95367978a203a68472dfdbaac094e49b291ce170
4
- data.tar.gz: a80c2295c6ea2d146f6a21f9d2c76320a0bedebac7261c88785a7e45f3a7f91e
3
+ metadata.gz: b70d947261ec2e9d94145b13c4831a54fa6c49864aa208e63d4151fd494de443
4
+ data.tar.gz: cda09e37794e00a0c56e66e7ade628f2acdf10312af790d0e2fd1d5c32bf30f1
5
5
  SHA512:
6
- metadata.gz: 3b8af19f1a91db15b14c9a3db994184b0b918db2dae08380813495b135f5cbf7d55563d75a155ba3924b023b7123c7934343bad913880c2b5511e34c99e86972
7
- data.tar.gz: 0eb96b3097cc63f8fbcda65de469effd3355f6381152b1e8344c35f2222e91c51adc669bc8c1ccc28a5706efdbea0b07926326e35a9dfa8fad1c545101485b9b
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
 
@@ -135,7 +135,7 @@ class Logger
135
135
  end
136
136
  end
137
137
 
138
- if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM
138
+ if /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os']
139
139
  def lock_shift_log
140
140
  yield
141
141
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Logger
4
- VERSION = "1.5.0"
4
+ VERSION = "1.5.2"
5
5
  end
data/lib/logger.rb CHANGED
@@ -11,6 +11,7 @@
11
11
  # A simple system for logging messages. See Logger for more documentation.
12
12
 
13
13
  require 'monitor'
14
+ require 'rbconfig'
14
15
 
15
16
  require_relative 'logger/version'
16
17
  require_relative 'logger/formatter'
@@ -18,216 +19,353 @@ require_relative 'logger/log_device'
18
19
  require_relative 'logger/severity'
19
20
  require_relative 'logger/errors'
20
21
 
21
- # == 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.
22
28
  #
23
- # The Logger class provides a simple but sophisticated logging utility that
24
- # you can use to output messages.
29
+ # == About the Examples
25
30
  #
26
- # The messages have associated levels, such as +INFO+ or +ERROR+ that indicate
27
- # their importance. You can then give the Logger a level, and only messages
28
- # at that level or higher will be printed.
31
+ # All examples on this page assume that \Logger has been required:
29
32
  #
30
- # The levels are:
33
+ # require 'logger'
31
34
  #
32
- # +UNKNOWN+:: An unknown message that should always be logged.
33
- # +FATAL+:: An unhandleable error that results in a program crash.
34
- # +ERROR+:: A handleable error condition.
35
- # +WARN+:: A warning.
36
- # +INFO+:: Generic (useful) information about system operation.
37
- # +DEBUG+:: Low-level information for developers.
35
+ # == Synopsis
38
36
  #
39
- # For instance, in a production system, you may have your Logger set to
40
- # +INFO+ or even +WARN+.
41
- # When you are developing the system, however, you probably
42
- # want to know about the program's internal state, and would set the Logger to
43
- # +DEBUG+.
37
+ # Create a log with Logger.new:
44
38
  #
45
- # *Note*: Logger does not escape or sanitize any messages passed to it.
46
- # Developers should be aware of when potentially malicious data (user-input)
47
- # 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)
48
47
  #
49
- # logger.info("User-input: #{input.dump}")
50
- # logger.info("User-input: %p" % input)
48
+ # Add entries (level, message) with Logger#add:
51
49
  #
52
- # 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')
53
56
  #
54
- # original_formatter = Logger::Formatter.new
55
- # logger.formatter = proc { |severity, datetime, progname, msg|
56
- # original_formatter.call(severity, datetime, progname, msg.dump)
57
- # }
58
- # logger.info(input)
57
+ # Close the log with Logger#close:
59
58
  #
60
- # === Example
59
+ # logger.close
61
60
  #
62
- # This creates a Logger that outputs to the standard output stream, with a
63
- # level of +WARN+:
61
+ # == Entries
64
62
  #
65
- # 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
66
145
  #
67
- # logger = Logger.new(STDOUT)
68
- # logger.level = Logger::WARN
146
+ # The timestamp for a log entry is generated automatically
147
+ # when the entry is created.
69
148
  #
70
- # logger.debug("Created logger")
71
- # logger.info("Program started")
72
- # 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:
73
152
  #
74
- # path = "a_non_existent_file"
153
+ # '%Y-%m-%dT%H:%M:%S.%6N'
75
154
  #
76
- # begin
77
- # File.foreach(path) do |line|
78
- # unless line =~ /^(\w+) = (.*)$/
79
- # logger.error("Line in wrong format: #{line.chomp}")
80
- # end
81
- # end
82
- # rescue => err
83
- # logger.fatal("Caught exception; exiting")
84
- # logger.fatal(err)
85
- # end
155
+ # Example:
86
156
  #
87
- # Because the Logger's level is set to +WARN+, only the warning, error, and
88
- # fatal messages are recorded. The debug and info messages are silently
89
- # discarded.
157
+ # logger = Logger.new($stdout)
158
+ # logger.add(Logger::INFO)
159
+ # # => I, [2022-05-07T17:04:32.318331 #20536] INFO -- : nil
90
160
  #
91
- # === Features
161
+ # You can set a different format using method #datetime_format=.
92
162
  #
93
- # There are several interesting features that Logger provides, like
94
- # auto-rolling of log files, setting the format of log messages, and
95
- # specifying a program name in conjunction with the message. The next section
96
- # shows you how to achieve these things.
163
+ # === Message
97
164
  #
165
+ # The message is an optional argument to an entry method:
98
166
  #
99
- # == 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
100
170
  #
101
- # === How to create a logger
171
+ # For the default entry formatter, <tt>Logger::Formatter</tt>,
172
+ # the message object may be:
102
173
  #
103
- # The options below give you various choices, in more or less increasing
104
- # 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.
105
177
  #
106
- # 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.
107
182
  #
108
- # logger = Logger.new(STDERR)
109
- # 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].
110
185
  #
111
- # 2. Create a logger for the file which has the specified name.
186
+ # === Program Name
112
187
  #
113
- # logger = Logger.new('logfile.log')
188
+ # The program name is an optional argument to an entry method:
114
189
  #
115
- # 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
116
193
  #
117
- # file = File.open('foo.log', File::WRONLY | File::APPEND)
118
- # # To create new logfile, add File::CREAT like:
119
- # # file = File.open('foo.log', File::WRONLY | File::APPEND | File::CREAT)
120
- # 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+:
121
196
  #
122
- # 4. Create a logger which ages the logfile once it reaches a certain size.
123
- # Leave 10 "old" log files where each file is about 1,024,000 bytes.
197
+ # logger = Logger.new('t.log', progname: 'mung')
124
198
  #
125
- # 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=:
126
201
  #
127
- # 5. Create a logger which ages the logfile daily/weekly/monthly.
202
+ # logger.progname = 'mung'
128
203
  #
129
- # logger = Logger.new('foo.log', 'daily')
130
- # logger = Logger.new('foo.log', 'weekly')
131
- # logger = Logger.new('foo.log', 'monthly')
204
+ # The current program name may be retrieved with method
205
+ # {progname}[Logger.html#attribute-i-progname]:
132
206
  #
133
- # === How to log a message
207
+ # logger.progname # => "mung"
134
208
  #
135
- # Notice the different methods (+fatal+, +error+, +info+) being used to log
136
- # messages of various levels? Other methods in this family are +warn+ and
137
- # +debug+. +add+ is used below to log a message of an arbitrary (perhaps
138
- # dynamic) level.
209
+ # == Log Level
139
210
  #
140
- # 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.
141
213
  #
142
- # logger.fatal { "Argument 'foo' not given." }
214
+ # These are the defined severities (least severe to most severe):
143
215
  #
144
- # 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
145
229
  #
146
- # 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:
147
232
  #
148
- # 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
149
237
  #
150
- # logger.info('initialize') { "Initializing..." }
238
+ # You can specify a different setting in a new logger
239
+ # using keyword argument +level+ with an appropriate value:
151
240
  #
152
- # 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
153
245
  #
154
- # 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:
155
248
  #
156
- # The block form allows you to create potentially complex log messages,
157
- # but to delay their evaluation until and unless the message is
158
- # 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.
159
253
  #
160
- # logger.debug { "This is a " + potentially + " expensive operation" }
254
+ # You can set the log level for an existing logger
255
+ # with method #level=:
161
256
  #
162
- # If the logger's level is +INFO+ or higher, no debug messages will be logged,
163
- # and the entire block will not even be evaluated. Compare to this:
257
+ # logger.level = Logger::ERROR
164
258
  #
165
- # logger.debug("This is a " + potentially + " expensive operation")
259
+ # These shorthand methods also set the level:
166
260
  #
167
- # Here, the string concatenation is done every time, even if the log
168
- # 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
169
266
  #
170
- # === How to close a logger
267
+ # You can retrieve the log level with method
268
+ # {level}[Logger.html#attribute-i-level]:
171
269
  #
172
- # logger.close
270
+ # logger.level = Logger::ERROR
271
+ # logger.level # => 3
173
272
  #
174
- # === Setting severity threshold
273
+ # These methods return whether a given
274
+ # level is to be written:
175
275
  #
176
- # 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
177
282
  #
178
- # logger.sev_threshold = Logger::WARN
283
+ # == Log File Rotation
179
284
  #
180
- # 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.
181
287
  #
182
- # 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:
183
290
  #
184
- # # 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.
185
295
  #
186
- # 3. Symbol or String (case insensitive)
296
+ # === Size-Based Rotation
187
297
  #
188
- # logger.level = :info
189
- # logger.level = 'INFO'
298
+ # For size-based log file rotation, call Logger.new with:
190
299
  #
191
- # # :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).
192
306
  #
193
- # 4. Constructor
307
+ # Examples:
194
308
  #
195
- # Logger.new(logdev, level: Logger::INFO)
196
- # Logger.new(logdev, level: :info)
197
- # 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.
198
311
  #
199
- # == Format
312
+ # For these examples, suppose:
200
313
  #
201
- # Log messages are rendered in the output stream in a certain format by
202
- # default. The default format and a sample are shown below:
314
+ # logger = Logger.new('t.log', 3)
203
315
  #
204
- # Log format:
205
- # 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+.
206
319
  #
207
- # Log sample:
208
- # I, [1999-03-03T02:34:24.895701 #19074] INFO -- Main: info.
320
+ # The first time +t.log+ is full:
209
321
  #
210
- # 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.
211
324
  #
212
- # logger.datetime_format = '%Y-%m-%d %H:%M:%S'
213
- # # e.g. "2004-01-03 00:54:26"
325
+ # The second time +t.log+ is full:
214
326
  #
215
- # 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.
216
330
  #
217
- # 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:
218
333
  #
219
- # 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.
220
338
  #
221
- # logger.formatter = proc do |severity, datetime, progname, msg|
222
- # "#{datetime}: #{msg}\n"
223
- # end
224
- # # e.g. "2005-09-22 08:51:08 +0900: hello world"
339
+ # === Periodic Rotation
225
340
  #
226
- # or via the constructor.
341
+ # For periodic rotation, call Logger.new with:
227
342
  #
228
- # Logger.new(logdev, formatter: proc {|severity, datetime, progname, msg|
229
- # "#{datetime}: #{msg}\n"
230
- # })
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].
231
369
  #
232
370
  class Logger
233
371
  _, name, rev = %w$Id$
@@ -244,9 +382,18 @@ class Logger
244
382
  # Logging severity threshold (e.g. <tt>Logger::INFO</tt>).
245
383
  attr_reader :level
246
384
 
247
- # 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=.
248
396
  #
249
- # +severity+:: The Severity of the log message.
250
397
  def level=(severity)
251
398
  if severity.is_a?(Integer)
252
399
  @level = severity
@@ -273,109 +420,159 @@ class Logger
273
420
  # Program name to include in log messages.
274
421
  attr_accessor :progname
275
422
 
276
- # 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>.
277
430
  #
278
- # +datetime_format+:: A string suitable for passing to +strftime+.
279
431
  def datetime_format=(datetime_format)
280
432
  @default_formatter.datetime_format = datetime_format
281
433
  end
282
434
 
283
- # Returns the date format being used. See #datetime_format=
435
+ # Returns the date-time format; see #datetime_format=.
436
+ #
284
437
  def datetime_format
285
438
  @default_formatter.datetime_format
286
439
  end
287
440
 
288
- # Logging formatter, as a +Proc+ that will take four arguments and
289
- # return the formatted message. The arguments are:
441
+ # Sets or retrieves the logger entry formatter proc.
290
442
  #
291
- # +severity+:: The Severity of the log message.
292
- # +time+:: A Time instance representing when the message was logged.
293
- # +progname+:: The #progname configured, or passed to the logger method.
294
- # +msg+:: The _Object_ the user passed to the log message; not necessarily a
295
- # 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\\\""
296
471
  #
297
- # The block should return an Object that can be written to the logging
298
- # device via +write+. The default formatter is used when no formatter is
299
- # set.
300
472
  attr_accessor :formatter
301
473
 
302
474
  alias sev_threshold level
303
475
  alias sev_threshold= level=
304
476
 
305
- # Returns +true+ if and only if the current severity level allows for the printing of
306
- # +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
+ #
307
481
  def debug?; level <= DEBUG; end
308
482
 
309
- # Sets the severity to DEBUG.
483
+ # Sets the log level to Logger::DEBUG.
484
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
485
+ #
310
486
  def debug!; self.level = DEBUG; end
311
487
 
312
- # Returns +true+ if and only if the current severity level allows for the printing of
313
- # +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
+ #
314
492
  def info?; level <= INFO; end
315
493
 
316
- # Sets the severity to INFO.
494
+ # Sets the log level to Logger::INFO.
495
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
496
+ #
317
497
  def info!; self.level = INFO; end
318
498
 
319
- # Returns +true+ if and only if the current severity level allows for the printing of
320
- # +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
+ #
321
503
  def warn?; level <= WARN; end
322
504
 
323
- # Sets the severity to WARN.
505
+ # Sets the log level to Logger::WARN.
506
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
507
+ #
324
508
  def warn!; self.level = WARN; end
325
509
 
326
- # Returns +true+ if and only if the current severity level allows for the printing of
327
- # +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
+ #
328
514
  def error?; level <= ERROR; end
329
515
 
330
- # Sets the severity to ERROR.
516
+ # Sets the log level to Logger::ERROR.
517
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
518
+ #
331
519
  def error!; self.level = ERROR; end
332
520
 
333
- # Returns +true+ if and only if the current severity level allows for the printing of
334
- # +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
+ #
335
525
  def fatal?; level <= FATAL; end
336
526
 
337
- # Sets the severity to FATAL.
527
+ # Sets the log level to Logger::FATAL.
528
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
529
+ #
338
530
  def fatal!; self.level = FATAL; end
339
531
 
340
- #
341
532
  # :call-seq:
342
- # Logger.new(logdev, shift_age = 0, shift_size = 1048576)
343
- # Logger.new(logdev, shift_age = 'weekly')
344
- # Logger.new(logdev, level: :info)
345
- # Logger.new(logdev, progname: 'progname')
346
- # Logger.new(logdev, formatter: formatter)
347
- # Logger.new(logdev, datetime_format: '%Y-%m-%d %H:%M:%S')
348
- #
349
- # === Args
350
- #
351
- # +logdev+::
352
- # The log device. This is a filename (String), IO object (typically
353
- # +STDOUT+, +STDERR+, or an open file), +nil+ (it writes nothing) or
354
- # +File::NULL+ (same as +nil+).
355
- # +shift_age+::
356
- # Number of old log files to keep, *or* frequency of rotation (+daily+,
357
- # +weekly+ or +monthly+). Default value is 0, which disables log file
358
- # rotation.
359
- # +shift_size+::
360
- # Maximum logfile size in bytes (only applies when +shift_age+ is a positive
361
- # Integer). Defaults to +1048576+ (1MB).
362
- # +level+::
363
- # Logging severity threshold. Default values is Logger::DEBUG.
364
- # +progname+::
365
- # Program name to include in log messages. Default value is nil.
366
- # +formatter+::
367
- # Logging formatter. Default values is an instance of Logger::Formatter.
368
- # +datetime_format+::
369
- # Date and time format. Default value is '%Y-%m-%d %H:%M:%S'.
370
- # +binmode+::
371
- # Use binary mode on the log device. Default value is false.
372
- # +shift_period_suffix+::
373
- # The log file suffix format for +daily+, +weekly+ or +monthly+ rotation.
374
- # Default is '%Y%m%d'.
375
- #
376
- # === Description
377
- #
378
- # 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].
379
576
  #
380
577
  def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
381
578
  progname: nil, formatter: nil, datetime_format: nil,
@@ -394,67 +591,60 @@ class Logger
394
591
  end
395
592
  end
396
593
 
397
- #
398
- # :call-seq:
399
- # Logger#reopen
400
- # Logger#reopen(logdev)
401
- #
402
- # === Args
403
- #
404
- # +logdev+::
405
- # The log device. This is a filename (String) or IO object (typically
406
- # +STDOUT+, +STDERR+, or an open file). reopen the same filename if
407
- # it is +nil+, do nothing for IO. Default is +nil+.
408
- #
409
- # === Description
410
- #
411
- # 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"]
412
616
  #
413
617
  def reopen(logdev = nil)
414
618
  @logdev&.reopen(logdev)
415
619
  self
416
620
  end
417
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.
418
626
  #
419
- # :call-seq:
420
- # Logger#add(severity, message = nil, progname = nil) { ... }
421
- #
422
- # === Args
423
- #
424
- # +severity+::
425
- # Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+,
426
- # +WARN+, +ERROR+, +FATAL+, or +UNKNOWN+.
427
- # +message+::
428
- # The log message. A String or Exception.
429
- # +progname+::
430
- # Program name string. Can be omitted. Treated as a message if no
431
- # +message+ and +block+ are given.
432
- # +block+::
433
- # Can be omitted. Called to get a message string if +message+ is nil.
434
- #
435
- # === Return
436
- #
437
- # When the given severity is not high enough (for this particular logger),
438
- # log no message, and return +true+.
627
+ # Examples:
439
628
  #
440
- # === 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')
441
633
  #
442
- # Log a message if the given severity is high enough. This is the generic
443
- # logging method. Users will be more inclined to use #debug, #info, #warn,
444
- # #error, and #fatal.
634
+ # Output:
445
635
  #
446
- # <b>Message format</b>: +message+ can be any object, but it has to be
447
- # converted to a String in order to log it. Generally, +inspect+ is used
448
- # if the given object is not a String.
449
- # A special case is an +Exception+ object, which will be printed in detail,
450
- # including message, class, and backtrace. See #msg2str for the
451
- # 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
452
639
  #
453
- # === Bugs
640
+ # These convenience methods have implicit severity:
454
641
  #
455
- # * Logfile is not locked.
456
- # * Append open does not need to lock file.
457
- # * If the OS supports multi I/O, records possibly may be mixed.
642
+ # - #debug.
643
+ # - #info.
644
+ # - #warn.
645
+ # - #error.
646
+ # - #fatal.
647
+ # - #unknown.
458
648
  #
459
649
  def add(severity, message = nil, progname = nil)
460
650
  severity ||= UNKNOWN
@@ -478,104 +668,71 @@ class Logger
478
668
  end
479
669
  alias log add
480
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:
481
674
  #
482
- # Dump given message to the log device without any formatting. If no log
483
- # device exists, return +nil+.
675
+ # logger = Logger.new($stdout)
676
+ # logger << 'My message.' # => 10
677
+ #
678
+ # Output:
679
+ #
680
+ # My message.
484
681
  #
485
682
  def <<(msg)
486
683
  @logdev&.write(msg)
487
684
  end
488
685
 
489
- #
490
- # Log a +DEBUG+ message.
491
- #
492
- # See #info for more information.
686
+ # Equivalent to calling #add with severity <tt>Logger::DEBUG</tt>.
493
687
  #
494
688
  def debug(progname = nil, &block)
495
689
  add(DEBUG, nil, progname, &block)
496
690
  end
497
691
 
498
- #
499
- # :call-seq:
500
- # info(message)
501
- # info(progname, &block)
502
- #
503
- # Log an +INFO+ message.
504
- #
505
- # +message+:: The message to log; does not need to be a String.
506
- # +progname+:: In the block form, this is the #progname to use in the
507
- # log message. The default can be set with #progname=.
508
- # +block+:: Evaluates to the message to log. This is not evaluated unless
509
- # the logger's level is sufficient to log the message. This
510
- # allows you to create potentially expensive logging messages that
511
- # are only called when the logger is configured to show them.
512
- #
513
- # === Examples
514
- #
515
- # logger.info("MainApp") { "Received connection from #{ip}" }
516
- # # ...
517
- # logger.info "Waiting for input from user"
518
- # # ...
519
- # logger.info { "User typed #{input}" }
520
- #
521
- # You'll probably stick to the second form above, unless you want to provide a
522
- # program name (which you can do with #progname= as well).
523
- #
524
- # === Return
525
- #
526
- # See #add.
692
+ # Equivalent to calling #add with severity <tt>Logger::INFO</tt>.
527
693
  #
528
694
  def info(progname = nil, &block)
529
695
  add(INFO, nil, progname, &block)
530
696
  end
531
697
 
532
- #
533
- # Log a +WARN+ message.
534
- #
535
- # See #info for more information.
698
+ # Equivalent to calling #add with severity <tt>Logger::WARN</tt>.
536
699
  #
537
700
  def warn(progname = nil, &block)
538
701
  add(WARN, nil, progname, &block)
539
702
  end
540
703
 
541
- #
542
- # Log an +ERROR+ message.
543
- #
544
- # See #info for more information.
704
+ # Equivalent to calling #add with severity <tt>Logger::ERROR</tt>.
545
705
  #
546
706
  def error(progname = nil, &block)
547
707
  add(ERROR, nil, progname, &block)
548
708
  end
549
709
 
550
- #
551
- # Log a +FATAL+ message.
552
- #
553
- # See #info for more information.
710
+ # Equivalent to calling #add with severity <tt>Logger::FATAL</tt>.
554
711
  #
555
712
  def fatal(progname = nil, &block)
556
713
  add(FATAL, nil, progname, &block)
557
714
  end
558
715
 
559
- #
560
- # Log an +UNKNOWN+ message. This will be printed no matter what the logger's
561
- # level is.
562
- #
563
- # See #info for more information.
716
+ # Equivalent to calling #add with severity <tt>Logger::UNKNOWN</tt>.
564
717
  #
565
718
  def unknown(progname = nil, &block)
566
719
  add(UNKNOWN, nil, progname, &block)
567
720
  end
568
721
 
722
+ # Closes the logger; returns +nil+:
569
723
  #
570
- # Close the logging device.
724
+ # logger = Logger.new('t.log')
725
+ # logger.close # => nil
726
+ # logger.info('foo') # Prints "log writing failed. closed stream"
571
727
  #
728
+ # Related: Logger#reopen.
572
729
  def close
573
730
  @logdev&.close
574
731
  end
575
732
 
576
733
  private
577
734
 
578
- # Severity label for logging (max 5 chars).
735
+ # \Severity label for logging (max 5 chars).
579
736
  SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY).freeze
580
737
 
581
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.0
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: 2021-12-20 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
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.3.0.dev
106
+ rubygems_version: 3.4.0.dev
107
107
  signing_key:
108
108
  specification_version: 4
109
109
  summary: Provides a simple logging utility for outputting messages.