logger 1.4.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be49be41055335fa90e79c26a714b7176077de04b414def791b1a9524169ad80
4
- data.tar.gz: f064246f7c9e483f96e9838ace1d079ce0d9acea770eb68d5a492a792157bb83
3
+ metadata.gz: 25185d093ab5e02f9933ce7d395e5929f1ad6f345301fbbbded9e720f67c16e4
4
+ data.tar.gz: 44d81cc02f511f27d70f3ece4bf99670e9b292a625b0984a47dc128c836385e9
5
5
  SHA512:
6
- metadata.gz: 8dc3387289106d3f98eda8384351d9486b8ad5bb21e5c58a3932595b101705600b1b66c64666eabab90a11f1d90a4b7f01e6f0ce658249bfb9ede51d76414ef4
7
- data.tar.gz: 693e411b78fc95e47d008b3ced6247606ebb641f7a17368321e8e0002fa450694267794a620fc76f949ac9cf2a7e5ac8b891416d7d4accb738f8c2c228421388
6
+ metadata.gz: 7055c80ccdc88976a5616b6a648ba877c6c2fba8a6d6c575ed88dda70a537ba2aa698574128b8824f68521715762cb38a7f2c1847713a6ba5ff7941241d99e24
7
+ data.tar.gz: 0c7d1bdf93857052c4fbbf64536445d2b2eefddb33b527d18bd2a6b638b0771b92b846b669d57b7500c280bd8fe4ae836ecad5e8b92517a0d2d4aaac66784182
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,8 @@
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
+ DatetimeFormat = "%Y-%m-%dT%H:%M:%S.%6N"
7
8
 
8
9
  attr_accessor :datetime_format
9
10
 
@@ -12,14 +13,13 @@ class Logger
12
13
  end
13
14
 
14
15
  def call(severity, time, progname, msg)
15
- Format % [severity[0..0], format_datetime(time), Process.pid, severity, progname,
16
- msg2str(msg)]
16
+ sprintf(Format, severity, format_datetime(time), Process.pid, severity, progname, msg2str(msg))
17
17
  end
18
18
 
19
19
  private
20
20
 
21
21
  def format_datetime(time)
22
- time.strftime(@datetime_format || "%Y-%m-%dT%H:%M:%S.%6N ")
22
+ time.strftime(@datetime_format || DatetimeFormat)
23
23
  end
24
24
 
25
25
  def msg2str(msg)
@@ -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)
@@ -135,7 +137,7 @@ class Logger
135
137
  end
136
138
  end
137
139
 
138
- if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM
140
+ if /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os']
139
141
  def lock_shift_log
140
142
  yield
141
143
  end
@@ -15,5 +15,24 @@ class Logger
15
15
  FATAL = 4
16
16
  # An unknown message that should always be logged.
17
17
  UNKNOWN = 5
18
+
19
+ LEVELS = {
20
+ "debug" => DEBUG,
21
+ "info" => INFO,
22
+ "warn" => WARN,
23
+ "error" => ERROR,
24
+ "fatal" => FATAL,
25
+ "unknown" => UNKNOWN,
26
+ }
27
+ private_constant :LEVELS
28
+
29
+ def self.coerce(severity)
30
+ if severity.is_a?(Integer)
31
+ severity
32
+ else
33
+ key = severity.to_s.downcase
34
+ LEVELS[key] || raise(ArgumentError, "invalid log level: #{severity}")
35
+ end
36
+ end
18
37
  end
19
38
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Logger
4
- VERSION = "1.4.3"
4
+ VERSION = "1.6.0"
5
5
  end
data/lib/logger.rb CHANGED
@@ -10,7 +10,9 @@
10
10
  #
11
11
  # A simple system for logging messages. See Logger for more documentation.
12
12
 
13
+ require 'fiber'
13
14
  require 'monitor'
15
+ require 'rbconfig'
14
16
 
15
17
  require_relative 'logger/version'
16
18
  require_relative 'logger/formatter'
@@ -18,216 +20,352 @@ require_relative 'logger/log_device'
18
20
  require_relative 'logger/severity'
19
21
  require_relative 'logger/errors'
20
22
 
21
- # == Description
23
+ # \Class \Logger provides a simple but sophisticated logging utility that
24
+ # you can use to create one or more
25
+ # {event logs}[https://en.wikipedia.org/wiki/Logging_(software)#Event_logs]
26
+ # for your program.
27
+ # Each such log contains a chronological sequence of entries
28
+ # that provides a record of the program's activities.
22
29
  #
23
- # The Logger class provides a simple but sophisticated logging utility that
24
- # you can use to output messages.
30
+ # == About the Examples
25
31
  #
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.
32
+ # All examples on this page assume that \Logger has been required:
29
33
  #
30
- # The levels are:
34
+ # require 'logger'
31
35
  #
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.
36
+ # == Synopsis
38
37
  #
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+.
38
+ # Create a log with Logger.new:
44
39
  #
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:
40
+ # # Single log file.
41
+ # logger = Logger.new('t.log')
42
+ # # Size-based rotated logging: 3 10-megabyte files.
43
+ # logger = Logger.new('t.log', 3, 10485760)
44
+ # # Period-based rotated logging: daily (also allowed: 'weekly', 'monthly').
45
+ # logger = Logger.new('t.log', 'daily')
46
+ # # Log to an IO stream.
47
+ # logger = Logger.new($stdout)
48
48
  #
49
- # logger.info("User-input: #{input.dump}")
50
- # logger.info("User-input: %p" % input)
49
+ # Add entries (level, message) with Logger#add:
51
50
  #
52
- # You can use #formatter= for escaping all data.
51
+ # logger.add(Logger::DEBUG, 'Maximal debugging info')
52
+ # logger.add(Logger::INFO, 'Non-error information')
53
+ # logger.add(Logger::WARN, 'Non-error warning')
54
+ # logger.add(Logger::ERROR, 'Non-fatal error')
55
+ # logger.add(Logger::FATAL, 'Fatal error')
56
+ # logger.add(Logger::UNKNOWN, 'Most severe')
53
57
  #
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)
58
+ # Close the log with Logger#close:
59
59
  #
60
- # === Example
60
+ # logger.close
61
61
  #
62
- # This creates a Logger that outputs to the standard output stream, with a
63
- # level of +WARN+:
62
+ # == Entries
64
63
  #
65
- # require 'logger'
64
+ # You can add entries with method Logger#add:
65
+ #
66
+ # logger.add(Logger::DEBUG, 'Maximal debugging info')
67
+ # logger.add(Logger::INFO, 'Non-error information')
68
+ # logger.add(Logger::WARN, 'Non-error warning')
69
+ # logger.add(Logger::ERROR, 'Non-fatal error')
70
+ # logger.add(Logger::FATAL, 'Fatal error')
71
+ # logger.add(Logger::UNKNOWN, 'Most severe')
72
+ #
73
+ # These shorthand methods also add entries:
74
+ #
75
+ # logger.debug('Maximal debugging info')
76
+ # logger.info('Non-error information')
77
+ # logger.warn('Non-error warning')
78
+ # logger.error('Non-fatal error')
79
+ # logger.fatal('Fatal error')
80
+ # logger.unknown('Most severe')
81
+ #
82
+ # When you call any of these methods,
83
+ # the entry may or may not be written to the log,
84
+ # depending on the entry's severity and on the log level;
85
+ # see {Log Level}[rdoc-ref:Logger@Log+Level]
86
+ #
87
+ # An entry always has:
88
+ #
89
+ # - A severity (the required argument to #add).
90
+ # - An automatically created timestamp.
91
+ #
92
+ # And may also have:
93
+ #
94
+ # - A message.
95
+ # - A program name.
96
+ #
97
+ # Example:
98
+ #
99
+ # logger = Logger.new($stdout)
100
+ # logger.add(Logger::INFO, 'My message.', 'mung')
101
+ # # => I, [2022-05-07T17:21:46.536234 #20536] INFO -- mung: My message.
102
+ #
103
+ # The default format for an entry is:
104
+ #
105
+ # "%s, [%s #%d] %5s -- %s: %s\n"
106
+ #
107
+ # where the values to be formatted are:
108
+ #
109
+ # - \Severity (one letter).
110
+ # - Timestamp.
111
+ # - Process id.
112
+ # - \Severity (word).
113
+ # - Program name.
114
+ # - Message.
115
+ #
116
+ # You can use a different entry format by:
117
+ #
118
+ # - Setting a custom format proc (affects following entries);
119
+ # see {formatter=}[Logger.html#attribute-i-formatter].
120
+ # - Calling any of the methods above with a block
121
+ # (affects only the one entry).
122
+ # Doing so can have two benefits:
123
+ #
124
+ # - Context: the block can evaluate the entire program context
125
+ # and create a context-dependent message.
126
+ # - Performance: the block is not evaluated unless the log level
127
+ # permits the entry actually to be written:
128
+ #
129
+ # logger.error { my_slow_message_generator }
130
+ #
131
+ # Contrast this with the string form, where the string is
132
+ # always evaluated, regardless of the log level:
133
+ #
134
+ # logger.error("#{my_slow_message_generator}")
135
+ #
136
+ # === \Severity
137
+ #
138
+ # The severity of a log entry has two effects:
139
+ #
140
+ # - Determines whether the entry is selected for inclusion in the log;
141
+ # see {Log Level}[rdoc-ref:Logger@Log+Level].
142
+ # - Indicates to any log reader (whether a person or a program)
143
+ # the relative importance of the entry.
144
+ #
145
+ # === Timestamp
66
146
  #
67
- # logger = Logger.new(STDOUT)
68
- # logger.level = Logger::WARN
147
+ # The timestamp for a log entry is generated automatically
148
+ # when the entry is created.
69
149
  #
70
- # logger.debug("Created logger")
71
- # logger.info("Program started")
72
- # logger.warn("Nothing to do!")
150
+ # The logged timestamp is formatted by method
151
+ # {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime]
152
+ # using this format string:
73
153
  #
74
- # path = "a_non_existent_file"
154
+ # '%Y-%m-%dT%H:%M:%S.%6N'
75
155
  #
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
156
+ # Example:
86
157
  #
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.
158
+ # logger = Logger.new($stdout)
159
+ # logger.add(Logger::INFO)
160
+ # # => I, [2022-05-07T17:04:32.318331 #20536] INFO -- : nil
90
161
  #
91
- # === Features
162
+ # You can set a different format using method #datetime_format=.
92
163
  #
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.
164
+ # === Message
97
165
  #
166
+ # The message is an optional argument to an entry method:
98
167
  #
99
- # == HOWTOs
168
+ # logger = Logger.new($stdout)
169
+ # logger.add(Logger::INFO, 'My message')
170
+ # # => I, [2022-05-07T18:15:37.647581 #20536] INFO -- : My message
100
171
  #
101
- # === How to create a logger
172
+ # For the default entry formatter, <tt>Logger::Formatter</tt>,
173
+ # the message object may be:
102
174
  #
103
- # The options below give you various choices, in more or less increasing
104
- # complexity.
175
+ # - A string: used as-is.
176
+ # - An Exception: <tt>message.message</tt> is used.
177
+ # - Anything else: <tt>message.inspect</tt> is used.
105
178
  #
106
- # 1. Create a logger which logs messages to STDERR/STDOUT.
179
+ # *Note*: Logger::Formatter does not escape or sanitize
180
+ # the message passed to it.
181
+ # Developers should be aware that malicious data (user input)
182
+ # may be in the message, and should explicitly escape untrusted data.
107
183
  #
108
- # logger = Logger.new(STDERR)
109
- # logger = Logger.new(STDOUT)
184
+ # You can use a custom formatter to escape message data;
185
+ # see the example at {formatter=}[Logger.html#attribute-i-formatter].
110
186
  #
111
- # 2. Create a logger for the file which has the specified name.
187
+ # === Program Name
112
188
  #
113
- # logger = Logger.new('logfile.log')
189
+ # The program name is an optional argument to an entry method:
114
190
  #
115
- # 3. Create a logger for the specified file.
191
+ # logger = Logger.new($stdout)
192
+ # logger.add(Logger::INFO, 'My message', 'mung')
193
+ # # => I, [2022-05-07T18:17:38.084716 #20536] INFO -- mung: My message
116
194
  #
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)
195
+ # The default program name for a new logger may be set in the call to
196
+ # Logger.new via optional keyword argument +progname+:
121
197
  #
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.
198
+ # logger = Logger.new('t.log', progname: 'mung')
124
199
  #
125
- # logger = Logger.new('foo.log', 10, 1024000)
200
+ # The default program name for an existing logger may be set
201
+ # by a call to method #progname=:
126
202
  #
127
- # 5. Create a logger which ages the logfile daily/weekly/monthly.
203
+ # logger.progname = 'mung'
128
204
  #
129
- # logger = Logger.new('foo.log', 'daily')
130
- # logger = Logger.new('foo.log', 'weekly')
131
- # logger = Logger.new('foo.log', 'monthly')
205
+ # The current program name may be retrieved with method
206
+ # {progname}[Logger.html#attribute-i-progname]:
132
207
  #
133
- # === How to log a message
208
+ # logger.progname # => "mung"
134
209
  #
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.
210
+ # == Log Level
139
211
  #
140
- # 1. Message in a block.
212
+ # The log level setting determines whether an entry is actually
213
+ # written to the log, based on the entry's severity.
141
214
  #
142
- # logger.fatal { "Argument 'foo' not given." }
215
+ # These are the defined severities (least severe to most severe):
143
216
  #
144
- # 2. Message as a string.
217
+ # logger = Logger.new($stdout)
218
+ # logger.add(Logger::DEBUG, 'Maximal debugging info')
219
+ # # => D, [2022-05-07T17:57:41.776220 #20536] DEBUG -- : Maximal debugging info
220
+ # logger.add(Logger::INFO, 'Non-error information')
221
+ # # => I, [2022-05-07T17:59:14.349167 #20536] INFO -- : Non-error information
222
+ # logger.add(Logger::WARN, 'Non-error warning')
223
+ # # => W, [2022-05-07T18:00:45.337538 #20536] WARN -- : Non-error warning
224
+ # logger.add(Logger::ERROR, 'Non-fatal error')
225
+ # # => E, [2022-05-07T18:02:41.592912 #20536] ERROR -- : Non-fatal error
226
+ # logger.add(Logger::FATAL, 'Fatal error')
227
+ # # => F, [2022-05-07T18:05:24.703931 #20536] FATAL -- : Fatal error
228
+ # logger.add(Logger::UNKNOWN, 'Most severe')
229
+ # # => A, [2022-05-07T18:07:54.657491 #20536] ANY -- : Most severe
145
230
  #
146
- # logger.error "Argument #{@foo} mismatch."
231
+ # The default initial level setting is Logger::DEBUG, the lowest level,
232
+ # which means that all entries are to be written, regardless of severity:
147
233
  #
148
- # 3. With progname.
234
+ # logger = Logger.new($stdout)
235
+ # logger.level # => 0
236
+ # logger.add(0, "My message")
237
+ # # => D, [2022-05-11T15:10:59.773668 #20536] DEBUG -- : My message
149
238
  #
150
- # logger.info('initialize') { "Initializing..." }
239
+ # You can specify a different setting in a new logger
240
+ # using keyword argument +level+ with an appropriate value:
151
241
  #
152
- # 4. With severity.
242
+ # logger = Logger.new($stdout, level: Logger::ERROR)
243
+ # logger = Logger.new($stdout, level: 'error')
244
+ # logger = Logger.new($stdout, level: :error)
245
+ # logger.level # => 3
153
246
  #
154
- # logger.add(Logger::FATAL) { 'Fatal error!' }
247
+ # With this level, entries with severity Logger::ERROR and higher
248
+ # are written, while those with lower severities are not written:
155
249
  #
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:
250
+ # logger = Logger.new($stdout, level: Logger::ERROR)
251
+ # logger.add(3)
252
+ # # => E, [2022-05-11T15:17:20.933362 #20536] ERROR -- : nil
253
+ # logger.add(2) # Silent.
159
254
  #
160
- # logger.debug { "This is a " + potentially + " expensive operation" }
255
+ # You can set the log level for an existing logger
256
+ # with method #level=:
161
257
  #
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:
258
+ # logger.level = Logger::ERROR
164
259
  #
165
- # logger.debug("This is a " + potentially + " expensive operation")
260
+ # These shorthand methods also set the level:
166
261
  #
167
- # Here, the string concatenation is done every time, even if the log
168
- # level is not set to show the debug message.
262
+ # logger.debug! # => 0
263
+ # logger.info! # => 1
264
+ # logger.warn! # => 2
265
+ # logger.error! # => 3
266
+ # logger.fatal! # => 4
169
267
  #
170
- # === How to close a logger
268
+ # You can retrieve the log level with method #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$
@@ -242,30 +380,40 @@ class Logger
242
380
  include Severity
243
381
 
244
382
  # Logging severity threshold (e.g. <tt>Logger::INFO</tt>).
245
- attr_reader :level
383
+ def level
384
+ @level_override[Fiber.current] || @level
385
+ end
246
386
 
247
- # Set logging severity threshold.
387
+ # Sets the log level; returns +severity+.
388
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
389
+ #
390
+ # Argument +severity+ may be an integer, a string, or a symbol:
391
+ #
392
+ # logger.level = Logger::ERROR # => 3
393
+ # logger.level = 3 # => 3
394
+ # logger.level = 'error' # => "error"
395
+ # logger.level = :error # => :error
396
+ #
397
+ # Logger#sev_threshold= is an alias for Logger#level=.
248
398
  #
249
- # +severity+:: The Severity of the log message.
250
399
  def level=(severity)
251
- if severity.is_a?(Integer)
252
- @level = severity
253
- else
254
- case severity.to_s.downcase
255
- when 'debug'
256
- @level = DEBUG
257
- when 'info'
258
- @level = INFO
259
- when 'warn'
260
- @level = WARN
261
- when 'error'
262
- @level = ERROR
263
- when 'fatal'
264
- @level = FATAL
265
- when 'unknown'
266
- @level = UNKNOWN
400
+ @level = Severity.coerce(severity)
401
+ end
402
+
403
+ # Adjust the log level during the block execution for the current Fiber only
404
+ #
405
+ # logger.with_level(:debug) do
406
+ # logger.debug { "Hello" }
407
+ # end
408
+ def with_level(severity)
409
+ prev, @level_override[Fiber.current] = level, Severity.coerce(severity)
410
+ begin
411
+ yield
412
+ ensure
413
+ if prev
414
+ @level_override[Fiber.current] = prev
267
415
  else
268
- raise ArgumentError, "invalid log level: #{severity}"
416
+ @level_override.delete(Fiber.current)
269
417
  end
270
418
  end
271
419
  end
@@ -273,109 +421,159 @@ class Logger
273
421
  # Program name to include in log messages.
274
422
  attr_accessor :progname
275
423
 
276
- # Set date-time format.
424
+ # Sets the date-time format.
425
+ #
426
+ # Argument +datetime_format+ should be either of these:
427
+ #
428
+ # - A string suitable for use as a format for method
429
+ # {Time#strftime}[https://docs.ruby-lang.org/en/master/Time.html#method-i-strftime].
430
+ # - +nil+: the logger uses <tt>'%Y-%m-%dT%H:%M:%S.%6N'</tt>.
277
431
  #
278
- # +datetime_format+:: A string suitable for passing to +strftime+.
279
432
  def datetime_format=(datetime_format)
280
433
  @default_formatter.datetime_format = datetime_format
281
434
  end
282
435
 
283
- # Returns the date format being used. See #datetime_format=
436
+ # Returns the date-time format; see #datetime_format=.
437
+ #
284
438
  def datetime_format
285
439
  @default_formatter.datetime_format
286
440
  end
287
441
 
288
- # Logging formatter, as a +Proc+ that will take four arguments and
289
- # return the formatted message. The arguments are:
442
+ # Sets or retrieves the logger entry formatter proc.
443
+ #
444
+ # When +formatter+ is +nil+, the logger uses Logger::Formatter.
445
+ #
446
+ # When +formatter+ is a proc, a new entry is formatted by the proc,
447
+ # which is called with four arguments:
448
+ #
449
+ # - +severity+: The severity of the entry.
450
+ # - +time+: A Time object representing the entry's timestamp.
451
+ # - +progname+: The program name for the entry.
452
+ # - +msg+: The message for the entry (string or string-convertible object).
453
+ #
454
+ # The proc should return a string containing the formatted entry.
290
455
  #
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.
456
+ # This custom formatter uses
457
+ # {String#dump}[https://docs.ruby-lang.org/en/master/String.html#method-i-dump]
458
+ # to escape the message string:
459
+ #
460
+ # logger = Logger.new($stdout, progname: 'mung')
461
+ # original_formatter = logger.formatter || Logger::Formatter.new
462
+ # logger.formatter = proc { |severity, time, progname, msg|
463
+ # original_formatter.call(severity, time, progname, msg.dump)
464
+ # }
465
+ # logger.add(Logger::INFO, "hello \n ''")
466
+ # logger.add(Logger::INFO, "\f\x00\xff\\\"")
467
+ #
468
+ # Output:
469
+ #
470
+ # I, [2022-05-13T13:16:29.637488 #8492] INFO -- mung: "hello \n ''"
471
+ # I, [2022-05-13T13:16:29.637610 #8492] INFO -- mung: "\f\x00\xFF\\\""
296
472
  #
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
473
  attr_accessor :formatter
301
474
 
302
475
  alias sev_threshold level
303
476
  alias sev_threshold= level=
304
477
 
305
- # Returns +true+ iff the current severity level allows for the printing of
306
- # +DEBUG+ messages.
478
+ # Returns +true+ if the log level allows entries with severity
479
+ # Logger::DEBUG to be written, +false+ otherwise.
480
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
481
+ #
307
482
  def debug?; level <= DEBUG; end
308
483
 
309
- # Sets the severity to DEBUG.
484
+ # Sets the log level to Logger::DEBUG.
485
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
486
+ #
310
487
  def debug!; self.level = DEBUG; end
311
488
 
312
- # Returns +true+ iff the current severity level allows for the printing of
313
- # +INFO+ messages.
489
+ # Returns +true+ if the log level allows entries with severity
490
+ # Logger::INFO to be written, +false+ otherwise.
491
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
492
+ #
314
493
  def info?; level <= INFO; end
315
494
 
316
- # Sets the severity to INFO.
495
+ # Sets the log level to Logger::INFO.
496
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
497
+ #
317
498
  def info!; self.level = INFO; end
318
499
 
319
- # Returns +true+ iff the current severity level allows for the printing of
320
- # +WARN+ messages.
500
+ # Returns +true+ if the log level allows entries with severity
501
+ # Logger::WARN to be written, +false+ otherwise.
502
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
503
+ #
321
504
  def warn?; level <= WARN; end
322
505
 
323
- # Sets the severity to WARN.
506
+ # Sets the log level to Logger::WARN.
507
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
508
+ #
324
509
  def warn!; self.level = WARN; end
325
510
 
326
- # Returns +true+ iff the current severity level allows for the printing of
327
- # +ERROR+ messages.
511
+ # Returns +true+ if the log level allows entries with severity
512
+ # Logger::ERROR to be written, +false+ otherwise.
513
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
514
+ #
328
515
  def error?; level <= ERROR; end
329
516
 
330
- # Sets the severity to ERROR.
517
+ # Sets the log level to Logger::ERROR.
518
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
519
+ #
331
520
  def error!; self.level = ERROR; end
332
521
 
333
- # Returns +true+ iff the current severity level allows for the printing of
334
- # +FATAL+ messages.
522
+ # Returns +true+ if the log level allows entries with severity
523
+ # Logger::FATAL to be written, +false+ otherwise.
524
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
525
+ #
335
526
  def fatal?; level <= FATAL; end
336
527
 
337
- # Sets the severity to FATAL.
528
+ # Sets the log level to Logger::FATAL.
529
+ # See {Log Level}[rdoc-ref:Logger@Log+Level].
530
+ #
338
531
  def fatal!; self.level = FATAL; end
339
532
 
340
- #
341
533
  # :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.
534
+ # Logger.new(logdev, shift_age = 0, shift_size = 1048576, **options)
535
+ #
536
+ # With the single argument +logdev+,
537
+ # returns a new logger with all default options:
538
+ #
539
+ # Logger.new('t.log') # => #<Logger:0x000001e685dc6ac8>
540
+ #
541
+ # Argument +logdev+ must be one of:
542
+ #
543
+ # - A string filepath: entries are to be written
544
+ # to the file at that path; if the file at that path exists,
545
+ # new entries are appended.
546
+ # - An IO stream (typically +$stdout+, +$stderr+. or an open file):
547
+ # entries are to be written to the given stream.
548
+ # - +nil+ or +File::NULL+: no entries are to be written.
549
+ #
550
+ # Examples:
551
+ #
552
+ # Logger.new('t.log')
553
+ # Logger.new($stdout)
554
+ #
555
+ # The keyword options are:
556
+ #
557
+ # - +level+: sets the log level; default value is Logger::DEBUG.
558
+ # See {Log Level}[rdoc-ref:Logger@Log+Level]:
559
+ #
560
+ # Logger.new('t.log', level: Logger::ERROR)
561
+ #
562
+ # - +progname+: sets the default program name; default is +nil+.
563
+ # See {Program Name}[rdoc-ref:Logger@Program+Name]:
564
+ #
565
+ # Logger.new('t.log', progname: 'mung')
566
+ #
567
+ # - +formatter+: sets the entry formatter; default is +nil+.
568
+ # See {formatter=}[Logger.html#attribute-i-formatter].
569
+ # - +datetime_format+: sets the format for entry timestamp;
570
+ # default is +nil+.
571
+ # See #datetime_format=.
572
+ # - +binmode+: sets whether the logger writes in binary mode;
573
+ # default is +false+.
574
+ # - +shift_period_suffix+: sets the format for the filename suffix
575
+ # for periodic log file rotation; default is <tt>'%Y%m%d'</tt>.
576
+ # See {Periodic Rotation}[rdoc-ref:Logger@Periodic+Rotation].
379
577
  #
380
578
  def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
381
579
  progname: nil, formatter: nil, datetime_format: nil,
@@ -386,6 +584,7 @@ class Logger
386
584
  self.datetime_format = datetime_format
387
585
  self.formatter = formatter
388
586
  @logdev = nil
587
+ @level_override = {}
389
588
  if logdev && logdev != File::NULL
390
589
  @logdev = LogDevice.new(logdev, shift_age: shift_age,
391
590
  shift_size: shift_size,
@@ -394,67 +593,60 @@ class Logger
394
593
  end
395
594
  end
396
595
 
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.
596
+ # Sets the logger's output stream:
597
+ #
598
+ # - If +logdev+ is +nil+, reopens the current output stream.
599
+ # - If +logdev+ is a filepath, opens the indicated file for append.
600
+ # - If +logdev+ is an IO stream
601
+ # (usually <tt>$stdout</tt>, <tt>$stderr</tt>, or an open File object),
602
+ # opens the stream for append.
603
+ #
604
+ # Example:
605
+ #
606
+ # logger = Logger.new('t.log')
607
+ # logger.add(Logger::ERROR, 'one')
608
+ # logger.close
609
+ # logger.add(Logger::ERROR, 'two') # Prints 'log writing failed. closed stream'
610
+ # logger.reopen
611
+ # logger.add(Logger::ERROR, 'three')
612
+ # logger.close
613
+ # File.readlines('t.log')
614
+ # # =>
615
+ # # ["# Logfile created on 2022-05-12 14:21:19 -0500 by logger.rb/v1.5.0\n",
616
+ # # "E, [2022-05-12T14:21:27.596726 #22428] ERROR -- : one\n",
617
+ # # "E, [2022-05-12T14:23:05.847241 #22428] ERROR -- : three\n"]
412
618
  #
413
619
  def reopen(logdev = nil)
414
620
  @logdev&.reopen(logdev)
415
621
  self
416
622
  end
417
623
 
624
+ # Creates a log entry, which may or may not be written to the log,
625
+ # depending on the entry's severity and on the log level.
626
+ # See {Log Level}[rdoc-ref:Logger@Log+Level]
627
+ # and {Entries}[rdoc-ref:Logger@Entries] for details.
418
628
  #
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
629
+ # Examples:
436
630
  #
437
- # When the given severity is not high enough (for this particular logger),
438
- # log no message, and return +true+.
631
+ # logger = Logger.new($stdout, progname: 'mung')
632
+ # logger.add(Logger::INFO)
633
+ # logger.add(Logger::ERROR, 'No good')
634
+ # logger.add(Logger::ERROR, 'No good', 'gnum')
439
635
  #
440
- # === Description
636
+ # Output:
441
637
  #
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.
638
+ # I, [2022-05-12T16:25:31.469726 #36328] INFO -- mung: mung
639
+ # E, [2022-05-12T16:25:55.349414 #36328] ERROR -- mung: No good
640
+ # E, [2022-05-12T16:26:35.841134 #36328] ERROR -- gnum: No good
445
641
  #
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.
642
+ # These convenience methods have implicit severity:
452
643
  #
453
- # === Bugs
454
- #
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.
644
+ # - #debug.
645
+ # - #info.
646
+ # - #warn.
647
+ # - #error.
648
+ # - #fatal.
649
+ # - #unknown.
458
650
  #
459
651
  def add(severity, message = nil, progname = nil)
460
652
  severity ||= UNKNOWN
@@ -478,104 +670,71 @@ class Logger
478
670
  end
479
671
  alias log add
480
672
 
673
+ # Writes the given +msg+ to the log with no formatting;
674
+ # returns the number of characters written,
675
+ # or +nil+ if no log device exists:
676
+ #
677
+ # logger = Logger.new($stdout)
678
+ # logger << 'My message.' # => 10
679
+ #
680
+ # Output:
481
681
  #
482
- # Dump given message to the log device without any formatting. If no log
483
- # device exists, return +nil+.
682
+ # My message.
484
683
  #
485
684
  def <<(msg)
486
685
  @logdev&.write(msg)
487
686
  end
488
687
 
489
- #
490
- # Log a +DEBUG+ message.
491
- #
492
- # See #info for more information.
688
+ # Equivalent to calling #add with severity <tt>Logger::DEBUG</tt>.
493
689
  #
494
690
  def debug(progname = nil, &block)
495
691
  add(DEBUG, nil, progname, &block)
496
692
  end
497
693
 
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.
694
+ # Equivalent to calling #add with severity <tt>Logger::INFO</tt>.
527
695
  #
528
696
  def info(progname = nil, &block)
529
697
  add(INFO, nil, progname, &block)
530
698
  end
531
699
 
532
- #
533
- # Log a +WARN+ message.
534
- #
535
- # See #info for more information.
700
+ # Equivalent to calling #add with severity <tt>Logger::WARN</tt>.
536
701
  #
537
702
  def warn(progname = nil, &block)
538
703
  add(WARN, nil, progname, &block)
539
704
  end
540
705
 
541
- #
542
- # Log an +ERROR+ message.
543
- #
544
- # See #info for more information.
706
+ # Equivalent to calling #add with severity <tt>Logger::ERROR</tt>.
545
707
  #
546
708
  def error(progname = nil, &block)
547
709
  add(ERROR, nil, progname, &block)
548
710
  end
549
711
 
550
- #
551
- # Log a +FATAL+ message.
552
- #
553
- # See #info for more information.
712
+ # Equivalent to calling #add with severity <tt>Logger::FATAL</tt>.
554
713
  #
555
714
  def fatal(progname = nil, &block)
556
715
  add(FATAL, nil, progname, &block)
557
716
  end
558
717
 
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.
718
+ # Equivalent to calling #add with severity <tt>Logger::UNKNOWN</tt>.
564
719
  #
565
720
  def unknown(progname = nil, &block)
566
721
  add(UNKNOWN, nil, progname, &block)
567
722
  end
568
723
 
724
+ # Closes the logger; returns +nil+:
569
725
  #
570
- # Close the logging device.
726
+ # logger = Logger.new('t.log')
727
+ # logger.close # => nil
728
+ # logger.info('foo') # Prints "log writing failed. closed stream"
571
729
  #
730
+ # Related: Logger#reopen.
572
731
  def close
573
732
  @logdev&.close
574
733
  end
575
734
 
576
735
  private
577
736
 
578
- # Severity label for logging (max 5 chars).
737
+ # \Severity label for logging (max 5 chars).
579
738
  SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY).freeze
580
739
 
581
740
  def format_severity(severity)
data/logger.gemspec CHANGED
@@ -16,14 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.licenses = ["Ruby", "BSD-2-Clause"]
17
17
 
18
18
  spec.files = Dir.glob("lib/**/*.rb") + ["logger.gemspec"]
19
- spec.bindir = "exe"
20
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
19
  spec.require_paths = ["lib"]
22
20
 
23
- spec.required_ruby_version = ">= 2.3.0"
24
-
25
- spec.add_development_dependency "bundler", ">= 0"
26
- spec.add_development_dependency "rake", ">= 12.3.3"
27
- spec.add_development_dependency "test-unit"
28
- spec.add_development_dependency "rdoc"
21
+ spec.required_ruby_version = ">= 2.5.0"
29
22
  end
metadata CHANGED
@@ -1,72 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
8
8
  - SHIBATA Hiroshi
9
9
  autorequire:
10
- bindir: exe
10
+ bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-22 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: bundler
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: '0'
21
- type: :development
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: '0'
28
- - !ruby/object:Gem::Dependency
29
- name: rake
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: 12.3.3
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: 12.3.3
42
- - !ruby/object:Gem::Dependency
43
- name: test-unit
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
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'
12
+ date: 2023-11-07 00:00:00.000000000 Z
13
+ dependencies: []
70
14
  description: Provides a simple logging utility for outputting messages.
71
15
  email:
72
16
  - sonots@gmail.com
@@ -96,14 +40,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
96
40
  requirements:
97
41
  - - ">="
98
42
  - !ruby/object:Gem::Version
99
- version: 2.3.0
43
+ version: 2.5.0
100
44
  required_rubygems_version: !ruby/object:Gem::Requirement
101
45
  requirements:
102
46
  - - ">="
103
47
  - !ruby/object:Gem::Version
104
48
  version: '0'
105
49
  requirements: []
106
- rubygems_version: 3.2.2
50
+ rubygems_version: 3.5.0.dev
107
51
  signing_key:
108
52
  specification_version: 4
109
53
  summary: Provides a simple logging utility for outputting messages.