3

I am trying to add a custom format field in my library. I know this is either done with a Filter or a LoggerAdapter object. However, in the examples I have seen (like this one: How do I add custom field to Python log format string?) the custom field they want to generate is static and known when the logger is created.

I need to be able to send a variable to my log record that I really don't know until just before I write the log record. I guess I am just not seeing the solution but how best to accomplish this?

Currently I set up my logger this way:

import logging

class MyClass:
    filehandler = logging.handlers.RotatingRileHandler(r'C:\Users\Me\Desktop\Logs', 
            maxBytes=1000000, backupCount=4, encoding='ASCII')
    formatter = logging.Formatter('[%(asctime)s] : %(levelname)-8s: Para: %(parameter)-15s'
                                  ' - %(message)s')
    # parameter is my custom name I want to inject
    self.logger = logging.getLogger(__name__)
    self.logger.setLevel(logging.DEBUG)
    self.logger.addHandler(file_handler)

    d = {'parameter': ''}
    self.logger = logging.LoggerAdapter(self.logger, extra=d)

And in my test I write:

my_obj = MyClass()
my_obj.logger.error('This is my error.', extra={'parameter': 'True'}

but this makes the parameter field '' (blank string) always. Is there a way to set up the d dictionary for each time I make the log call (error(), debug(), etc.)?

0

1 Answer 1

7

I've investigated a bit further into this and the LoggerAdapter's 'extra' argument takes precedence over the 'extra' argument in the actual log action. This is also described in the documentation.

To achieve what you want you can override the LoggerAdapter class and customize the process method as follows:

class CustomLoggerAdapter(logging.LoggerAdapter):

    def process(self, msg, kwargs):
        """
        Process the Logging message and keyword arguments passed in to
        a logging call to insert contextual information. The extra argument
        of the LoggerAdapter will be merged with the extra argument of the
        logging call where the logging call's argument take precedence.
        """
        try:
            kwargs["extra"] = {**self.extra, **kwargs["extra"]}
        except KeyError as e:
            kwargs["extra"] = self.extra
        return msg, kwargs

This will merge the LoggerAdapter's extra argument with that of the logging call. The logging call's argument takes precedence.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.