18

I hope to add the following log points to my application and display the full contents of extra on console, e.g.,

logger.info('Status', extra={'foo':data})
logger.info('Status', extra={'bar':data})
logger.info('Status', extra={'foo':data, 'bar':data}) 

and I hope to see:

2016-10-10 15:28:31,408, INFO, Status, foo=data
2016-10-10 15:38:31,408, INFO, Status, bar=data
2016-10-10 15:48:31,408, INFO, Status, foo=data, bar=data

Is this even possible? According to official logging documentation, the Formatter must be set up with a format string that expects foo and bar but in my case all I want is to dump out the entire kwargs of extra without prior knowledge of foo and bar.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
CJLam
  • 801
  • 3
  • 10
  • 15
  • Take a look at https://bugs.python.org/file4410/logging.py. I don't have time to work out a full example, but I think you could abuse the args attr on the LogRecord and just pass in a dict. – Stats4224 Nov 30 '18 at 16:59

3 Answers3

6

Trying to solve the same problem right now. The problem is that anything passed to extra is added as a property of LogRecord and the formatter cannot distinguish it from other LogRecord properties. I only came up with a hackish approach of creating a dummy record and comparing it with the actual one:

class ExtraLogFormatter(logging.Formatter):                                                                             
    def format(self, record):                                                                                           
        dummy = logging.LogRecord(None,None,None,None,None,None,None)                                                   
        extra_txt = ''                                                                                                  
        for k,v in record.__dict__.items():                                                                             
            if k not in dummy.__dict__:                                                                                 
                extra_txt += ', {}={}'.format(k,v)                                                                      
        message = super().format(record)                                                                                
        return message + extra_txt 
washeck
  • 324
  • 3
  • 5
6

Entries of the object passed as extra will become member variables of the LogRecord.

logger.info('Status', extra={'my_params':{'foo':3, 'bar':4}})

Then you can format it as:

handler.setFormatter(logging.Formatter('%(message)s %(my_params)s'))

Which will result in the following log:

#> Status {'foo':3, 'bar':4}}

This assumes you have control over the 'extra' parameter at the time of logging.

Voy
  • 5,286
  • 1
  • 49
  • 59
0

One option would be to define a simple utility function:

def extra(**kwargs):
    return {"extra": kwargs}

Then your usage:

logger.info('Status', extra={'foo':data, 'bar':data}) 

Becomes not too different:

logger.info('Status', **extra(foo=data, bar=data)) 

And you can set the formatting easily:

handler.setFormatter(logging.Formatter('%(message)s %(extra)s'))
Resigned June 2023
  • 4,638
  • 3
  • 38
  • 49