pythonstring-formattingpython-logging

Is it possible to conditionally override levelname in formatting of Python logger?


I am currently working on some Python code that will be executed by a larger C# web project. The C# code uses NLog to create log files. I have got my Python logger logging to the same file. Also, I have it matching the output format being used by NLog almost exactly by using the following setup:

format='%(asctime)s.%(msecs)04d - %(levelname)8s - %(module)s, Line %(lineno)d - %(message)s\n',
datefmt='%Y-%m-%d %H:%M:%S'

The only issue is that the logging level names don't match. Obviously, Python doesn't have Trace, which is fine: I have decided to just include the kinds of things that would be Trace messages in the C# code as Debug messages in the Python code. However, Warn in NLog is Warning in Python and Fatal is Critical.

Users of my app actually choose their logging level through the UI, and the choices presented to them use the NLog levels, so I want the log file to consistently show levels that match the options presented to the user. Also, the NLog entries right-justify the log level within a 5-character-wide space so that logging messages align vertically after the date, time, and level info. (No NLog logging level is more than 5 characters long.)

As you can see in my code above, I am right-justifying my Python log levels within an 8-character-wide space because 'critical' is 8 characters long. This means the Python logging messages will always align with each other, but never align with the NLog messages within the same log file.

So is there some way in the Python logger formatting to conditionally override the levelname? Really, all I need is something like levelname == "CRITICAL" ? "FATAL" : (levelname == "WARNING" ? "WARN" : levelname), but I have no idea how to work that into the format property (or if it's even possible).


Solution

  • You can use logging.addLevelName to change the name of an existing logging level:

    import logging
    
    logging.warning('foo')
    logging.addLevelName(logging.WARN, 'WARN')
    logging.warning('bar')
    

    This outputs:

    WARNING:root:foo
    WARN:root:bar
    

    Demo here