Найти в Дзене

[Часть 3]Простой блог на Python

Всем увееееееей ребята, сегодня мы поговорим о конфигах и логах python. Ну что-ж меньше слов больше дела, приступим. Конфиги. Все хранят их по разному. Кто-то в .yaml, кто-то в .ini, а кто-то вообще в исходном коде. Я же буду делать в .ini . Ладно, раз уж мы решили, что хранить данные в коде — не круто, то давайте искать альтернативу. Для конфигурационных файлов изобретено немалое количество различных форматов, в последнее время набирают большую популярность toml. Но мы начнём с того, что нам предлагает сам Python — .ini. В стандартной библиотеке имеется библиотека configparser. Файл config.ini: [program] name=pythonlogexample Напоминаю что значения надо писать без кавычек иначе пример ниже выведет "pythonlogexample" а не просто pythonlogexample (без кавычек) Файл python import configparser  # импортируем библиотеку config = configparser.ConfigParser() # создаём объекта парсера config.read("config.ini") # читаем конфиг print(config["program"]["name"]) # обращаемся как к обычному словар
Оглавление

Всем увееееееей ребята, сегодня мы поговорим о конфигах и логах python. Ну что-ж меньше слов больше дела, приступим.

Конфиги. Все хранят их по разному. Кто-то в .yaml, кто-то в .ini, а кто-то вообще в исходном коде. Я же буду делать в .ini .

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

Но мы начнём с того, что нам предлагает сам Python — .ini. В стандартной библиотеке имеется библиотека configparser.

Файл config.ini:

[program]
name=pythonlogexample

Напоминаю что значения надо писать без кавычек иначе пример ниже выведет "pythonlogexample" а не просто pythonlogexample (без кавычек)

Файл python

import configparser  # импортируем библиотеку
config = configparser.ConfigParser() # создаём объекта парсера
config.read("config.ini") # читаем конфиг
print(config["program"]["name"]) # обращаемся как к обычному словарю!

Вывод: pythonlogexample

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

Если вы — новичок, то вы, наверняка, привыкли пользоваться командой print(), выводя с её помощью определённые значения в ходе работы программы, проверяя, работает ли код так, как от него ожидается. Использование print() вполне может оправдать себя при отладке маленьких Python-программ. Но, когда вы перейдёте к более крупным и сложным проектам, вам понадобится постоянный журнал, содержащий больше информации о поведении вашего кода, помогающий вам планомерно отлаживать и отслеживать ошибки.

Подключим лог:

import logging

Дадим краткие характеристики уровней логирования:

  • Debug (10): самый низкий уровень логирования, предназначенный для отладочных сообщений, для вывода диагностической информации о приложении.
  • Info (20): этот уровень предназначен для вывода данных о фрагментах кода, работающих так, как ожидается.
  • Warning (30): этот уровень логирования предусматривает вывод предупреждений, он применяется для записи сведений о событиях, на которые программист обычно обращает внимание. Такие события вполне могут привести к проблемам при работе приложения. Если явно не задать уровень логирования — по умолчанию используется именно warning.
  • Error (40): этот уровень логирования предусматривает вывод сведений об ошибках — о том, что часть приложения работает не так как ожидается, о том, что программа не смогла правильно выполниться.
  • Critical (50): этот уровень используется для вывода сведений об очень серьёзных ошибках, наличие которых угрожает нормальному функционированию всего приложения. Если не исправить такую ошибку — это может привести к тому, что приложение прекратит работу.

Теперь попробуем вывести что-нибудь в лог:

logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Вывод будет таков:

WARNING:root:A WARNING
ERROR:root:An ERROR
CRITICAL:root:A message of CRITICAL severity

Как видите, сообщения, выведенные с уровнями логирования warning, error и critical, попадают в консоль. А сообщения с уровнями debug и info — не попадают.

Это так из-за того, что в консоль выводятся лишь сообщения с уровнями от warning и выше. Но это можно изменить, настроив логгер и указав ему, что в консоль надо выводить сообщения, начиная с некоего, заданного вами, уровня логирования.

Подобный подход к логированию, когда данные выводятся в консоль, не особо лучше использования print(). На практике может понадобиться записывать логируемые сообщения в файл. Этот файл будет хранить данные и после того, как работа программы завершится. Такой файл можно использовать в качестве журнала отладки.

Логирование в файл

Для того чтобы настроить простую систему логирования в файл — можно воспользоваться конструктором basicConfig(). Вот как это выглядит:

logging.basicConfig(level=logging.INFO, filename="py_log.log",filemode="w")
logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Поговорим о логгере root, рассмотрим параметры basicConfig():

  • level: это — уровень, на котором нужно начинать логирование. Если он установлен в info — это значит, что все сообщения с уровнем debug игнорируются.
  • filename: этот параметр указывает на объект обработчика файла. Тут можно указать имя файла, в который нужно осуществлять логирование.
  • filemode: это — необязательный параметр, указывающий режим, в котором предполагается работать с файлом журнала, заданным параметром filename. Установка filemode в значение w (write, запись) приводит к тому, что логи перезаписываются при каждом запуске модуля. По умолчанию параметр filemode установлен в значение a (append, присоединение), то есть — в файл будут попадать записи из всех сеансов работы программы.

Я рекомендую filemode ставить значение "a" тк если забыть прочитать лог и сразу запустить программу то лог будет очищен.

После выполнения модуля можно будет увидеть, что в текущей рабочей директории был создан файл журнала, py_log.log.

Так как мы установили уровень логирования в значение info — в файл попадут записи с уровнем info и с более высокими уровнями

Записи в лог-файле имеют формат <logging-level>:<name-of-the-logger>:<message>. По умолчанию <name-of-the-logger>, имя логгера, установлено в root, так как мы пока не настраивали пользовательские логгеры.

Помимо базовой информации, выводимой в лог, может понадобится снабдить записи отметками времени, указывающими на момент вывода той или иной записи. Это упрощает анализ логов. Сделать это можно, воспользовавшись параметром конструктора format:

logging.basicConfig(level=logging.INFO,
filename="py_log.log",
filemode="w",
format="%(asctime)s %(levelname)s %(message)s")
logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Более удобные логи

Для начала создадим директорию logs/ в папке проекта а далее изменим код на этот:

import logging
from datetime import date
date = date.today()
logging.basicConfig(level=logging.INFO,
filename=f"logs/{date}.log",
filemode="a",
format="%(asctime)s %(levelname)s %(message)s")
logging.debug("A DEBUG Message")
logging.info("An INFO")
logging.warning("A WARNING")
logging.error("An ERROR")
logging.critical("A message of CRITICAL severity")

Теперь каждый новый день будет создаваться новый файл лога чтобы легче было найти проблему, но и здесь есть проблема это то что имя файла это дата запуска, поэтому если программа будет работать более чем 24 часа, то дня будет 2 а лог 1.

Кодировка лога

Попробуем занести в лог русский текст:

import logging
from datetime import date
date = date.today()
logging.basicConfig(level=logging.INFO,
filename=f"logs/{date}.log",
filemode="a",
format="%(asctime)s %(levelname)s %(message)s")
logging.info("Русский текст")

В логе будет:

2023-12-19 18:07:38,147 INFO ������� �����

чтобы это исправить добавим кодировку "UTF-8" так

logging.basicConfig(level=logging.INFO,
filename=f"logs/{date}.log",
filemode="a",
format="%(asctime)s %(levelname)s %(message)s",
encoding = "UTF-8")

те добавим последнюю строчку. Теперь в логе:

2023-12-19 18:09:37,919 INFO Русский текст

Конфиг+лог

теперь объединим всё чтобы сделать строчку в конфиге debug=true

файл питона:

import logging
import configparser
from datetime import date
date = date.today()
config = configparser.ConfigParser()
config.read("config.ini")
if(config['log']['debug']=="true"):
logging.basicConfig(level=logging.DEBUG,
filename=f"logs/{date}.log",
filemode="a",
format="%(asctime)s %(levelname)s %(message)s",
encoding = "UTF-8")
else:
logging.basicConfig(level=logging.INFO,
filename=f"logs/{date}.log",
filemode="a",
format="%(asctime)s %(levelname)s %(message)s",
encoding = "UTF-8")
logging.info("Русский текст")
logging.debug("Русский текст")

Файл конфига:

[log]
debug=false

Теперь если debug=true то и сообщения отладки будут в логе иначе нет.

Подписывайтесь, ведь скоро часть 4 где мы объединим знания и создадим сайт на flask