How to Configure the OpenTelemetry Collector
Use the OpenTelemetry Collector to route telemetry from applications to duckdb-otlp. You can forward OTLP/HTTP to the server image, or write OTLP files for later DuckDB analysis.
Forward to the Server Image
Section titled “Forward to the Server Image”Start a local DuckLake-backed server:
cat > .env <<'EOF'DUCKDB_MODE=local-ducklakeDUCKDB_OTLP_TOKEN=dev-token-123456
DUCKLAKE_NAME=lakeDUCKLAKE_CATALOG_PATH=/data/ducklake/catalog.duckdbDUCKLAKE_DATA_PATH=/data/ducklake/storage
DUCKDB_QUACK_ENABLED=1DUCKDB_QUACK_ADDR=0.0.0.0:9494DUCKDB_QUACK_TOKEN=dev-quack-token-123456EOF
mkdir -p data
docker run --rm --name duckdb-otlp \ --env-file .env \ -p 4318:4318 \ -p 9494:9494 \ -v "$(pwd)/data:/data" \ ghcr.io/smithclay/duckdb-otlp:latestIn another terminal, create collector-to-duckdb.yaml:
receivers: otlp: protocols: grpc: http:
processors: batch:
exporters: otlp_http/duckdb: endpoint: http://localhost:4318 headers: Authorization: Bearer dev-token-123456
service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [otlp_http/duckdb] logs: receivers: [otlp] processors: [batch] exporters: [otlp_http/duckdb] metrics: receivers: [otlp] processors: [batch] exporters: [otlp_http/duckdb]Run the collector:
otelcol-contrib --config collector-to-duckdb.yamlPoint applications at the collector’s OTLP endpoints:
- OTLP/gRPC:
http://localhost:4317 - OTLP/HTTP:
http://localhost:4318
The collector forwards traces, logs, and metrics to duckdb-otlp, which writes them into DuckLake tables.
If the collector itself runs in Docker, use http://host.docker.internal:4318 for the exporter endpoint. On Linux, add host.docker.internal with Docker’s host-gateway support.
Query Forwarded Telemetry
Section titled “Query Forwarded Telemetry”Flush buffered telemetry and query through the running duckdb-otlp container:
duckdb <<'SQL'INSTALL quack;LOAD quack;
FROM quack_query( 'quack:localhost:9494', 'SELECT * FROM otlp_flush(''otlp:0.0.0.0:4318'')', token = 'dev-quack-token-123456');
FROM quack_query( 'quack:localhost:9494', $$ SELECT service_name, name, count(*) AS spans FROM lake.main.otlp_traces GROUP BY service_name, name ORDER BY spans DESC LIMIT 20 $$, token = 'dev-quack-token-123456');SQLThe server image is distroless and has no shell or DuckDB CLI, so run inspection SQL from a host DuckDB process through Quack instead of docker exec ... sh -c.
Write OTLP Files Instead
Section titled “Write OTLP Files Instead”Use the file exporter when you want files that DuckDB can query without a running server.
Create collector-to-files.yaml:
receivers: otlp: protocols: grpc: http:
processors: batch:
exporters: file/otel-json: path: ./otel-export/telemetry.jsonl rotation: max_megabytes: 50 max_days: 1 encoding: json
service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [file/otel-json] logs: receivers: [otlp] processors: [batch] exporters: [file/otel-json] metrics: receivers: [otlp] processors: [batch] exporters: [file/otel-json]Run it:
otelcol-contrib --config collector-to-files.yamlThe collector listens on the OTLP ports and writes JSONL files under ./otel-export/.
To generate protobuf files, switch the exporter to encoding: proto.
Query Exported Files
Section titled “Query Exported Files”INSTALL otlp FROM community;LOAD otlp;
SELECT trace_id, name, duration_time_unix_nanoFROM read_otlp_traces('otel-export/*.jsonl')ORDER BY start_time_unix_nano DESCLIMIT 20;
SELECT time_unix_nano, severity_text, bodyFROM read_otlp_logs('otel-export/*.jsonl')WHERE severity_text IN ('ERROR', 'FATAL');
SELECT time_unix_nano, name, coalesce(double_value, int_value::DOUBLE) AS valueFROM read_otlp_metrics_gauge('otel-export/*.jsonl');