skip to content

How do you configure an OTLP exporter in an OpenTelemetry SDK — gRPC versus HTTP transport and their conventional ports, the endpoint environment variables and their differing path rules, headers, compression and timeout — and what does a 'partial success' response from the receiver mean?

level: seniorimportance: should knowfreq 42%

answer

  1. grpc 4317 / http 4318, protocol set explicitly
  2. generic endpoint appends /v1/traces; per-signal is verbatim
  3. headers = credentials, per-signal overrides generic
  4. retry on 429/503/UNAVAILABLE, not on 4xx
  5. partial success = rejected count, no retry

basics

~20 s

OTLP runs over gRPC (conventionally port 4317) or HTTP with protobuf or JSON payloads (port 4318). A generic endpoint variable has the per-signal path appended; a per-signal endpoint variable is used exactly as given. Headers carry auth, gzip compresses, and partial success means some items were rejected while the request itself succeeded.

solid answer

~50 s

**Transport**: `OTEL_EXPORTER_OTLP_PROTOCOL` selects `grpc`, `http/protobuf` or `http/json`. Conventional ports are 4317 for gRPC and 4318 for HTTP; defaults have differed across SDKs and versions, so set it explicitly rather than inferring it from a port. **Endpoint**: with the generic `OTEL_EXPORTER_OTLP_ENDPOINT` over HTTP the SDK appends the signal path (`/v1/traces`, `/v1/metrics`, `/v1/logs`). With the per-signal `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` the URL is used **verbatim**, so you must include the path yourself. Forgetting that is the classic 404. **Other knobs**: `OTEL_EXPORTER_OTLP_HEADERS` (comma-separated `key=value`, where API keys go), `OTEL_EXPORTER_OTLP_COMPRESSION=gzip`, `OTEL_EXPORTER_OTLP_TIMEOUT` (commonly 10s), and certificate/client-key variables for TLS and mTLS. Every variable has per-signal forms that override the generic one. **Partial success**: the response carries a count of rejected items plus a message — the request was accepted, some data was not. It is logged and not retried, so unnoticed partial success is silent data loss.

go deeper

for a junior

Know the two transports and their conventional ports, and that the endpoint, headers and timeout come from environment variables.

for a middle

Get the path rule right for generic versus per-signal endpoints, and explain compression, timeout and header-based auth.

for a senior

Cover retry and throttling behaviour, partial success as silent loss, timeout interaction with the batch processor, and metric temporality.

for a principal

Decide the fleet's export topology — collector versus direct — with credential handling, egress and buffering responsibilities placed deliberately.

## What OTLP is OTLP is OpenTelemetry's own wire protocol, defined for all three signals. Its bindings: - **grpc** — protobuf over gRPC, conventionally port 4317, streaming-friendly, needs a gRPC-capable path (some proxies and load balancers are not). - **http/protobuf** — the same protobuf messages POSTed over HTTP/1.1 or HTTP/2, conventionally port 4318, at `/v1/traces`, `/v1/metrics`, `/v1/logs`. Traverses ordinary HTTP infrastructure, which is why it is often the safer default. - **http/json** — the same messages JSON-encoded; readable, larger, less uniformly supported. Default protocol choice has genuinely varied between SDKs and releases, so pin `OTEL_EXPORTER_OTLP_PROTOCOL` rather than relying on a default. ## The endpoint path rule This is the single most common configuration bug. Two families of variable exist: - Generic: `OTEL_EXPORTER_OTLP_ENDPOINT` — for HTTP the SDK **appends** the per-signal path, so `https://collector:4318` becomes `https://collector:4318/v1/traces`. - Per-signal: `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` (and the metrics/logs equivalents) — used **as-is**, so it must be the complete URL including `/v1/traces`. Set the per-signal form without the path and every export 404s. Set the generic form *with* the path and you get a doubled suffix. Per-signal values override the generic one, and the same override pattern applies to headers, timeout, compression and TLS settings. Under gRPC the endpoint is a host:port target; the path concept does not apply, and whether a scheme implies TLS is a per-SDK detail worth checking. ## Auth, compression, timeouts, TLS `OTEL_EXPORTER_OTLP_HEADERS` takes a comma-separated `key=value` list and is where vendor API keys or tenant identifiers live — which makes it a secret, to be injected like any other credential rather than baked into an image. `OTEL_EXPORTER_OTLP_COMPRESSION=gzip` trades CPU for bandwidth and is usually worth it for egress across a network boundary, less so to a collector on localhost. `OTEL_EXPORTER_OTLP_TIMEOUT` bounds one export attempt (commonly 10s); it must sit sensibly against the batching processor's own timeout and schedule delay, or a stalled backend backs the queue up. Certificate, client-certificate and client-key variables cover TLS and mTLS to a collector. ## Retries and back-pressure Exporters retry transient failures with exponential backoff and jitter on retryable conditions — a gRPC UNAVAILABLE, an HTTP 429 or 503 — and honour throttling hints where the receiver supplies them. Non-retryable failures (a 400-class rejection, a bad payload) are dropped and logged; retrying them would only burn the queue. Retrying is not free: while the exporter retries, the processor's queue keeps filling behind it, and past a point the correct outcome is to shed rather than to persist. ## Partial success OTLP responses can report **partial success**: the request was accepted, but the receiver rejected some number of spans, metric points or log records, with a human-readable message. Typical causes are payload or attribute limits, malformed or unsupported fields, and quota or cardinality rules on the receiving side. Two things matter. First, this is **not** a failure from the transport's point of view, so it does not trigger a retry — the rejected data is gone. Second, SDKs surface it only through their internal logging, so nobody notices unless someone is looking. Treat 'rejected item count greater than zero' as an alertable condition; it is one of the few forms of data loss that announces itself and is still routinely ignored. ## Metrics-specific settings Metric export also has a **temporality preference** (`OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE`: cumulative, delta, or a low-memory mix). Backends differ in what they want — pull-based ecosystems generally expect cumulative, several vendors prefer delta — and choosing wrongly produces charts that look plausible and are wrong, so it is a per-backend decision made once. ## Choosing where to send Most fleets export to a local or nearby **collector** rather than straight to a vendor: the process-side timeout is tiny, credentials and endpoints live in one place instead of in every service's environment, and retry and buffering happen outside the application. Direct-to-vendor export is reasonable for small deployments and for environments where running a collector is not possible.

  • An SDK exports over HTTP and every request returns 404, yet the collector is healthy and reachable. What is the likely cause?
    A per-signal endpoint variable set to a bare host and port. The per-signal form is used verbatim, so it must include the path such as /v1/traces; only the generic endpoint variable gets the signal path appended. The mirror-image bug is putting the path into the generic variable, producing a doubled suffix.
  • Would you export straight to a vendor backend or through a collector?
    Through a collector in most fleets: the in-process export becomes a short local hop, credentials and endpoint live in one configuration instead of every service's environment, and retry, buffering, enrichment and any post-hoc filtering happen outside the application. Direct export is fine for small deployments or where running a collector is impractical, but then every service owns credentials and network egress.

saying these in an interview costs you the question

  • Assuming the per-signal endpoint variable gets a path appended like the generic one
  • Inferring the protocol from the port instead of setting it explicitly
  • Treating a partial-success response as success — it is unretried data loss
  • Baking API keys into an image via the headers variable instead of injecting them as secrets
  • Setting an export timeout that is long compared with the batch processor's schedule delay

context