класс 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 есть несколько интересных функций, таких как автоматическое создание новых файлов логов, настройка формата сообщений логов и указание имени программы вместе с сообщением. Следующий раздел показывает, как этого добиться.
Руководства
Как создать логгер
Ниже приведены варианты, в порядке возрастания сложности.
-
Создайте логгер, который записывает сообщения в STDERR/STDOUT.
logger = Logger.new(STDERR) logger = Logger.new(STDOUT)
-
Создайте логгер для файла, имя которого указано.
logger = Logger.new('logfile.log') -
Создайте логгер для указанного файла.
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) -
Создайте логгер, который обновляет файл журнала, когда он достигает определенного размера. Оставить 10 «старых» файлов журнала, где каждый файл составляет примерно 1 024 000 байт.
logger = Logger.new('foo.log', 10, 1024000) -
Создайте логгер, который обновляет файл журнала ежедневно/еженедельно/ежемесячно.
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" }
Если уровень логгера INFO или выше, сообщения отладки не будут записаны, и весь блок даже не будет оценён. Сравните с этим:
logger.debug("This is a " + potentially + " expensive operation")
Здесь конкатенация строк выполняется каждый раз, даже если уровень лога не настроен на отображение сообщения отладки.
Как закрыть логгер
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"
})
Константы
- ProgName
- SEV_LABEL
-
Метка уровня серьезности для ведения журнала (максимум 5 символов).
Атрибуты
Форматировщик логов, как Proc , который принимает четыре аргумента и возвращает отформатированное сообщение. Аргументы:
-
severity -
Уровень серьезности сообщения журнала.
-
time -
Экземпляр
Time, представляющий время записи сообщения. -
progname -
progname, настроенный или переданный методу логгера. -
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 -
Формат даты
Dateи времени. Значение по умолчанию '%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 -
Серьезность. Константы определены в пространстве имен
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 -
Уровень серьёзности сообщения журнала.
# 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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.