I have some python like this:
def foo():
logger = logging.getLogger()
# do something here
logger.debug('blah blah {}'.format(expensive_func()))
foo()
where expensive_func()
is a function that returns string and that it is expensive to execute.
When developping, the log level is set to DEBUG, and expensive_func()
get executed, the message get logged, everything is fine.
The problem is that when I set the log level strictly greater than DEBUG, say WARNING, in production env, obviously the return value of expensive_func()
won't get logged, but the expensive function itself will still be executed.
My question is: how to prevent python from excutting the expensive function when the logging level is WARNING?
I don't want to delete that debug line or add something like if level > DEBUG: return
in the expensive function.
Thanks.
EDIT
I visited Lazy logger message string evaluation just now, but not satisfied with it, mainly because:
- It's some what ugly;
- Even if I wrap the expensive function with some Lazy class, what shoud I do when I have two expensive functions? (shown below).
class Lazy:
def __init__(self, func, *a, **ka):
self.func= func
self.a = a
self.ka= ka
def __str__(self):
return str(self.func(*self.a, **self.ka))
# Though this is ugly, it works
logger.debug('Message: %s', Lazy(expensive_func))
# What if I wanted to do this?
# logger.debug('Message: {}'.format(expf_1(expf_2(some_arg))))
# Maybe I can modify class Lazy to make something like this to work
# but it really doesn't feel right
# logger.debug('Message: {}', Lazy(expf_1, Lazy(expf_2, some_arg)))
As Vinay Sajip suggests, you can do the following:
Which is already lazy!
That's because the then-expressions
are only evaluated if and only if
logger.isEnabledFor(logging.DEBUG)
returnsTrue
, i.e. if and only if their evaluation is needed.Even more
is not as lazy as one may think:
DeferredMessage(expensive_func, 1, 2)
have to be evaluated in an eager fashion. Which is in addition slower than evaluating:Look at this part of the documentation.
Update: Logging already supports lazy evaluation, but slightly differently to the way described in your comnment. For example, see the following script:
When the above script is run, it should print
which shows that a potentially expensive function is only called when necessary. The example above can, of course, be generalised to allow the format string to be passed to the
DeferredMessage
, and to usekwargs
, and so on.You can use
stringlike
library to add laziness to your messagesE.g.:
Lib link: https://github.com/CovenantEyes/py_stringlike