Настройка формата журнала в функциях python Azure

#python #azure #logging #azure-functions

Вопрос:

Я пишу много функций Python Azure. Я хочу, чтобы каждая строка в журналах имела префикс invocation-id от context , чтобы легко разделять и сопоставлять журналы.

Я знаю, что есть несколько способов сделать это для обычного/автономного приложения на python. Здесь среда выполнения функций Azure предоставляет среду, в которой вызывается мой код. Я не-хочу — /предпочитаю-не-:

  • возитесь с существующими обработчиками/форматерами, зарегистрированными средой выполнения функций Azure, или
  • напишите мои собственные обработчики/форматеры

(потому что все, что зарегистрировано по умолчанию, отправляет журналы в рабочую область Azure Log Analytics и включает мои панели мониторинга и т. Д.)

Например, следующий код:

 import logging
from azure import functions as func

def main(msg: func.QueueMessage, ctx: func.Context) -> None:
    logging.info('entry')
    logging.info('invocation id of this run: %s', ctx.invocation_id)
    logging.debug('doing something...')
    logging.info('exit with success')
 

будет производить журналы, такие как:

 entry
invocation id of this run: 111-222-33-4444
doing something...
exit with success
 

вместо этого я хочу, чтобы:

 (111-222-33-4444) entry
(111-222-33-4444) invocation id of this run: 111-222-33-4444
(111-222-33-4444) doing something...
(111-222-33-4444) exit with success
 

Я видел некоторые документы в Azure, они кажутся бесполезными.

Ответ №1:

Вы можете использовать a LoggerAdapter для этого, как показано в следующей запускаемой программе:

 import logging

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

def main(msg, ctx):
    logger = Adapter(logging.getLogger(), {'context': ctx})
    logger.info('entry')
    logger.info('invocation id of this run: %s', ctx)
    logger.debug('doing something ...')
    logger.info('exit with success')

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG, format='%(message)s')
    main('hello', '111-222-33-4444')
 

Очевидно, я удалил ссылки на Azure, чтобы запустить его локально, но вы должны понять суть. Предыдущий сценарий печатает

 (111-222-33-4444) entry
(111-222-33-4444) invocation id of this run: 111-222-33-4444
(111-222-33-4444) doing something ...
(111-222-33-4444) exit with success
 

Обновление: Если вы не хотите/не можете использовать LoggerAdapter , то вы можете создать подкласс Logger , как описано здесь, или использовать a Filter , как описано здесь. Но в последнем случае вам все равно придется подключить фильтр ко всем регистраторам (или обработчикам, что было бы проще), представляющим интерес.

Комментарии:

1. Спасибо. Но это похоже на объект-оболочку, который мне придется передавать/создавать в каждой вызываемой функции/модуле. Будет работать только для МОЕГО кода. Например, если я использую какую-либо библиотеку, в которой журналы, использующие logging.info() эти журналы, не будут иметь префикса.