简体   繁体   中英

Python Logging - How To Check If Logger Is Empty

I just implemented logging in my app, and I'd like to know if there's a method to check if a logger is empty or not.

What I have in mind is to set two handlers in my script:

  • One for console with level WARNING
  • One for file with level DEBUG

At the end of the script, I need to check if CONSOLE logger is not empty. This means that during the run, some messages with level >= WARNING were logged, and in this case I'd like to send the log file with debug level thru smtp to my mailbox.

Is this check possible inside the python script itself, without shell redirection to file?

There's a general purpose way to count the number of times a function was called using decorators you can check out here

If you wrap this decorator around class calls you are interested in you could find out how many times each member function was called, something like this:

def counted(fn):
    def wrapper(*args, **kwargs):
        wrapper.called += 1
        return fn(*args, **kwargs)
    wrapper.called = 0
    wrapper.__name__ = fn.__name__
    return wrapper

class MyLogger(logging.Logger, object):

    @counted
    def info(self, *args, **kwargs):
        super(MyLogger, self).info(*args, **kwargs)

    @counted
    def warning(self, *args, **kwargs):
        super(MyLogger, self).warning(*args, **kwargs)

Next just set up your logger like any other and use it as you normally would:

log = my_logger.MyLogger('test_logger')
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
log.addHandler(ch)
log.setLevel(logging.DEBUG)

>>> log.info('no big deal')
no big deal
>>> log.info('harmless message')
harmless message
>>> log.warning('oh no')
oh no

>>> log.info.called
2
>>> log.warning.called
1

You would need to decorate all of the classes you wanted counted, so exception, debug etc.

I'm sorry, I forgot to complete this thread.
Following Mike's idea, I came up with something like this :

in a module called logset.py :

def counted(fn):

    def wrapper(*args, **kwargs):
        wrapper.count += 1
        return fn(*args, **kwargs)
    wrapper.count = 0
    wrapper.__name__ = fn.__name__
    return wrapper

class MyLogger(logging.Logger):

    def __init__(self, name=None, level=logging.NOTSET):
        super(MyLogger, self).__init__(name, level)

    @counted
    def info(self, *args, **kwargs):
        super(MyLogger, self).info(*args, **kwargs)

    @counted
    def warning(self, *args, **kwargs):
        super(MyLogger, self).warning(*args, **kwargs)

    @counted
    def critical(self, msg, *args, **kwargs):
        super(MyLogger, self).warning(*args, **kwargs)

    @counted
    def error(self, *args, **kwargs):
        super(MyLogger, self).warning(*args, **kwargs)

    def logfile(self):
        for h in self.handlers:
            if hasattr(h, 'baseFilename'):
                return h.baseFilename

    def empty(self):
        if self.warning.count or self.critical.count or self.error.count:
            return False
        else:
            return True

    def status(self):
        msg = "WARNINGS:%s ERRORS:%s CRITICAL:%s" % (self.warning.count, self.error.count, self.critical.count)
        return msg

def addLogFile(logger, filepath):

    handler = logging.FileHandler(filepath, "w", encoding=None, delay="true")
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter("%(levelname)s\t: %(message)s")
    handler.setFormatter(formatter)
    logger.addHandler(handler)

def addLogConsole(logger):

    handler = logging.StreamHandler()
    handler.setLevel(logging.WARNING)
    formatter = logging.Formatter("%(levelname)s\t: %(message)s")
    handler.setFormatter(formatter)
    logger.addHandler(handler)

def myLog(level=None):

    if not LOGGER.handlers:
        # "Adding Handlers..."
        addLogConsole(LOGGER)
        addLogFile(LOGGER, '#YOUR LOG FILE#')

    return LOGGER

LOGGER = MyLogger("root")

In my app's start file :

from logset import myLog
.
.
. # Initialize the log
root = myLog()
.
.
. # Do something in your app and at end check :

if not root.empty():
    print "\nProgram has logged some errors, check log : %s" % root.logfile()
    print root.status()
    # now I can send root.logfile() via smtp for further examination

You can repeat the import in every module that needs logging, it always refers to the same logger object:

from logset import myLog
log = myLog()
.
.
.
log.info("Adding something")
log.debug("this var has value : %s" % value)

Thank you for your help and attention.
Enrico

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM