Spec-Zone.ru › Ruby 3.4

класс Logger

Родительский класс:
Object
Подключенные модули:
Logger::Severity

Класс 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"

где форматируемые значения — это:

  • Уровень серьёзности (одна буква).

  • Временная метка.

  • Идентификатор процесса.

  • Уровень серьёзности (словом).

  • Имя программы.

  • Сообщение.

Можно использовать другой формат записи:

  • Задав пользовательский proc форматирования (влияет на последующие записи); см. 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 [RW]

Задает или возвращает proc форматирования записи журнала.

Если formatter — nil, журнал использует Logger::Formatter.

Если formatter — proc, новая запись форматируется с помощью proc, который вызывается с четырьмя аргументами:

  • severity: уровень серьезности записи.

  • time: объект Time, представляющий временную метку записи.

  • progname: имя программы для записи.

  • msg: сообщение для записи (строка или объект, преобразуемый в строку).

Proc должен возвращать строку с отформатированной записью.

Этот пользовательский форматтер использует 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\\\""
progname [RW]

Имя программы, включаемое в сообщения журнала.

Открытые методы класса

new(logdev, shift_age = 0, shift_size = 1048576, **options) Показать исходный код
# File lib/logger.rb, line 581
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',
               reraise_write_errors: [])
  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,
      reraise_write_errors: reraise_write_errors)
  end
end

Если передан единственный аргумент logdev, возвращает новый объект logger со всеми параметрами по умолчанию:

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: задает, записывает ли logger данные в двоичном режиме; значение по умолчанию — false.

  • shift_period_suffix: задает формат суффикса имени файла для периодической ротации файлов журнала; значение по умолчанию — '%Y%m%d'. См. раздел Периодическая ротация.

  • reraise_write_errors: массив классов исключений, которые будут повторно вызваны при ошибке записи в устройство журнала. По умолчанию все возникающие исключения подавляются.

Открытые методы экземпляра

<< (msg) Показать исходный код
# File lib/logger.rb, line 689
def <<(msg)
  @logdev&.write(msg)
end

Записывает заданное msg в журнал без форматирования; возвращает количество записанных символов или nil, если устройство журнала отсутствует:

logger = Logger.new($stdout)
logger << 'My message.' # => 10

Вывод:

My message.
add (severity, message = nil, progname = nil) { || ... } Показать исходный код
# File lib/logger.rb, line 656
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

Следующие вспомогательные методы используют неявный уровень серьезности:

  • debug.

  • info.

  • warn.

  • error.

  • fatal.

  • unknown.

Также имеет псевдоним: log
close () Показать исходный код
# File lib/logger.rb, line 736
def close
  @logdev&.close
end

Закрывает logger; возвращает nil:

logger = Logger.new('t.log')
logger.close       # => nil
logger.info('foo') # Prints "log writing failed. closed stream"

См. также: Logger#reopen.

datetime_format () Показать исходный код
# File lib/logger.rb, line 438
def datetime_format
  @default_formatter.datetime_format
end

Возвращает формат даты и времени; см. datetime_format=.

datetime_format= (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: logger использует '%Y-%m-%dT%H:%M:%S.%6N'.

debug (progname = nil, &block) Показать исходный код
# File lib/logger.rb, line 695
def debug(progname = nil, &block)
  add(DEBUG, nil, progname, &block)
end

Эквивалентен вызову add с уровнем серьезности Logger::DEBUG.

debug! () Показать исходный код
# File lib/logger.rb, line 487
def debug!; self.level = DEBUG; end

Устанавливает уровень журнала Logger::DEBUG. См. раздел Уровень журнала.

debug? () Показать исходный код
# File lib/logger.rb, line 482
def debug?; level <= DEBUG; end

Возвращает true, если уровень журнала разрешает запись записей с уровнем серьезности Logger::DEBUG, и false в противном случае. См. раздел Уровень журнала.

error (progname = nil, &block) Показать исходный код
# File lib/logger.rb, line 713
def error(progname = nil, &block)
  add(ERROR, nil, progname, &block)
end

Эквивалентен вызову add с уровнем серьезности Logger::ERROR.

error! () Показать исходный код
# File lib/logger.rb, line 520
def error!; self.level = ERROR; end

Устанавливает уровень журнала Logger::ERROR. См. раздел Уровень журнала.

error? () Показать исходный код
# File lib/logger.rb, line 515
def error?; level <= ERROR; end

Возвращает true, если уровень журнала разрешает запись записей с уровнем серьезности Logger::ERROR, и false в противном случае. См. раздел Уровень журнала.

fatal (progname = nil, &block) Показать исходный код
# File lib/logger.rb, line 719
def fatal(progname = nil, &block)
  add(FATAL, nil, progname, &block)
end

Эквивалентен вызову add с уровнем серьезности Logger::FATAL.

fatal! () Показать исходный код
# File lib/logger.rb, line 531
def fatal!; self.level = FATAL; end

Устанавливает уровень журнала Logger::FATAL. См. раздел Уровень журнала.

fatal? () Показать исходный код
# File lib/logger.rb, line 526
def fatal?; level <= FATAL; end

Возвращает true, если уровень журнала разрешает запись записей с уровнем серьезности Logger::FATAL, и false в противном случае. См. раздел Уровень журнала.

info (progname = nil, &block) Показать исходный код
# File lib/logger.rb, line 701
def info(progname = nil, &block)
  add(INFO, nil, progname, &block)
end

Эквивалентен вызову add с уровнем серьезности Logger::INFO.

info! () Показать исходный код
# File lib/logger.rb, line 498
def info!; self.level = INFO; end

Устанавливает уровень журнала Logger::INFO. См. раздел Уровень журнала.

info? () Показать исходный код
# File lib/logger.rb, line 493
def info?; level <= INFO; end

Возвращает true, если уровень журнала разрешает запись записей с уровнем серьезности Logger::INFO, и false в противном случае. См. раздел Уровень журнала.

level () Показать исходный код
# File lib/logger.rb, line 383
def level
  level_override[level_key] || @level
end

Порог уровня серьезности журнала (например, Logger::INFO).

Также имеет псевдоним: sev_threshold
level= (severity) Показать исходный код
# 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=.

Также имеет псевдоним: sev_threshold=
log (severity, message = nil, progname = nil)
Псевдоним метода: add
reopen (logdev = nil) Показать исходный код
# File lib/logger.rb, line 624
def reopen(logdev = nil)
  @logdev&.reopen(logdev)
  self
end

Задает выходной поток logger:

  • Если 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"]
sev_threshold ()
Псевдоним метода: level
sev_threshold= (severity)
Псевдоним метода: level=
unknown (progname = nil, &block) Показать исходный код
# File lib/logger.rb, line 725
def unknown(progname = nil, &block)
  add(UNKNOWN, nil, progname, &block)
end

Эквивалентен вызову add с уровнем серьезности Logger::UNKNOWN.

warn (progname = nil, &block) Показать исходный код
# File lib/logger.rb, line 707
def warn(progname = nil, &block)
  add(WARN, nil, progname, &block)
end

Эквивалентен вызову add с уровнем серьезности Logger::WARN.

warn! () Показать исходный код
# File lib/logger.rb, line 509
def warn!; self.level = WARN; end

Устанавливает уровень журнала Logger::WARN. См. раздел Уровень журнала.

warn? () Показать исходный код
# File lib/logger.rb, line 504
def warn?; level <= WARN; end

Возвращает true, если уровень журнала разрешает запись записей с уровнем серьезности Logger::WARN, и false в противном случае. См. раздел Уровень журнала.

with_level (severity) { || ... } Показать исходный код
# File lib/logger.rb, line 408
def with_level(severity)
  prev, level_override[level_key] = level, Severity.coerce(severity)
  begin
    yield
  ensure
    if prev
      level_override[level_key] = prev
    else
      level_override.delete(level_key)
    end
  end
end

Изменяет уровень журнала на время выполнения блока только для текущего Fiber

logger.with_level(:debug) do
  logger.debug { "Hello" }
end

Закрытые методы экземпляра

format_message (severity, datetime, progname, msg) Показать исходный код
# File lib/logger.rb, line 758
def format_message(severity, datetime, progname, msg)
  (@formatter || @default_formatter).call(severity, datetime, progname, msg)
end
format_severity (severity) Показать исходный код
# File lib/logger.rb, line 745
def format_severity(severity)
  SEV_LABEL[severity] || 'ANY'
end
level_key () Показать исходный код
# File lib/logger.rb, line 754
def level_key
  Fiber.current
end
level_override () Показать исходный код
# File lib/logger.rb, line 750
def level_override
  @level_override ||= {}
end

Обеспечивает наличие этой переменной экземпляра, даже если подклассы не вызывают конструктор суперкласса.

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API