Simplify Python Logging with a Wrapper that Captures Accurate Call Sites
Learn how to create a Python logging wrapper that reduces repetitive code, ensures log entries show the correct filename and line number using the inspect module, and loads configuration once for global use, improving readability and maintainability in large applications.
Motivation for a logging wrapper
Direct use of Python's logging module in many places leads to repetitive boiler‑plate and, when the calls are wrapped, the recorded filename and line number point to the wrapper instead of the real call site. A thin wrapper class can centralise configuration, eliminate duplication, and preserve accurate caller information.
Implementation
The wrapper is a class with class‑level logger configuration and convenience methods for each log level. The configuration file is loaded once at class definition time.
import logging
import logging.config
import inspect
class Log(object):
# Load configuration a single time
logging.config.fileConfig('/etc/logging.conf')
__logger = logging.getLogger('script')
@classmethod
def set_level(cls, level):
cls.__logger.setLevel(level)
@classmethod
def debug(cls, msg, *args, **kwargs):
cls._log(logging.DEBUG, msg, *args, **kwargs)
@classmethod
def info(cls, msg, *args, **kwargs):
cls._log(logging.INFO, msg, *args, **kwargs)
@classmethod
def warning(cls, msg, *args, **kwargs):
cls._log(logging.WARNING, msg, *args, **kwargs)
@classmethod
def error(cls, msg, *args, **kwargs):
cls._log(logging.ERROR, msg, *args, **kwargs)
@classmethod
def critical(cls, msg, *args, **kwargs):
cls._log(logging.CRITICAL, msg, *args, **kwargs)
@classmethod
def _log(cls, level, msg, *args, **kwargs):
# Retrieve the frame of the original caller (two levels up)
frame = inspect.currentframe().f_back.f_back
caller = inspect.getframeinfo(frame)
# Pass accurate filename and line number via the extra dict
cls.__logger.log(level, msg, *args, **kwargs,
extra={'filename': caller.filename,
'lineno': caller.lineno})
@classmethod
def get_logger(cls):
return cls.__loggerHow caller information is obtained
The inspect module inspects the call stack at runtime. In _log the following steps are performed: inspect.currentframe() returns the current stack frame (the _log method). .f_back moves one level up to the public wrapper method ( debug, info, etc.). .f_back.f_back reaches the frame that invoked the wrapper, i.e., the real call site in user code. inspect.getframeinfo(frame) extracts filename and lineno, which are then supplied to the logger via the extra argument.
Convenient logging methods
Each log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) is exposed as a class method that forwards its arguments to _log. This allows developers to write concise statements such as Log.info('operation completed') without manually obtaining a logger or handling configuration.
Configuration loading
The call to logging.config.fileConfig('/etc/logging.conf') occurs when the class is defined, ensuring the configuration file is parsed only once. All subsequent logging calls share the same settings, eliminating repeated I/O and guaranteeing consistent formatting, handlers, and level thresholds across the entire application.
Benefits
Simplified usage : One‑line calls ( Log.debug(...), Log.error(...)) replace repetitive logger acquisition code.
Accurate source location : By inspecting two frames up, the log record contains the true filename and line number of the original call.
Single configuration load : The logging configuration is read once, reducing overhead and ensuring uniform behavior.
Conclusion
Wrapping the standard logging module in a lightweight class that leverages inspect solves the common problem of misplaced log locations while keeping the API terse. This pattern is especially valuable in large Python projects where consistent, readable logging and minimal boiler‑plate are critical for debugging and maintenance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
