/docs/opentelemetry-docker
container logs + docker_stats
free plan / 1 gb-mo
telemtra.io
// docker

OpenTelemetry with Docker
and docker-compose.

Run the OpenTelemetry Collector as a Docker container, ingest OTLP from your app containers, collect Docker daemon stats, and forward everything to Telemtra in one docker-compose.yml.

Why run a Collector container

Apps can send OTLP straight to Telemtra from inside Docker, but running the OpenTelemetry Collector alongside them gives you batching, retries, and a single egress connection regardless of how many app containers you scale to. The Collector is also where you collect container logs from Docker's JSON file driver and scrape Docker daemon stats — neither of which the app SDK does on its own.

Where this goes in your project

If you already have a docker-compose.yml, you are adding one service and one config file. If you have a Dockerfile for your app, it stays unchanged — the OTel SDK reads its config from environment variables you pass via Compose.

my-service/
├── Dockerfile                      # your existing app image (unchanged)
├── docker-compose.yml              # add the "otelcol" service and OTEL_* env on "app"
├── otel-collector-config.yaml      # NEW: the Collector config from the next section
└── .env                            # TELEMTRA_API_KEY=...

1. Save otel-collector-config.yaml at the same level as docker-compose.yml (the YAML in the next section).

2. Append the otelcol service to your existing docker-compose.yml and add the four OTEL_* environment variables to your existing app service. No code changes needed inside the app if you already use the OpenTelemetry SDK.

3. Put your API key in .env (Compose loads it automatically):

TELEMTRA_API_KEY=tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

4. Bring everything up:

docker compose up -d

The Collector starts first because your app depends on it; the app then exports OTLP to http://otelcol:4318 on the Compose network.

Collector config

Save this as otel-collector-config.yaml next to your docker-compose.yml:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
  filelog:
    include: [/var/lib/docker/containers/*/*-json.log]
    start_at: end
    operators:
      - type: json_parser
        parse_from: body
      - type: move
        from: attributes.log
        to: body
  docker_stats:
    endpoint: unix:///var/run/docker.sock
    collection_interval: 30s

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 256
  batch:
    timeout: 5s
    send_batch_size: 1024

exporters:
  otlphttp/telemtra:
    endpoint: https://ingest.telemtra.io
    headers:
      x-api-key: ${env:TELEMTRA_API_KEY}

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlphttp/telemtra]
    metrics:
      receivers: [otlp, docker_stats]
      processors: [memory_limiter, batch]
      exporters: [otlphttp/telemtra]
    logs:
      receivers: [otlp, filelog]
      processors: [memory_limiter, batch]
      exporters: [otlphttp/telemtra]

docker-compose.yml

services:
  otelcol:
    image: otel/opentelemetry-collector-contrib:latest
    command: ["--config=/etc/otel/config.yaml"]
    environment:
      - TELEMTRA_API_KEY=${TELEMTRA_API_KEY}
    volumes:
      - ./otel-collector-config.yaml:/etc/otel/config.yaml:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "4317:4317"
      - "4318:4318"
    restart: unless-stopped

  app:
    image: your-app:latest
    environment:
      - OTEL_SERVICE_NAME=checkout-api
      - OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
      - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4318
      - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
    depends_on:
      - otelcol

Run TELEMTRA_API_KEY=your_key docker compose up -d. Your app sends OTLP to the Collector on the internal Compose network; the Collector batches and forwards to Telemtra.

Point your app at the Collector

Inside the Compose network, the Collector is reachable by service name. Set OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4318 in the app container. For OTLP gRPC, use http://otelcol:4317.

Container logs

The filelog receiver reads Docker's JSON log driver output from /var/lib/docker/containers/*/*-json.log. The json_parser operator parses each line, then we move log into the body. Container name and image come from Docker's per-container metadata; you can add a resource processor to enrich.

Docker daemon metrics

The docker_stats receiver talks to the Docker socket and emits per-container CPU, memory, network, and block IO metrics. In Telemtra you can chart them with the same widgets as OTLP-native metrics.

Troubleshooting

  • filelog reads nothing. Confirm Docker is using the json-file log driver, not journald or local. docker info | grep "Logging Driver".
  • docker_stats permission denied. The Collector container needs the Docker socket mounted; mount it read-only as shown above.
  • 403 to Telemtra. Confirm TELEMTRA_API_KEY is set in the host environment when you run docker compose up.
  • High memory usage. Lower limit_mib on memory_limiter and reduce send_batch_size.

For Kubernetes, see OpenTelemetry on Kubernetes. For protocol details, see What is OTLP? New to Telemtra? The quickstart includes a docker-compose snippet that talks straight to ingest.telemtra.io. Create a workspace to get an API key.

Further reading