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/