LinkMesh

Search docs, blog and changelog

ENDE

Snippets · Destinations

Send OTLP over gRPC (with headers and TLS)

OTLP over gRPC is how collectors talk to most backends and to each other. This exporter sends all three signals with gzip, a tenant header taken from the environment, a sending queue and retries, so a short backend outage does not lose data.

Signals
LogsMetricsTraces
Source
OTLP
Components
otlpbatchmemory_limiterotlp
Destination
OTLP/gRPC endpoint

OpenTelemetry Collector

OpenTelemetry Collector YAML
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 80
    spike_limit_percentage: 25
  batch:
    timeout: 5s

exporters:
  otlp:
    endpoint: tempo.example.internal:4317
    tls:
      insecure: false
    headers:
      x-scope-orgid: ${env:TENANT_ID}
    compression: gzip
    timeout: 10s
    sending_queue:
      enabled: true
      queue_size: 5000
    retry_on_failure:
      enabled: true
      initial_interval: 5s
      max_interval: 30s
      max_elapsed_time: 300s

service:
  pipelines:
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp]
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp]

LinkMesh

Library › Destinations › OTLP gRPC

Endpoint
tempo.example.internal:4317
Headers
{"x-scope-orgid":"${env:TENANT_ID}"}
Compression
gzip
Timeout
10s
Durable Delivery
true

What LinkMesh then pushes to the collector, under exporters:

Pushed to the collector
otlp/output_dst_00000502:
  compression: gzip
  endpoint: tempo.example.internal:4317
  headers:
    x-scope-orgid: ${env:TENANT_ID}
  sending_queue:
    block_on_overflow: false
    enabled: true
    storage: file_storage/output_dst_00000502
  timeout: 10s

# extensions:
file_storage/output_dst_00000502:
  create_directory: true
  directory: /var/lib/otelcol-supervisor/sending-queue/output_dst_00000502

The same, as an API call (see automation recipes):

API call
curl -X POST "$LINKMESH/destinations" \
  -H "Authorization: Bearer $LMSAT" \
  -H "Content-Type: application/json" \
  -d '{
  "defaultConfig": {
    "compression": "gzip",
    "durable_queue": true,
    "endpoint": "tempo.example.internal:4317",
    "headers": {
      "x-scope-orgid": "${env:TENANT_ID}"
    },
    "timeout": "10s"
  },
  "exporterType": "otlp",
  "name": "OTLP gRPC",
  "signalTypes": [
    "logs",
    "metrics",
    "traces"
  ]
}'

The rest of the collector config above (memory_limiter, batch) is not part of this template: in LinkMesh those are separate sources, processors and destinations on the route.

Generated from LinkMesh's template catalogue by linkmesh-server snippet-render 1.464.3, not written by hand.

Download config.yamlValidated with otelcol-contrib v0.161.0 on 2026-10-26

Complete config files, each checked with the collector's own validate command (otelcol-contrib v0.161.0).

The gotcha

TLS is on unless you turn it off. In our test, pointed at a plaintext OTLP receiver, the exporter delivered nothing and the collector only logged gRPC transport warnings, not an error; with tls.insecure: true the same record arrived. Use insecure: true only on a trusted network, otherwise give the receiver a certificate.

Manage this across a fleet

LinkMesh manages collector configuration across a fleet from one self-hosted control plane, so a change like this is made once rather than host by host. The first 25 Collectors are free after a no-card registration in the OpenSight Customer Portal (5 without one).

Doing this in LinkMesh: Destinations