Customize log format in python Azure Functions

Viewed 435

I am writing many Python Azure Functions. I want every line in logs to be prefixed with invocation-id from context to segregate and correlate the logs easily.

I know there are multiple ways to do this for a normal/stand-alone python application. Here Azure Function runtime provides an environment where it invokes my code. I don't-want-to/prefer-not-to:

  • mess around with existing handlers/formatters registered by Azure Function runtime or
  • write my own handlers/formatters

(because whatever is registered by default sends the logs to Azure Log Analytics workspace and powers my dashboards etc)

E.g. following code:

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')

will produce logs like:

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

what I want instead is:

(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

I've seen some docs on Azure, seem useless.

1 Answers

You can use a LoggerAdapter to do this, as shown by the following runnable program:

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')

Obviously I've removed the Azure references so that I can run it locally, but you should get the gist. The preceding script prints

(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

Update: If you don't want to/can't use LoggerAdapter, then you can subclass Logger as documented here or use a Filter as documented here. But in the latter case you'd still have to attach the filter to all loggers (or handlers, which would be easier) of interest.

Related