Reputation: 12596
I'd like to log information about some instance. However, I want to show different levels of detail depending on the log level I'm using. For example:
LOGGER.level
# => 20
LOGGER.info('Car info: %s', Car())
# => [INFO]: Car info: Celica
LOGGER.setLevel(logging.DEBUG)
LOGGER.info('Car info: %s', Car())
# => [INFO]: Car info: {'name': 'Celica', 'year': 1998, 'model': 'GT-Four'}
So far, I came up with something like the following:
import logging
LOGGER = logging.getLogger()
logging.basicConfig(
format='[%(levelname)s]: %(message)s',
level=logging.INFO)
class Car:
def __init__(self):
self.name = 'Celica'
self.year = 1998
self.model = 'GT-Four'
def __repr__(self):
if LOGGER.level == logging.DEBUG:
return str(self.__dict__)
return f'{self.name}'
I have the feeling that this is a bit too "custom" and hardcoded, somehow. Using LOGGER
or logging
in __repr__
feels a bit odd. Is this the correct way to proceed, or is there a better way?
Upvotes: 1
Views: 929
Reputation: 99365
Yes, that would be unusual logic to have in a __repr__
- perhaps a code smell, as you've identified. Normally presentation logic would be placed in a Formatter
subclass, but you could also do it in a filter. Here's a simple working example; you should be able to adapt the basic idea into a more general scheme:
import logging
LOGGER = logging.getLogger()
class Car:
def __init__(self):
self.name = 'Celica'
self.year = 1998
self.model = 'GT-Four'
def filter(record):
if record.args:
args = []
for arg in record.args:
if isinstance(arg, Car):
if record.levelno == logging.DEBUG:
arg = str(arg.__dict__)
else:
arg = arg.name
args.append(arg)
record.args = tuple(args)
return True
def main():
LOGGER.setLevel(logging.DEBUG)
f = logging.Formatter('[%(levelname)-5s]: %(message)s')
h = logging.StreamHandler()
h.setFormatter(f)
LOGGER.addHandler(h)
LOGGER.addFilter(filter)
car = Car()
LOGGER.info('basic : %s', car)
LOGGER.debug('detail: %s', car)
LOGGER.debug('no car in this %s', 'message')
LOGGER.debug('nor in this one')
if __name__ == '__main__':
main()
When run, the above script prints:
[INFO ]: basic : Celica
[DEBUG]: detail: {'name': 'Celica', 'year': 1998, 'model': 'GT-Four'}
[DEBUG]: no car in this message
[DEBUG]: nor in this one
Upvotes: 1