Before jumping into the example scripts, let me give you a quick overview of loggers, the backbone of Python logging.
- A logger is an object provided by Python's logging module that your application uses to record events (messages) during execution. Each logger has a name and a level; loggers form a hierarchy (for example, "app" is a parent of "app.module") and decide whether to pass a message on to handlers based on its level.
Why use loggers?
- Visibility: Record runtime information for debugging and monitoring without sprinkling print() calls throughout code.
- Control: Attach handlers to route messages to different destinations (console, files, syslog, external services) and use formatters to standardize output.
- Configurability: Change levels, formats and handlers without touching application logic (ideal for production vs. development).
- Performance: Logging can be filtered efficiently by level so expensive message construction can be avoided when not needed.
This repo has a collection of small scripts that show common logging patterns in Python. Each script focuses on one concept, with just enough code to explain how it works.
The goal is simple: go through these examples to understand how to set up logging, add handlers, format logs, and configure them properly.
main.py
: Basic logging and logging.basicConfig
- Purpose: Show basic usage of the root logger, the logging levels, and how calling logging.basicConfig controls output format and level.
- Key lines:
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
: Sets the root logging level and message format. (See line referenced in original script.)logging.debug/info/warning/error/critical(...)
: Examples of messages at each level.
- What this demonstrates:
- By default the root logger prints WARNING and above. basicConfig lets you lower that to DEBUG so everything is shown.
- The format string includes a timestamp, the logger name, the level and the message.
- Result:
- All five messages (DEBUG...CRITICAL) should appear in the console because basicConfig set level to DEBUG.
custom_logger.py
: Creating a named logger and stopping propagation
- Purpose: Demonstrates creating a module-level named logger and disabling propagation so messages aren't duplicated when imported by other modules.
- Key lines:
logger = logging.getLogger(__name__)
: Creates a logger named after the module (usually 'custom_logger').logger.propagate = False
: Prevents messages from being passed to the root logger (useful when you attach your own handlers).
- What this demonstrates:
- Use named loggers in libraries to avoid forcing global configuration on the application.
- Propagation can cause duplicate messages if both the module and the root logger have handlers.
- Result:
- The module logs the initialization message via the named logger. If you import it into a script that has a configured root logger, disabling propagation prevents duplicates.
custom_config.py
: Using a config file with logging.config.fileConfig
- Purpose: Demonstrates loading logger configuration from a file (custom.conf) using fileConfig.
- Key lines:
logging.config.fileConfig('custom.conf')
: Loads handlers/formatters/levels as defined in the config file.logger = logging.getLogger('myLogger')
: Obtains the logger defined inside the configuration file.
- What this demonstrates:
- Externalizing logging configuration is a good practice for complex applications. You can change handlers or levels without changing code.
- How to run:
- python custom_config.py
- Make sure
custom.conf
is in the same directory (it is in this repo).
- What to look for:
- The message logged with logger.debug(...) will appear or not depending on the config file's level settings. Inspect
custom.conf
to see configured handlers and levels.
- The message logged with logger.debug(...) will appear or not depending on the config file's level settings. Inspect
handlers.py
: Multiple handlers with different levels and formatters
- Purpose: Show how to attach multiple handlers (console and file) to a logger and set levels/formatters per handler.
- Key lines:
- Whole Code so please refer
.py
file, pweaseee...
- Whole Code so please refer
- What this demonstrates:
- Handlers let you send different severities to different places (console vs file).
- Formatters let each handler present messages differently.
- Result:
- The WARNING message will print to the console.
- The ERROR message will be written to
file.log
(this message will print to the console as well, refer comment in code file).
add_traces.py
: Logging exceptions with traceback/exc_info
- Purpose: Demonstrates two ways to include stack traces in logs when exceptions occur.
- Key lines and methods:
logging.error(e, exc_info=True)
: Passes the exception info to the logger which prints the traceback.- Using the traceback module and
logging.error(traceback.format_exc())
: Formats the traceback as a string and logs it.
- What this demonstrates:
- Prefer logger.exception() inside an except block (not shown in the example) because it both logs the message and the traceback at ERROR level.
- Result:
- The logged messages include a full traceback which helps debugging.
rotating_filehandler.py
: Size/Time based rotating log files
- Purpose: Demonstrates the use of TimedRotatingFileHandler (and comments mention RotatingFileHandler) to rotate logs based on time or size.
- Key lines:
- Whole Code so please refer
.py
file, here we go again \^o^/
- Whole Code so please refer
- What this demonstrates:
- Timed rotation creates new files at the specified interval and keeps only backupCount files.
- RotatingFileHandler does size based rotation (see commented example in the file).
- How to run:
- python rotating_filehandler.py
- Observe files like
app.log.1
andtimed_logging.log.2025-09-21_05-40-17
appearing in the directory.
- Result:
- New rotated files created at the interval; older files removed when backupCount is exceeded.
- Prefer getting a named logger with
logging.getLogger(__name__)
in libraries; configure logging in your application entry point. - Avoid logging configuration inside library modules, load config from your application or a dedicated config file.
- Use logger.exception("message") inside except blocks to include tracebacks automatically.
- Use handlers for separating concerns (console vs file vs remote sink). Each handler can have its own level and formatter.
- Use RotatingFileHandler or TimedRotatingFileHandler in long running processes to prevent log files from growing without bound.
- Keep formats stable (use ISO8601 timestamps) when logs are consumed by machines.