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

# Logging and redaction

> Secure application logging with trace correlation and shared redaction for logs and spans

The **`bb_ai_sdk.logging`** module scrubs secrets from log lines and stamps **trace** and **span** IDs on each record. The same redaction engine covers **OpenTelemetry span attributes** when you call **`bb_ai_sdk.logging.init()`** at startup.

Tracing setup lives on the **[Observability](/agentic-ai/bb-ai-sdk/observability)** page. This page covers log formats, redaction patterns, coverage, and how logging cooperates with **`configure_observability()`**.

## What the SDK provides

After **`logging.basicConfig`** (or dictConfig) and one call to **`bb_ai_sdk.logging.init()`**:

| Capability                       | What it does                                                                                                                                     |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Redaction at record creation** | Scrubs every `LogRecord` at the factory level—including **`uvicorn.access`** and other loggers that do not propagate to root                     |
| **Redaction at format time**     | Wraps root handler formatters so tracebacks and rendered **`extra`** fields are scrubbed before output                                           |
| **Trace correlation**            | Adds **`trace_id`** and **`span_id`** to each record from the active OpenTelemetry span (or **`"-"`** when no span is active)                    |
| **Shared patterns for spans**    | The global filter from **`init()`** is what **`bb_ai_sdk.observability`** uses for span-attribute redaction—one pattern list for logs and traces |

Built-in patterns cover common secrets: API keys, tokens, passwords, secrets, and Langfuse credentials. Replacements use typed tags such as **`[REDACTED:api_key]`** so audits show what was redacted.

<Info>
  Deep reference (architecture, performance, troubleshooting) lives in the [bb-ai-sdk repository](https://github.com/backbase/bb-ai-sdk) under `docs/logging/` (`OVERVIEW.md`, `LOGGING_GUIDE.md`).
</Info>

## Startup

Use the same order as **[What you call at startup](/agentic-ai/bb-ai-sdk/observability#what-you-call-at-startup)** on the Observability page:

1. **`logging.basicConfig`** (or dictConfig) with a format preset that includes **`%(trace_id)s`** and **`%(span_id)s`**
2. **`bb_ai_sdk.logging.init()`** — once, before serving traffic
3. **`configure_observability(...)`** — tracing and instrumentors

```python theme={"system"}
import logging
from dotenv import load_dotenv
from fastapi import FastAPI

load_dotenv()

from bb_ai_sdk.logging import DEFAULT_DATEFMT, STANDARD_FORMAT, init as init_logging
from bb_ai_sdk.observability import configure_observability

app = FastAPI(title="my-agent-api")

logging.basicConfig(
    level=logging.INFO,
    format=STANDARD_FORMAT,
    datefmt=DEFAULT_DATEFMT,
)
init_logging(capture_warnings=True)

configure_observability(
    fastapi_app=app,
    framework="agno",
    service_name="my-agent-api",
    environment="development",
)
```

Use **`logging.getLogger(__name__)`** everywhere. This module does not export a shared **`logger`** object.

<Note>
  Call **`bb_ai_sdk.logging.init()`** even when you only care about span redaction. Without it, observability falls back to built-in default patterns only—**`BB_AI_SDK_REDACTION_PATTERNS*`** env vars and custom patterns from **`init(redaction_patterns=...)`** are not applied to spans.
</Note>

### `init()` parameters

| Parameter                      | Default     | Purpose                                                                                           |
| ------------------------------ | ----------- | ------------------------------------------------------------------------------------------------- |
| **`redact`**                   | **`True`**  | Install global redaction at record creation and wrap formatters                                   |
| **`correlate_traces`**         | **`True`**  | Stamp **`trace_id`** / **`span_id`** on each record                                               |
| **`capture_warnings`**         | **`False`** | Route **`warnings.warn(...)`** through logging (and redaction). Set **`True`** for agent services |
| **`wrap_existing_formatters`** | **`True`**  | Scrub tracebacks and formatted **`extra`** on root handlers                                       |
| **`record_redactions`**        | **`False`** | Attach pattern names that fired on each record (audit trail)                                      |

**`init()`** is idempotent—the first call wins. To reconfigure, call **`disable_redaction()`** first.

## Log format presets

Import ready-made format strings from **`bb_ai_sdk.logging`** and pass them to **`logging.basicConfig`** or dictConfig. Every preset includes **`%(trace_id)s`** and **`%(span_id)s`**—those fields are populated after you call **`init()`**.

| Constant                   | Format string                                                                                         | Use when                                                                     |
| -------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| **`STANDARD_FORMAT`**      | `%(asctime)s \| %(name)s \| %(levelname)s \| [trace_id=%(trace_id)s span_id=%(span_id)s] %(message)s` | Default — timestamp, logger name, level, trace/span IDs, message             |
| **`COMPACT_FORMAT`**       | `%(asctime)s \| %(levelname)s \| [trace_id=%(trace_id)s span_id=%(span_id)s] %(message)s`             | Shorter lines when the logger name is redundant                              |
| **`MINIMAL_FORMAT`**       | `%(levelname)s [trace_id=%(trace_id)s span_id=%(span_id)s] %(message)s`                               | Level, correlation IDs, and message only                                     |
| **`MESSAGE_TRACE_FORMAT`** | `%(message)s \| trace_id=%(trace_id)s span_id=%(span_id)s`                                            | Message-first layout (tests or REPL demos)                                   |
| **`DEFAULT_DATEFMT`**      | `%Y-%m-%d %H:%M:%S`                                                                                   | Recommended **`datefmt`** for **`STANDARD_FORMAT`** and **`COMPACT_FORMAT`** |

**`LOG_FORMATS`** maps short names to the same strings: **`standard`**, **`compact`**, **`minimal`**, **`message_trace`**.

When no OpenTelemetry span is active, **`trace_id`** and **`span_id`** appear as **`"-"`**. That is expected for startup logs before the first request span.

## Operator-driven patterns (no redeploy)

Add patterns via environment variables (merged with built-ins when **`init()`** runs):

```bash theme={"system"}
# JSON array of {name, pattern, replacement}
BB_AI_SDK_REDACTION_PATTERNS='[{"name":"iban","pattern":"...","replacement":"..."}]'

# Or shorthand: name|pattern|replacement; separate multiple with ;
BB_AI_SDK_REDACTION_PATTERNS_SHORTHAND='ssn|(?P<ssn>ssn)\s*[:=]\s*\d{3}-\d{2}-\d{4}|\g<ssn>=[REDACTED:ssn]'
```

Or at runtime (applies to logs and spans immediately):

```python theme={"system"}
from bb_ai_sdk.logging import add_redaction_pattern

add_redaction_pattern({
    "name": "creditcard",
    "pattern": r"(?P<cc>(?:cc|card))\s*[:=]\s*\d{12,19}",
    "replacement": r"\g<cc>=[REDACTED:creditcard]",
})
```

## What gets redacted

| Surface                                        | Covered?                                                 |
| ---------------------------------------------- | -------------------------------------------------------- |
| **`logger.info("api_key=sk-...")`**            | Yes — **`LogRecord`** factory                            |
| Formatted args, tracebacks                     | Yes — **`RedactingFormatter`** on root handlers          |
| **`logger.info("x", extra={"token": "..."})`** | Yes — formatter / record scrubbing                       |
| **`warnings.warn(...)`**                       | Yes if **`init(capture_warnings=True)`**                 |
| OpenTelemetry span attributes                  | Yes when **`logging.init()`** ran — same global filter   |
| Raw **`print()`** / stdout                     | No — route through logging (see SDK **`LOGGING_GUIDE`**) |

Span attributes also redact by **key name** (for example **`api_key`**, **`token`**, **`password`**) even when the value would pass content patterns unchanged.

## Optional: audit trail on records

Pass **`record_redactions=True`** on the **first** **`init()`** call:

```python theme={"system"}
init(capture_warnings=True, record_redactions=True)
```

Each redacted record gets metadata listing which pattern names fired—useful for security reviews.

## Troubleshooting

**Trace IDs always show `"-"` in logs** — No active OpenTelemetry span when the line was emitted (startup noise), or **`configure_observability()`** is not initialized. IDs populate inside instrumented request or agent spans.

**Secrets visible in Langfuse but redacted in stdout** — **`logging.init()`** was not called; observability used the lazy default filter for spans only. Call **`logging.init()`** at startup.

**Custom env patterns ignored on spans** — Same cause. Env vars are read inside **`logging.init()`**, not inside **`configure_observability()`**.

**Malformed `BB_AI_SDK_REDACTION_PATTERNS`** — **`init()`** raises **`ValueError`** at startup with the JSON index and reason. Fix the env var before serving traffic.

## Starters

Wire **`bb_ai_sdk.logging.init()`** in your central **`logger.py`** (or **`main.py`**) after **`basicConfig`**. Use **`STANDARD_FORMAT`** and **`DEFAULT_DATEFMT`**, drive level from **`LOG_LEVEL`** in app settings, and call **`init(capture_warnings=True)`**. See the [Multi agent starter](/agentic-ai/starter-kits/multi-agent#logging-and-redaction) for a full example.

<Card title="Observability" icon="chart-line" href="/agentic-ai/bb-ai-sdk/observability">
  Tracing, `bb.*` attributes, and export setup
</Card>
