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

# OpenTelemetry

> Export SDK operational metrics to your own observability backend via OpenTelemetry.

## Overview

Core SDK 0.25.0 can export operational metrics through [OpenTelemetry](https://opentelemetry.io) (OTel) to your collector. Use them alongside application logs to investigate processing time, usage and audio conditions. Metrics alone do not establish audio quality or authorization.

<Note>
  This export is separate from [product telemetry](/reference/concepts/sdk-telemetry) sent to ai-coustics.
</Note>

## What is OpenTelemetry?

OpenTelemetry is a vendor-neutral, open-source framework for collecting metrics, traces and logs. Its collector forwards data to your observability backend. The ai-coustics SDK exports **metrics only** through this pipeline.

## Configuration

Set `AIC_SDK_OTEL_ENABLE=1` and the OpenTelemetry endpoint variables in your runtime environment, then restart the service. No integration code changes are required.

```bash theme={null}
# Activate the OTel metrics pipeline
export AIC_SDK_OTEL_ENABLE=1

# Point to your OTLP-compatible endpoint (default: http://localhost:4318)
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
```

The SDK exports metrics using the **OpenTelemetry Protocol (OTLP) over HTTP** with **Protobuf** encoding. It registers all instruments under:

* **Service name:** `aic-sdk`
* **Meter name:** `aic_usage`

<Note>
  OTel metrics export requires a native SDK build; WebAssembly is unsupported.
</Note>

<Note>
  The `api.key` attribute is a SHA-256 hash of the credential identifier used by the session. It is not the raw SDK key or bearer token. Hashes and session IDs can still correlate activity: restrict access, avoid personal data in custom session IDs and apply your retention policy.
</Note>

### Environment variables

| Variable | Description |
| :- | :- |
| **`AIC_SDK_OTEL_ENABLE`** | Set to `1` to activate the OTel metrics pipeline. Any other value disables it. |
| **`OTEL_EXPORTER_OTLP_ENDPOINT`** | Base OTLP/HTTP URL; the exporter appends `/v1/metrics`. Defaults to `http://localhost:4318`. |
| **`OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`** | Complete metrics URL, including its path. Overrides the general endpoint and is used without adding a path. |
| **`OTEL_EXPORTER_OTLP_HEADERS`** | Comma-separated `key=value` pairs for authentication headers. |
| **`OTEL_EXPORTER_OTLP_METRICS_HEADERS`** | Metrics-specific headers; overrides the general headers setting. |

<Note>
  Set `export_interval_ms` on the `AicOtelConfig` passed to `aic_processor_create`. A value of `0` uses the default of 60,000 ms.
</Note>

See the [OTLP exporter configuration](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) for standard endpoint and header settings. The SDK uses its own per-instance export interval; do not assume every generic OpenTelemetry SDK variable applies.

## Use OpenTelemetry with Pipecat

The [Pipecat quickstart](/models/get-started/pipecat-quickstart) uses `pipecat-ai==1.11.0` with `aic-sdk==3.1.0` (core SDK 0.23.0). Its `AICFilter` reads the native SDK's environment configuration when it creates a processor. The same environment configuration applies to `AICQuailVADAnalyzer` when it creates its voice activity detection (VAD) session.

### Set the bot's environment

Start the [local collector](#verify-with-a-local-collector) in a separate terminal. In the terminal that runs `bot.py`, activate your Pipecat environment and set:

```bash theme={null}
export AIC_SDK_OTEL_ENABLE=1
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4318"
python bot.py -t webrtc -v
```

Keep the `AIC_SDK_LICENSE` setup from the quickstart. To use a `.env` file instead, add these lines to the file next to `bot.py`:

```dotenv theme={null}
AIC_SDK_OTEL_ENABLE=1
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
```

Load `.env` with Pipecat's `python-dotenv` dependency. Add this before the Pipecat imports and filter/VAD creation in `bot.py`:

```python theme={null}
from pathlib import Path
from dotenv import load_dotenv

load_dotenv(Path(__file__).with_name(".env"), override=False)
```

Reuse the quickstart's `Path` import. With `override=False`, process variables take precedence over `.env`. Keep credential files out of version control. Restart the bot, connect the local client and send audio.

### Point to your collector

Replace `http://127.0.0.1:4318` with the address the **bot process** can reach. Use the collector's OTLP/HTTP Protobuf receiver, usually port `4318`, rather than gRPC on `4317`. The exporter appends `/v1/metrics` to `OTEL_EXPORTER_OTLP_ENDPOINT`.

For a collector that provides a complete metrics URL, set this instead:

```dotenv theme={null}
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://collector.example.com/v1/metrics
```

`OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` overrides the general endpoint without adding a path; unset it to use the general endpoint again. Supply authentication through `OTEL_EXPORTER_OTLP_HEADERS` or its metrics-specific override, `OTEL_EXPORTER_OTLP_METRICS_HEADERS`. Store credentials in a secret manager.

In Docker or Kubernetes, `127.0.0.1` reaches the bot's network namespace. For a separate collector container or pod, use a reachable service address, such as `http://otel-collector:4318`, and bind its receiver to the appropriate interface. Inject the variables into the bot container, not just the host.

### Verify receipt

With the client connected, process audio and leave the session running through the default 60-second export interval. In the collector output, look for `service.name: aic-sdk`, meter `aic_usage`, the selected `model.id` and a positive `usage.processed` value. Send more audio in the same session and confirm that the total increases. Also check the quickstart's initialization and processing-error signals: audible passthrough alone does not prove that enhancement activated.

Pipecat 1.11.0's filter and VAD analyzer do not expose an `otel_config` parameter. They use the native SDK's default interval; `OTEL_METRIC_EXPORT_INTERVAL` does not change it. The per-processor `OtelConfig` example below is for direct SDK integrations.

These are native SDK metrics. Pipecat's tracing setup and pipeline metrics flags configure separate instrumentation and are not required to enable this export. If no metrics arrive, check the bot's effective environment, endpoint path, collector metrics pipeline and network routing before changing audio settings.

## Session attributes

Filter and group observations with these attributes:

| Attribute | Description |
| :- | :- |
| `api.key` | SHA-256 hash of the session credential identifier; for JWT credentials this derives from the token subject. |
| `session.id` | Unique identifier for the processing session. |
| `sdk.version` | Version of the ai-coustics SDK. |
| `model.id` | Identifier of the enhancement model in use. |

## Metrics reference

### Usage

Cumulative session totals exported as gauges in core SDK 0.25.0. Account for new sessions and resets when calculating rates; do not treat these as monotonic counter instruments.

| Metric | Type | Unit | Description |
| :- | :- | :- | :- |
| `usage.processed` | Gauge (u64) | ms | Cumulative duration of audio processed this session. |
| `usage.disallowed` | Gauge (u64) | ms | Cumulative audio duration for which processing was disallowed. This does not establish that your application emitted bypassed audio; handle the binding's error explicitly. |

### Audio configuration

Gauges reflecting the audio stream configuration for the session. These describe the configured stream; observations are produced when audio is processed.

| Metric | Type | Unit | Description |
| :- | :- | :- | :- |
| `audio.sample_rate` | Gauge (u64) | Hz | Sample rate of the audio stream. |
| `audio.channels` | Gauge (u64) | | Number of audio channels. Kept for backwards compatibility, always reports 1 since the audio APIs are mono only. |
| `audio.frame_size` | Gauge (u64) | samples | Number of mono samples per processing block. |

### Processor state

Gauges reflecting the current state of the audio processor.

| Metric | Type | Unit | Description |
| :- | :- | :- | :- |
| `processor.output_delay` | Gauge (u64) | samples | Audio delay introduced by the enhancement model. Convert to ms: $\text{delay\_ms} = \frac{\text{value} \times 1000}{\text{sample\_rate}}$. Lower is better. |
| `processor.enhancement_level` | Gauge (f64) | | Current enhancement strength (0.0 to 1.0). Higher = more aggressive enhancement. |
| `processor.bypass` | Gauge (u64) | | Whether the processor is in bypass mode. 1 = bypass active, 0 = processing active. |
| `processor.vad_created` | Gauge (u64) | | Whether the session runs a dedicated voice activity detection (VAD) model. 1 = VAD model, 0 = another model. |

<a id="experimental-metrics" />

### Additional metrics

Keep the `experimental.` prefix when querying these metrics in core SDK 0.23.0 through 0.25.0.

#### Performance

| Metric | Type | Unit | Description |
| :- | :- | :- | :- |
| `experimental.processor.realtime_violations` | Counter (u64) | | Cumulative number of `process()` calls that exceeded the audio buffer duration, indicating real-time budget overruns. Lower is better; sustained values indicate CPU pressure or thread contention. |
| `experimental.processor.process_duration_avg` | Gauge (f64) | ns | Average wall-clock time spent inside `process()` per call over the last export interval. Lower is better. |
| `experimental.processor.process_duration_max` | Gauge (u64) | ns | Peak wall-clock time spent inside `process()` in any single call during the last export interval. Lower is better. |

#### Voice activity detection

| Metric | Type | Unit | Description |
| :- | :- | :- | :- |
| `experimental.vad.speech_duration` | Gauge (u64) | ms | Cumulative duration classified as speech by a dedicated VAD model. Zero for enhancement and bypass models. |

#### Audio quality

| Metric | Type | Unit | Description |
| :- | :- | :- | :- |
| `experimental.audio.input_clipping_samples` | Counter (u64) | samples | Cumulative number of input samples whose absolute value reached or exceeded 1.0 (full-scale clipping). Lower is better; sustained values indicate bad hardware or encoding upstream. |
| `experimental.audio.output_clipping_samples` | Counter (u64) | samples | Cumulative number of output samples whose absolute value reached or exceeded 1.0 after enhancement. Lower is better. |
| `experimental.audio.snr` | Gauge (f64) | dB | Estimated signal-to-noise ratio of enhanced audio over the last export interval, using the input/output residual as noise. Computed as $10 \log_{10} \left( \frac{\text{signal\_power}}{\text{noise\_power}} \right)$. Not a ground-truth speech-quality score. Not reported during bypass or when the estimate is unavailable. |

## Deployment examples

### Verify with a local collector

Install the [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/installation/) and ensure `otelcol` is on your path. Save the following as `otel-collector-config.yaml`. This example accepts metrics only from the local host and prints them for inspection.

```yaml theme={null}
receivers:
  otlp:
    protocols:
      http:
        endpoint: 127.0.0.1:4318
exporters:
  debug:
    verbosity: detailed
service:
  pipelines:
    metrics:
      receivers: [otlp]
      exporters: [debug]
```

Start the collector in one terminal:

```bash theme={null}
otelcol --config=otel-collector-config.yaml
```

In the terminal that runs your existing native SDK integration, set:

```bash theme={null}
export AIC_SDK_OTEL_ENABLE=1
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4318"
```

Run the [SDK quickstart](/models/get-started/sdk-quickstart) with a valid credential and a non-silent input file. Keep the instance alive through an export interval, or finish with the binding's normal session teardown. For a shorter diagnostic interval in Python 3.3.0, pass this optional configuration when constructing the processor:

```python theme={null}
# model, license_key and config come from your SDK initialization.
otel_config = aic.OtelConfig(enable=True, export_interval_ms=1000)
processor = aic.Processor(model, license_key, config, otel_config=otel_config)
```

After processing, check the collector for `service.name: aic-sdk`, meter `aic_usage`, the configured `model.id` and session totals in `usage.processed`.

For production, replace the debug exporter with your backend's supported exporter and configure transport security and authentication. Keep collector credentials in your secret manager. In containers, `localhost` refers to the container itself; use a reachable collector address and bind the receiver appropriately for your network.

## Runtime behavior

* Native sessions share a telemetry executor, while each enabled session has its own metrics pipeline and exporter in core SDK 0.25.0.
* Observations include `session.id`, `api.key`, `sdk.version` and `model.id`. Per-session identifiers can create high cardinality; plan aggregation and retention in the collector.
* An unreachable customer collector causes metrics export failures, independently of SDK authorization and usage reporting. Do not treat the exporter as a durable event log or rely on every interval arriving.
* Offline-license behavior can differ from online sessions. Verify metric availability for your exact entitlement before depending on it operationally.

## Operational diagnostics

| Signal | Investigate |
| :- | :- |
| `usage.disallowed` increases | Authorization or session lifecycle; inspect the application's checked error path. |
| `processor.bypass` is 1 | The processor's bypass setting; a bypass value alone is not an authorization diagnosis. |
| Real-time violations increase | CPU contention, resource limits, concurrency and audio work scheduled on the wrong thread. |
| Process duration approaches the frame duration | Capacity headroom and queue growth. Convert nanoseconds to milliseconds before comparison. |
| Clipping counts increase | Input scaling, upstream gain and output amplitude. |
| No speech duration appears | Confirm a dedicated VAD session and representative speech input; enhancement sessions report zero. |

Do not log audio or credentials to diagnose these signals. Use a controlled fixture and the [troubleshooting guide](/production/troubleshooting).

## Troubleshooting

<AccordionGroup>
  <Accordion title="Metrics are not appearing in my backend">
    1. Verify `AIC_SDK_OTEL_ENABLE=1` before instance creation, and check for a per-instance configuration that overrides it.
    2. Confirm a native build is in use. WebAssembly does not export these metrics.
    3. Process audio; an idle initialized instance is not sufficient.
    4. Check that the collector accepts OTLP/HTTP Protobuf and that its metrics pipeline includes the receiver.
    5. Check container routing, endpoint paths, authentication and firewall rules. Keep the session alive for the configured export interval.
  </Accordion>

  <Accordion title="How often are metrics exported?">
    Set `export_interval_ms` on `AicOtelConfig` or the binding's equivalent. A value of `0` selects the default of 60,000 ms. Use a shorter interval for a bounded diagnostic run, then evaluate export overhead before adopting it in production.
  </Accordion>

  <Accordion title="What is the exporter timeout?">
    Do not rely on `OTEL_METRIC_EXPORT_TIMEOUT` to bound SDK exports: the SDK manages them directly without a periodic metric reader. Test failure and shutdown timing with your release and collector.
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.