класс 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идентификатор. -
Уровень важности (слово).
-
Имя программы.
-
Сообщение.
Вы можете использовать другой формат записи, выполнив следующие действия:
-
Установите пользовательский формат 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
Атрибуты
Устанавливает или извлекает процедуру форматирования записей логгера.
Когда formatter равно nil, логгер использует Logger::Formatter.
Когда formatter является процедурой, новая запись форматируется этой процедурой, которая вызывается с четырьмя аргументами:
-
severity: Уровень серьезности записи. -
time: ОбъектTime, представляющий временную метку записи. -
progname: Имя программы для записи. -
msg: Сообщение для записи (строка или объект, преобразуемый в строку).
Процедура должна возвращать строку, содержащую отформатированную запись.
Этот пользовательский форматер использует 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
Эквивалентно вызову add с уровнем серьезности Logger::DEBUG.
Исходный код
# 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
Возвращает true если уровень логирования позволяет записывать записи с уровнем серьезности Logger::DEBUG, false в противном случае. См. Уровень логирования.
Исходный код
# File lib/logger.rb, line 713 def error(progname = nil, &block) add(ERROR, nil, progname, &block) end
Эквивалентно вызову add с уровнем серьезности Logger::ERROR.
Исходный код
# 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
Возвращает true если уровень логирования позволяет записывать записи с уровнем серьезности Logger::ERROR, false в противном случае. См. Уровень логирования.
Исходный код
# File lib/logger.rb, line 719 def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end
Эквивалентно вызову add с уровнем серьезности Logger::FATAL.
Исходный код
# 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
Возвращает true если уровень логирования позволяет записывать записи с уровнем серьезности Logger::FATAL, false в противном случае. См. Уровень логирования.
Исходный код
# File lib/logger.rb, line 701 def info(progname = nil, &block) add(INFO, nil, progname, &block) end
Эквивалентно вызову add с уровнем серьезности Logger::INFO.
Исходный код
# 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
Возвращает true, если уровень логирования разрешает запись сообщений с уровнем Logger::INFO, 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
Logger#sev_threshold= является псевдонимом для Logger#level=.
Исходный код
# 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
Эквивалентно вызову add с уровнем серьезности Logger::UNKNOWN.
Исходный код
# File lib/logger.rb, line 707 def warn(progname = nil, &block) add(WARN, nil, progname, &block) end
Эквивалентно вызову add с уровнем серьезности Logger::WARN.
Исходный код
# 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
Возвращает true, если уровень логирования разрешает запись сообщений с уровнем Logger::WARN, 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 даже когда подклассы не вызывают конструктор суперкласса.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.