Python: логгирование с помощью модуля logging

Автор: | 01/02/2015
 

PythonВ модуле logging используются четыре основных класса, которые нас интересуют:

  • Loggers – используются приложением для передачи сообщений системе логирования;
  • Formatters – форматирование сообщений;
  • Filters – фильтрация сообщений;
  • Handlers – отправка форматированных сообщений в определённом направлении, например – в файл.

Далее мы кратко рассмотрим создание LoggerHandler и Formatter.

Для создания объекта-логгера достаточно указать:

log = logging.getLogger(__name__)

Такое создание логгера создаст объект с именем, отвечающим имени модуля, в котором он создаётся, что потом поможет разобраться в логах.

Создадим простой скрипт:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# импортируем модуль
import logging

# задаём уровень логгирования
logging.basicConfig(level=logging.INFO)

# создаём объект с именем модуля
logger = logging.getLogger(__name__)

# логгируем запись на уровне INFO
logger.info('Start logging INFO')

И результат его выполнения:

$ ./logger1.py
INFO:__main__:Start logging INFO

Для каждого события можно указать уровень важности:

CRITICAL
ERROR
WARNING
INFO
DEBUG
NOTSET

Меняя уровень важности для Logger или Handler-а – можно устанавливать, какие данные заносить в лог – а какие нет:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# импортируем модуль
import logging

# задаём уровень логгирования
logging.basicConfig(level=logging.INFO)

# создаём объект с именем модуля
logger = logging.getLogger(__name__)

# логгируем запись на уровне INFO
logger.info('Start logging INFO')

# добавлем запись на уровне DEBUG
logger.debug('Start logging DEBUG')

Так как в параметрах логгера (logging.basicConfig) задан уровень важности INFO – то запись с уровнем DEBUG не пройдёт:

$ ./logger1.py
INFO:__main__:Start logging INFO

Если же изменить уровень на DEBUG:

logging.basicConfig(level=logging.DEBUG)

То:

$ ./logger1.py
INFO:__main__:Start logging INFO
DEBUG:__main__:Start logging DEBUG

Далее, добавим использование FileHandler, что бы использовать запись в файл, и Formatter – что бы настроить формат записей в файле:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# импортируем модуль
import logging

# создаём объект с именем модуля
logger = logging.getLogger(__name__)

# задаём уровень логгирования
logger.setLevel(logging.INFO)

# создаём обрабочтик файла лога
handler = logging.FileHandler('logger1.log')

# задаём уровень логгирования
handler.setLevel(logging.INFO)

# форматируем записи
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# устанавливаем формат для обработчика
handler.setFormatter(formatter)

# добавляем обработчик к логгеру
logger.addHandler(handler)

# записываем сообщение
logger.info('Hello baby')

Проверяем файл:

$ cat logger1.log
2015-01-28 13:14:38,834 - __main__ - INFO - Hello baby

Запись логов из разных модулей

Создадим script1:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging
import script2

logging.basicConfig(level=logging.INFO)

if __name__ == '__main__':
    logging.info('Started script 1')
    script2.somefunc()
    logging.info('Finished script 1')

И script2:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

def somefunc ():
    logging.info('Started script 2')

Запускаем script1:

 $ ./script1.py
INFO:root:Started script 1
INFO:root:Started script 2
INFO:root:Finished script 1

Усложним логгирование, что  бы каждый модуль записывал своё имя в лог:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging
import script2

logging.basicConfig(level=logging.INFO)

if __name__ == '__main__':
    logger = logging.getLogger(__name__)
    logger.info('Started script 1')
    script2.somefunc()
    logger.info('Finished script 1')
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

def somefunc ():
    logger = logging.getLogger(__name__)
    logger.info('Started script 2')

Результат:

$ ./script1.py
INFO:__main__:Started script 1
INFO:script2:Started script 2
INFO:__main__:Finished script 1

Таким образом, каждый модуль программы будет задавать своё имя в логе.

Добавим запись в файл и форматирование:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging
import script2

logging.basicConfig(filename='logger.log', level=logging.INFO, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s')

if __name__ == '__main__':
    logger = logging.getLogger(__name__)
    logger.info('Started script 1')
    script2.somefunc()
    logger.info('Finished script 1')

И script2:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

def somefunc ():
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    logger.info('Started script 2')
    # эта строка не попадёт в лог
    logger.debug('Started Script 2 DEBUG')

Проверяем:

$ ./script1.py
$ cat logger.log
2015-01-28 13:48:23,410 __main__     INFO     Started script 1
2015-01-28 13:48:23,411 script2      INFO     Started script 2
2015-01-28 13:48:23,411 __main__     INFO     Finished script 1

Кроме записи в файл – можно сделать вывод сообщений на консоль, вместо использования print().

Добавим StreamHandler и FileHandler:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')

console = logging.StreamHandler()
console.setLevel(logging.WARNING)
console.setFormatter(formatter)

filehandler = logging.FileHandler('logger.log')
filehandler.setLevel(logging.INFO)
filehandler.setFormatter(formatter)

logger.addHandler(console)
logger.addHandler(filehandler)

if __name__ == '__main__':
    logger.info('Started logging')
    # эта строка пойдёт и в файл и на консоль
    logger.warning('Started logging to console and log')
    logger.info('Finished logging')

Результат:

$ ./script1.py
2015-01-28 14:07:47,089 __main__     WARNING  Started logging to console and log
$ cat logger.log
2015-01-28 14:07:47,088 __main__     INFO     Started logging
2015-01-28 14:07:47,089 __main__     WARNING  Started logging to console and log
2015-01-28 14:07:47,089 __main__     INFO     Finished logging

Возможностей у модуля logging очень много, поэтому – ссылки по теме:

https://docs.python.org

https://docs.python.org

http://blog.tplus1.com

http://pieces.openpolitics.com

http://victorlin.me