====== Логирование ======
===== Общее =====
[[https://habr.com/ru/company/otus/blog/590067/|Статья]]\\
:!: Вырезки
{{:develop:pyton:2022-12-03_11-21.png?direct&600|}}
{{:develop:pyton:2022-12-03_11-31.png?direct&600|}}
===== Применение =====
[[https://docs.python.org/3/library/logging.html#logger-objects|Дока]]\\
[[https://docs.python.org/3/library/logging.config.html|Дока]]\\
Классы логгера наследуются, в блоке "root" можно определить базовые параметры для всех создаваемых потом подклассов\\
Собсна структура конфига ниже, перечисляются форматтеры, логгеры, хендлеры, можно создавать несколько разных комбинаций, каждая со своими параметрами и для каждой применяются указанные правила логирования (место, формат, устр-во и т.д.)\\
Конфиг можно хранить в отдельном файле, но тогда нет возможности использовать переменные, можно обернуть в python объект, тогда чики-пики. [[https://habr.com/ru/company/otus/blog/590067/|тут есть пример]]\\
Настройка целевого уровня задается и в loggers и в handlers, сначала фильтруется в первом, затем во втором\\
{
"version": 1,
"disable_existing_loggers": False,
"formatters": { },
"handlers": { },
"loggers": { },
"root": { },
}
Для использования JSON нужен модуль [[https://pypi.org/project/python-json-logger/|"python-json-logger"]]\\
:!: Боевой пример. Три типа логов
Три типа логов:
* Общий
* Только ошибки
* Логирование спец событий, в данном случае д-я пользователей
Использование
#!/usr/bin/python3.8
import loggers
logger = loggers.get_logger('main')
usr_logger = loggers.get_logger('usrlog', template = "usr_actions")
logger.info("Simple logger, level == info")
logger.error("Simple logger, level == error")
usr_logger.info("User log, level == info", extra={"username": "myname"})
Создание объекта логгера
#!/usr/bin/python3.8
import os
import json
import logging
import logging.config
FOLDER_LOG = "log"
LOGGING_CONFIG_FILE = 'logger_config.json'
def create_log_folder(folder=FOLDER_LOG):
if not os.path.exists(folder):
os.mkdir(folder)
def get_logger(name, template='simple'):
create_log_folder()
with open(LOGGING_CONFIG_FILE, "r") as f:
dict_config = json.load(f)
dict_config["loggers"][name] = dict_config["loggers"][template]
logging.config.dictConfig(dict_config)
return logging.getLogger(name)
Конфиг
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"strings": {
"format": "%(asctime)s - %(processName)-10s - %(name)-10s - %(levelname)-8s - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
},
"json": {
"()": "pythonjsonlogger.jsonlogger.JsonFormatter",
"format": "[ %(asctime)s ] %(username)s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
"json_indent": 4
}
},
"handlers": {
"mainlog": {
"formatter": "strings",
"level": "INFO",
"class": "logging.handlers.RotatingFileHandler",
"filename": "log/main.log",
"backupCount": 2
},
"errorlog": {
"formatter": "strings",
"level": "ERROR",
"class": "logging.handlers.RotatingFileHandler",
"filename": "log/error.log",
"backupCount": 2
},
"json": {
"formatter": "json",
"level": "INFO",
"class": "logging.handlers.RotatingFileHandler",
"filename": "log/usrlog.xml"
}
},
"loggers": {
"simple": {
"level": "DEBUG",
"handlers": ["mainlog", "errorlog"]
},
"usr_actions": {
"level": "DEBUG",
"handlers": ["json"]
}
}
}
===== Примеры =====
:!: Минимальный пример для логирования
import logging
from datetime import datetime
start_date = datetime.strftime(datetime.now(), "%Y%m%d_%H%M%S")
log_path = f"{start_date}.log"
#Настройка логирования.
log = logging.getLogger()
log.setLevel(logging.INFO)
fh = logging.FileHandler(filename=log_path)
fh.setLevel(logging.INFO)
formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s: %(message)s')
fh.setFormatter(formatter)
log.addHandler(fh)
log.info("test test ")
:!: Еще примеры
import logging
logging.basicConfig(
level=logging.DEBUG,
filename = "mylog.log",
format = "%(asctime)s - %(module)s - %(levelname)s - %(funcName)s: %(lineno)d - %(message)s",
datefmt='%H:%M:%S',
)
logging.info('Hello')
import logging
logging.basicConfig(level=logging.INFO, filename="py_log.log",filemode="w",
format="%(asctime)s %(levelname)s %(message)s")
x_vals = [2,3,6,4,10]
y_vals = [5,7,12,0,1]
for x_val,y_val in zip(x_vals,y_vals):
x,y = x_val,y_val
logging.info(f"The values of x and y are {x} and {y}.")
try:
x/y
logging.info(f"x/y successful with result: {x/y}.")
except ZeroDivisionError as err:
#logging.exception("ZeroDivisionError")
logging.error("ZeroDivisionError",exc_info=True)
import logging
from test_div import test_division
# получение пользовательского логгера и установка уровня логирования
py_logger = logging.getLogger(__name__)
py_logger.setLevel(logging.INFO)
# настройка обработчика и форматировщика в соответствии с нашими нуждами
py_handler = logging.FileHandler(f"{__name__}.log", mode='w')
py_formatter = logging.Formatter("%(name)s %(asctime)s %(levelname)s %(message)s")
# добавление форматировщика к обработчику
py_handler.setFormatter(py_formatter)
# добавление обработчика к логгеру
py_logger.addHandler(py_handler)
py_logger.info(f"Testing the custom logger for module {__name__}...")
x_vals = [2,3,6,4,10]
y_vals = [5,7,12,0,1]
for x_val,y_val in zip(x_vals,y_vals):
x,y = x_val, y_val
# вызов test_division
test_division(x,y)
py_logger.info(f"Call test_division with args {x} and {y}")