On 15May2019 17:37, mak apuf <[email protected]> wrote:
Let's consider logging.debug(expensive_function())

There are a few possibilities to run an expensive function when
logging only if the log is effectively output :

- eager formatting + calling by using fstrings or .format(expensive_func())
- formatting being done lazily by separating the log string from the
arguments (by using % syntax which is dated maybe)
- creating a Lazy object that calls expensive_func when calling its
__str__ method, but that it a bit cumbersome because you have to
provide a lazy class for each, that only work for string values and
the cost of creating Lazy is eager.
- checking logging.isEnabledFor(lvl) explicitely (but then the level
is displayed twice, in enabled_for and in logging.LEVEL)

I think c is the most viable solution. The "only works for string values" isn't such a big deal: logging writes strings, so string output is the end game anyway.

Then you can go:

 logging.debug("Wow: This: %s", Lazy(expensive_function, args...))

However, there's still a problem: the logging documentation suggests that the message is assembled before decenting the log tree to dispatch it, which means that Lazy.__str__ gets called even when debug level logging is not happening.

The logging infrastructure would need to make an intenral change so that the message composition (the implicit % formatting of the args) only happens if it is needed, maybe where the handler.emit method gets called.

With taht, I think your Lazy class simply using __str__ instead of __lazy__ might be all you need, and it wouldn't need to be part of the logging module: roll your own.

The other solutions seem to either:

A: Require some kind of change to Python to support deferring function calls so that some simple variation on:

 logging.debug(expensive_function())

somehow does not call expensive_function, or a different form of .debug() (and friends) where expensive_function was some kind of callback to be triggered at need, which is where you already are with the .emit issue above.

B: Require careful polling of the logging status, which is intrusive. As I understand it, logging.debug() just submits a message with "debug" level, and the logging tree decides where it gets used. In a sense you're back to the Lazy.__str__ approach if the enabled stuff (isEnabledFor, getEffectiveLevel) don't suffice.

Disclaimer: my logging fu is a bit weak; I've got a wrapper module for it largely to avoid thinking about it, just providing a simple call layer to the root logger :-)

Cheers,
Cameron Simpson <[email protected]>
_______________________________________________
Python-ideas mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to