Simply displaying an error message in logs is often insufficient. Logs become useful for debugging and monitoring only when they contain metadata such as “when,” “in which file,” and “on which line” the event occurred.
In Python’s logging module, you can automatically embed this information into logs by specifying a format string.
This article explains how to specify log formats and lists the main available variables.
List of Variables Available in Log Formats
In the logging module, you can reference log record attributes in the format %(variable_name)s or %(variable_name)d. Here are the main variables:
| Variable Name | Meaning | Data Type |
%(asctime)s | Log timestamp (Default: YYYY-MM-DD HH:MM:SS,mmm) | String |
%(name)s | Logger name (name specified in getLogger) | String |
%(levelname)s | Log level name (DEBUG, INFO, WARNING, ERROR, CRITICAL) | String |
%(levelno)s | Numeric log level (10, 20, 30, 40, 50) | Number |
%(message)s | Log message body | String |
%(filename)s | Name of the file where the log was output | String |
%(pathname)s | Full path of the file where the log was output | String |
%(module)s | Module name (filename without extension) | String |
%(lineno)d | Line number in the source code where log was output | Number |
%(funcName)s | Name of the function where log was output | String |
%(process)d | Process ID | Number |
%(thread)d | Thread ID | Number |
%(threadName)s | Thread Name | String |
By combining these, you can create a log format tailored to your purpose.
How to Set the Format
To set the format, pass a string to the format argument of the logging.basicConfig function.
Practical Code Example
Here is an example of setting a format that includes date/time, process ID, and thread ID, making it easier to trace in multi-process or multi-thread environments.
import logging
import os
import threading
# Define log format
# Date - ProcessID - ThreadID - LoggerName - Level - Message
format_str = "%(asctime)s - %(process)d - %(thread)d - %(name)s - %(levelname)s - %(message)s"
# Apply format to basic configuration
logging.basicConfig(
format=format_str,
level=logging.INFO
)
# Get logger
logger = logging.getLogger(__name__)
def worker_task():
"""Function to test log output"""
logger.info("Starting worker thread process.")
try:
# Simulate error
x = 1 / 0
except ZeroDivisionError:
logger.error("Calculation error occurred.", exc_info=True)
logger.info("Worker thread process finished.")
# --- Main Processing ---
logger.info(f"Starting main process. (PID: {os.getpid()})")
# Create and run thread
thread = threading.Thread(target=worker_task, name="WorkerThread")
thread.start()
thread.join()
logger.info("All processes completed.")
Output:
2025-11-29 12:00:00,123 - 15640 - 140028987451200 - __main__ - INFO - Starting main process. (PID: 15640)
2025-11-29 12:00:00,124 - 15640 - 123145324654592 - __main__ - INFO - Starting worker thread process.
2025-11-29 12:00:00,125 - 15640 - 123145324654592 - __main__ - ERROR - Calculation error occurred.
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
2025-11-29 12:00:00,126 - 15640 - 123145324654592 - __main__ - INFO - Worker thread process finished.
2025-11-29 12:00:00,127 - 15640 - 140028987451200 - __main__ - INFO - All processes completed.
By specifying the format, it becomes obvious at a glance which process (15640) and which thread generated the log.
Summary
- You can customize the log output format with
logging.basicConfig(format="..."). - Using variables like
%(asctime)sand%(levelname)sautomatically embeds date/time and importance. - Including
%(filename)sand%(lineno)dmakes it easier to pinpoint error locations during debugging. - It is important to design an appropriate format according to the scale and requirements of the system.
