JSON formatter for Python's built-in logging package that enables structured, machine-readable log output
—
Functions for serializing complex Python types to JSON-compatible formats. The defaults module provides extensible type conversion system used by JSON formatters to handle non-standard Python objects.
import pythonjsonlogger.defaults as defaultsFor type checking:
from typing import Any, TypeGuard
from types import TracebackType
import datetime
import enum
import uuidFunctions that handle any object type as a fallback.
def unknown_default(obj: Any) -> str:
"""
Backup default function for any object type.
Attempts str() then repr(), falls back to placeholder string.
Parameters:
- obj: object to handle
Returns:
String representation or "__could_not_encode__"
"""Functions for handling Python type/class objects.
def use_type_default(obj: Any) -> TypeGuard[type]:
"""
Check if object is a type/class object.
Parameters:
- obj: object to check
Returns:
True if obj is a type object
"""
def type_default(obj: type) -> str:
"""
Convert type object to string representation.
Parameters:
- obj: type object to handle
Returns:
Class name as string
"""Functions for serializing dataclass instances.
def use_dataclass_default(obj: Any) -> bool:
"""
Check if object is a dataclass instance.
Parameters:
- obj: object to check
Returns:
True if obj is a dataclass instance (not class)
"""
def dataclass_default(obj) -> dict[str, Any]:
"""
Convert dataclass instance to dictionary.
Parameters:
- obj: dataclass instance to handle
Returns:
Dictionary representation of dataclass fields
"""Functions for handling various datetime types.
def use_time_default(obj: Any) -> TypeGuard[datetime.time]:
"""Check if object is datetime.time instance."""
def time_default(obj: datetime.time) -> str:
"""
Convert time object to ISO format string.
Parameters:
- obj: time object to handle
Returns:
ISO format time string
"""
def use_date_default(obj: Any) -> TypeGuard[datetime.date]:
"""Check if object is datetime.date instance."""
def date_default(obj: datetime.date) -> str:
"""
Convert date object to ISO format string.
Parameters:
- obj: date object to handle
Returns:
ISO format date string
"""
def use_datetime_default(obj: Any) -> TypeGuard[datetime.datetime]:
"""Check if object is datetime.datetime instance."""
def datetime_default(obj: datetime.datetime) -> str:
"""
Convert datetime object to ISO format string.
Parameters:
- obj: datetime object to handle
Returns:
ISO format datetime string
"""
def use_datetime_any(obj: Any) -> TypeGuard[datetime.time | datetime.date | datetime.datetime]:
"""Check if object is any datetime-related type."""
def datetime_any(obj: datetime.time | datetime.date | datetime.datetime) -> str:
"""
Convert any datetime-related object to ISO format string.
Parameters:
- obj: datetime-related object to handle
Returns:
ISO format string representation
"""Functions for serializing exceptions and traceback objects.
def use_exception_default(obj: Any) -> TypeGuard[BaseException]:
"""
Check if object is an exception instance.
Parameters:
- obj: object to check
Returns:
True if obj is BaseException instance
"""
def exception_default(obj: BaseException) -> str:
"""
Convert exception to string representation.
Parameters:
- obj: exception instance to handle
Returns:
String in format "ExceptionClass: message"
"""
def use_traceback_default(obj: Any) -> TypeGuard[TracebackType]:
"""
Check if object is a traceback object.
Parameters:
- obj: object to check
Returns:
True if obj is traceback object
"""
def traceback_default(obj: TracebackType) -> str:
"""
Convert traceback to formatted string.
Parameters:
- obj: traceback object to handle
Returns:
Formatted traceback string
"""Functions for serializing enum objects and classes.
def use_enum_default(obj: Any) -> TypeGuard[enum.Enum | enum.EnumMeta]:
"""
Check if object is enum instance or enum class.
Parameters:
- obj: object to check
Returns:
True if obj is enum instance or enum class
"""
def enum_default(obj: enum.Enum | enum.EnumMeta) -> Any | list[Any]:
"""
Convert enum to value representation.
For enum instances returns the value.
For enum classes returns list of all values.
Parameters:
- obj: enum instance or class to handle
Returns:
Enum value or list of enum values
"""Functions for serializing UUID objects.
def use_uuid_default(obj: Any) -> TypeGuard[uuid.UUID]:
"""
Check if object is UUID instance.
Parameters:
- obj: object to check
Returns:
True if obj is UUID instance
"""
def uuid_default(obj: uuid.UUID) -> str:
"""
Convert UUID to hyphenated string format.
Parameters:
- obj: UUID object to handle
Returns:
UUID string in hyphenated format
"""Functions for serializing bytes and bytearray objects.
def use_bytes_default(obj: Any) -> TypeGuard[bytes | bytearray]:
"""
Check if object is bytes or bytearray.
Parameters:
- obj: object to check
Returns:
True if obj is bytes or bytearray
"""
def bytes_default(obj: bytes | bytearray, url_safe: bool = True) -> str:
"""
Convert bytes to base64 string representation.
Parameters:
- obj: bytes or bytearray object to handle
- url_safe: use URL-safe base64 character set
Returns:
Base64 encoded string
"""from pythonjsonlogger.json import JsonFormatter
import pythonjsonlogger.defaults as defaults
import decimal
import pathlib
def custom_json_default(obj):
# Handle custom types
if isinstance(obj, decimal.Decimal):
return float(obj)
elif isinstance(obj, pathlib.Path):
return str(obj)
# Use built-in type handlers
if defaults.use_datetime_any(obj):
return defaults.datetime_any(obj)
elif defaults.use_dataclass_default(obj):
return defaults.dataclass_default(obj)
elif defaults.use_enum_default(obj):
return defaults.enum_default(obj)
elif defaults.use_exception_default(obj):
return defaults.exception_default(obj)
# Fallback
return defaults.unknown_default(obj)
# Use custom default function
formatter = JsonFormatter(
'%(levelname)s %(message)s',
json_default=custom_json_default
)import pythonjsonlogger.defaults as defaults
def build_json_default(*handlers):
"""Build a composite default function from multiple type handlers."""
def json_default(obj):
# Try each handler in order
for use_func, default_func in handlers:
if use_func(obj):
return default_func(obj)
# Final fallback
return defaults.unknown_default(obj)
return json_default
# Create composite handler
custom_default = build_json_default(
(defaults.use_datetime_any, defaults.datetime_any),
(defaults.use_dataclass_default, defaults.dataclass_default),
(defaults.use_enum_default, defaults.enum_default),
(defaults.use_exception_default, defaults.exception_default),
(defaults.use_uuid_default, defaults.uuid_default),
)import logging
from pythonjsonlogger.json import JsonFormatter
from dataclasses import dataclass
from enum import Enum
from datetime import datetime
import uuid
@dataclass
class User:
id: int
name: str
email: str
class Status(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
# Set up logger with JSON formatter
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = JsonFormatter('%(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# Log complex objects - they'll be automatically converted
user = User(id=123, name="John Doe", email="john@example.com")
status = Status.ACTIVE
timestamp = datetime.now()
session_id = uuid.uuid4()
logger.info("User logged in", extra={
"user": user, # Converted to dict
"status": status, # Converted to "active"
"login_time": timestamp, # Converted to ISO string
"session_id": session_id # Converted to UUID string
})from pythonjsonlogger.json import JsonFormatter
import pythonjsonlogger.defaults as defaults
def custom_bytes_handler(obj):
if defaults.use_bytes_default(obj):
# Use standard base64 instead of URL-safe
return defaults.bytes_default(obj, url_safe=False)
return defaults.unknown_default(obj)
formatter = JsonFormatter(
'%(levelname)s %(message)s',
json_default=custom_bytes_handler
)
# Log with bytes data
logger.info("Binary data received", extra={
"data": b"some binary data" # Will be base64 encoded
})These types are handled by the JsonEncoder automatically:
Functions starting with use_ act as TypeGuard functions for type checking and provide type narrowing for mypy and other type checkers.
All default functions are designed to never raise exceptions. The unknown_default function provides a safe fallback that attempts multiple conversion methods before returning a placeholder string.
Install with Tessl CLI
npx tessl i tessl/pypi-python-json-logger