Hacker News new | ask | show | jobs
by memco 1508 days ago
The article links to some docs for the logging module here: https://docs.python.org/3/howto/logging.html#optimization asserting that f-strings are less optimal but the docs do not say that they do not optimize our the expression evaluation of f-strings: only that the logging module tried to perform evaluation as late as possible: where is the f-string described as suboptimal?

Relatedly the logging optimization suggests setting: raiseExceptions to false for production logging code: where is that set? On the logger, handler or something else?

3 comments

I was also confused by the expression evaluation thing. Reading between the lines, it seems like

    logger.debug("hello %s", foo)
may be better than

    logger.debug(f"hello {foo}")
in the case when loglevel is higher than debug. In the first version, the final string does not have to be computed, while in the second version, we might construct the string and then do nothing since the loglevel is excluded.
The first is better also because you can do things with loggers other than print out their contents. For example, suppose you had a statement like:

    logger.debug('Database error: %s', error_message)
You probably have a logging handler that did the normal string. But you can also have one that keeps a count of how many `Database error: %s` hits there are (as opposed to `Network error: %s`) there are over time. Doing the string substitution would break this aggregation.
That's exactly it.

Although this becomes more complicated because printf-style string formatting is not free (though it's the cheapest of all methods save fstrings if I remember correctly), and because python does not support lazy parameters if `foo` is a non-trivial expression odds are good it will far outcost either formatting.

You're also able to add additional log-specific processors to the log record in the first case.
> where is the f-string described as suboptimal?

I guess it's implicit in that f-strings, as arguments, will be evaluated before the logging function can even run whereas `debug("...", heavy_obj)` will avoid a potentially expensive `str(heavy_obj)` (or whatever the string conversion warrants.)

As for raiseExceptions, I'm not sure it's for optimization. It looks like an old sanity check for bad logging configurations.

The "Use logging's interpolation" warning has always annoyed me. If logging is in your hot path, that might be an issue. Me f-string interpolating some info logs that run once for convenience is not.

Low value junk like this is not helpful.