LinkMesh

Search docs, blog and changelog

ENDE

Snippets · Destinations

Send logs to Loki over native OTLP

Loki 3 accepts OTLP natively at /otlp, so the standard otlphttp exporter sends logs to it with the tenant header and compression, and resource attributes arrive as structured metadata.

Signals
Logs
Source
OTLP
Components
otlpbatchmemory_limiterotlphttp
Destination
Grafana Loki

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:
  otlphttp/loki:
    # Loki 3.x accepts OTLP natively at /otlp; no loki exporter needed.
    endpoint: http://loki.example.internal:3100/otlp
    headers:
      X-Scope-OrgID: ${env:LOKI_TENANT}
    compression: gzip
    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: [otlphttp/loki]

LinkMesh

Library › Destinations › Loki

Endpoint
http://loki.example.internal:3100/loki/api/v1/push
Tenant ID
${env:LOKI_TENANT}

What LinkMesh then pushes to the collector, under exporters:

Pushed to the collector
otlphttp/output_dst_00000502:
  endpoint: http://loki.example.internal:3100/otlp
  headers:
    X-Scope-OrgID: ${env:LOKI_TENANT}

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": {
    "endpoint": "http://loki.example.internal:3100/loki/api/v1/push",
    "tenant_id": "${env:LOKI_TENANT}"
  },
  "exporterType": "loki",
  "name": "Loki",
  "signalTypes": [
    "logs"
  ]
}'

The rest of the collector config above (otlp, 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

Many guides still show the loki exporter. It is gone: in our test otelcol-contrib 0.161.0 refused a config using it with "\'exporters\' unknown type: \"loki\"" - the only loki component left is a receiver. Use otlphttp against Loki's /otlp endpoint, as here.

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