pythondatetimeloggingtimedeltaloguru

How to format elapsed time (timedelta) in loguru?


Elapsed time in loguru is a datetime.timedelta object. (loguru docs)

I want the time to be formatted as minutes and seconds. So, if elapsed.seconds = 123, it would become 2m3s.
This would normally be attainable by {elapsed.seconds//60}m{elapsed.seconds%60}s in an f-string or using .format().

But if I use f-string in loguru's format argument string, it obviously does not recognise the variable elapsed.seconds as that belongs to loguru and not the current scope. And so it gives the error AttributeError: 'datetime.timedelta' object has no attribute 'seconds//60' in case of f-strings and NameError: name 'elapsed' is not defined in case of trying to use .format() Here's the code to replicate-

from loguru import logger

logger_format = ('{time:DD-MMM-YYYY HH:mm:ss}'
                  '|{level:<8}| '
                  '({elapsed.seconds}s)')

logger.add('test.log', delay=True, format=logger_format, level='DEBUG')

def print_something(x):
    if type(x) == int:
        print(x)
        logger.debug('Printing int')
        
print_something(2)

Here's the log it could print if running time was 123s:

07-Jul-2022 18:20:19|DEBUG   | (123s) Printing int

Here's the log I want it to print:

07-Jul-2022 18:20:19|DEBUG   | (2m3s) Printing int

Solution

  • The format argument can be a format string, but it can also be a callable that takes a record dictionary and returns a string, like so:

    from loguru import logger
    
    def my_format(record):
        mins = record['elapsed'].seconds // 60
        secs = record['elapsed'].seconds % 60
        return '|{level:<8}| ({mins}m{secs}s)\n{exception}'.format(**record, mins=mins, secs=secs)
    
    logger.add('test.log', delay=True, format=my_format, level='DEBUG')
    

    You could also use an f-string if you prefer.