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

# OpenTelemetry Export (OTLP)

> Ship the whole gateway's traces, logs and metrics to your OTLP collector — the endpoint and header format KnoxCall expects, then copy-paste recipes for Grafana Cloud, Honeycomb, New Relic, Datadog, SigNoz, Elastic, Axiom, Sentry and a self-run OpenTelemetry Collector.

# OpenTelemetry Export (OTLP)

The **OpenTelemetry export** card ships the **whole gateway's** telemetry — one `SERVER` span per request, one log record per proxied request and webhook delivery, and request count / latency metrics every 60 seconds — to a single OTLP/HTTP endpoint. What each signal contains is documented in [OpenTelemetry export](/monitoring/opentelemetry); this page is the setup.

**Scope: Global defaults** only. This is the deployment operator's view of KnoxCall itself: on KnoxCall Cloud it is KnoxCall's; on a self-hosted deployment it is yours. A workspace that wants *its own* request logs and metrics in *its own* collector uses [Telemetry export](/integrations/setup/telemetry-export) instead.

## The three fields

| Field                  | What to enter                                                                                                                                                                |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **OTLP HTTP endpoint** | The collector's OTLP/HTTP **base** URL. KnoxCall appends `/v1/traces`, `/v1/logs` and `/v1/metrics` itself — a value ending in `/v1/traces` produces `/v1/traces/v1/traces`. |
| **OTLP auth headers**  | Comma-separated `name=value` pairs, e.g. `Authorization=Bearer <token>, X-Scope-OrgID=acme`. Stored encrypted because it carries the credential.                             |
| **Service name**       | The resource `service.name`; default `knoxcall`.                                                                                                                             |

Plus three toggles — **Export traces**, **Export integration logs**, **Export metrics** — all on by default. Turn a signal off rather than pointing it at a backend that rejects it (see Sentry below).

## 1. Configure

1. **Settings → Integrations → Global defaults → OpenTelemetry export** → *Configure*.
2. Endpoint, headers, service name from the recipe for your backend below.
3. **Save.** Export starts immediately in the API server, across all its workers — no restart.

## 2. Verify

Spans and log records should appear in your backend within a minute of the next proxied request; metrics on the next 60-second tick. Nothing is logged locally on success, so the backend is the check.

## Recipes

Endpoints and header names are those published by each vendor at the time of writing; confirm on the vendor's OTLP settings page, which is also where you mint the credential. Mint a **write-only ingest** credential in every case — never an admin API key.

### Grafana Cloud

1. Grafana Cloud portal → your stack → **Connections → OpenTelemetry** (or **Configure** on the OTLP tile). It shows the endpoint, your **instance id** and a **token** generation button.
2. Create a token with the `metrics:write`, `logs:write` and `traces:write` scopes.
3. Grafana authenticates with HTTP Basic: `base64("<instance id>:<token>")`.

| Field    | Value                                              |
| -------- | -------------------------------------------------- |
| Endpoint | `https://otlp-gateway-<region>.grafana.net/otlp`   |
| Headers  | `Authorization=Basic <base64 of instanceid:token>` |

### Honeycomb

1. **Environment settings → API keys → Create ingest key** (Send events only).
2. Metrics land in a dataset named by a header; traces and logs use the service name.

| Field    | Value                                                                 |
| -------- | --------------------------------------------------------------------- |
| Endpoint | `https://api.honeycomb.io` (EU: `https://api.eu1.honeycomb.io`)       |
| Headers  | `x-honeycomb-team=<ingest key>, x-honeycomb-dataset=knoxcall-metrics` |

### New Relic

Use an **ingest license key**, not a user key.

| Field    | Value                                                            |
| -------- | ---------------------------------------------------------------- |
| Endpoint | `https://otlp.nr-data.net` (EU: `https://otlp.eu01.nr-data.net`) |
| Headers  | `api-key=<license key>`                                          |

### Datadog

Datadog ingests OTLP through the **Datadog Agent** or an OpenTelemetry Collector with the Datadog exporter, not a public OTLP URL. Enable the Agent's OTLP/HTTP receiver (`otlp_config.receiver.protocols.http.endpoint: 0.0.0.0:4318`) and point KnoxCall at it — over a private network or TLS, since the Agent has no auth of its own.

| Field    | Value                                                                  |
| -------- | ---------------------------------------------------------------------- |
| Endpoint | `https://<agent host>:4318`                                            |
| Headers  | *(none)* — put the receiver on a private network or behind a TLS proxy |

### SigNoz

| Field    | SigNoz Cloud                               | Self-hosted SigNoz    |
| -------- | ------------------------------------------ | --------------------- |
| Endpoint | `https://ingest.<region>.signoz.cloud:443` | `https://<host>:4318` |
| Headers  | `signoz-ingestion-key=<ingestion key>`     | *(none by default)*   |

### Elastic

Elastic Cloud and Elastic APM Server accept OTLP/HTTP natively.

| Field    | Value                                                                                                       |
| -------- | ----------------------------------------------------------------------------------------------------------- |
| Endpoint | The APM Server / managed OTLP endpoint of your deployment (`https://<deployment>.apm.<region>.cloud.es.io`) |
| Headers  | `Authorization=ApiKey <api key>` (or `Authorization=Bearer <secret token>`)                                 |

### Axiom

| Field    | Value                                                         |
| -------- | ------------------------------------------------------------- |
| Endpoint | `https://api.axiom.co`                                        |
| Headers  | `Authorization=Bearer <API token>, X-Axiom-Dataset=<dataset>` |

### Sentry

Sentry ingests OTLP **traces and logs** into the same project as your errors, but **not metrics** — untick **Export metrics** or the metric exporter is rejected every 60 seconds. Values and the caveats are in [Sentry as an OTLP backend](/monitoring/opentelemetry#sentry-as-an-otlp-backend).

### Splunk, Dynatrace and everything else: a self-run Collector

Any backend that speaks OTLP or has a Collector exporter can be reached through an [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) you run. Point KnoxCall at the Collector's OTLP/HTTP receiver and fan out from there:

```yaml theme={"dark"}
receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318
exporters:
  otlphttp/backend:
    endpoint: https://your-backend.example/otlp
    headers:
      Authorization: "Bearer ${env:BACKEND_TOKEN}"
service:
  pipelines:
    traces:  { receivers: [otlp], exporters: [otlphttp/backend] }
    logs:    { receivers: [otlp], exporters: [otlphttp/backend] }
    metrics: { receivers: [otlp], exporters: [otlphttp/backend] }
```

Put a TLS terminator with a bearer-token check in front of the receiver, and give KnoxCall that token in **OTLP auth headers** — a bare receiver on a public address accepts telemetry from anyone.

## Environment variables, and who reads what

| Variable                                                                               | Purpose                                                                                                                                             |
| -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OTEL_EXPORTER_OTLP_ENDPOINT`                                                          | Base endpoint — **when set, the stored row is ignored entirely**                                                                                    |
| `OTEL_EXPORTER_OTLP_HEADERS`                                                           | Headers, `name=value,name2=value2`                                                                                                                  |
| `OTEL_SERVICE_NAME`                                                                    | Service name                                                                                                                                        |
| `OTEL_TRACES_EXPORTER=none` / `OTEL_LOGS_EXPORTER=none` / `OTEL_METRICS_EXPORTER=none` | Disable one signal                                                                                                                                  |
| `OTEL_EXPORTER_OTLP_{TRACES,LOGS,METRICS}_ENDPOINT` and `_HEADERS`                     | Send one signal elsewhere. A signal endpoint is used **verbatim** (give the full `/v1/<signal>` path) and its headers **replace** the generic ones. |

Two rules a self-hosted operator needs to know:

* **The environment wins.** This is the opposite of most integrations. If `OTEL_EXPORTER_OTLP_ENDPOINT` is set on the host, editing the card changes nothing.
* **The stored row reaches the API server only.** Scheduled jobs, workflow workers and the standalone proxy read the environment variables and never the row. If you want every process covered, configure the environment; use the card for a quick change on the API server.

## Things that bite

* **Base endpoint only.** The most common mistake is pasting a URL that already ends in `/v1/traces`.
* **Headers are a single line.** `name=value` pairs separated by commas; a header value containing a comma cannot be expressed here — use the environment variable form with an env-quoted value, or a Collector.
* **Metrics carry a `knoxcall.tenant_id` dimension** on this export, so cardinality grows with workspaces; per-workspace exports do not carry it.

## Related

* [OpenTelemetry export](/monitoring/opentelemetry) — what each signal contains, semantic conventions
* [Telemetry export (per workspace)](/integrations/setup/telemetry-export)
* [Error tracking (Sentry)](/integrations/setup/sentry)
