txaio icon indicating copy to clipboard operation
txaio copied to clipboard

Logging content of a dict just prints '1970-01-01T01:00:00'

Open aberres opened this issue 7 years ago • 9 comments

Stumbled upon this in my application which uses autobahn-python.

See the following sample code:

import logging

txaio.use_asyncio()
txaio.start_logging(level='debug')

logging.info('Working dict output: %s', str({'a': 1}))

logging.info('Broken dict output: %s', {'a': 1})

Expectation is that the content of the dict is logged in both cases.

Actual output:

2017-09-19T11:54:41 Working dict output: {'a': 1} 1970-01-01T01:00:00

Expected output:

2017-09-19T11:54:41 Working dict output: {'a': 1} 2017-09-19T11:54:41 Broken dict output: {'a': 1}

aberres avatar Sep 19 '17 10:09 aberres

That's "interesting" output, but also that's not how the logging should be used -- you should use the {name} syntax, like so:

logging.info('Some dict output: {a}', a=1)

meejah avatar Sep 19 '17 14:09 meejah

(That said, I can't explain what happens in the second case ;) )

meejah avatar Sep 19 '17 14:09 meejah

Thanks for the reply.

I've never seen the name syntax in a logging call. And does not seem to work in a quick test of mine.

{'a': 1} is just an example in my case. It could be any more or less complex dict. Without starting txaio logging this works as expected.

aberres avatar Sep 19 '17 14:09 aberres

That syntax is a new string-interpolation syntax in python; the names in {}'s correspond to keyword args. Even with the other syntax, you wouldn't typically pass a dict -- instead a tuple. Anyway, this is based on Twisted's new logger syntax to provide semi-structured logging.

(How does the dict syntax ever work? dicts don't have order, so without naming the strings it can't possibly work...?)

meejah avatar Sep 19 '17 15:09 meejah

I think we should leave this bug open as an "improve documentation" bug; we don't explicitly describe this syntax (even though it sort-of appears in the examples): http://txaio.readthedocs.io/en/latest/programming-guide.html#logging

meejah avatar Sep 19 '17 15:09 meejah

you can do the same with %s syntax

eg: logging.debug("foo bar: %(foo)s, %(bar)s", {'foo': 'asdf', 'bar': 'qwerty'})

the .format equivalent of his original code would be to just replace the %s with {} as the .format method does not require variable names be filled in. In that case, just like %s syntax, the substitutions must be in the correct order.

the .format system is just a newer form of %s imho. Personally I have been sticking with %s. I only use .format form when working on someone else's code that is using that method.

I find it is very useful to log the contents of various variables at points in your code to help debug/monitor how things are working. I often add similar logging statements to log a list or dictionary's contents. But I have normally wrapped them in str(foo) to ensure proper conversion. Logging is not the same as the print command that will always output the str(foo) form.

dol-sen avatar Sep 19 '17 16:09 dol-sen

I am a bit confused. This is valid Python, isn't it?

import logging

logging.warning('My state is messed up: %s', {'a': 1})

The docs state

When you’re using libraries that are already doing logging, but not using the txaio APIs, you shouldn’t need to do anything.

When I use the above code with txaio, e.g., because I start to use autoboahn-python, it will stop working. Not a big problem but more than missing documentation IMHO.

aberres avatar Sep 20 '17 05:09 aberres

txaio is a compatibility library so we can write "the same" code across asyncio and Twisted. The logging system in here is built as a mostly-thin wrapper over Twisted's new logging system, giving us semi-structured logging -- that is, you can completely ignore the format string and just log the kwargs you get (which will be objects).

This also has speed benefits: because the string interpolation is delayed, un-logged levels (e.g. .trace or .debug) never get interpolated into strings.

If you really do want to do your own string-interpolation stuff, you can follow a pattern like this: log.info("{msg}", msg="some %s" % ("thing",))

meejah avatar Sep 20 '17 05:09 meejah

Hmm, actually perhaps I glossed over the original report too quickly -- that code is indeed using the logging library (that is not txaio). So what's happening is this: it is creating a string which has { and } characters in it (because it repr'd a dict) and then the txaio (or Twisted) logger is trying to do string-interpolation on that.

So, either that statement from the docs can't be true, or something has to be done to txaio logging in the case of getting a single string containing "{" characters but no kwargs at all. Is there something that can be done here ...?

meejah avatar Sep 20 '17 05:09 meejah