класс 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идентификатор. -
Уровень важности (слово).
-
Имя программы.
-
Сообщение.
Вы можете использовать другой формат записи, выполнив:
-
Установка пользовательского формата (влияет на последующие записи); см. 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 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 При использовании одного аргумента 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'. См. Периодическая ротация.
Публичные методы экземпляра
# File lib/logger.rb, line 684 def <<(msg) @logdev&.write(msg) end
Записывает заданное msg в лог без форматирования; возвращает количество записанных символов или nil если устройство логирования отсутствует:
logger = Logger.new($stdout) logger << 'My message.' # => 10
Вывод:
My message.
# 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 Создает запись в журнале, которая может быть или не быть записана в журнал в зависимости от серьезности записи и уровня журнала. См. Уровень журнала и Записи для получения подробной информации.
Примеры:
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 731 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 690 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 708 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 714 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 696 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[Fiber.current] || @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 619 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 720 def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end
Эквивалентно вызову add с уровнем серьезности Logger::UNKNOWN.
# File lib/logger.rb, line 702 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[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 Изменяет уровень журнала во время выполнения блока только для текущего Fiber
logger.with_level(:debug) do
logger.debug { "Hello" }
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
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.