# Logging API Inventory

Technical inventory of the main APIs for the phased `pytools.logging` subsystem.

## Design Contract

- **Source of truth:** `LoggingState` in `state.py`
- **Pure/data stages:** `bootstrap`, `resolve`, `mutate`, `export`
- **Runtime side effects only:** `apply_config`, `apply_state`
- **App-specific precedence logic:** stays outside this package (for example in `ai_server/cli.py`)

## Core Data Model

### `pytools.logging.state.LoggingState`

Authoritative in-memory logging configuration.

Fields:
- `version: int` (dictConfig version, default `1`)
- `disable_existing_loggers: bool`
- `formatters: dict[str, dict[str, Any]]`
- `handlers: dict[str, dict[str, Any]]`
- `root: dict[str, Any]` (`level`, `handlers`)
- `loggers: dict[str, dict[str, Any]]`

## Bootstrap APIs

### `pytools.logging.bootstrap.bootstrap(...) -> LoggingState`

Creates baseline logging state without mutating Python runtime.

Parameters:
- `root_level: int = logging.WARNING`
- `logger_levels: dict[str, int] | None = None`
- `formatters: dict[str, dict[str, Any]] | None = None`
- `handlers: dict[str, dict[str, Any]] | None = None`
- `disable_existing_loggers: bool = False`

Behavior:
- seeds default handler (`pytools.logging.factories.create_rich_console_handler`) when no handlers are provided
- sets root handlers
- sets default `pytools.logging` logger level to `WARNING` unless overridden

Side effects: **none**

## Resolve APIs

### `pytools.logging.resolve.resolve_logging_env_path(explicit_path=None, *, env_var="PYTOOLS_LOGGING_CONFIG_FILE") -> str | None`

Resolves optional config file path using precedence:
1. explicit path argument
2. environment variable (`PYTOOLS_LOGGING_CONFIG_FILE` by default)
3. `{project_root}/.env.pytools_logging`

Side effects: **none** (read-only discovery)

## Mutate APIs

All mutate APIs return a copied `LoggingState` with updates.

### `pytools.logging.mutate.set_root_level(state, level) -> LoggingState`
- updates `state.root["level"]`

### `pytools.logging.mutate.set_root_handlers(state, handlers) -> LoggingState`
- updates `state.root["handlers"]`

### `pytools.logging.mutate.merge_logger_levels(state, levels) -> LoggingState`
- merges `{logger_name: level}` into `state.loggers`
- overwrites existing level for matching logger keys

### `pytools.logging.mutate.merge_logger_specs(state, specs) -> LoggingState`
- shallow-merges dictConfig logger fragments into `state.loggers[name]`

Side effects: **none**

## Export APIs

### `pytools.logging.export.export_config(state) -> dict`

Pure conversion from `LoggingState` to stdlib `dictConfig` mapping:
- deep-copies state payloads
- produces portable config artifact for subprocess runtimes (for example Uvicorn workers)

Side effects: **none** (logging calls inside this function should remain non-essential)

## Apply APIs (Activation Boundary)

### `pytools.logging.apply.apply_config(config: dict) -> None`

Activates logging runtime with `logging.config.dictConfig(config)`.

Side effects: **yes** (mutates Python logging runtime)

### `pytools.logging.apply.apply_state(state: LoggingState) -> None`

Equivalent to:
1. `export_config(state)`
2. `apply_config(config)`

Side effects: **yes**

## Public Re-Exports (`pytools.logging`)

Main symbols exported via `shared/logging/__init__.py`:
- `LoggingState`
- `bootstrap`
- `resolve_logging_env_path`
- `merge_logger_levels`
- `merge_logger_specs`
- `set_root_level`
- `set_root_handlers`
- `export_config`
- `apply_config`
- `apply_state`