How can I configure Python’s logging module to log to both a file and print to stdout?
I’m using Python’s logging module to log debug strings to a file, and that works great. Now, I want to log the same messages to the console (stdout) in addition to the file. Here’s the code I’m currently using to log to a file:
import logging
import logging.handlers
logger = logging.getLogger("")
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
LOGFILE, maxBytes=(1048576*5), backupCount=7
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
Then, I call a logger function like:
logger.debug("I am written to the file")
Can you help me with how to also log these messages to the console (stdout)?
To log messages to both a file and the console in Python, you can use the StreamHandler to output logs to stdout and a FileHandler to write logs to a file. Here’s a basic approach:
import logging
import sys
# Create the logger
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s")
rootLogger = logging.getLogger()
# FileHandler for logging to file
fileHandler = logging.FileHandler("your_logfile.log")
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)
# StreamHandler for logging to console
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)
# Set logging level
rootLogger.setLevel(logging.DEBUG)
This will output logs both to the file and to stdout, with the messages formatted with the timestamp, thread name, and log level.
If you prefer a more concise approach without creating a custom logger, you can directly add handlers to the root logger like so:
import logging
# Add a stream handler to print logs to stdout
logging.getLogger().addHandler(logging.StreamHandler())
# Add a file handler to log messages to a file
logging.getLogger().addHandler(logging.FileHandler('your_logfile.log'))
# Set the logging level
logging.basicConfig(level=logging.DEBUG)
You can also configure logging using the logging.config module, which allows for a more flexible and structured configuration. Here’s an example:
import logging.config
logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'your_logfile.log',
'formatter': 'detailed'
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'formatter': 'detailed'
},
},
'formatters': {
'detailed': {
'format': '%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s'
},
},
'loggers': {
'': {
'handlers': ['file', 'console'],
'level': 'DEBUG',
'propagate': True,
},
}
})
This method gives you more control over the configuration and allows for easy modification or expansion in the future.