开发者

How can I determine if any errors were logged during a python program's execute?

开发者 https://www.devze.com 2023-02-08 21:34 出处:网络
I have a python script which calls log.error() and log.exception() in several places.These exceptions are ca开发者_JAVA技巧ught so that the script can continue to run, however, I would like to be able

I have a python script which calls log.error() and log.exception() in several places. These exceptions are ca开发者_JAVA技巧ught so that the script can continue to run, however, I would like to be able to determine if log.error() and/or log.exception() were ever called so I can exit the script with an error code by calling sys.exit(1). A naive implementation using an "error" variable is included below. It seems to me there must be a better way.

error = False

try:
  ...
except:
   log.exception("Something bad occurred.")
   error = True

if error:
   sys.exit(1)


I had the same issue as the original poster: I wanted to exit my Python script with an error code if any messages of error or greater severity were logged. For my application, it's desirable for execution to continue as long as no unhandled exceptions are raised. However, continuous integrations builds should fail if any errors are logged.

I found the errorhandler python package, which does just what we need. See the GitHub, PyPI page, and docs.

Below is the code I used:

import logging
import sys

import errorhandler

# Track if message gets logged with severity of error or greater
error_handler = errorhandler.ErrorHandler()

# Also log to stderr
stream_handler = logging.StreamHandler(stream=sys.stderr)
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # Set whatever logging level for stderr
logger.addHandler(stream_handler)

# Do your program here

if error_handler.fired:
    logger.critical('Failure: exiting with code 1 due to logged errors')
    raise SystemExit(1)


You can check logger._cache. It returns a dictionary with keys corresponding to the numeric value of the error level logged. So for checking if an error was logged you could do:

if 40 in logger._cache and logger._cache[40]


I think that your solution is not the best option. Logging is one aspect of your script, returning an error code depending on the control flow is another. Perhaps using exceptions would be a better option.

But if you want to track the calls to log, you can wrap it within a decorator. A simple example of a decorator follows (without inheritance or dynamic attribute access):

class LogWrapper:

    def __init__(self, log):
        self.log = log
        self.error = False

    def exception(self, message)
        self.error = True
        self.log.exception(message)


whenever logger._cache is not a solution (when other packages / modules log on their own which won't end in logger._cache), there's a way to build a ContextFilter which will record the worst called log level:

class ContextFilterWorstLevel(logging.Filter):
    def __init__(self):
        self.worst_level = logging.INFO
    def filter(self, record):
        if record.levelno > self.worst_level:
            self.worst_level = record.levelno
        return True


# Create a logger object and add the filter     
logger = logging.getLogger()
logger.addFilter(ContextFilterWorstLevel())

# Check the worst log level called later
for filter in logger.filters:
    if isinstance(filter, ContextFilterWorstLevel):
        print(filter.worst_level)


You can employ a counter. If you want to track individual exceptions, create a dictionary with the exception as the key and the integer counter as the value.

0

精彩评论

暂无评论...
验证码 换一张
取 消