logger 1.5.1 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55dfc9db8783f8e0bce997c8f6c162b10e4602bcbe968354bb8f4a0f3a6c1764
4
- data.tar.gz: '08e336951520fc4cc5ab2553ec563509a769a20fb461f47d4e0f2b561745783e'
3
+ metadata.gz: 299d68259bad0228e1e6519f73ddbef94902a8e04f230ad8bbc38f1cb7c45dee
4
+ data.tar.gz: 9178b4b52d2e025fefb9dcadebd94ff6a95392d5d381b949f8d2cb454d456bab
5
5
  SHA512:
6
- metadata.gz: 001ea8a77429868cfe3e438b41a1d100ee0d5c1bba2d74685fd031add97efae2bb0f31b4d889a84a954f01dfcc96624512e488bb08da4703e33bc38432c3e606
7
- data.tar.gz: 747d62f6bf313cb3a120afcae4179feb47bbe816d40895793ccc719ca87bb4c1798c0cb72ac39862dbcbacc6468e59606d2d5600e395607562f0c0a58bbf3f6f
6
+ metadata.gz: 1ee506486c7af0e574c4c4c58b28ca10c2d0d4a0493d0b405e43af96e93bb0c397dee7b128d0d89e7793724b6f0cb186c8e2d33aa2ff8cfc6e847e830e6c0127
7
+ data.tar.gz: 70c4a17f55e4eb5d2323ef5218151de9638a70b8690f6a40180b051554a17bd58b4a09521bbc8ca6a55b60afc9215d51b1c37873c0883e5ba3f42d89e4965a36
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:
@@ -3,7 +3,7 @@
3
3
  class Logger
4
4
  # Default formatter for log messages.
5
5
  class Formatter
6
- Format = "%s, [%s #%d] %5s -- %s: %s\n"
6
+ Format = "%.1s, [%s #%d] %5s -- %s: %s\n"
7
7
  DatetimeFormat = "%Y-%m-%dT%H:%M:%S.%6N"
8
8
 
9
9
  attr_accessor :datetime_format
@@ -13,8 +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,
17
- msg2str(msg)]
16
+ sprintf(Format, severity, format_datetime(time), Process.pid, severity, progname, msg2str(msg))
18
17
  end
19
18
 
20
19
  private
@@ -79,8 +79,10 @@ class Logger
79
79
  def set_dev(log)
80
80
  if log.respond_to?(:write) and log.respond_to?(:close)
81
81
  @dev = log
82
- if log.respond_to?(:path)
83
- @filename = log.path
82
+ if log.respond_to?(:path) and path = log.path
83
+ if File.exist?(path)
84
+ @filename = path
85
+ end
84
86
  end
85
87
  else
86
88
  @dev = open_logfile(log)
@@ -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.3"
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)
data/logger.gemspec CHANGED
@@ -23,5 +23,4 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", ">= 0"
24
24
  spec.add_development_dependency "rake", ">= 12.3.3"
25
25
  spec.add_development_dependency "test-unit"
26
- spec.add_development_dependency "rdoc"
27
26
  end
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.3
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-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -53,20 +53,6 @@ dependencies:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
- - !ruby/object:Gem::Dependency
57
- name: rdoc
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
56
  description: Provides a simple logging utility for outputting messages.
71
57
  email:
72
58
  - sonots@gmail.com
@@ -103,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
89
  - !ruby/object:Gem::Version
104
90
  version: '0'
105
91
  requirements: []
106
- rubygems_version: 3.4.0.dev
92
+ rubygems_version: 3.3.26
107
93
  signing_key:
108
94
  specification_version: 4
109
95
  summary: Provides a simple logging utility for outputting messages.