GoBlue_MathMan
GoBlue_MathMan

Reputation: 1148

Logging with two handlers - one to file and one to stderr

I have the following code to create two logging handlers. The goal is to have the stream_handler write only to the sterr and the file_handler only to file.

In the code below, stream_handler writes to the file as well, so I have duplicate log entries whenever I log a message. How can I modify it to get the stream_handler not to write to the file?

def create_timed_rotating_log(
        name='log',
        path='logs/',
        when='D',
        interval=1,
        backupCount=30,
        form='%(asctime)s | %(name)s |  %(levelname)s: %(message)s',
        sterr = False,
        verbose=False):

  logger = logging.getLogger(name)
  formatter = logging.Formatter(form)
  logger.setLevel(logging.DEBUG)

  if sterr:
      stream_handler = logging.StreamHandler()
      stream_handler.setLevel(logging.DEBUG if verbose else logging.ERROR)
      stream_handler.setFormatter(formatter)
      logger.addHandler(stream_handler)

  file_handler = TimedRotatingFileHandler(filename=path+name,
                                          when=when,
                                          interval=interval,
                                          backupCount=backupCount)
  file_handler.setFormatter(formatter)
  file_handler.setLevel(logging.DEBUG if verbose else logging.ERROR)
  logger.addHandler(file_handler)

  return logger

Upvotes: 0

Views: 361

Answers (2)

GoBlue_MathMan
GoBlue_MathMan

Reputation: 1148

Not exactly sure why this is the case but adding the StreamHandler first causes it to also write to the file. I moved the StreamHandler to after adding the TimedRotatingFileHandler and this resolved the problem.

Upvotes: 0

Dan D.
Dan D.

Reputation: 74655

Looks like you have considered that the messages go to both handlers as duplication. If you wanted the file not to receive messages and them to only go to stderr, when stderr=True, you never to put the code that adds the file handler in an else so that it is only added if stderr=False

Specifically:

if sterr:
    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(logging.DEBUG if verbose else logging.ERROR)
    stream_handler.setFormatter(formatter)
    logger.addHandler(stream_handler)
else:
    file_handler = TimedRotatingFileHandler(filename=path+name,
                                          when=when,
                                          interval=interval,
                                          backupCount=backupCount)
    file_handler.setFormatter(formatter)
    file_handler.setLevel(logging.DEBUG if verbose else logging.ERROR)
    logger.addHandler(file_handler)

I had considered this possible but less likely than the more common issue of setting up handlers multiple times when how you are supposed use logging is that in the main module you add the handlers to the root logger and then only get the logger for the current module via logger = logging.getLogger(__name__). This and import logging is the only logging code that should appear in any but the module where if __name__=="__main__": occurs where right after that it should setup the logging.


The only way you will have duplicates is if you call that function in your program twice. The issue isn't these two handlers but the other two handlers from the second call to this setup function.

You need to just add the handlers once to the root logger not once for every logger in each module.

Upvotes: 0

Related Questions