Конфигурация логгера для записи в файл и вывода на stdout
Я использую модуль logging в Python для записи строк отладки в файл, и это работает довольно хорошо. Теперь я хотел бы дополнительно использовать этот модуль для вывода строк в стандартный вывод (stdout). Как мне это сделать? Для записи строк в файл я использую следующий код:
import logging
import logging.handlers
logger = logging.getLogger("")
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
LOGFILE, maxBytes=(1048576*5), backupCount=7
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
Затем я вызываю функцию логирования следующим образом:
logger.debug("Я записан в файл")
Спасибо за помощь!
5 ответ(ов)
Чтобы добавить обработчик вывода логов в Python, можно просто получить корневой логгер и добавить к нему StreamHandler
. Этот обработчик по умолчанию записывает сообщения в stderr
. Если вам действительно нужно, чтобы сообщения выводились в stdout
вместо stderr
, просто укажите это при создании StreamHandler
.
Вот пример, который можно использовать:
import logging
# Создаем корневой логгер и добавляем обработчик для вывода в stderr
logging.getLogger().addHandler(logging.StreamHandler())
Если хотите выводить логи в stdout
, сделайте так:
import sys
# ...
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
Также вы можете добавить Formatter
для форматирования всех записей логов с общим заголовком, например:
import logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s")
rootLogger = logging.getLogger()
# Добавляем обработчик, который будет писать логи в файл
fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)
# Добавляем обработчик для вывода в консоль
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)
Такой код будет выводить сообщения в формате:
2012-12-05 16:58:26,618 [MainThread ] [INFO ] my message
Теперь у вас есть логирование как в файл, так и в консоль с одинаковым форматом сообщений.
Когда вы добавляете StreamHandler без указания аргументов, он по умолчанию использует stderr вместо stdout. Если другой процесс зависит от вывода в stdout (например, при написании плагина NRPE), убедитесь, что вы явно указываете stdout, иначе вы можете столкнуться с неожиданными проблемами.
Вот простой пример, который использует предполагаемые значения и переменную LOGFILE из вашего вопроса:
import logging
from logging.handlers import RotatingFileHandler
from logging import handlers
import sys
log = logging.getLogger('')
log.setLevel(logging.DEBUG)
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch = logging.StreamHandler(sys.stdout) # Явное указание на использование stdout
ch.setFormatter(format)
log.addHandler(ch)
fh = handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
fh.setFormatter(format)
log.addHandler(fh)
В этом коде мы создаем логгер, который отправляет сообщения как в stdout, так и в файл с помощью RotatingFileHandler. Обязательно указывайте sys.stdout
, чтобы избежать путаницы с выводом.
Вы можете либо вызвать basicConfig
с аргументом stream=sys.stdout
до настройки других обработчиков или записи каких-либо сообщений, либо вручную добавить StreamHandler
, который будет отправлять сообщения в stdout к корневому логгеру (или любому другому логгеру, который вам нужен).
Чтобы настроить логирование в Python так, чтобы сообщения выводились в stdout
и в файл с ротацией, следуя разным уровням и форматам, вы можете использовать следующий код:
import logging
import logging.handlers
import sys
if __name__ == "__main__":
# Изменяем уровень корневого логгера с WARNING (по умолчанию) на NOTSET, чтобы все сообщения обрабатывались.
logging.getLogger().setLevel(logging.NOTSET)
# Добавляем обработчик для вывода в stdout с уровнем INFO
console = logging.StreamHandler(sys.stdout)
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-13s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger().addHandler(console)
# Добавляем обработчик для ротации файла с уровнем DEBUG
rotatingHandler = logging.handlers.RotatingFileHandler(filename='rotating.log', maxBytes=1000, backupCount=5)
rotatingHandler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
rotatingHandler.setFormatter(formatter)
logging.getLogger().addHandler(rotatingHandler)
log = logging.getLogger("app." + __name__)
log.debug('Debug message, should only appear in the file.')
log.info('Info message, should appear in file and stdout.')
log.warning('Warning message, should appear in file and stdout.')
log.error('Error message, should appear in file and stdout.')
Объяснение кода:
- Уровень логирования: Изменяем уровень корневого логгера на
NOTSET
, чтобы все сообщения обрабатывались. - Обработчик для stdout: Создаем
StreamHandler
, который будет выводить сообщения уровняINFO
и выше в стандартный вывод (stdout). Формат сообщений задается с помощьюFormatter
. - Обработчик для файла: Используем
RotatingFileHandler
, чтобы логировать сообщения уровняDEBUG
и выше в файлrotating.log
. Если размер файла превышает 1000 байт, он будет ротироваться, сохраняя до 5 резервных копий. Формат сообщений для файла отличается от формата для консоли. - Логирование сообщений: В конце демонстрируется, как различные уровни логирования будут выводиться в консоль и файл.
Таким образом, с помощью вышеописанного кода вы сможете одновременно вести логирование как в stdout, так и в файл, используя разные уровни и форматы сообщений.
После многократного использования кода Waterboy в различных пакетах Python, я наконец создал небольшой самостоятельный пакет Python, который вы можете найти здесь:
https://github.com/acschaefer/duallog
Код хорошо документирован и легко в использовании. Просто скачайте файл .py
и добавьте его в свой проект, или установите весь пакет с помощью команды pip install duallog
.
Сохранение сообщений об исключениях в Python
Как зарегистрировать ошибку в Python с отладочной информацией?
Как получить даты/времена создания и изменения файла?
Как удалить не пустую папку?
Как вывести стандартный вывод print() в консоль во время выполнения pytest?