Skip to content

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.