logger configuration to log to file and print to stdout logger configuration to log to file and print to stdout python python

logger configuration to log to file and print to stdout

Just get a handle to the root logger and add the StreamHandler. The StreamHandler writes to stderr. Not sure if you really need stdout over stderr, but this is what I use when I setup the Python logger and I also add the FileHandler as well. Then all my logs go to both places (which is what it sounds like you want).

import logginglogging.getLogger().addHandler(logging.StreamHandler())

If you want to output to stdout instead of stderr, you just need to specify it to the StreamHandler constructor.

import sys# ...logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))

You could also add a Formatter to it so all your log lines have a common header.


import logginglogFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")rootLogger = logging.getLogger()fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))fileHandler.setFormatter(logFormatter)rootLogger.addHandler(fileHandler)consoleHandler = logging.StreamHandler()consoleHandler.setFormatter(logFormatter)rootLogger.addHandler(consoleHandler)

Prints to the format of:

2012-12-05 16:58:26,618 [MainThread  ] [INFO ]  my message

logging.basicConfig() can take a keyword argument handlers since Python 3.3, which simplifies logging setup a lot, especially when setting up multiple handlers with the same formatter:

handlers – If specified, this should be an iterable of already created handlers to add to the root logger. Any handlers which don’t already have a formatter set will be assigned the default formatter created in this function.

The whole setup can therefore be done with a single call like this:

import logginglogging.basicConfig(    level=logging.INFO,    format="%(asctime)s [%(levelname)s] %(message)s",    handlers=[        logging.FileHandler("debug.log"),        logging.StreamHandler()    ])

(Or with import sys + StreamHandler(sys.stdout) per original question's requirements – the default for StreamHandler is to write to stderr. Look at LogRecord attributes if you want to customize the log format and add things like filename/line, thread info etc.)

The setup above needs to be done only once near the beginning of the script. You can use the logging from all other places in the codebase later like this:

logging.info('Useful message')logging.error('Something bad happened')...

Note: If it doesn't work, someone else has probably already initialized the logging system differently. Comments suggest doing logging.root.handlers = [] before the call to basicConfig().

Adding a StreamHandler without arguments goes to stderr instead of stdout. If some other process has a dependency on the stdout dump (i.e. when writing an NRPE plugin), then make sure to specify stdout explicitly or you might run into some unexpected troubles.

Here's a quick example reusing the assumed values and LOGFILE from the question:

import loggingfrom logging.handlers import RotatingFileHandlerfrom logging import handlersimport syslog = logging.getLogger('')log.setLevel(logging.DEBUG)format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")ch = logging.StreamHandler(sys.stdout)ch.setFormatter(format)log.addHandler(ch)fh = handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)fh.setFormatter(format)log.addHandler(fh)