类 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')

当您调用这些方法中的任何一个时,条目可能写入日志,也可能不写入日志,具体取决于条目的严重程度和日志级别;请参阅 日志级别

条目始终具有

并且可能还具有

示例

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"

其中要格式化的值为

您可以通过以下方式使用不同的条目格式

严重程度

日志条目的严重程度有两个影响

时间戳

日志条目的时间戳在创建条目时自动生成。

记录的时间戳使用此格式字符串由方法 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,消息对象可以是

注意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

示例

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 已满时,日志文件都会轮换

定期轮换

对于定期轮换,请使用以下参数调用 Logger.new

示例

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')

当给定周期到期时

后缀的默认格式为 '%Y%m%d',它会生成类似于上述后缀。您可以使用创建时选项 shift_period_suffix 设置不同的格式;有关详细信息和建议,请参阅 Time#strftime

常量

ProgName
SEV_LABEL

用于日志记录的严重性标签(最多 5 个字符)。

VERSION

属性

formatter[RW]

设置或检索日志条目格式化程序 proc。

formatternil 时,日志记录器使用 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\\\""
progname[RW]

要包含在日志消息中的程序名称。

公共类方法

new(logdev, shift_age = 0, shift_size = 1048576, **options) 点击切换源代码

使用单个参数 logdev,返回一个具有所有默认选项的新记录器

Logger.new('t.log') # => #<Logger:0x000001e685dc6ac8>

参数 logdev 必须是以下之一

  • 字符串文件路径:条目将写入该路径下的文件;如果该路径下的文件存在,则将追加新条目。

  • 一个 IO 流(通常是 +$stdout+、+$stderr+ 或一个打开的文件):条目将写入给定的流。

  • nilFile::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) 点击切换源代码

将给定的 msg 写入日志,不进行任何格式化;返回写入的字符数,如果不存在日志设备,则返回 nil

logger = Logger.new($stdout)
logger << 'My message.' # => 10

输出

My message.
# File lib/logger.rb, line 684
def <<(msg)
  @logdev&.write(msg)
end
add(severity, message = nil, progname = nil) { || ... } 点击切换源代码

创建一个日志条目,该条目可能会或可能不会写入日志,具体取决于条目的严重性和日志级别。请参阅 日志级别条目 以了解详细信息。

示例

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
也称为:log
close() 点击切换源代码

关闭日志记录器;返回 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() 点击切换源代码

返回日期时间格式;参见 datetime_format=.

# File lib/logger.rb, line 438
def datetime_format
  @default_formatter.datetime_format
end
datetime_format=(datetime_format) 点击切换源代码

设置日期时间格式。

参数 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
debug(progname = nil, &block) 点击切换源代码

等效于使用严重级别 Logger::DEBUG 调用 add

# File lib/logger.rb, line 690
def debug(progname = nil, &block)
  add(DEBUG, nil, progname, &block)
end
debug!() 点击切换源代码

将日志级别设置为 Logger::DEBUG。参见 日志级别.

# File lib/logger.rb, line 487
def debug!; self.level = DEBUG; end
debug?() 点击切换源代码

如果日志级别允许写入严重级别为 Logger::DEBUG 的条目,则返回 true,否则返回 false。参见 日志级别.

# File lib/logger.rb, line 482
def debug?; level <= DEBUG; end
error(progname = nil, &block) 点击切换源代码

等效于使用严重级别 Logger::ERROR 调用 add

# File lib/logger.rb, line 708
def error(progname = nil, &block)
  add(ERROR, nil, progname, &block)
end
error!() 点击切换源代码

将日志级别设置为 Logger::ERROR。参见 日志级别.

# File lib/logger.rb, line 520
def error!; self.level = ERROR; end
error?() 点击切换源代码

如果日志级别允许写入严重级别为 Logger::ERROR 的条目,则返回 true,否则返回 false。参见 日志级别.

# File lib/logger.rb, line 515
def error?; level <= ERROR; end
fatal(progname = nil, &block) 点击切换源代码

等效于使用严重级别 Logger::FATAL 调用 add

# File lib/logger.rb, line 714
def fatal(progname = nil, &block)
  add(FATAL, nil, progname, &block)
end
fatal!() 点击切换源代码

将日志级别设置为 Logger::FATAL。参见 日志级别.

# File lib/logger.rb, line 531
def fatal!; self.level = FATAL; end
fatal?() 点击切换源代码

如果日志级别允许写入严重级别为 Logger::FATAL 的条目,则返回 true,否则返回 false。参见 日志级别.

# File lib/logger.rb, line 526
def fatal?; level <= FATAL; end
info(progname = nil, &block) 点击切换源代码

等效于使用严重级别 Logger::INFO 调用 add

# File lib/logger.rb, line 696
def info(progname = nil, &block)
  add(INFO, nil, progname, &block)
end
info!() 点击切换源代码

将日志级别设置为 Logger::INFO。参见 日志级别

# File lib/logger.rb, line 498
def info!; self.level = INFO; end
info?() 点击切换源代码

如果日志级别允许写入严重程度为 Logger::INFO 的条目,则返回 true,否则返回 false。参见 日志级别

# File lib/logger.rb, line 493
def info?; level <= INFO; end
level() 点击切换源代码

日志严重程度阈值(例如 Logger::INFO)。

# File lib/logger.rb, line 383
def level
  @level_override[Fiber.current] || @level
end
也称为:sev_threshold
level=(severity) 点击切换源代码

设置日志级别;返回 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
也称为:sev_threshold=
log(severity, message = nil, progname = nil)
别名:add
reopen(logdev = nil) 点击切换源代码

设置日志记录器的输出流。

  • 如果 logdevnil,则重新打开当前输出流。

  • 如果 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
sev_threshold()
别名:level
sev_threshold=(severity)
别名:level=
unknown(progname = nil, &block) 点击切换源代码

等效于使用严重程度 Logger::UNKNOWN 调用 add

# File lib/logger.rb, line 720
def unknown(progname = nil, &block)
  add(UNKNOWN, nil, progname, &block)
end
warn(progname = nil, &block) 点击切换源代码

等同于使用严重性级别 Logger::WARN 调用 add

# File lib/logger.rb, line 702
def warn(progname = nil, &block)
  add(WARN, nil, progname, &block)
end
warn!() 点击切换源代码

将日志级别设置为 Logger::WARN。参见 日志级别

# File lib/logger.rb, line 509
def warn!; self.level = WARN; end
warn?() 点击切换源代码

如果日志级别允许写入严重性级别为 Logger::WARN 的条目,则返回 true,否则返回 false。参见 日志级别

# File lib/logger.rb, line 504
def warn?; level <= WARN; end
with_level(severity) { || ... } 点击切换源代码

仅在当前 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

私有实例方法

format_message(severity, datetime, progname, msg) 点击切换源代码
# File lib/logger.rb, line 744
def format_message(severity, datetime, progname, msg)
  (@formatter || @default_formatter).call(severity, datetime, progname, msg)
end
format_severity(severity) 点击切换源代码
# File lib/logger.rb, line 740
def format_severity(severity)
  SEV_LABEL[severity] || 'ANY'
end