Use logging print the output of pprint
Asked Answered
L

3

155

I want to use pprint's output to show a complex data structure, but I would like to output it using the logging module rather than stdout.

ds = [{'hello': 'there'}]
logging.debug( pprint.pprint(ds) ) # outputs as STDOUT
Lanlana answered 19/6, 2012 at 1:25 Comment(3)
i glanced through the docs and found pprint( {}, stream ), but found it rather awkward. i would have thought something like spprint might have been nicer than pformat (like in c).Lanlana
pprint.pformat() was on that page.Samhita
@Lattywayre - Not everyone who asks a question like this has skipped the docs. I read the same docs and also missed pformat. On stackoverflow you also sometimes get gems from other people's experience that weren't in the docs at all. Thanks yee379 for asking this.Opuscule
B
320

Use pprint.pformat to get a string, and then send it to your logging framework.

from pprint import pformat
ds = [{'hello': 'there'}]
logging.debug(pformat(ds))
Baskin answered 19/6, 2012 at 1:27 Comment(9)
If you don't remove this code after you're done debugging, you should probably guard it with "if Logger.isEnabledFor(logging.DEBUG):" to avoid running pformat when you won't use its output: docs.python.org/2/library/…Akilahakili
@EdBrannin Does pformat add that much overhead that it's worth the trouble of adding the conditionals to all the DEBUG log statements?Equuleus
@Equuleus Good question. Me-today wants to tell Me-2-years-ago to generate some A/B performance metrics.Akilahakili
I get AttributeError: 'function' object has no attribute 'pformat' any idea why?Devoir
solution: I needed from pprint import pprint,pformat then logging.debug((pformat(stuff))Devoir
I believe if you use logging.debug("%s", pformat(ds)) you should avoid the overhead of pformat when the logLevel is > DEBUG. Here is a link to good info on string formatting for logging.Inconstant
I was hoping you are right RoHS4U but I can't find any evidence in that link, the docs or anywhere else.Leathaleather
{'general': 'kenobi'}Standardize
logging.debug("%s", pformat(ds)) won't avoid the pformat call. That format simply means that, if debug logging is disabled, then a new string won't be created by formatting the template string with the other arguments. The arguments themselves, if results of a function call, will be evaluated.Stonehenge
S
25

The solution above didn't quite cut it for me because I'm also using a formatter to add name and levelname when logging. It looks a little untidy:

__main__    : DEBUG   : ['aaaaaaaaaaaaaaaaaaaa',
'bbbbbbbbbbbbbbbbbbbb',
'cccccccccccccccccccc',
'dddddddddddddddddddd']
__main__    : DEBUG   : Some other logging text

There may be a more elegant solution, but this:

for line in pprint.pformat(ds).split('\n'):
    logging.debug(line)

produces something a little nicer:

__main__    : DEBUG   : ['aaaaaaaaaaaaaaaaaaaa',
__main__    : DEBUG   :  'bbbbbbbbbbbbbbbbbbbb',
__main__    : DEBUG   :  'cccccccccccccccccccc',
__main__    : DEBUG   :  'dddddddddddddddddddd']
__main__    : DEBUG   : Some other logging text
Signora answered 9/1, 2014 at 15:33 Comment(5)
Nicer for human consumption. Not so great if you're shipping logs to logstash or similar tools, and want a single multiline message to be sent as, well, one message.Arvid
is there a way to pretty print at the handler/formatter level of the logger config? Seems like a valid use case to pretty print to console, but go unformatted to filePale
@CharlesDuffy Is there any easy way to handle both cases?Suppurate
Fwiw my solution has been to just add an extra \n character in the pformat. At least this way the block is together.Borges
@CharlesDuffy I think the proper solution would be to fix the default Python console logging handler, so knows about pformat() and prefixes every line in the output with the configured logger format.Evin
R
12

An alternative is to use json.dumps with the indent arg. In some cases (depending on logging format, data size, etc) it might give you nicer output.

logging.error('Malformed input data!')
logging.error(pformat(foo))

ERROR:root:Malformed input data!
ERROR:root:{'a': 1, 'b': 2, 'c': 'womp rat', 'd': 'turd sandwich'}

vs.

logging.error('Malformed input data!') 
logging.error(json.dumps(foo, indent=4))

ERROR:root:Malformed input data!
ERROR:root:{
    "a": 1,
    "b": 2,
    "c": "womp rat",
    "d": "turd sandwich"
}
Retch answered 28/12, 2021 at 20:31 Comment(2)
I thought this gave a nicer output than the accepted answer. +1!Golconda
Does not ATQ since it does not use pprint, but is a better general soln. May wish to prepend the dumps() with a \n.Legit

© 2022 - 2024 — McMap. All rights reserved.