Granitosaurus
Granitosaurus

Reputation: 21436

set default logging extra for python's Logger object

In built-in python's logging module you create a logger and log messages:

import logging
log = logging.getLogger('mylogger')
log.info('starting!')

You can also pass extras to the log message that will be used later by the formatter:

user = 'john doe'
log.info('starting!', extra={'user': 'john doe'})

However it's quite tedious to do it explicitly with every message. Is it possible to set extras for the whole logger, so they would be passed with every log?

Something like:

log = logging.getLogger('mylogger')
log.extras = {'user': 'john doe'}
log.info('starting!')

Currently the only way it seems is to monkey patch log() method:

def patch_default_extras(logger, extras):
    original_log = logger.log

    def log_with_extras(level, msg, *args, **kwargs):
        kwargs['extra'] = {**extras, **kwargs.get('extra', {})}
        return original_log(level, msg, *args, **kwargs)

    logger.log = log_with_extras


mylog = logging.getLogger('mylogger')
patch_default_extras(mylog, {'user': 'john doe'})
mylog = logging.getLogger('mylogger')
mylog.log(logging.ERROR, 'hello')

Which is rather ugly, but unless I'm missing something ‒ it's the only way?

Upvotes: 10

Views: 7114

Answers (1)

blues
blues

Reputation: 5185

The builtin way to do this is using a logging adapter. A filter would also work but for your described use-case adapters are perfect.

import logging

logging.basicConfig(level=logging.DEBUG, format='user: %(user)s - message: %(msg)s')

logger = logging.getLogger()
logger_with_user = logging.LoggerAdapter(logger, {'user': 'jane doe'})

logger_with_user.info('test') # user: jane doe - message: test

Upvotes: 20

Related Questions