Лого

Логирование в Python

Что такое логирование?

Логирование - это важный процесс в разработке программного обеспечения. Он помогает записывать и хранить необходимую информацию о работе системы, а также событиях, происходящих в приложении. Это актуально в те моменты, когда наши программы утолщаются и требует к себе большего внимания.

Зачем нужно логирование в разработке?

  • Выявлять и устранять ошибки
  • Обеспечивать мониторинг производительности
  • Анализировать инциденты
  • Обеспечивать безопасность
  • Контролировать состояние системы
  • Улучшать взаимодействие с пользователями

Уровни логирования модуля logging

Модуль logging в Python поддерживает несколько уровней логирования:

  • DEBUG - записывает практически каждое действие
  • INFO - фиксирует стандартные события и действия
  • WARNING - предупреждает о потенциальных проблемах
  • ERROR - записывает ошибки, которые мешают выполнять какие-либо задачи, хотя само ПО продолжает работать
  • CRITICAL - наивысший уровень, где указываются критические ошибки, после которых приложение не может функционировать

Формат сообщений логов

Можно настроить как угодно и под разные задачи. Различных атрибутов в документации очень много. Я однажды нашел на просторах интернета у гуру-хацкеров вот такой вид и теперь им пользуюсь:

    
        [%(asctime)s.%(msecs)03d] %(module)15s:%(lineno)-3d %(levelname)7s - %(message)s
    

  • %(asctime)s - время создания записи в формате ГГГГ-ММ-ДД ЧЧ:ММ:СС
  • %(msecs)03d - отображаются миллисекунды в виде трехзначного числа
  • %(module)15s - покажет имя модуля (файла) откуда был вызван логгер. Займет 15 символов и выравнен по правому краю будет. Если больше 15, то покажется полностью
  • %(lineno)-3d - указывает номер строки в коде, где произошла запись. Он будет выровнен по левому краю и займет 3 символа
  • %(levelname)7s - показывает уровень логирования
  • %(message)s - это само сообщения

Логи и их хранение

Для чего нужны логи мы уже говорили. Теперь затронем тему хранения:

  • Шифрование логов - обеспечивает конфиденциальность хранимых логов
  • Управление доступом - не каждому позволено смотреть такую информацию
  • Централизованные системы хранения - существуют сервисы, которые позволяют эффективно собирать, анализировать и хранить данные логов (ELK Stack, Graylog и т.д.)
  • Создание резервных копий - также надо шифрование сверху накидывать
  • Определение сроков хранения - чтобы у тебя не хранились терабайты информации и чтобы в случае слива полный объем не попал в руки черных шляп, а лишь какая-то часть

Моя неправильная практика работы с логами

У меня колоссальных проектов в работе пока еще не было, поэтому часть информации про безопасность, управление доступом и работы с ELK Stack пропустим, но не забываем про них никогда. В моем случае ограничимся простой записью логов в файл рядом с исполняемым файлом.

Подсмотрел когда-то вот такой метод:

    
        import logging
        from random import randint
        
        
        logger = logging.getLogger(__name__)
        
        
        def configure_logging(level=logging.INFO):
            logging.basicConfig(
                filename="app.log",
                filemode="a",
                level=level,
                datefmt="%Y-%m-%d %H:%M:%S",
                format="[%(asctime)s.%(msecs)03d] %(module)7s:%(lineno)-3d %(levelname)7s - %(message)s",
                encoding="utf-8"
            )
        
        
        def doing_main():
            logger.info("start doing main")
        
            res = randint(1, 100) ** 2
            logger.info("res: %s", res)  # передаем какие-либо данные через '%s'
        
        	try:
                1 / 0
            except ZeroDivisionError as e:
                logger.exception("error: %s", e)  # применяем exception, чтобы в лог вывелся traceback ошибки
        
        
            logger.info("end doing main")
        
        
        def main():
            configure_logging()
        
            logger.info("Hello! Starting main")
            doing_main()
            logger.info("Bye! Finished main")
        
        
        if __name__ == "__main__":
            main()
    

В этом примере создается файл app.log, где записаны сообщения. Вот такой текст внутри:

Текст файла с логами