класс 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 (and to remove old) 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." -
С progname.
logger.info('initialize') { "Initializing..." } -
С severity.
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
-
Символ или строка (регистр не учитывается)
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, или переданное методу логгера.
-
msg -
Объект, переданный пользователем в лог-сообщение; необязательно строка.
Блок должен возвращать Объект, который можно записать в устройство регистрации с помощью write. Используется по умолчанию, если форматировщик не установлен.
Пороговое значение уровня серьезности (например, Logger::INFO).
Имя программы, которое нужно включить в лог-сообщения.
Пороговое значение уровня серьезности (например, Logger::INFO).
Общедоступные методы класса
# File lib/logger.rb, line 376
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 478
def <<(msg)
unless @logdev.nil?
@logdev.write(msg)
end
end Выгружает заданное сообщение в устройство регистрации без форматирования. Если устройство регистрации отсутствует, возвращает nil.
# File lib/logger.rb, line 454
def add(severity, message = nil, progname = nil)
severity ||= UNKNOWN
if @logdev.nil? or severity < @level
return true
end
progname ||= @progname
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 -
Сообщение журнала. Строка или Exception.
-
progname -
Строка с именем программы. Может быть опущена. Рассматривается как сообщение, если не указаны
messageиblock. -
block -
Может быть опущена. Вызывается для получения строки сообщения, если
messageимеет значение nil.
Возвращаемое значение
Если заданный уровень серьезности недостаточно высок (для этого конкретного регистратора), сообщение не регистрируется, и возвращается true.
Описание
Регистрирует сообщение, если заданный уровень серьезности достаточно высок. Это универсальный метод регистрации. Пользователи чаще будут использовать debug, info, warn, error и fatal.
Формат сообщения: message может быть любым объектом, но он должен быть преобразован в строку для его регистрации. Как правило, используется inspect, если заданный объект не является строкой. Специальным случаем является объект Exception, который будет напечатан подробно, включая сообщение, класс и трассировку стека. См. msg2str для реализации, если необходимо.
Ошибки
-
Файл журнала не заблокирован.
-
Добавление открытого файла не требует блокировки файла.
-
Если ОС поддерживает многопоточный ввод-вывод, записи могут быть перемешаны.
# File lib/logger.rb, line 567 def close @logdev.close if @logdev end
Закрывает устройство регистрации.
# File lib/logger.rb, line 299 def datetime_format @default_formatter.datetime_format end
Возвращает используемый формат даты. См. datetime_format=
# File lib/logger.rb, line 294 def datetime_format=(datetime_format) @default_formatter.datetime_format = datetime_format end
Устанавливает формат даты и времени.
-
datetime_format -
Строка, подходящая для передачи в
strftime.
# File lib/logger.rb, line 489 def debug(progname = nil, &block) add(DEBUG, nil, progname, &block) end
Регистрирует сообщение DEBUG.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 322 def debug?; @level <= DEBUG; end
Возвращает true, если текущий уровень серьезности позволяет печатать сообщения DEBUG.
# File lib/logger.rb, line 541 def error(progname = nil, &block) add(ERROR, nil, progname, &block) end
Регистрирует сообщение ERROR.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 334 def error?; @level <= ERROR; end
Возвращает true, если текущий уровень серьезности позволяет печатать сообщения ERROR.
# File lib/logger.rb, line 550 def fatal(progname = nil, &block) add(FATAL, nil, progname, &block) end
Регистрирует сообщение FATAL.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 338 def fatal?; @level <= FATAL; end
Возвращает true, если текущий уровень серьезности позволяет печатать сообщения FATAL.
# File lib/logger.rb, line 523 def info(progname = nil, &block) add(INFO, nil, progname, &block) end
Регистрирует сообщение INFO.
-
message -
Сообщение для регистрации; не обязательно должно быть строкой.
-
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 326 def info?; @level <= INFO; end
Возвращает true, если текущий уровень серьезности позволяет печатать сообщения INFO.
# File lib/logger.rb, line 265
def level=(severity)
if severity.is_a?(Integer)
@level = severity
else
case severity.to_s.downcase
when 'debug'.freeze
@level = DEBUG
when 'info'.freeze
@level = INFO
when 'warn'.freeze
@level = WARN
when 'error'.freeze
@level = ERROR
when 'fatal'.freeze
@level = FATAL
when 'unknown'.freeze
@level = UNKNOWN
else
raise ArgumentError, "invalid log level: #{severity}"
end
end
end Устанавливает пороговый уровень серьезности регистрации.
-
severity -
Severity сообщения журнала.
# File lib/logger.rb, line 408 def reopen(logdev = nil) @logdev.reopen(logdev) self end
Аргументы
-
logdev -
Устройство регистрации. Это имя файла (строка) или объект IO (обычно
STDOUT,STDERRили открытый файл). Переоткрывает тот же файл, если онnil, ничего не делает для IO. По умолчаниюnil.
Описание
Переоткрывает устройство регистрации.
# File lib/logger.rb, line 560 def unknown(progname = nil, &block) add(UNKNOWN, nil, progname, &block) end
Записать UNKNOWN сообщение. Это сообщение будет выведено независимо от уровня регистрации.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 532 def warn(progname = nil, &block) add(WARN, nil, progname, &block) end
Записать WARN сообщение.
См. info для получения дополнительной информации.
# File lib/logger.rb, line 330 def warn?; @level <= WARN; end
Возвращает true только в том случае, если текущий уровень серьезности позволяет выводить сообщения WARN.
Приватные методы экземпляра
# File lib/logger.rb, line 580 def format_message(severity, datetime, progname, msg) (@formatter || @default_formatter).call(severity, datetime, progname, msg) end
# File lib/logger.rb, line 576 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.