class Logger
Logger 类提供一个简单但复杂的日志实用程序,您可以使用它为您的程序创建一个或多个 事件日志。每个这样的日志都包含一个按时间顺序排列的条目序列,用于记录程序的活动。
关于示例¶ ↑
此页面上的所有示例都假设已 require 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\\\""
要包含在日志消息中的程序名称。
公共类方法
来源
# File lib/logger.rb, line 581 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', reraise_write_errors: []) 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, reraise_write_errors: reraise_write_errors) end end
使用单个参数 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
:设置定期日志文件轮换的文件名后缀格式;默认为'%Y%m%d'
。请参阅 定期轮换。 -
reraise_write_errors
:一个异常类数组,当写入日志设备时发生错误,将会重新抛出这些异常。默认情况下会吞下所有抛出的异常。
公共实例方法
来源
# File lib/logger.rb, line 689 def <<(msg) @logdev&.write(msg) end
将给定的 msg
写入日志,不进行任何格式化;返回写入的字符数,如果不存在日志设备则返回 nil
logger = Logger.new($stdout) logger << 'My message.' # => 10
输出
My message.
来源
# File lib/logger.rb, line 656 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
创建一个日志条目,是否写入日志取决于条目的严重性和日志级别。有关详细信息,请参阅 日志级别 和 条目。
示例
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 736 def close @logdev&.close 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 438 def datetime_format @default_formatter.datetime_format end
返回日期时间格式;请参阅 datetime_format=
。
来源
# File lib/logger.rb, line 432 def datetime_format=(datetime_format) @default_formatter.datetime_format = datetime_format end
设置日期时间格式。
参数 datetime_format
应该是以下之一
-
适合用作方法
Time#strftime
的格式的字符串。 -
nil
:日志记录器使用'%Y-%m-%dT%H:%M:%S.%6N'
。
来源
# File lib/logger.rb, line 695 def debug(progname = nil, &block) add(DEBUG, nil, progname, &block) end
等效于使用严重级别 Logger::DEBUG
调用 add
。
来源
# File lib/logger.rb, line 487 def debug!; self.level = DEBUG; end
将日志级别设置为 Logger::DEBUG。请参阅 日志级别。
来源
# File lib/logger.rb, line 482 def debug?; level <= DEBUG; end
如果日志级别允许写入严重级别为 Logger::DEBUG 的条目,则返回 true
,否则返回 false
。请参阅 日志级别。
来源
# File lib/logger.rb, line 713 def error(progname = nil, &block) add(ERROR, nil, progname, &block) end
等效于使用严重级别 Logger::ERROR
调用 add
。
来源
# File lib/logger.rb, line 520 def error!; self.level = ERROR; end
将日志级别设置为 Logger::ERROR。请参阅 日志级别。
来源
# File lib/logger.rb, line 515 def error?; level <= ERROR; end
如果日志级别允许写入严重级别为 Logger::ERROR 的条目,则返回 true
,否则返回 false
。请参阅 日志级别。
来源
# File lib/logger.rb, line 719 def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end
等效于使用严重级别 Logger::FATAL
调用 add
。
来源
# File lib/logger.rb, line 531 def fatal!; self.level = FATAL; end
将日志级别设置为 Logger::FATAL。请参阅 日志级别。
来源
# File lib/logger.rb, line 526 def fatal?; level <= FATAL; end
如果日志级别允许写入严重级别为 Logger::FATAL 的条目,则返回 true
,否则返回 false
。请参阅 日志级别。
来源
# File lib/logger.rb, line 701 def info(progname = nil, &block) add(INFO, nil, progname, &block) end
等效于使用严重级别 Logger::INFO
调用 add
。
来源
# File lib/logger.rb, line 498 def info!; self.level = INFO; end
将日志级别设置为 Logger::INFO。请参阅 日志级别。
来源
# File lib/logger.rb, line 493 def info?; level <= INFO; end
如果日志级别允许写入严重级别为 Logger::INFO 的条目,则返回 true
,否则返回 false
。请参阅 日志级别。
来源
# File lib/logger.rb, line 383 def level level_override[level_key] || @level end
日志严重性阈值(例如, Logger::INFO
)。
来源
# File lib/logger.rb, line 399 def level=(severity) @level = Severity.coerce(severity) end
设置日志级别;返回 severity
。请参阅 日志级别。
参数 severity
可以是整数、字符串或符号
logger.level = Logger::ERROR # => 3 logger.level = 3 # => 3 logger.level = 'error' # => "error" logger.level = :error # => :error
来源
# File lib/logger.rb, line 624 def reopen(logdev = nil) @logdev&.reopen(logdev) self 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 725 def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end
等效于使用严重级别 Logger::UNKNOWN
调用 add
。
来源
# File lib/logger.rb, line 707 def warn(progname = nil, &block) add(WARN, nil, progname, &block) end
等效于使用严重级别 Logger::WARN
调用 add
。
来源
# File lib/logger.rb, line 509 def warn!; self.level = WARN; end
将日志级别设置为 Logger::WARN。请参阅 日志级别。
来源
# File lib/logger.rb, line 504 def warn?; level <= WARN; end
如果日志级别允许写入严重级别为 Logger::WARN 的条目,则返回 true
,否则返回 false
。请参阅 日志级别。
来源
# File lib/logger.rb, line 408 def with_level(severity) prev, level_override[level_key] = level, Severity.coerce(severity) begin yield ensure if prev level_override[level_key] = prev else level_override.delete(level_key) end end end
仅在当前 Fiber
的块执行期间调整日志级别
logger.with_level(:debug) do logger.debug { "Hello" } end
私有实例方法
来源
# File lib/logger.rb, line 758 def format_message(severity, datetime, progname, msg) (@formatter || @default_formatter).call(severity, datetime, progname, msg) end
来源
# File lib/logger.rb, line 745 def format_severity(severity) SEV_LABEL[severity] || 'ANY' end
来源
# File lib/logger.rb, line 750 def level_override @level_override ||= {} end
即使子类不调用超类构造函数,也保证此 ivar 的存在。