How to log source file name and line number in Python
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Python's built-in logging module can include the source file name and line number automatically. In most cases, you do not need stack inspection or custom logger classes. You only need the right format string, and in wrapper-heavy code you may also need stacklevel so the log points to the caller instead of the helper function.
The Basic Formatter Fields
The two most common fields are:
- '
%(filename)sfor the file name' - '
%(lineno)dfor the source line number'
A minimal working example:
Typical output looks like:
This is the simplest and usually the correct solution.
Useful Variants of the File Information
Depending on how much detail you want, you can also use:
- '
%(pathname)sfor the full file path' - '
%(module)sfor the module name' - '
%(funcName)sfor the function name'
Example:
This is helpful when short file names are not unique across a larger codebase.
Logger Objects Work the Same Way
You do not have to use the root logger.
The key idea is the same: source metadata comes from the log record, and the formatter decides whether to display it.
The Wrapper Problem and stacklevel
If you wrap logging calls in helper functions, the logged file name and line number will point at the helper, not at the original caller.
That reports the line inside log_info, which is often not what you want.
Use stacklevel to shift the reported source location outward:
Now the log points to the caller of log_info, which is usually the real source location you care about.
When Full Paths Are Better Than File Names
%(filename)s is compact, but it can be ambiguous if multiple modules share the same file name, such as utils.py. In those cases, %(pathname)s or %(name)s may be more useful.
A common production compromise is:
That keeps logs readable while still giving enough context.
Avoid Manual Frame Inspection Unless You Really Need It
The logging module already captures filename and line information for you. Manual inspection through inspect or sys._getframe is usually unnecessary unless you are building a custom logging framework.
The built-in logging machinery is simpler and less fragile.
Common Pitfalls
- Using a formatter that omits
%(filename)sand%(lineno)d, then trying to recover the data manually. - Forgetting that wrapper functions change the apparent call site.
- Using
%(filename)swhen identical file names exist in multiple packages. - Adding custom stack inspection even though the standard logging record already has the data.
- Expecting line numbers to point at the original business call when a helper wrapper did not pass
stacklevel.
Summary
- Use
%(filename)sand%(lineno)din the logging format string to log source location. - '
%(pathname)sand%(funcName)sare useful when you need more context.' - Custom logger instances work the same way as the root logger.
- When logging through helper functions, use
stacklevelso the location points at the true caller. - The built-in logging module already provides this metadata without custom frame inspection.
Related reading
- how to log Spring 5 WebClient call
- How to log the active configuration in a Spring Boot application?
- How to log Trace messages with log4net?
- How to make nested variables optional in Helm
- How to loop backwards in python?
- How to loop over grouped Pandas dataframe?
- How to manage exceptions thrown in filters in Spring?
- How to monitor dead relus

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.