Of course! Here is a comprehensive guide to Python's logging module, often referred to as loggerinfo in searches. This guide covers everything from the basics to advanced configuration, making it suitable for both beginners and those looking to deepen their understanding.

What is the logging Module?
The logging module in Python is a powerful and flexible built-in library for tracking events that happen when your software runs. Instead of just using print() statements, the logging module provides a structured way to record information about errors, warnings, and general operational events.
Why use logging instead of print()?
| Feature | print() |
logging |
|---|---|---|
| Verbosity Control | Manual (commenting out) | Easy (set a global level like INFO or WARNING) |
| Log Levels | None | DEBUG, INFO, WARNING, ERROR, CRITICAL |
| Output Destination | Only console | Console, files, network sockets, etc. |
| Log Formatting | Basic | Highly customizable (timestamps, log level, module name, etc.) |
| Contextual Info | Manual | Automatically includes timestamp, log level, and module name. |
| Performance | Slow for disabled logs | Fast; string formatting is skipped if the log level is disabled. |
The Basic Setup (The "Hello, World!" of Logging)
The simplest way to start logging is to call the basicConfig function. This is great for small scripts or quick debugging.
import logging
# Configure the basic logging
logging.basicConfig(
level=logging.INFO, # Set the minimum level of messages to display
format='%(asctime)s - %(levelname)s - %(message)s', # Format of the log message
datefmt='%Y-%m-%d %H:%M:%S' # Format for the timestamp
)
# --- Now, let's log some messages ---
logging.debug("This is a debug message. It won't be shown.")
logging.info("This is an info message. It will be shown.")
logging.warning("This is a warning message. It will be shown.")
logging.error("This is an error message. It will be shown.")
logging.critical("This is a critical message. It will be shown.")
Output:
2025-10-27 10:30:00 - INFO - This is an info message. It will be shown.
2025-10-27 10:30:00 - WARNING - This is a warning message. It will be shown.
2025-10-27 10:30:00 - ERROR - This is an error message. It will be shown.
2025-10-27 10:30:00 - CRITICAL - This is a critical message. It will be shown.
Notice that the DEBUG message was not printed. This is because we set the level to INFO, which is higher than DEBUG. The logger only displays messages at or above its configured level.

Log Levels
The logging module has five standard levels that indicate the severity of an event. They are listed in increasing order of severity:
| Level | Numeric Value | Use Case |
|---|---|---|
DEBUG |
10 | Detailed information, typically of interest only when diagnosing problems. |
INFO |
20 | Confirmation that things are working as expected. |
WARNING |
30 | An indication that something unexpected happened, or a problem might occur in the near future (e.g., ‘disk space low’). The software is still working as expected. |
ERROR |
40 | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL |
50 | A very serious error, indicating that the program itself may be unable to continue running. |
You can also use the numeric values directly, but it's better to use the named constants for clarity.
Log Formatting
The format string in basicConfig uses special placeholders, called LogRecord attributes, to customize the output of your log messages.
| Placeholder | Description |
|---|---|
%(asctime)s |
Human-readable time when the LogRecord was created. |
%(levelname)s |
Text logging level for the message (DEBUG, INFO, etc.). |
%(message)s |
The logged message. |
%(name)s |
The name of the logger (e.g., 'my_app'). |
%(module)s |
The module (filename portion) of the source file. |
%(funcName)s |
The function name. |
%(lineno)d |
The source line number where the logging call was made. |
%(process)d |
Process ID. |
%(thread)d |
Thread ID. |
Example of a detailed format:

logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(name)s - %(module)s.%(funcName)s:%(lineno)d - %(message)s'
)
logging.info("Application started.")
Output:
2025-10-27 10:35:15,123 - INFO - __main__ - <module>.<module>:1 - Application started.
Loggers, Handlers, and Formatters (The Advanced Way)
For larger applications, you'll want more control. The logging module uses a hierarchical system with three key components:
- Loggers: Expose the interface that your application code directly uses. You get a logger by calling
logging.getLogger(name). Loggers are organized in a hierarchy using dots (e.g.,'my_app.database'is a child of'my_app'). - Handlers: Send the log records (created by loggers) to the appropriate destination. Examples include
StreamHandler(for console),FileHandler(for files), andRotatingFileHandler(for files that rotate when they get too big). - Formatters: Specify the layout of final log messages. A formatter is usually specified with a handler.
Why use this structure?
- Separation of Concerns: You can configure different handlers to send different loggers to different places. For example, send all logs from the
'database'module to a file, but only sendWARNINGand above from the entire application to the console. - Reusability: You can configure a logger once and reuse it throughout your application.
Example: Advanced Configuration
Let's create a logger that sends INFO and above to the console, and DEBUG and above to a file.
import logging
# 1. Create a custom logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) # Set the lowest level this logger will handle
# 2. Create handlers
# c_handler for console
c_handler = logging.StreamHandler()
c_handler.setLevel(logging.WARNING) # Console will only show WARNING and above
# f_handler for file
f_handler = logging.FileHandler('file.log')
f_handler.setLevel(logging.DEBUG) # File will show DEBUG and above
# 3. Create formatters and add them to handlers
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)
# 4. Add handlers to the logger
logger.addHandler(c_handler)
logger.addHandler(f_handler)
# --- Test the logger ---
logger.info('This is an info message') # Only goes to file
logger.warning('This is a warning message') # Goes to both console and file
logger.error('This is an error message') # Goes to both console and file
logger.debug('This is a debug message') # Only goes to file
Console Output:
__main__ - WARNING - This is a warning message
__main__ - ERROR - This is an error message
Content of file.log:
2025-10-27 10:40:00,123 - __main__ - INFO - This is an info message
2025-10-27 10:40:00,124 - __main__ - WARNING - This is a warning message
2025-10-27 10:40:00,124 - __main__ - ERROR - This is an error message
2025-10-27 10:40:00,124 - __main__ - DEBUG - This is a debug message
Best Practices
-
Use Named Loggers: Always get your logger using
logging.getLogger(__name__). This creates a logger hierarchy that matches your module hierarchy, making it easy to configure logging for specific parts of your application.# In my_app/database.py logger = logging.getLogger(__name__)
-
Don't Use
basicConfigin Libraries: If you are writing a library or module, never calllogging.basicConfig(). This call can only be made once and affects the root logger, which can interfere with the application using your library. Let the application configure logging. -
Use Exception Information: When logging an exception, pass the exception instance as the
exc_infoargument. This will automatically include the traceback in the log.try: 1 / 0 except ZeroDivisionError: logger.error("Division by zero failed!", exc_info=True) -
Use
logger.exception()for Errors: A shortcut for logging an error withexc_info=True.try: 1 / 0 except ZeroDivisionError: logger.exception("An error occurred during calculation.")
Summary Table
| Task | Simple Method (basicConfig) |
Advanced Method (Loggers/Handlers) |
|---|---|---|
| Start Logging | logging.basicConfig(level=logging.INFO) |
logger = logging.getLogger(__name__)logger.setLevel(logging.DEBUG) |
| Log a Message | logging.info("Message") |
logger.info("Message") |
| Change Log Level | level=logging.DEBUG in basicConfig |
logger.setLevel(logging.DEBUG)handler.setLevel(logging.INFO) |
| Change Output | filename='app.log' in basicConfig |
Create FileHandler('app.log') and add to logger |
| Customize Format | format='...' in basicConfig |
Create Formatter('...') and set on a handler |
This guide should give you a solid foundation for using Python's logging module effectively in any project. Start with basicConfig for simple scripts and graduate to the logger/handler system for more complex applications.
