класс Logger
Описание
Класс Logger предоставляет простую, но эффективную утилиту для ведения логов, позволяющую выводить сообщения.
Сообщения имеют ассоциированные уровни, такие как INFO или ERROR, указывающие на их важность. Вы можете задать Logger уровень, и будут выводиться только сообщения не ниже этого уровня.
Уровни:
-
UNKNOWN -
Неизвестное сообщение, которое всегда должно быть записано в лог.
-
FATAL -
Необрабатываемая ошибка, приводящая к аварийному завершению программы.
-
ERROR -
Обрабатываемое условие ошибки.
-
WARN -
Предупреждение.
-
INFO -
Общая (полезная) информация о работе системы.
-
DEBUG -
Подробная информация для разработчиков.
Например, в производственной системе вы можете установить Logger на уровень INFO или даже WARN. При разработке же системы, вероятно, вам потребуется информация о внутреннем состоянии программы, и вы установите Logger на уровень DEBUG.
Примечание: Logger не экранирует и не очищает сообщения, передаваемые ему. Разработчики должны учитывать потенциально вредоносные данные (ввод пользователя), передаваемые Logger, и вручную экранировать недоверенные данные:
logger.info("User-input: #{input.dump}")
logger.info("User-input: %p" % input)
Вы можете использовать formatter= для экранирования всех данных.
original_formatter = Logger::Formatter.new
logger.formatter = proc { |severity, datetime, progname, msg|
original_formatter.call(severity, datetime, progname, msg.dump)
}
logger.info(input)
Пример
Это создаёт Logger, который выводит данные в стандартный поток вывода со значением уровня WARN:
require 'logger'
logger = Logger.new(STDOUT)
logger.level = Logger::WARN
logger.debug("Created logger")
logger.info("Program started")
logger.warn("Nothing to do!")
path = "a_non_existent_file"
begin
File.foreach(path) do |line|
unless line =~ /^(\w+) = (.*)$/
logger.error("Line in wrong format: #{line.chomp}")
end
end
rescue => err
logger.fatal("Caught exception; exiting")
logger.fatal(err)
end
Поскольку уровень Logger установлен на WARN, записываются только предупреждения, ошибки и фатальные сообщения. Сообщения отладки и информации игнорируются.
Функциональные возможности
Класс Logger предоставляет несколько интересных функций, таких как автоматическое переименование файлов логов, установка формата сообщений логов и указание имени программы в сочетании с сообщением. Следующий раздел покажет, как это сделать.
Инструкции
Как создать Logger
Ниже представлены варианты, от простых до более сложных.
-
Создать Logger, который записывает сообщения в STDERR/STDOUT.
logger = Logger.new(STDERR) logger = Logger.new(STDOUT)
-
Создать Logger для файла с указанным именем.
logger = Logger.new('logfile.log') -
Создать Logger для указанного файла.
file = File.open('foo.log', File::WRONLY | File::APPEND) # To create new logfile, add File::CREAT like: # file = File.open('foo.log', File::WRONLY | File::APPEND | File::CREAT) logger = Logger.new(file) -
Создать Logger, который переименовывает лог-файл по достижении определенного размера. Оставить 10 «старых» лог-файлов, каждый размером примерно в 1 024 000 байт.
logger = Logger.new('foo.log', 10, 1024000) -
Создать Logger, который переименовывает лог-файл ежедневно/еженедельно/ежемесячно.
logger = Logger.new('foo.log', 'daily') logger = Logger.new('foo.log', 'weekly') logger = Logger.new('foo.log', 'monthly')
Как записать сообщение в лог
Заметьте различные методы (fatal, error, info ), используемые для записи сообщений разных уровней? Другие методы этой серии — warn и debug . add используется ниже для записи сообщения с произвольным (возможно, динамическим) уровнем.
-
Сообщения в блоке.
logger.fatal { "Argument 'foo' not given." } -
Сообщения как строки.
logger.error "Argument #{@foo} mismatch." -
С именем программы.
logger.info('initialize') { "Initializing..." } -
С уровнем важности.
logger.add(Logger::FATAL) { 'Fatal error!' }
Форма блока позволяет создавать потенциально сложные сообщения лога, но откладывать их вычисление до тех пор, пока сообщение не будет записано. Например, если у нас есть следующее:
logger.debug { "This is a " + potentially + " expensive operation" }
Если уровень Logger равен INFO или выше, сообщения отладки не будут записаны, и весь блок не будет вычисляться. Сравните со следующим:
logger.debug("This is a " + potentially + " expensive operation")
Здесь конкатенация строк выполняется каждый раз, даже если уровень лога не настроен на вывод сообщения отладки.
Как закрыть Logger
logger.close
Установка порогового значения уровня важности
-
Исходный интерфейс.
logger.sev_threshold = Logger::WARN
-
Интерфейс, совместимый с Log4r (в некоторой степени).
logger.level = Logger::INFO # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
-
SymbolилиString(регистр не учитывается)logger.level = :info logger.level = 'INFO' # :debug < :info < :warn < :error < :fatal < :unknown
-
Конструктор
Logger.new(logdev, level: Logger::INFO) Logger.new(logdev, level: :info) Logger.new(logdev, level: 'INFO')
Формат
Сообщения логов отображаются в потоке вывода в определенном формате по умолчанию. Ниже показан стандартный формат и пример:
Формат лога:
SeverityID, [DateTime #pid] SeverityLabel -- ProgName: message
Пример лога:
I, [1999-03-03T02:34:24.895701 #19074] INFO -- Main: info.
Вы можете изменить формат даты и времени через datetime_format=.
logger.datetime_format = '%Y-%m-%d %H:%M:%S'
# e.g. "2004-01-03 00:54:26"
или через конструктор.
Logger.new(logdev, datetime_format: '%Y-%m-%d %H:%M:%S')
Или вы можете изменить общий формат через метод formatter=.
logger.formatter = proc do |severity, datetime, progname, msg|
"#{datetime}: #{msg}\n"
end
# e.g. "2005-09-22 08:51:08 +0900: hello world"
или через конструктор.
Logger.new(logdev, formatter: proc {|severity, datetime, progname, msg|
"#{datetime}: #{msg}\n"
})
не используется после 1.2.7. только для совместимости.
Константы
- ProgName
- SEV_LABEL
-
Severityметка для ведения лога (максимум 5 символов). - VERSION
Атрибуты
Форматировщик логов, как Proc , принимающий четыре аргумента и возвращающий отформатированное сообщение. Аргументы:
-
severity -
Severityсообщения лога. -
time -
Экземпляр
Time, представляющий время записи сообщения. -
progname -
progname, настроенный или переданный методу Logger. -
msg -
Объект, переданный пользователем в сообщение лога; необязательно
String.
Блок должен возвращать Object, который может быть записан в устройство ведения лога с помощью write. Форматировщик по умолчанию используется, если форматировщик не задан.
Пороговое значение уровня важности для ведения лога (например, Logger::INFO).
Имя программы для включения в сообщения логов.
Пороговое значение уровня важности для ведения лога (например, Logger::INFO).
Открытые методы класса
# File lib/logger.rb, line 380
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
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 -
Устройство ведения лога. Это имя файла (
String), объектIO(обычноSTDOUT,STDERR, или открытый файл),nil(ничего не записывает) илиFile::NULL(то же, чтоnil). -
shift_age -
Количество старых лог-файлов для сохранения, или частота переименования (
daily,weeklyилиmonthly). Значение по умолчанию — 0, что отключает переименование лог-файла. -
shift_size -
Максимальный размер лог-файла в байтах (применяется только когда
shift_age— положительное целоеInteger). По умолчанию1048576(1 МБ). -
level -
Пороговое значение уровня важности для ведения лога. Значение по умолчанию Logger::DEBUG.
-
progname -
Имя программы для включения в сообщения логов. Значение по умолчанию — nil.
-
formatter -
Форматировщик логов. По умолчанию — экземпляр
Logger::Formatter. -
datetime_format -
Формат даты и времени. Значение по умолчанию «%Y-%m-%d %H:%M:%S».
-
binmode -
Использовать бинарный режим для устройства лога. Значение по умолчанию — false.
-
shift_period_suffix -
Формат суффикса имени лог-файла для переименования
daily,weeklyилиmonthly. Значение по умолчанию — ‘%Y%m%d’.
Описание
Создать экземпляр.
Публичные методы экземпляра
# File lib/logger.rb, line 485 def <<(msg) @logdev&.write(msg) end
Выгрузить заданное сообщение в устройство регистрации без форматирования. Если устройство регистрации не существует, вернуть nil.
# File lib/logger.rb, line 459
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 Аргументы
-
severity -
Severity. Константы определены в пространстве именLogger:DEBUG,INFO,WARN,ERROR,FATAL, илиUNKNOWN. -
message -
progname -
Строка имени программы. Может быть опущена. Рассматривается как сообщение, если не заданы
messageиblock. -
block -
Может быть опущена. Вызывается для получения строки сообщения, если
messageравно nil.
Возвращаемое значение
Когда заданная серьезность недостаточно высока (для этого конкретного регистратора), не регистрировать сообщение и вернуть true.
Описание
Зарегистрировать сообщение, если заданная серьезность достаточно высока. Это универсальный метод регистрации. Пользователи будут более склонны использовать debug, info, warn, error и fatal.
Формат сообщения: message может быть любым объектом, но он должен быть преобразован в String для его регистрации. Как правило, используется inspect, если заданный объект не является String. Специальным случаем является объект Exception, который будет напечатан подробно, включая сообщение, класс и трассировку стека. См. msg2str для реализации, если необходимо.
Ошибки
-
Файл журнала не заблокирован.
-
Открытие в режиме добавления не требует блокировки файла.
-
Если ОС поддерживает многопоточный ввод-вывод, записи могут быть перемешаны.
# File lib/logger.rb, line 572 def close @logdev&.close end
Закрыть устройство регистрации.
# File lib/logger.rb, line 284 def datetime_format @default_formatter.datetime_format end
Возвращает используемый формат даты. См. datetime_format=
# File lib/logger.rb, line 279 def datetime_format=(datetime_format) @default_formatter.datetime_format = datetime_format end
Set формат даты и времени.
-
datetime_format -
Строка, подходящая для передачи в
strftime.
# File lib/logger.rb, line 494 def debug(progname = nil, &block) add(DEBUG, nil, progname, &block) end
Зарегистрировать сообщение DEBUG.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 310 def debug!; self.level = DEBUG; end
Устанавливает серьезность в DEBUG.
# File lib/logger.rb, line 307 def debug?; level <= DEBUG; end
Возвращает true, если и только если текущий уровень серьезности позволяет печатать сообщения DEBUG.
# File lib/logger.rb, line 546 def error(progname = nil, &block) add(ERROR, nil, progname, &block) end
Зарегистрировать сообщение ERROR.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 331 def error!; self.level = ERROR; end
Устанавливает серьезность в ERROR.
# File lib/logger.rb, line 328 def error?; level <= ERROR; end
Возвращает true, если и только если текущий уровень серьезности позволяет печатать сообщения ERROR.
# File lib/logger.rb, line 555 def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end
Зарегистрировать сообщение FATAL.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 338 def fatal!; self.level = FATAL; end
Устанавливает серьезность в FATAL.
# File lib/logger.rb, line 335 def fatal?; level <= FATAL; end
Возвращает true, если и только если текущий уровень серьезности позволяет печатать сообщения FATAL.
# File lib/logger.rb, line 528 def info(progname = nil, &block) add(INFO, nil, progname, &block) end
Зарегистрировать сообщение INFO.
-
message -
Сообщение для регистрации; не обязательно должно быть
String. -
progname -
В форме блока это
progname, используемый в сообщении журнала. Значение по умолчанию может быть установлено с помощьюprogname=. -
block -
Вычисляется в сообщение для регистрации. Это не вычисляется, если уровень регистратора недостаточен для регистрации сообщения. Это позволяет создавать потенциально дорогостоящие сообщения журнала, которые вызываются только тогда, когда регистратор настроен на их отображение.
Примеры
logger.info("MainApp") { "Received connection from #{ip}" }
# ...
logger.info "Waiting for input from user"
# ...
logger.info { "User typed #{input}" }
Вы, вероятно, будете придерживаться второй формы выше, если только вы не хотите указать имя программы (что вы также можете сделать с помощью progname=).
Возвращаемое значение
См. add.
# File lib/logger.rb, line 317 def info!; self.level = INFO; end
Устанавливает серьезность в INFO.
# File lib/logger.rb, line 314 def info?; level <= INFO; end
Возвращает true, если и только если текущий уровень серьезности позволяет печатать сообщения INFO.
# File lib/logger.rb, line 250
def level=(severity)
if severity.is_a?(Integer)
@level = severity
else
case severity.to_s.downcase
when 'debug'
@level = DEBUG
when 'info'
@level = INFO
when 'warn'
@level = WARN
when 'error'
@level = ERROR
when 'fatal'
@level = FATAL
when 'unknown'
@level = UNKNOWN
else
raise ArgumentError, "invalid log level: #{severity}"
end
end
end Устанавливает пороговое значение для уровня протоколирования.
-
severity -
Уровень
Severityсообщения журнала.
# File lib/logger.rb, line 413 def reopen(logdev = nil) @logdev&.reopen(logdev) self end
Аргументы
-
logdev -
Устройство протоколирования. Это имя файла (
String) или объектIO(обычноSTDOUT,STDERR, или открытый файл). Переоткрывает тот же файл, если онnil, ничего не делает дляIO. По умолчаниюnil.
Описание
Переоткрывает устройство протоколирования.
# File lib/logger.rb, line 565 def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end
Протоколирует сообщение UNKNOWN. Оно будет выведено независимо от уровня журнала.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 537 def warn(progname = nil, &block) add(WARN, nil, progname, &block) end
Протоколирует сообщение WARN.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 324 def warn!; self.level = WARN; end
Устанавливает уровень серьезности в WARN.
# File lib/logger.rb, line 321 def warn?; level <= WARN; end
Возвращает true, если и только если текущий уровень серьезности позволяет выводить сообщения WARN.
Приватные методы экземпляра
# File lib/logger.rb, line 585 def format_message(severity, datetime, progname, msg) (@formatter || @default_formatter).call(severity, datetime, progname, msg) end
# File lib/logger.rb, line 581 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.