类 Logger
类 Logger 提供了一个简单但功能强大的日志记录工具,您可以使用它为您的程序创建一个或多个 事件日志。每个这样的日志包含一个事件的按时间顺序排列的序列,记录了程序的活动。
关于示例¶ ↑
本页的所有示例都假设 Logger 已经加载
require 'logger'
概要¶ ↑
使用 Logger.new
创建日志
# Single log file. logger = Logger.new('t.log') # Size-based rotated logging: 3 10-megabyte files. logger = Logger.new('t.log', 3, 10485760) # Period-based rotated logging: daily (also allowed: 'weekly', 'monthly'). logger = Logger.new('t.log', 'daily') # Log to an IO stream. logger = Logger.new($stdout)
使用 Logger#add
添加条目(级别、消息)
logger.add(Logger::DEBUG, 'Maximal debugging info') logger.add(Logger::INFO, 'Non-error information') logger.add(Logger::WARN, 'Non-error warning') logger.add(Logger::ERROR, 'Non-fatal error') logger.add(Logger::FATAL, 'Fatal error') logger.add(Logger::UNKNOWN, 'Most severe')
使用 Logger#close
关闭日志
logger.close
条目¶ ↑
您可以使用方法 Logger#add
添加条目
logger.add(Logger::DEBUG, 'Maximal debugging info') logger.add(Logger::INFO, 'Non-error information') logger.add(Logger::WARN, 'Non-error warning') logger.add(Logger::ERROR, 'Non-fatal error') logger.add(Logger::FATAL, 'Fatal error') logger.add(Logger::UNKNOWN, 'Most severe')
这些简写方法也会添加条目
logger.debug('Maximal debugging info') logger.info('Non-error information') logger.warn('Non-error warning') logger.error('Non-fatal error') logger.fatal('Fatal error') logger.unknown('Most severe')
当您调用这些方法中的任何一个时,条目可能写入日志,也可能不写入日志,具体取决于条目的严重程度和日志级别;请参阅 日志级别
条目始终具有
-
严重程度(
add
的必需参数)。 -
自动创建的时间戳。
并且可能还具有
-
消息。
-
程序名称。
示例
logger = Logger.new($stdout) logger.add(Logger::INFO, 'My message.', 'mung') # => I, [2022-05-07T17:21:46.536234 #20536] INFO -- mung: My message.
条目的默认格式为
"%s, [%s #%d] %5s -- %s: %s\n"
其中要格式化的值为
-
严重程度(一个字母)。
-
时间戳。
-
Process
ID。 -
严重程度(单词)。
-
程序名称。
-
消息。
您可以通过以下方式使用不同的条目格式
-
设置自定义格式 proc(影响后续条目);请参阅 formatter=。
-
使用块调用上述任何方法(仅影响一个条目)。这样做有两个好处
-
上下文:块可以评估整个程序上下文并创建依赖于上下文的邮件。
-
性能:除非日志级别允许实际写入条目,否则不会评估块
logger.error { my_slow_message_generator }
将此与字符串形式进行对比,在字符串形式中,始终会评估字符串,而与日志级别无关
logger.error("#{my_slow_message_generator}")
-
严重程度¶ ↑
日志条目的严重程度有两个影响
-
确定是否选择将条目包含在日志中;请参阅 日志级别。
-
向任何日志阅读器(无论是人还是程序)指示条目的相对重要性。
时间戳¶ ↑
日志条目的时间戳在创建条目时自动生成。
记录的时间戳使用此格式字符串由方法 Time#strftime
格式化
'%Y-%m-%dT%H:%M:%S.%6N'
示例
logger = Logger.new($stdout) logger.add(Logger::INFO) # => I, [2022-05-07T17:04:32.318331 #20536] INFO -- : nil
您可以使用方法 datetime_format=
设置不同的格式。
消息¶ ↑
消息是条目方法的可选参数
logger = Logger.new($stdout) logger.add(Logger::INFO, 'My message') # => I, [2022-05-07T18:15:37.647581 #20536] INFO -- : My message
对于默认条目格式化程序 Logger::Formatter
,消息对象可以是
-
字符串:按原样使用。
-
异常:使用
message.message
。 -
其他情况:使用
message.inspect
。
注意:Logger::Formatter
不会对传递给它的消息进行转义或清理。开发人员应注意,消息中可能包含恶意数据(用户输入),并应明确转义不可信数据。
可以使用自定义格式化程序来转义消息数据;请参阅 formatter= 中的示例。
程序名称¶ ↑
程序名称是条目方法的可选参数。
logger = Logger.new($stdout) logger.add(Logger::INFO, 'My message', 'mung') # => I, [2022-05-07T18:17:38.084716 #20536] INFO -- mung: My message
新日志记录器的默认程序名称可以在调用 Logger.new
时通过可选关键字参数 progname
设置。
logger = Logger.new('t.log', progname: 'mung')
现有日志记录器的默认程序名称可以通过调用方法 progname=
设置。
logger.progname = 'mung'
可以使用方法 progname 获取当前程序名称。
logger.progname # => "mung"
日志级别¶ ↑
日志级别设置决定是否将条目实际写入日志,具体取决于条目的严重程度。
以下是定义的严重程度(从最不严重到最严重):
logger = Logger.new($stdout) logger.add(Logger::DEBUG, 'Maximal debugging info') # => D, [2022-05-07T17:57:41.776220 #20536] DEBUG -- : Maximal debugging info logger.add(Logger::INFO, 'Non-error information') # => I, [2022-05-07T17:59:14.349167 #20536] INFO -- : Non-error information logger.add(Logger::WARN, 'Non-error warning') # => W, [2022-05-07T18:00:45.337538 #20536] WARN -- : Non-error warning logger.add(Logger::ERROR, 'Non-fatal error') # => E, [2022-05-07T18:02:41.592912 #20536] ERROR -- : Non-fatal error logger.add(Logger::FATAL, 'Fatal error') # => F, [2022-05-07T18:05:24.703931 #20536] FATAL -- : Fatal error logger.add(Logger::UNKNOWN, 'Most severe') # => A, [2022-05-07T18:07:54.657491 #20536] ANY -- : Most severe
默认的初始级别设置为 Logger::DEBUG,这是最低级别,这意味着将写入所有条目,无论严重程度如何。
logger = Logger.new($stdout) logger.level # => 0 logger.add(0, "My message") # => D, [2022-05-11T15:10:59.773668 #20536] DEBUG -- : My message
可以使用关键字参数 level
和适当的值在新的日志记录器中指定不同的设置。
logger = Logger.new($stdout, level: Logger::ERROR) logger = Logger.new($stdout, level: 'error') logger = Logger.new($stdout, level: :error) logger.level # => 3
使用此级别,将写入严重程度为 Logger::ERROR 及更高的条目,而不会写入严重程度较低的条目。
logger = Logger.new($stdout, level: Logger::ERROR) logger.add(3) # => E, [2022-05-11T15:17:20.933362 #20536] ERROR -- : nil logger.add(2) # Silent.
可以使用方法 level=
为现有日志记录器设置日志级别。
logger.level = Logger::ERROR
这些简写方法也会设置级别。
logger.debug! # => 0 logger.info! # => 1 logger.warn! # => 2 logger.error! # => 3 logger.fatal! # => 4
可以使用方法 level
获取日志级别。
logger.level = Logger::ERROR logger.level # => 3
这些方法返回是否要写入给定级别。
logger.level = Logger::ERROR logger.debug? # => false logger.info? # => false logger.warn? # => false logger.error? # => true logger.fatal? # => true
日志 File
轮换¶ ↑
默认情况下,日志文件是一个单一文件,会无限期地增长(直到显式关闭);没有文件轮换。
为了将日志文件的大小控制在可管理的范围内,可以使用日志文件轮换,它使用多个日志文件。
-
每个日志文件都包含非重叠时间间隔的条目。
-
仅最新的日志文件处于打开和活动状态;其他日志文件已关闭且处于非活动状态。
基于大小的轮换¶ ↑
对于基于大小的日志文件轮换,请使用以下参数调用 Logger.new
:
-
参数
logdev
为文件路径。 -
参数
shift_age
为正整数:轮换中日志文件的数量。 -
参数
shift_size
为正整数:每个日志文件的最大大小(以字节为单位);默认为 1048576(1 兆字节)。
示例
logger = Logger.new('t.log', 3) # Three 1-megabyte files. logger = Logger.new('t.log', 5, 10485760) # Five 10-megabyte files.
对于以下示例,假设
logger = Logger.new('t.log', 3)
日志记录从新的日志文件 t.log
开始;当新条目会导致日志文件大小超过 shift_size
时,日志文件将“已满”并准备轮换。
第一次 t.log
已满
-
t.log
关闭并重命名为t.log.0
。 -
打开一个新的文件
t.log
。
第二次 t.log
已满
-
t.log.0
重命名为t.log.1
。 -
t.log
关闭并重命名为t.log.0
。 -
打开一个新的文件
t.log
。
每次 t.log
已满时,日志文件都会轮换
-
t.log.1
被删除。 -
t.log.0
重命名为t.log.1
。 -
t.log
关闭并重命名为t.log.0
。 -
打开一个新的文件
t.log
。
定期轮换¶ ↑
对于定期轮换,请使用以下参数调用 Logger.new
:
-
参数
logdev
为文件路径。 -
参数
shift_age
为字符串周期指示符。
示例
logger = Logger.new('t.log', 'daily') # Rotate log files daily. logger = Logger.new('t.log', 'weekly') # Rotate log files weekly. logger = Logger.new('t.log', 'monthly') # Rotate log files monthly.
示例
logger = Logger.new('t.log', 'daily')
当给定周期到期时
-
基本日志文件
t.log
关闭并使用基于日期的后缀重命名,例如t.log.20220509
。 -
打开一个新的日志文件
t.log
。 -
不会删除任何内容。
后缀的默认格式为 '%Y%m%d'
,它会生成类似于上述后缀。您可以使用创建时选项 shift_period_suffix
设置不同的格式;有关详细信息和建议,请参阅 Time#strftime
。
常量
- ProgName
- SEV_LABEL
用于日志记录的严重性标签(最多 5 个字符)。
- VERSION
属性
设置或检索日志条目格式化程序 proc。
当 formatter
为 nil
时,日志记录器使用 Logger::Formatter
。
当 formatter
为 proc 时,新条目将由 proc 格式化,该 proc 将使用四个参数调用
-
severity
:条目的严重性。 -
time
:表示条目时间戳的Time
对象。 -
progname
:条目的程序名称。 -
msg
:条目的消息(字符串或可转换为字符串的对象)。
proc 应返回包含格式化条目的字符串。
此自定义格式化程序使用 String#dump
来转义消息字符串
logger = Logger.new($stdout, progname: 'mung') original_formatter = logger.formatter || Logger::Formatter.new logger.formatter = proc { |severity, time, progname, msg| original_formatter.call(severity, time, progname, msg.dump) } logger.add(Logger::INFO, "hello \n ''") logger.add(Logger::INFO, "\f\x00\xff\\\"")
输出
I, [2022-05-13T13:16:29.637488 #8492] INFO -- mung: "hello \n ''" I, [2022-05-13T13:16:29.637610 #8492] INFO -- mung: "\f\x00\xFF\\\""
要包含在日志消息中的程序名称。
公共类方法
使用单个参数 logdev
,返回一个具有所有默认选项的新记录器
Logger.new('t.log') # => #<Logger:0x000001e685dc6ac8>
参数 logdev
必须是以下之一
-
字符串文件路径:条目将写入该路径下的文件;如果该路径下的文件存在,则将追加新条目。
-
一个
IO
流(通常是 +$stdout+、+$stderr+ 或一个打开的文件):条目将写入给定的流。 -
nil
或File::NULL
:不写入任何条目。
示例
Logger.new('t.log') Logger.new($stdout)
关键字选项是
-
level
:设置日志级别;默认值为 Logger::DEBUG。请参阅 日志级别Logger.new('t.log', level: Logger::ERROR)
-
progname
:设置默认程序名称;默认值为nil
。请参阅 程序名称Logger.new('t.log', progname: 'mung')
-
formatter
:设置条目格式化程序;默认值为nil
。请参阅 formatter=。 -
datetime_format
:设置条目时间戳的格式;默认值为nil
。请参阅datetime_format=
。 -
binmode
:设置记录器是否以二进制模式写入;默认值为false
。 -
shift_period_suffix
:设置定期日志文件轮换的 filename 后缀格式;默认值为'%Y%m%d'
。请参阅 定期轮换。
# File lib/logger.rb, line 578 def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG, progname: nil, formatter: nil, datetime_format: nil, binmode: false, shift_period_suffix: '%Y%m%d') self.level = level self.progname = progname @default_formatter = Formatter.new self.datetime_format = datetime_format self.formatter = formatter @logdev = nil @level_override = {} if logdev && logdev != File::NULL @logdev = LogDevice.new(logdev, shift_age: shift_age, shift_size: shift_size, shift_period_suffix: shift_period_suffix, binmode: binmode) end end
公共实例方法
将给定的 msg
写入日志,不进行任何格式化;返回写入的字符数,如果不存在日志设备,则返回 nil
logger = Logger.new($stdout) logger << 'My message.' # => 10
输出
My message.
# File lib/logger.rb, line 684 def <<(msg) @logdev&.write(msg) end
创建一个日志条目,该条目可能会或可能不会写入日志,具体取决于条目的严重性和日志级别。请参阅 日志级别 和 条目 以了解详细信息。
示例
logger = Logger.new($stdout, progname: 'mung') logger.add(Logger::INFO) logger.add(Logger::ERROR, 'No good') logger.add(Logger::ERROR, 'No good', 'gnum')
输出
I, [2022-05-12T16:25:31.469726 #36328] INFO -- mung: mung E, [2022-05-12T16:25:55.349414 #36328] ERROR -- mung: No good E, [2022-05-12T16:26:35.841134 #36328] ERROR -- gnum: No good
这些便捷方法具有隐式严重性
# File lib/logger.rb, line 651 def add(severity, message = nil, progname = nil) severity ||= UNKNOWN if @logdev.nil? or severity < level return true end if progname.nil? progname = @progname end if message.nil? if block_given? message = yield else message = progname progname = @progname end end @logdev.write( format_message(format_severity(severity), Time.now, progname, message)) true end
关闭日志记录器;返回 nil
logger = Logger.new('t.log') logger.close # => nil logger.info('foo') # Prints "log writing failed. closed stream"
相关:Logger#reopen
.
# File lib/logger.rb, line 731 def close @logdev&.close end
返回日期时间格式;参见 datetime_format=
.
# File lib/logger.rb, line 438 def datetime_format @default_formatter.datetime_format end
设置日期时间格式。
参数 datetime_format
应该为以下之一
-
适合用作
Time#strftime
方法格式的字符串。 -
nil
: 日志记录器使用'%Y-%m-%dT%H:%M:%S.%6N'
。
# File lib/logger.rb, line 432 def datetime_format=(datetime_format) @default_formatter.datetime_format = datetime_format end
等效于使用严重级别 Logger::DEBUG
调用 add
。
# File lib/logger.rb, line 690 def debug(progname = nil, &block) add(DEBUG, nil, progname, &block) end
将日志级别设置为 Logger::DEBUG。参见 日志级别.
# File lib/logger.rb, line 487 def debug!; self.level = DEBUG; end
如果日志级别允许写入严重级别为 Logger::DEBUG 的条目,则返回 true
,否则返回 false
。参见 日志级别.
# File lib/logger.rb, line 482 def debug?; level <= DEBUG; end
等效于使用严重级别 Logger::ERROR
调用 add
。
# File lib/logger.rb, line 708 def error(progname = nil, &block) add(ERROR, nil, progname, &block) end
将日志级别设置为 Logger::ERROR。参见 日志级别.
# File lib/logger.rb, line 520 def error!; self.level = ERROR; end
如果日志级别允许写入严重级别为 Logger::ERROR 的条目,则返回 true
,否则返回 false
。参见 日志级别.
# File lib/logger.rb, line 515 def error?; level <= ERROR; end
等效于使用严重级别 Logger::FATAL
调用 add
。
# File lib/logger.rb, line 714 def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end
将日志级别设置为 Logger::FATAL。参见 日志级别.
# File lib/logger.rb, line 531 def fatal!; self.level = FATAL; end
如果日志级别允许写入严重级别为 Logger::FATAL 的条目,则返回 true
,否则返回 false
。参见 日志级别.
# File lib/logger.rb, line 526 def fatal?; level <= FATAL; end
等效于使用严重级别 Logger::INFO
调用 add
。
# File lib/logger.rb, line 696 def info(progname = nil, &block) add(INFO, nil, progname, &block) end
将日志级别设置为 Logger::INFO。参见 日志级别。
# File lib/logger.rb, line 498 def info!; self.level = INFO; end
如果日志级别允许写入严重程度为 Logger::INFO 的条目,则返回 true
,否则返回 false
。参见 日志级别。
# File lib/logger.rb, line 493 def info?; level <= INFO; end
日志严重程度阈值(例如 Logger::INFO
)。
# File lib/logger.rb, line 383 def level @level_override[Fiber.current] || @level end
设置日志级别;返回 severity
。参见 日志级别。
参数 severity
可以是整数、字符串或符号。
logger.level = Logger::ERROR # => 3 logger.level = 3 # => 3 logger.level = 'error' # => "error" logger.level = :error # => :error
Logger#sev_threshold=
是 Logger#level=
的别名。
# File lib/logger.rb, line 399 def level=(severity) @level = Severity.coerce(severity) end
设置日志记录器的输出流。
-
如果
logdev
为nil
,则重新打开当前输出流。 -
如果
logdev
是一个文件路径,则打开指定文件以进行追加。 -
如果
logdev
是一个IO
流(通常是$stdout
、$stderr
或一个打开的File
对象),则打开流以进行追加。
示例
logger = Logger.new('t.log') logger.add(Logger::ERROR, 'one') logger.close logger.add(Logger::ERROR, 'two') # Prints 'log writing failed. closed stream' logger.reopen logger.add(Logger::ERROR, 'three') logger.close File.readlines('t.log') # => # ["# Logfile created on 2022-05-12 14:21:19 -0500 by logger.rb/v1.5.0\n", # "E, [2022-05-12T14:21:27.596726 #22428] ERROR -- : one\n", # "E, [2022-05-12T14:23:05.847241 #22428] ERROR -- : three\n"]
# File lib/logger.rb, line 619 def reopen(logdev = nil) @logdev&.reopen(logdev) self end
等效于使用严重程度 Logger::UNKNOWN
调用 add
。
# File lib/logger.rb, line 720 def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end
等同于使用严重性级别 Logger::WARN
调用 add
。
# File lib/logger.rb, line 702 def warn(progname = nil, &block) add(WARN, nil, progname, &block) end
将日志级别设置为 Logger::WARN。参见 日志级别。
# File lib/logger.rb, line 509 def warn!; self.level = WARN; end
如果日志级别允许写入严重性级别为 Logger::WARN 的条目,则返回 true
,否则返回 false
。参见 日志级别。
# File lib/logger.rb, line 504 def warn?; level <= WARN; end
仅在当前 Fiber
的块执行期间调整日志级别。
logger.with_level(:debug) do logger.debug { "Hello" } end
# File lib/logger.rb, line 408 def with_level(severity) prev, @level_override[Fiber.current] = level, Severity.coerce(severity) begin yield ensure if prev @level_override[Fiber.current] = prev else @level_override.delete(Fiber.current) end end end
私有实例方法
# File lib/logger.rb, line 744 def format_message(severity, datetime, progname, msg) (@formatter || @default_formatter).call(severity, datetime, progname, msg) end
# File lib/logger.rb, line 740 def format_severity(severity) SEV_LABEL[severity] || 'ANY' end