
May 15, 2025
Introducing Annotated Logger: A Python Package to Aid in Adding Metadata to Logs
Introducing Annotated Logger: A Python Package to Aid in Adding Metadata to Logs
Ever struggled to identify that one important piece of information in countless log files? Logs should simplify debugging, but without metadata, they become chaotic. What if you could automatically add significant context to your logs without manually adding fields?
This is why Annotated Logger exists. Add structured information easily using this open-source Python module to improve logging. No longer using duplicate log fields across functions, from now on. A simple decorator makes logs smart, searchable, and simpler to deal with. Let's try it!
Why Annotated Logger?
Logging becomes a problem in big Python projects. Although Python's built-in logging module is excellent, adding custom metadata like request IDs, Git branches, or runtime metrics requires explicitly supplying additional fields everywhere.
I have managed logs across different projects, duplicating code to guarantee context. This is when Annotated Logger became life saver for me.
This package lets you:
- Automatically integrate metadata such as; function names, timestamps, and custom fields.
- Decorate functions for easy logging
- Filter logs with structured JSON output in Splunk
- Manage errors graciously with automated exception logging.
Let's install and test it.
Install & Setup
Initial setup of Annotated Logger is as simple as running:
pip install annotated-logger
First, let us set up a logger and check it out:
from annotated_logger import AnnotatedLogger
al = AnnotatedLogger(name="example_logger", annotations={"env": "production"})
annotate_logs = al.annotate_logs
Finished! We now have a working logger that automatically adds metadata in our logs. Now it's time to make if functional.
Using Annotated Logger in Your Code
Decorator @annotate_logs() does magic. Put this decorator on top of every function to let Annotated Logger handle logging.
Here's a simple example:
@annotate_logs()
def greet():
return "Hello, Logger!"
print(greet())
And here's what the output looks like:
{
"created": 1733176439.5067494,
"levelname": "INFO",
"name": "annotated_logger.example",
"message": "Function executed successfully",
"success": true
}
See that? It logs/records function execution with timestamps, log levels, and function names. No manual logs required!
Adding Custom Metadata
My favorite part about Annotated Logger is how simple custom annotations are. You may annotate a function to log which user triggered it:
@annotate_logs()
def user_login(annotated_logger, username):
annotated_logger.annotate(user=username)
annotated_logger.info("User logged in.")
user_login("admin")
All log entries from this function now contain the username. This is helpful for multi-user application debugging!
Handling Errors Like a Pro
We all know logs are most valuable in emergencies. The good news? Without your intervention, Annotated Logger logs exceptions.
Consider a function that may cause an error:
@annotate_logs()
def divide(a, b):
return a / b
try:
divide(10, 0)
except ZeroDivisionError:
print("Oops! Something went wrong.")
Here's the log output when an error occurs:
{
"created": 1733349913.7200255,
"levelname": "ERROR",
"name": "annotated_logger.example",
"message": "ZeroDivisionError: division by zero",
"success": false
}
Do not wrap every function in try-except blocks to log errors. Annotated Logger saves you!
Logging for Classes
While functions are fantastic, what if you want to log every class method? Decorate the class to provide every method an annotated_logger object.
@annotate_logs()
class Calculator:
def add(self, a, b):
return a + b
def multiply(self, a, b):
return a * b
calc = Calculator()
print(calc.add(2, 3))
print(calc.multiply(4, 5))
Logging every method call is now automatic. This is the next level of debugging power!
Plugins: Extend Logging Even Further
Another nice feature? Plugins. Annotated Logger has plugins for redacting sensitive data and interacting with third-party monitoring programs.
Suppose you want to keep passwords confidential in logs. Make a plugin like this:
from annotated_logger.plugins import BasePlugin
class RedactPlugin(BasePlugin):
def filter(self, record):
record.msg = record.msg.replace("password", "******")
return True
Now, any log message containing the word "password" will automatically be censored.
Performance Considerations
Does adding metadata slow things down? The good news is that no, not very much. Annotated Logger is perfect for adding metadata with very little slowdown.
However, set log levels suitably in high-frequency routines to minimize unwanted log entries.
Conclusion
If you suffer with unstructured logs, Annotated Logger changes everything. Automatically adding metadata, resolving errors, and making logs searchable, organized, and simpler to deal with simplifies logging.
So, why log manually after reading this? Try Annotated Logger to manage your logs immediately!
58 views