1

I have a basic logger handler in Python setup to log to a file. I want this log handler to log any/all stdout or stderr messages that would ordinarily be printed to the console, but I don't want to redirect or capture it. In other words, I still want everything to be printed in the usual way.

The use case here is that I don't want to wrap each and every command in my application with

try:
    do_something_that_could_raise_exception()
except Exception as e:
    logger.exception(e)

Instead, I just want to let the application run, and be able to look in the log file to see a stack trace from any errors that are encountered. I just want all stdout/stderr messages to also appear in my log file.

This seems like a twist on a topic that has been asked many times on SO. I've read Logging Python stdout to File... with active stdout (backspacing/updating), Redirect stdout to a file in Python?, and many others, but those don't seem to address the situation I have. All the questions I've seen talk about how to use multiple handlers to print to both a log and stdout, or how to redirect stdout to the log such that nothing is displayed in the terminal.

EDIT

Editing for posterity. After some more searching I found https://code.tutsplus.com/tutorials/professional-error-handling-with-python--cms-25950, which demonstrates how to add a function decorator that will direct exceptions to a given logging handler. This isn't quite as concise as I was hoping (since I still have to add the function decorator to all my function definitions), but it is quite a bit less verbose than wrapping all my function calls in try-except.

def log_error(logger)

    def decorated(f):
        @functools.wraps(f)
        def wrapped(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except Exception as e:
                if logger:
                    logger.exception(e)
                raise
        return wrapped

    return decorated

Here is how to use it:
01
02
03
04
05
06
07
08
09
10
11

import logging
logger = logging.getLogger()

@log_error(logger)
def f():
    raise Exception('I am exceptional')
hobscrk777
  • 2,347
  • 4
  • 23
  • 29

1 Answers1

1

Since it seems you are only interested in exceptions you can use sys.excepthook instead of that wrappper as explained here: Logging uncaught exceptions in Python

That way it only has to be defined once and you can't forget it when you define new functions.

blues
  • 4,547
  • 3
  • 23
  • 39