0

I have some pretty long functions which are only used in debugging, but they execute while running in higher loglevels, even though I don't want them to. I understand that I can use if logger.getEffectiveLevel() to bypass this, but is there a "prettier" way to do this?

Example:

import logging
import time

def waitsec():
    time.sleep(5)

logger = logging.getLogger("Logger")
logger.setLevel(logging.ERROR)

logger.error(f'Before call waitsec')
logger.debug(f'This is not printed, but still waits 5 seconds {waitsec()}') # I want it to skip 
                                                                            # this completely
logger.error(f'After call waitsec')

Output:

Before call waitsec
After call waitsec
vvvvv
  • 25,404
  • 19
  • 49
  • 81
  • I've answered specifically to your use case, but there's a more generalized version of this question with some other options, some of which don't require lambda: https://stackoverflow.com/questions/42497625/how-to-postpone-defer-the-evaluation-of-f-strings – ryanc Mar 23 '23 at 13:25
  • Can you please tag this as `python-3.x` in addition to `python`, since f-strings are a Python 3 feature? – ryanc Mar 23 '23 at 13:53
  • 1
    @ryanc Since Python 2 is officially dead for over 3 years now, I don't think Python 3 needs to be labelled. – Matthias Mar 23 '23 at 14:51
  • The tag info (which perhaps should be updated) says to tag it if version specific https://stackoverflow.com/questions/tagged/python – ryanc Mar 23 '23 at 16:03

2 Answers2

0

waitsec() has to be evaluated to produce the argument for logger.debug before logger.debug is called. You can (redundantly) check the logging level before calling logger.debug or waitsec:

if logger.isEnabledFor(logging.DEBUG):
    logger.debug(f'This is printed after the necessary 5 seconds {waitsec()}')
# else:
#    pass  # No waiting, no output

or factor out the call to waitsec and provide a dummy string for the argument that won't be logged.

foo = waitsec() if logger.isEnabledFor(logging.DEBUG) else ""
logger.debug(f'This is not printed, but does not wait 5 seconds {foo}')
chepner
  • 497,756
  • 71
  • 530
  • 681
0

Depending on your aesthetics, something like this might suit:

import logging
import time

logger = logging.getLogger("Logger")
logger.setLevel(logging.ERROR)

def waitsec():
    time.sleep(5)

def lazy_debug(func):
    """Log the result of a function called with no arguments"""
    if logger.getEffectiveLevel() <= logging.DEBUG:
        logger.debug(func())

lazy_debug(lambda: f'This is not printed, and does not wait 5 seconds {waitsec()}')

You could also subclass logger to add a method like this.

ryanc
  • 1,304
  • 9
  • 16