Содержание

Логирование

Общее

Статья

:!: Вырезки

Применение

Дока
Дока

Классы логгера наследуются, в блоке «root» можно определить базовые параметры для всех создаваемых потом подклассов

Собсна структура конфига ниже, перечисляются форматтеры, логгеры, хендлеры, можно создавать несколько разных комбинаций, каждая со своими параметрами и для каждой применяются указанные правила логирования (место, формат, устр-во и т.д.)

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

Настройка целевого уровня задается и в loggers и в handlers, сначала фильтруется в первом, затем во втором

{
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": { },
    "handlers": { },
    "loggers": { },
    "root": { },
}

Для использования JSON нужен модуль "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}")