Пользовательские дополнительные данные в журнале python с несколькими модулями - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь реализовать регистратор в python, который включает в себя много модулей. Основные функции включают в себя микросервис gRP C, который принимает полезную нагрузку, генерирует идентификатор и выполняет некоторую оптимизацию.

Когда одновременно поступает несколько запросов, журнал может перепутаться. То, что я хотел бы сделать, это пометить строки регистратора с run_id так, чтобы run_id печатал в журнале для каждого вызова функции, сделанного в родительском и всех импортированных модулях.

Я попробовал это:

logger = logging.getLogger("myservice")
log_file = "logs/solver.log"
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(log_id)s - %(name)s - %(message)s", datefmt="%y/%m/%d %H:%M:%S")  #: log_id is custom data
log_data = {'log_id': None}

concise_log = logging.FileHandler(log_file)                 #: file handler for concise log
concise_log.setLevel(logging.INFO)
concise_log.setFormatter(formatter)

#: Add the logging hanlders to the logger
logger.addHandler(concise_log)
logger.addHandler(detailed_log)

logger.info(f"log_file: {log_file}", extra=log_data)
logger.info("LOG START", extra=log_data)
logger.debug("Debug level messages are being recorded.", extra=log_data)

Первоначально я использовал фиктивное значение для log_data, так как в противном случае регистратор выдаст ошибку.

Позже я установлю log_id и буду регистрировать различные вещи, например:

    log_id = str(uuid.uuid4())
    log_data = {'log_id': log_id}      #: extra data for logger

    #: load the server config:
    logger.info("loading server config...", extra=log_data)

This работает нормально, но если я сделаю вызовы своему регистратору в любой импортированной функции, он выдаст ошибку, потому что у этих функций нет log_data.

То, что я хотел бы сделать, это установить log_id в более глобальный способ, чтобы у регистратора всегда был правильный log_id в импортированных модулях, который будет меняться от запроса к запросу.

Есть ли другой шаблон, который я должен использовать для достижения sh this?

1 Ответ

1 голос
/ 03 апреля 2020

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

class LogIdAdapter(logging.LoggerAdapter):
    def process(self, msg, kwargs):
        return '[%s] %s' % (self.extra['log_id'], msg), kwargs

tmp_logger = logging.getLogger("myservice")
# ... set up handlers etc here. do not include log_id in formatter, it will be added later
logger = LogIdAdapter(tmp_logger, {'log_id': str(uuid.uuid4())})

logger.info("some text") # this log will have log_id prepended
...