LinkMesh

Search docs, blog and changelog

ENDE

Snippets · Destinations

Write telemetry to a file (JSON lines, rotated)

Sometimes the destination is a file: to inspect exactly what the collector sends, to hand telemetry over from an air-gapped network, or to replay it later. The file exporter writes OTLP JSON, one line per batch, and rotates by size, age and count.

Signals
LogsMetricsTraces
Source
OTLP
Components
otlpbatchmemory_limiter
Destination
Local file

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:
  file:
    path: /var/log/otelcol/export.jsonl
    format: json
    rotation:
      max_megabytes: 100
      max_backups: 5
      max_days: 7

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

LinkMesh

Library › Destinations › File

File Path
/var/log/otelcol/export.jsonl

What LinkMesh then pushes to the collector, under exporters:

Pushed to the collector
file/output_dst_00000502:
  path: /var/log/otelcol/export.jsonl

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": {
    "path": "/var/log/otelcol/export.jsonl"
  },
  "exporterType": "file",
  "name": "File",
  "signalTypes": [
    "logs",
    "metrics",
    "traces"
  ]
}'

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).

Before and after

Example telemetry in, and what this exact config sent out when we ran it in otelcol-contrib v0.161.0. CI re-runs it on every change and fails if the output differs. Changed values are highlighted.

2 log records in, 2 log records out

  1. Before

    body
    order 1002 accepted
    timestamp
    2025-10-09T08:53:20.000Z
    severity
    INFO
    severity_number
    9
    resource.service.name
    checkout

    After

    body
    order 1002 accepted
    timestamp
    2025-10-09T08:53:20.000Z
    severity
    INFO
    severity_number
    9
    resource.service.name
    checkout
  2. Before

    body
    payment provider timeout
    timestamp
    2025-10-09T08:53:21.000Z
    severity
    ERROR
    severity_number
    17
    resource.service.name
    checkout

    After

    body
    payment provider timeout
    timestamp
    2025-10-09T08:53:21.000Z
    severity
    ERROR
    severity_number
    17
    resource.service.name
    checkout

The gotcha

The directory must exist. In our test, with the path pointing into a missing directory, the collector exited at start with "failed to start \"file\" exporter: ... open /var/log/otelcol-missing: no such file or directory" - the file exporter does not create it. Create the directory, writable by the collector user, before you start.

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