When implementing logging in your application, structure your log messages and parameters consistently to improve readability, searchability, and integration with monitoring tools. Consider these practices:
When implementing logging in your application, structure your log messages and parameters consistently to improve readability, searchability, and integration with monitoring tools. Consider these practices:
logger.exception()
only when capturing the current exception contextlogger.error()
with explicit exc_info=True
when you need to include exception details outside of an exception handler# Correct: Inside an exception handler
try:
dangerous_operation()
except Exception:
logger.exception("Operation failed") # Automatically includes traceback
# Correct: Outside an exception handler
if error_occurred:
logger.error("Operation failed", exc_info=True) # Explicitly include traceback
extra
parameter to add structured fields to your logs# Good: Structured logging with extra parameters
logger.debug(
"Query executed: %(sql)s; duration=%(duration).3f; alias=%(alias)s",
extra={
"duration": duration,
"sql": sql,
"params": params,
"alias": connection.alias,
}
)
# Performance-aware formatter
def format(self, record):
# Cache formatted values to avoid repeated processing
sql = None
formatted_sql = None
if args := record.args:
if isinstance(args, dict) and (sql := args.get("sql")):
args["sql"] = formatted_sql = format_sql(sql)
# Reuse formatted value if it's the same SQL
if extra_sql := getattr(record, "sql", None):
if extra_sql == sql:
record.sql = formatted_sql
else:
record.sql = format_sql(extra_sql)
return super().format(record)
By following these practices, you’ll create logs that are more useful for debugging, monitoring, and analysis while avoiding common performance pitfalls.
Enter the URL of a public GitHub repository