Skip to main content
OTLP

OpenTelemetry Protocol

Active

OTLP (OpenTelemetry Protocol) is the standard data delivery protocol for OpenTelemetry telemetry: traces, metrics, logs, and profiles. It defines how SDKs export telemetry to collectors and backends. OTLP runs over gRPC (OTLP/gRPC) or HTTP/1.1 and HTTP/2 (OTLP/HTTP) using Protobuf encoding or JSON. OTLP is implemented by every major observability backend (Jaeger, Prometheus, Grafana Tempo, Datadog, Honeycomb, New Relic, AWS X-Ray, Google Cloud Trace).

OTLPOpenTelemetryObservabilityTracesMetricsLogsCNCF2019

In one line

OTLP 1.11.0 (OpenTelemetry specification) is the wire protocol for exporting traces, metrics, and logs. Two transports: OTLP/gRPC (default, port 4317) and OTLP/HTTP (port 4318). Payload encoding: Protobuf (binary) or JSON. Export is unary request-response: ExportTraceServiceRequest → ExportTraceServiceResponse. Partial success is possible – response carries rejected_spans count. All major observability vendors accept OTLP natively, replacing vendor-specific agents.

Quick Reference

FieldSizeDescription
OTLP/gRPCPort 4317Default transport. Uses gRPC unary Export*ServiceRequest/Response. TLS optional (plain TCP default in collector, TLS in many managed backends). Endpoint: grpc://collector:4317. SDK env var: OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317.
OTLP/HTTPPort 4318HTTP/1.1 or HTTP/2 POST to /v1/traces, /v1/metrics, /v1/logs. Content-Type: application/x-protobuf (binary) or application/json. SDK env var: OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318.
Protobuf encodingapplication/x-protobufBinary encoding of ExportTraceServiceRequest, ExportMetricsServiceRequest, ExportLogsServiceRequest. Schema: github.com/open-telemetry/opentelemetry-proto. Smaller payload than JSON.
JSON encodingapplication/jsonHuman-readable alternative to Protobuf. Same schema, JSON-encoded. Useful for debugging. Protobuf field names map to camelCase JSON keys. All backends that accept OTLP must support both encodings.
Partial successrejected_* fieldsThe ExportTraceServiceResponse includes rejected_spans (int64) to indicate how many spans the server could not accept. A rejected_spans > 0 with error_message explains why. Clients should handle partial acceptance.
Retry semanticsRESOURCE_EXHAUSTED / UNAVAILABLEClients SHOULD retry on: RESOURCE_EXHAUSTED (429 equivalent), UNAVAILABLE (503 equivalent). Clients MUST NOT retry on: INVALID_ARGUMENT, UNIMPLEMENTED. Use exponential backoff for retries.
Signal paths/v1/traces, /v1/metrics, /v1/logsOTLP/HTTP endpoints by signal type. gRPC service methods: TraceService.Export, MetricsService.Export, LogsService.Export. Each signal has independent export.
Compressiongzip or noneServers MUST support gzip and none. Clients choose per-request. OTEL_EXPORTER_OTLP_COMPRESSION=gzip enables compression on SDK exporters. Strongly recommended for production to reduce bandwidth.

Key Characteristics

Vendor-neutral telemetry

OTLP is accepted by Jaeger, Prometheus (OTLP receiver), Grafana Tempo, Grafana Mimir, Datadog, Honeycomb, New Relic, AWS X-Ray, Google Cloud Trace, Azure Monitor, and OpenTelemetry Collector. One SDK, any backend.

Collector as middle layer

The OpenTelemetry Collector receives OTLP from SDKs, processes telemetry (filters, transforms, samples), and exports to backends. This decouples SDK configuration from backend configuration. Collectors can batch, compress, and retry.

Concurrent requests

High-throughput SDKs send concurrent unary OTLP requests without waiting for previous responses. Max concurrent requests is configurable. Throughput = max_concurrent × max_batch_size / (latency + response_time).

Profiles signal is in development

The profiles signal (continuous profiling data: CPU, memory, goroutine stacks) is in development status. Do not use in production. Traces, metrics, and logs are all stable.

Message Format

Request
http
# OTLP/gRPC: ExportTraceServiceRequest (Protobuf, shown as JSON equivalent)
POST /opentelemetry.proto.collector.trace.v1.TraceService/Export
Content-Type: application/grpc

# ExportTraceServiceRequest structure:
{
  "resourceSpans": [
    {
      "resource": {
        "attributes": [
          { "key": "service.name", "value": { "stringValue": "order-service" } },
          { "key": "service.version", "value": { "stringValue": "1.2.3" } }
        ]
      },
      "scopeSpans": [
        {
          "scope": { "name": "order-service-instrumentation" },
          "spans": [
            {
              "traceId": "<16-byte hex>",
              "spanId": "<8-byte hex>",
              "parentSpanId": "<8-byte hex>",
              "name": "POST /api/orders",
              "kind": 2,         // SPAN_KIND_SERVER
              "startTimeUnixNano": 1721908800000000000,
              "endTimeUnixNano":   1721908800050000000,
              "attributes": [
                { "key": "http.method", "value": { "stringValue": "POST" } },
                { "key": "http.status_code", "value": { "intValue": 201 } }
              ],
              "status": { "code": 1 }  // STATUS_CODE_OK
            }
          ]
        }
      ]
    }
  ]
}
Response
http
# ExportTraceServiceResponse
{
  "partialSuccess": {
    "rejectedSpans": 0,       // 0 = all accepted
    "errorMessage": ""        // empty if no rejection
  }
}

# Partial failure example (server at capacity):
{
  "partialSuccess": {
    "rejectedSpans": 47,
    "errorMessage": "quota exceeded for service order-service"
  }
}
# Client should retry rejected spans with exponential backoff

# OTLP/HTTP endpoint configuration:
# Traces:  POST http://collector:4318/v1/traces
# Metrics: POST http://collector:4318/v1/metrics
# Logs:    POST http://collector:4318/v1/logs

# SDK environment variables:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318  # OTLP/HTTP
OTEL_EXPORTER_OTLP_PROTOCOL=grpc                   # or http/protobuf or http/json
OTEL_EXPORTER_OTLP_COMPRESSION=gzip
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer token123"
OTEL_SERVICE_NAME=order-service

Implementations

linuxsince OpenTelemetry SDKs for all languages: Go, Python, Java, Node.js, Rust, .NET, Ruby, PHP, Swift, Erlang. OpenTelemetry Collector (official). Jaeger, Grafana, Prometheus all accept OTLP.available
macossince Same SDKs as Linux.available
windowssince OpenTelemetry .NET SDK, Java SDK, Node.js SDK. OpenTelemetry Collector Windows binary.available
iossince OpenTelemetry Swift SDK. OTLP/HTTP export from mobile apps.available
androidsince OpenTelemetry Android SDK (Java/Kotlin). OTLP/HTTP export.available