класс 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 «старых» лог-файлов, где каждый файл составляет около 1024000 байтов.
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
-
Severityметка для ведения журнала (максимум 5 символов). - VERSION
Атрибуты
Форматировщик сообщений журнала, как Proc который примет четыре аргумента и вернёт отформатированное сообщение. Аргументы:
-
severity -
Severityсообщения в журнале. -
time -
Экземпляр
Time, представляющий момент записи сообщения. -
progname -
prognameконфигурированный или переданный в метод logger. -
msg -
Объект, переданный пользователем в сообщение в журнале; необязательно
String.
Блок должен возвращать Object, который можно записать в устройство ведения журнала с помощью write. Форматировщик по умолчанию используется, если форматировщик не установлен.
Порог уровня тяжести записи в журнал (например, Logger::INFO).
Имя программы для включения в сообщения журнала.
Порог уровня тяжести записи в журнал (например, Logger::INFO).
Публичные методы класса
# File lib/logger.rb, line 377
def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
progname: nil, formatter: nil, datetime_format: nil,
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 = LogDevice.new(logdev, :shift_age => shift_age,
:shift_size => shift_size,
:shift_period_suffix => shift_period_suffix)
end
end Аргументы
-
logdev -
Устройство журнала. Это имя файла (строка) или объект
IO(обычноSTDOUT,STDERR, или открытый файл). -
shift_age -
Количество старых лог-файлов для хранения, или частота ротации (
daily,weeklyилиmonthly). Значение по умолчанию равно 0. -
shift_size -
Максимальный размер лог-файла в байтах (применяется только если
shift_ageявляется числом). По умолчанию1048576(1 МБ). -
level -
Порог уровня тяжести записи в журнал. Значение по умолчанию Logger::DEBUG.
-
progname -
Имя программы для включения в сообщения журнала. Значение по умолчанию — nil.
-
formatter -
Форматировщик сообщений журнала. Значение по умолчанию — экземпляр
Logger::Formatter. -
datetime_format -
Формат даты и времени. Значение по умолчанию — '%Y-%m-%d %H:%M:%S'.
-
shift_period_suffix -
Формат суффикса имени лог-файла для ротации
daily,weeklyилиmonthly. Значение по умолчанию — '%Y%m%d'.
Описание
Создаёт экземпляр.
Общедоступные методы экземпляров
# File lib/logger.rb, line 481 def <<(msg) @logdev&.write(msg) end
Вывести заданное сообщение в устройство регистрации без форматирования. Если устройство регистрации не существует, вернуть nil.
# File lib/logger.rb, line 455
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 -
Сообщение регистрации. Может быть строкой
Stringили исключениемException. -
progname -
Строка имени программы. Можно опустить. Будет обработана как сообщение, если не заданы
messageиblock. -
block -
Можно опустить. Вызывается для получения строки сообщения, если
messageравно null.
Возвращаемое значение
Если заданная степень важности недостаточна (для этого конкретного логгера), сообщение не регистрируется, и возвращается true.
Описание
Зарегистрировать сообщение, если заданная степень важности достаточна. Это общий метод регистрации. Пользователи чаще будут использовать debug, info, warn, error и fatal.
Формат сообщения: message может быть любым объектом, но он должен быть преобразован в строку String для регистрации. В общем случае, inspect используется, если данный объект не является String. Специальным случаем является объект Exception, который будет напечатан подробно, включая сообщение, класс и трассировку стека вызовов. См. msg2str для реализации, если требуется.
Ошибки
-
Файл логов не блокируется.
-
Открытие для добавления не требует блокировки файла.
-
Если ОС поддерживает многопоточную ввод-вывод, записи могут быть смешаны.
# File lib/logger.rb, line 568 def close @logdev&.close end
Закрыть устройство регистрации.
# File lib/logger.rb, line 300 def datetime_format @default_formatter.datetime_format end
Возвращает используемый формат даты. См. datetime_format=
# File lib/logger.rb, line 295 def datetime_format=(datetime_format) @default_formatter.datetime_format = datetime_format end
Set формат даты и времени.
-
datetime_format -
Строка, подходящая для передачи в
strftime.
# File lib/logger.rb, line 490 def debug(progname = nil, &block) add(DEBUG, nil, progname, &block) end
Зарегистрировать сообщение уровня отладки.
См. info для дополнительной информации.
# File lib/logger.rb, line 323 def debug?; @level <= DEBUG; end
Возвращает true , если текущий уровень важности позволяет выводить сообщения отладки.
# File lib/logger.rb, line 542 def error(progname = nil, &block) add(ERROR, nil, progname, &block) end
Зарегистрировать сообщение об ошибке.
См. info для дополнительной информации.
# File lib/logger.rb, line 335 def error?; @level <= ERROR; end
Возвращает true , если текущий уровень важности позволяет выводить сообщения об ошибках.
# File lib/logger.rb, line 551 def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end
Зарегистрировать критически важное сообщение.
См. info для дополнительной информации.
# File lib/logger.rb, line 339 def fatal?; @level <= FATAL; end
Возвращает true , если текущий уровень важности позволяет выводить критически важные сообщения.
# File lib/logger.rb, line 524 def info(progname = nil, &block) add(INFO, nil, progname, &block) end
Зарегистрировать сообщение информационного уровня.
-
message -
Сообщение для регистрации; не обязательно строкой
String. -
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 327 def info?; @level <= INFO; end
Возвращает true , если текущий уровень важности позволяет выводить информационные сообщения.
# File lib/logger.rb, line 266
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 Set порог степени важности регистрации.
-
severity -
Степень важности
Severityсообщения.
# File lib/logger.rb, line 409 def reopen(logdev = nil) @logdev.reopen(logdev) self end
Аргументы
-
logdev -
Устройство регистрации. Это имя файла (строка) или объект
IO(обычноSTDOUT,STDERR, или открытый файл). Переоткрывает тот же файл, если онnil, ничего не делает дляIO. По умолчаниюnil.
Описание
Переоткрывает устройство регистрации.
# File lib/logger.rb, line 561 def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end
Записывает сообщение UNKNOWN. Это будет выведено независимо от уровня регистрации.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 533 def warn(progname = nil, &block) add(WARN, nil, progname, &block) end
Записывает сообщение WARN.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 331 def warn?; @level <= WARN; end
Возвращает true, если текущий уровень серьезности разрешает вывод сообщений WARN.
Приватные методы экземпляра
# File lib/logger.rb, line 581 def format_message(severity, datetime, progname, msg) (@formatter || @default_formatter).call(severity, datetime, progname, msg) end
# File lib/logger.rb, line 577 def format_severity(severity) SEV_LABEL[severity] || 'ANY' end
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.