> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bioptimus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# bioptimus.observability.logging

Structured JSON logging for the SDK.

Provides a JSON log formatter, a helper for emitting structured events with a machine-readable error code and arbitrary fields, and a [`configure_logging`](/sdk-reference/observability/logging#configure_logging) entry point for explicit setup.

Logging works with zero setup: importing the package has no side effects, but the first emitted event auto-installs a default file handler (see [`default_log_file`](/sdk-reference/observability/logging#default_log_file)) so a durable record always exists; the console stays silent unless `configure_logging(console=True)` (or an explicit `stream`) is passed, and records always propagate to the application's own logging hierarchy. Call [`configure_logging`](/sdk-reference/observability/logging#configure_logging) to override the destination, level, or anonymization, or set `BIOPTIMUS_LOG_FILE` to redirect the file. Setting `BIOPTIMUS_LOG_FILE` to an empty string disables the SDK's own **file** sink and auto-init — it does not silence logging, since records still propagate to any handlers the host application (or `configure_logging(console=True)`) has installed. Each emitted line carries a timestamp, the level, an `event` slug (the log message), the active `run -> slide -> request` correlation context, any structured fields passed via [`log_event`](/sdk-reference/observability/logging#log_event), and an optional `error_code`. PII is redacted by `bioptimus.observability.anonymize.AnonymizingFilter` when enabled.

***

#### STRUCTURED\_KEY

Custom LogRecord attribute holding the structured-field payload.

## JsonFormatter

```python theme={null}
class JsonFormatter(logging.Formatter)
```

Formats log records as single-line JSON objects.

The output object always includes `timestamp` (ISO 8601, UTC), `level`, `event` (the formatted message), and `logger`. Structured fields attached via [`log_event`](/sdk-reference/observability/logging#log_event), together with the active correlation context, are merged in at the top level. Exception and stack information, when present, are rendered under `exception` and `stack`.

***

#### format

```python theme={null}
def format(record: logging.LogRecord) -> str
```

Renders the record as a JSON string.

<ParamField body="record">
  The log record to serialize.
</ParamField>

**Returns**:

A single-line JSON document describing the record.

## ConsoleFormatter

```python theme={null}
class ConsoleFormatter(logging.Formatter)
```

Human-readable single-line formatter for console output.

Renders `timestamp level event [key=value ...]` so logs are easy to scan in a terminal or notebook, while the file handler retains full JSON.

***

#### format

```python theme={null}
def format(record: logging.LogRecord) -> str
```

Renders the record as a readable text line.

<ParamField body="record">
  The log record to format.
</ParamField>

**Returns**:

A human-readable single-line message, or a compact multiline
message when structured fields are present.

***

#### log\_event

```python theme={null}
def log_event(logger: logging.Logger,
              level: int,
              event: str,
              *,
              error_code: ErrorCode | str | None = None,
              exc_info: bool | BaseException = False,
              fields: dict[str, Any] | None = None,
              **extra: Any) -> None
```

Emits a structured log event.

<ParamField body="logger">
  The logger to emit on.
</ParamField>

<ParamField body="level">
  The logging level, for example `logging.WARNING`.
</ParamField>

<ParamField body="event">
  A short, stable event slug used as the log message, for example `"wsi_backend_unavailable"`.
</ParamField>

<ParamField body="error_code">
  Optional machine-readable error code recorded under `error_code`.
</ParamField>

<ParamField body="exc_info">
  Exception information forwarded to the logging call, enabling an `exception` field in the output.
</ParamField>

<ParamField body="fields">
  Structured fields supplied as a single dict, merged into the log object. Callers with untrusted keys (for example an error's `context`) pass them here so a key such as `error_code` cannot collide with this function's named parameters. Explicit `extra` keyword arguments win on collision.
</ParamField>

<ParamField body="**extra">
  Structured fields supplied as keyword arguments, for example `backend="cucim"` or `reason="missing library"`. Convenient for hardcoded literals at the call site.
</ParamField>

***

#### log\_error

```python theme={null}
def log_error(logger: logging.Logger,
              error: BioptimusError,
              *,
              level: int = logging.ERROR,
              exc_info: bool | BaseException = False,
              **fields: Any) -> None
```

Logs a [`BioptimusError`](/sdk-reference/observability/errors#bioptimuserror) once, with its code, context, and fix.

Flattens the error's structured `context` and attaches its machine-readable `error_code`, `message`, and `remediation` so a single boundary log line fully explains the failure and how to resolve it. Extra `fields` override context entries on collision.

<ParamField body="logger">
  The logger to emit on.
</ParamField>

<ParamField body="error">
  The typed error to record.
</ParamField>

<ParamField body="level">
  The logging level. Defaults to `logging.ERROR`.
</ParamField>

<ParamField body="exc_info">
  Exception information forwarded to the logging call, enabling an `exception` field in the output.
</ParamField>

<ParamField body="**fields">
  Extra structured fields merged on top of the error context.
</ParamField>

***

#### is\_logged

```python theme={null}
def is_logged(exc: BaseException) -> bool
```

Reports whether a boundary has already logged an exception.

<ParamField body="exc">
  The exception to inspect.
</ParamField>

**Returns**:

`True` when a [`log_failures`](/sdk-reference/observability/logging#log_failures) boundary has already recorded the
exception, so an outer boundary can avoid logging it a second time.

***

#### log\_failures

```python theme={null}
def log_failures(func: F | None = None,
                 *,
                 logger: logging.Logger | None = None,
                 level: int = logging.ERROR) -> F | Callable[[F], F]
```

Logs any failure from a public SDK call once, then re-raises it unchanged.

Wraps a public function or method so that any `Exception` it raises is recorded exactly once before propagating: a `BioptimusError` is logged with its code, context, and remediation, and any other exception with its type and message, each with a full traceback. The original exception is re-raised unchanged, so existing `except` handlers and return contracts are preserved.

Recording the failure at the boundary the user called guarantees a durable record reaches the configured sink (see [`configure_logging`](/sdk-reference/observability/logging#configure_logging)) even if the process or its console is killed afterwards. Internal helpers do not log; they raise, and the outermost boundary records the failure once. A marker on the exception keeps an outer boundary from logging it again. Both synchronous and asynchronous callables are supported; `KeyboardInterrupt`, `SystemExit`, and `asyncio.CancelledError` do not derive from `Exception` and are never caught.

<ParamField body="func">
  The callable to wrap, supplied automatically when used as a bare `@log_failures` decorator.
</ParamField>

<ParamField body="logger">
  Logger to record on. Defaults to the logger named after the wrapped callable's module.
</ParamField>

<ParamField body="level">
  Level for the boundary log line. Defaults to `logging.ERROR`.
</ParamField>

**Returns**:

The wrapped callable when *func* is given, otherwise a decorator that
wraps a callable.

***

#### default\_log\_file

```python theme={null}
def default_log_file() -> Path
```

Returns the default log-file path under the system temp directory.

This cross-platform location is `bioptimus.log` inside the directory reported by `tempfile.gettempdir` (honoring `TMPDIR`/`TEMP`/`TMP` on the respective platforms). It is where [`configure_logging`](/sdk-reference/observability/logging#configure_logging) falls back to when neither an explicit `log_file` argument nor the `BIOPTIMUS_LOG_FILE` environment variable is set, so logging works with no setup while remaining easy to discover and override.

**Returns**:

The default log-file path.

***

#### get\_log\_file

```python theme={null}
def get_log_file() -> Path | None
```

Returns the log-file path the SDK is currently writing to.

Resolution order:

1. Path set via `configure_logging(log_file=...)` — highest priority.
2. `BIOPTIMUS_LOG_FILE` environment variable (empty string disables).
3. Default temp path (e.g. `/tmp/bioptimus.log`).

**Returns**:

The active log-file path, or `None` when file logging is disabled.

***

#### configure\_logging

```python theme={null}
def configure_logging(
    *,
    level: int | str = logging.INFO,
    stream: TextIO | None = None,
    log_file: str | Path | None = None,
    anonymize: bool = False,
    logger_name: str | None = _DEFAULT_LOGGER,
    when: str = _DEFAULT_WHEN,
    backup_count: int = _DEFAULT_BACKUP_COUNT,
    console: bool = False,
    file_handler_factory: Callable[[Path], logging.Handler] | None = None
) -> logging.Logger
```

Configures structured JSON logging for the SDK.

Installs a time-rotating file handler on the target logger, attaching correlation-context injection and optional PII anonymization. Importing the package has no logging side effects; the first emitted event auto-installs this same default configuration, and calling this function explicitly overrides it (for a custom path, level, or anonymization). Repeated calls replace the handlers a previous call installed, so the helper is safe to call more than once.

Rotated files are suffixed with the UTC date (for example `sdk.log.2026-06-24`), which keeps them easy to match to a support window.

By default the SDK is **silent on the console** — log records go only to the file sink (for support bundles) and propagate up Python's logger hierarchy. If the application has its own root-logger handlers, SDK logs appear there automatically. To additionally install the SDK's own console handler, pass `console=True`; passing an explicit `stream` implies `console=True`.

The file sink works with no setup: when `log_file` is omitted, the path is resolved from the `BIOPTIMUS_LOG_FILE` environment variable, and when that is unset it defaults to [`default_log_file`](/sdk-reference/observability/logging#default_log_file) (`bioptimus.log` under the system temp directory). To send logs elsewhere, pass `log_file` or set the variable; to disable file logging entirely, set the variable to an empty string.

Time-based rotation is the default, but the retention strategy is overridable: pass `file_handler_factory` to supply any handler (for example a size-based `logging.handlers.RotatingFileHandler`). The SDK still resolves the path, applies the JSON formatter, injects correlation context, and manages the handler's lifecycle, so `when` and `backup_count` are ignored when a factory is given.

<ParamField body="level">
  Minimum level to emit, as a level name or numeric level.
</ParamField>

<ParamField body="stream">
  Stream for the console handler. When provided, implies `console=True`. Defaults to `sys.stderr` when a console handler is installed.
</ParamField>

<ParamField body="log_file">
  Optional path enabling a time-rotating file handler. When omitted, the `BIOPTIMUS_LOG_FILE` environment variable is used and, if that is unset, [`default_log_file`](/sdk-reference/observability/logging#default_log_file); an explicit argument always takes precedence. Setting the variable to an empty string disables file logging.
</ParamField>

<ParamField body="anonymize">
  When `True`, redacts PII from every emitted record, including the on-disk file (redaction at rest). Defaults to `False`, so records retain full detail and anonymization happens only on export.
</ParamField>

<ParamField body="logger_name">
  Logger to configure. `None` targets the root logger; the default targets the `"bioptimus"` package logger.
</ParamField>

<ParamField body="when">
  Rotation interval passed to `logging.handlers.TimedRotatingFileHandler`, for example `"midnight"` (the default), `"H"`, or `"D"`.
</ParamField>

<ParamField body="backup_count">
  Number of rotated files to retain before the oldest is deleted. Defaults to 14, matching the recommended retention window.
</ParamField>

<ParamField body="console">
  When `True`, installs the SDK's own console handler with human-readable output on `sys.stderr`. Defaults to `False` so the SDK stays silent on the console; log records still propagate to the caller's logging hierarchy, appearing in whatever handlers the application has configured (e.g. on the root logger).
</ParamField>

<ParamField body="file_handler_factory">
  Optional callable that builds the file handler from the resolved log path, replacing the default `logging.handlers.TimedRotatingFileHandler`. Enables a different retention strategy (for example size-based rotation via `logging.handlers.RotatingFileHandler`) while the SDK retains ownership of the path, formatter, and context injection. When given, `when` and `backup_count` are ignored.
</ParamField>

**Returns**:

The configured `logging.Logger`.
