logging-json
logging-json is a Python library that provides a JSON formatter for the standard `logging` module, allowing applications to output logs in a structured JSON format. This is particularly useful for centralized logging systems and machine readability. The current version is 0.6.0, and it generally maintains an active release cadence with periodic updates for bug fixes and new features.
Common errors
-
TypeError: Object of type <YourCustomType> is not JSON serializable
cause You are attempting to log an object of a custom type or a non-standard Python type (e.g., a `set`) directly in your log message or within the `extra` dictionary, and the default JSON encoder does not know how to serialize it.fixBefore logging, convert the object to a basic JSON-serializable type (e.g., `str(obj)`, `list(obj_set)`, `obj.to_dict()`). Alternatively, for more advanced cases, you can provide a custom `json_encoder` argument to `JSONFormatter` to handle specific types. -
Logs are not appearing in JSON format, or default Python log format is shown.
cause The `JSONFormatter` was either not correctly assigned to a handler, or the handler with the `JSONFormatter` was not added to the logger instance. This can also happen if `basicConfig` overrides custom handler setup.fixVerify that `handler.setFormatter(json_formatter)` was called with your `JSONFormatter` instance and that `logger.addHandler(handler)` was called for each logger you intend to use. Avoid using `logging.basicConfig()` after custom handler setup, or ensure your `basicConfig` setup explicitly configures the desired handler and formatter. -
AttributeError: 'dict' object has no attribute 'str' (or similar error related to extra fields)
cause In older versions (prior to 0.6.0), there were specific bugs related to how `extra` dictionary values were processed, particularly when they were complex objects or dictionaries themselves. This could lead to unexpected `AttributeError` when the formatter tried to apply `str()` to an already-dict-like object.fixUpgrade `logging-json` to version 0.6.0 or higher, which includes fixes for how `extra` fields are handled. Always ensure the values in your `extra` dictionary are fundamentally JSON-serializable (strings, numbers, lists, etc.) to prevent such issues.
Warnings
- breaking Versions 0.5.0 and later of `logging-json` require Python 3.9 or higher. Previous versions supported Python 3.7+.
- gotcha The `extra` dictionary passed to logging calls is merged directly into the top-level JSON object. Ensure values within `extra` are JSON-serializable or expect them to be stringified by default. Complex objects (e.g., custom classes) can lead to serialization errors if not handled.
- gotcha Directly using `logging.basicConfig()` with `logging-json` can be tricky as `basicConfig` doesn't easily allow setting a custom formatter with specific parameters beyond a basic format string. You often need to manually configure handlers.
Install
-
pip install logging-json
Imports
- JSONFormatter
from logging_json import JSONFormatter
Quickstart
import logging
from logging_json import JSONFormatter
import sys
# Configure a logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# Create a stream handler (e.g., to stdout)
handler = logging.StreamHandler(sys.stdout)
# Create a JSON formatter instance
# Optional: Customize indentation, ASCII encoding, or datetime format
formatter = JSONFormatter(
json_indent=2, # Pretty-print JSON
json_ensure_ascii=False, # Allow non-ASCII characters directly
datetime_format="%Y-%m-%dT%H:%M:%S%z" # Custom datetime format with timezone
)
# Set the formatter for the handler
handler.setFormatter(formatter)
# Add the handler to the logger
logger.addHandler(handler)
# Log messages with standard fields and extra context
logger.info("This is an info message.")
logger.warning("Something potentially bad happened.", extra={"user_id": 123, "session": "abc"})
try:
raise ValueError("Example error")
except ValueError:
# logger.exception automatically includes traceback
logger.exception("An error occurred during processing.")
logger.debug("This message will not be shown as level is INFO.")