Log information is crucial when developing and operating applications. While you want to check operations in real-time on the console (screen) during development, you also need to permanently save logs as “files” for production operations and later error analysis.
In Python’s logging module, you can freely control the output destination of logs using a mechanism called “Handlers.” This article explains how to output logs to both the screen and a file by combining StreamHandler (for console) and FileHandler (for files).
What are Log Handlers?
A handler is a component responsible for “sending log messages generated by a logger to the appropriate destination (file, console, email, etc.).”
Two representative handlers are:
logging.StreamHandler(): Outputs logs to standard output (Console/Terminal).logging.FileHandler("filename"): Outputs (saves) logs to a specified file. It writes in append mode by default.
By passing these as a list to the handlers argument of logging.basicConfig, you can set multiple output destinations simultaneously.
Implementation Example: Simultaneous Screen Display and File Saving
We will create code that simulates a system startup process, displaying logs on the screen while also saving them to a file named system.log.
import logging
# 1. Define Log Format
# Date - Logger Name - Level - Message
log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# 2. Create Handlers
# For Console Output
stream_handler = logging.StreamHandler()
# For File Output (Save to system.log)
file_handler = logging.FileHandler("system.log", encoding="utf-8")
# 3. Basic Log Configuration (basicConfig)
# Pass the created handlers as a list to the handlers argument
logging.basicConfig(
level=logging.DEBUG,
format=log_format,
handlers=[stream_handler, file_handler]
)
# 4. Get Logger and Execute Log Output
logger = logging.getLogger(__name__)
logger.info("System initialization started.")
logger.debug("Loading configuration file config.ini...")
logger.warning("Deprecated setting found: timeout=0")
try:
# Simulate error occurrence
process_result = 10 / 0
except ZeroDivisionError:
logger.error("Critical error occurred: Zero Division", exc_info=True)
logger.info("System shutting down.")
Checking Execution Results
Running this script yields the following two results.
1. Console (Screen) Output
Logs are displayed in real-time on the terminal.
2025-11-29 15:00:01,123 - __main__ - INFO - System initialization started.
2025-11-29 15:00:01,124 - __main__ - DEBUG - Loading configuration file config.ini...
2025-11-29 15:00:01,125 - __main__ - WARNING - Deprecated setting found: timeout=0
2025-11-29 15:00:01,126 - __main__ - ERROR - Critical error occurred: Zero Division
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
2025-11-29 15:00:01,127 - __main__ - INFO - System shutting down.
2. Content of Log File (system.log)
A system.log file is created in the same directory as the script, and the same content as the console is written to it.
2025-11-29 15:00:01,123 - __main__ - INFO - System initialization started.
2025-11-29 15:00:01,124 - __main__ - DEBUG - Loading configuration file config.ini...
2025-11-29 15:00:01,125 - __main__ - WARNING - Deprecated setting found: timeout=0
2025-11-29 15:00:01,126 - __main__ - ERROR - Critical error occurred: Zero Division
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
2025-11-29 15:00:01,127 - __main__ - INFO - System shutting down.
Summary
The key points for controlling output destinations with the logging module are:
StreamHandler: For screen output.FileHandler: For file saving.basicConfig(handlers=[...]): By passing multiple handlers in a list, you can record logs to multiple locations with a single logging command.
This allows for flexible operations, such as “checking on the screen during development and keeping records in files during operation (or doing both).”
