dossier.dossier
dossier.dossier
_logger_cache
module-attribute
_logger_cache = {}
_cache_lock
module-attribute
_cache_lock = Lock()
_structlog_configured
module-attribute
_structlog_configured = False
Dossier
Session-based structured logger with smart object unpacking and flexible metadata.
Wraps structlog for session management and automatic object unpacking.
__init__
__init__(
session_id,
session_dir,
stdlib_logger_base_name,
processors=None,
)
Internal initialization - use get_session() instead.
info
info(event=None, **kwargs)
Log info-level event.
error
error(event=None, **kwargs)
Log error-level event.
debug
debug(event=None, **kwargs)
Log debug-level event.
warning
warning(event=None, **kwargs)
Log warning-level event.
bind
bind(namespace=None, **kwargs)
Add context to logger for subsequent log calls.
Example
logger.bind(request_id="abc-123", user_id="user_456") logger.info("processing_request")
Includes: request_id="abc-123", user_id="user_456"
Bind to specific namespace:
logger.bind(worker_id="w1", namespace="worker") logger.info("task", namespace="worker") # Has worker_id="w1"
unbind
unbind(*keys, namespace=None)
Remove context keys from logger.
Example
logger.bind(request_id="123", user_id="456") logger.info("test") # Has both
logger.unbind("request_id") logger.info("test2") # Only has user_id
Unbind from specific namespace:
logger.unbind("worker_id", namespace="worker")
get_session_path
get_session_path()
Get the path to the current session directory.
get_session_id
get_session_id()
Get the current session ID.
make_json_safe
make_json_safe(logger, method_name, event_dict)
Convert non-JSON-serializable values to strings.
unpack_objects
unpack_objects(logger, method_name, event_dict)
Unpack dataclasses, Pydantic models, and generic objects to dicts.
Priority: dataclass > Pydantic model_dump > generic dict.
_infer_event_type_from_object
_infer_event_type_from_object(obj)
Infer event type from object class name.
infer_event
infer_event(func)
Decorator that handles event type inference from objects.
If the first arg (event) is an object (not a string): - Infers event type from class name - Adds object to kwargs as "_obj" for unpacking processor - Calls the underlying method with inferred event type
_ensure_structlog_configured
_ensure_structlog_configured()
Configure structlog once globally if not already configured.
_create_logger_infrastructure
_create_logger_infrastructure(
log_file, stdlib_logger_name, processors=None
)
Create a logger for a specific namespace.
get_session
get_session(
log_dir="logs",
session_id=None,
processors=None,
force_new=False,
)
Get or create a dossier logging session. Returns existing session if session_id already exists.
Similar to logging.getLogger(name), this function caches session instances by session_id. Subsequent calls with the same session_id return the cached instance.
The session_id is user-facing and simple (e.g., "main", "production"), while the actual log directory is timestamped (e.g., "main_20251118_120000/"). This allows easy session retrieval while maintaining chronological organization of log files.
Namespaced Logging:
Use the namespace kwarg on logging methods to route logs to separate files:
logger = get_session(session_id="main")
logger.info("event") # logs to events.jsonl
logger.info("event", namespace="worker") # logs to worker.jsonl
logger.info("event", namespace="api.requests") # logs to api.requests.jsonl
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
log_dir
|
str | Path
|
Directory to store log files |
'logs'
|
session_id
|
str | None
|
Simple session identifier (e.g., "main", "worker"). If None, defaults to "session". |
None
|
processors
|
list[Any] | None
|
Optional list of custom structlog processors |
None
|
force_new
|
bool
|
If True, creates new timestamped log directory even if session_id exists in cache. Useful for restarting sessions with same name. |
False
|
Returns:
| Type | Description |
|---|---|
Dossier
|
Started Dossier instance (either cached or newly created) |
Example
Simple session ID, timestamped directory created automatically
logger = get_session(session_id="main")
Logs to: logs/main_TIMESTAMP/events.jsonl
Subsequent calls return the same instance
logger2 = get_session(session_id="main") assert logger is logger2
Namespaced logging - single logger, multiple files
logger.info("event", namespace="worker") # logs to main_TIMESTAMP/worker.jsonl
Force new session - creates new timestamped directory
logger3 = get_session(session_id="main", force_new=True)
Logs to: logs/main_NEW_TIMESTAMP/events.jsonl
Now logger3 is cached under "main"
With context manager (auto-closes session on exit)
with get_session(session_id="task1") as logger: logger.info("log to temporary session")
close_session
close_session(session_id)
Close session and all the namespaced loggers.
Raises:
| Type | Description |
|---|---|
KeyError
|
If session_id is not found in the cache. |