The time has come to convert all prints into logging calls in a library I'm maintaining. Some of the print calls are using str.format
, like this (simplified):
>>> n = 4000000
>>> print(f"this bird wouldn't voom if you put {n:,} volts through it!")
this bird wouldn't voom if you put 4,000,000 volts through it!
When I try to log it:
>>> log.warning("this bird wouldn't voom if you put %d, volts through it!", n)
WARNING:root:this bird wouldn't voom if you put 4000000, volts through it!
Seems this is not specifying the thousands separator correctly. How do you specify the thousands separator when using the %-formatting syntax which Python's stdlib logging module necessitates?
Currently using this workaround, which does give the desired output, but seems wrong since the variable is formatted first using str.format
and then formatted as a string again, instead of logging as a number directly:
>>> log.warning("this bird wouldn't voom if you put %s volts through it!", format(n, ','))
WARNING:root:this bird wouldn't voom if you put 4,000,000 volts through it!
That's a limitation with logging
and it's actually mentioned in (at least one place in) the documentation:
logging.debug(msg, *args, **kwargs)
Logs a message with level
DEBUG
on the root logger. The msg is the message format string, and the args are the arguments which are merged intomsg
using the string formatting operator. (Note that this means that you can use keywords in the format string, together with a single dictionary argument.)
(emphasis mine)
But the string formatting operator %
doesn't support thousand seperators.
You could however adapt a recipe from the official cookbook
:
import logging
class Message(object):
def __init__(self, fmt, args):
self.fmt = fmt
self.args = args
def __str__(self):
return self.fmt.format(*self.args)
class StyleAdapter(logging.LoggerAdapter):
def __init__(self, logger, extra=None):
super(StyleAdapter, self).__init__(logger, extra or {})
def log(self, level, msg, *args, **kwargs):
if self.isEnabledFor(level):
msg, kwargs = self.process(msg, kwargs)
self.logger._log(level, Message(msg, args), (), **kwargs)
logger = StyleAdapter(logging.getLogger(__name__))
def main():
# this changed
logger.warning("this bird wouldn't voom if you put {:,} volts through it!", 4000000)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
main()
WARNING:__main__:
this bird wouldn't voom if you put 4,000,000 volts through it!
This is actually copied verbatim (I just changed the message) from the last example in the "Use of alternative formatting styles" section.
Personally I would just go with your format(n, ',')
solution. It may not be perfect but it doesn't require setting up a custom LoggerAdapter
to print a different thousand seperator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With