Snippets · Destinations
Store telemetry in ClickHouse
ClickHouse is a popular self-hosted store for high-volume telemetry. With create_schema the clickhouse exporter creates the database and its tables on start, and ttl sets how long rows live. In our test against ClickHouse 24.8 it created otel.otel_logs and wrote three log records into it.
- Source
- OTLP
- Components
- otlpbatchmemory_limiter
- Destination
- ClickHouse
OpenTelemetry Collector
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:
clickhouse:
endpoint: tcp://clickhouse.example.internal:9000?dial_timeout=10s
database: otel
username: ${env:CLICKHOUSE_USER}
password: ${env:CLICKHOUSE_PASSWORD}
# Creates the database and the otel_logs / otel_traces / otel_metrics_*
# tables on start.
create_schema: true
ttl: 720h
logs_table_name: otel_logs
traces_table_name: otel_traces
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: [clickhouse]
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [clickhouse]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [clickhouse]
LinkMesh
LinkMesh has no built-in template for this job. Add it as a custom destination in raw mode, with clickhouse as the component type and this body - the same lines as under clickhouse in the collector config:
endpoint: tcp://clickhouse.example.internal:9000?dial_timeout=10s
database: otel
username: ${env:CLICKHOUSE_USER}
password: ${env:CLICKHOUSE_PASSWORD}
create_schema: true
ttl: 720h
logs_table_name: otel_logs
traces_table_name: otel_traces
sending_queue:
enabled: true
queue_size: 5000
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
How custom components are validated and rolled out: create a custom destination.
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
The ttl becomes part of the table definition. In our test ttl: 720h turned into "TTL toDateTime(Timestamp) + toIntervalDay(30)" in the CREATE TABLE statement the exporter issued, so retention is part of the table definition from the first start. Set ttl before the collector first runs against an empty database.
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: Create a custom source or destination
Related snippets
- Agents to a gateway tier, load-balanced by trace IDAgents route every span of a trace to the same gateway, so tail sampling on the gateways sees complete traces.
- Send to Azure Monitor (Application Insights)Logs, metrics and traces to Application Insights, authenticated by the connection string from the environment.
- Send to DatadogLogs, metrics and traces to Datadog, with the API key from the environment and a queue in front of the exporter.
- Deduplicate repeated log recordsCollapse a burst of identical errors into one record with a count, instead of storing it a thousand times.