Docker
Collect Docker logs and cAdvisor metrics in Parseable
Overview
Collect Docker container logs and cAdvisor metrics in Parseable, so you can see what your containers are writing and how they are using CPU, memory, network, storage, and other runtime resources. Metrics are collected from cAdvisor and forwarded through Prometheus Remote Write, while logs can move through Fluent Bit or a direct HTTP push.
Along with the raw logs and metrics, you can attach Docker metadata such as container, image, project, and service. Once the data starts flowing, you can also import the Docker Monitoring dashboard to see the same signals in a ready-made view.
Prerequisites
- Docker installed
- Parseable instance accessible
- Parseable API key with ingest access
- Prometheus and cAdvisor for metrics
- Fluent Bit or a logging driver for logs
Collect Docker metrics
cAdvisor exports container and machine metrics in Prometheus format. Prometheus scrapes cAdvisor and forwards the samples to Parseable through Prometheus Remote Write.
Docker Engine -> cAdvisor :8080 -> Prometheus -> Parseable /v1/prometheus/write
(docker-metrics dataset)Configure Prometheus
Create prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: cadvisor
static_configs:
- targets: ["cadvisor:8080"]
labels:
node: docker-host
metric_relabel_configs:
- source_labels: [name]
target_label: container
- source_labels: [container_label_com_docker_compose_project]
target_label: project
- source_labels: [container_label_com_docker_compose_service]
target_label: service
remote_write:
- url: "https://<parseable-ingestor>/v1/prometheus/write"
headers:
X-API-Key: <parseable-api-key>
X-P-Stream: docker-metrics
X-P-Log-Source: otel-metricsX-API-Key authorizes the write to Parseable. X-P-Stream selects the Parseable dataset. Keep X-P-Log-Source set to otel-metrics. Change the node label when monitoring more than one Docker host.
The metric relabel rules expose the cAdvisor name label as container and shorten Docker Compose's project and service label names. These names match the dashboard variables and queries.
Run cAdvisor and Prometheus
Create docker-compose.yml beside prometheus.yml:
services:
cadvisor:
image: ghcr.io/google/cadvisor:v0.60.5
container_name: cadvisor
privileged: true
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /sys:/sys:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
prometheus:
image: prom/prometheus:latest
container_name: prometheus
command:
- --config.file=/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
depends_on:
- cadvisor
restart: unless-stoppedStart both services:
docker compose up -dOpen http://localhost:9090/targets and confirm that the cadvisor target is UP. You can also check cAdvisor directly:
curl http://localhost:8080/metricsIn Parseable, select the docker-metrics dataset and run a PromQL query such as:
up{job="cadvisor"}Common cAdvisor families include container_cpu_usage_seconds_total, container_memory_working_set_bytes, container_network_receive_bytes_total, container_fs_usage_bytes, and container_last_seen.
Once the samples are ingested, open the docker-metrics dataset in Parseable. You should be able to see the cAdvisor metric families, filter by labels such as container or node, and move into PromQL when you want to inspect a specific series.

Collect Docker logs
Docker logs can be sent to Parseable in a few different ways. Fluent Bit is the most common path because it can receive logs from Docker's Fluentd logging driver or tail Docker's JSON log files directly.
Option 1: Fluent Bit sidecar
Deploy Fluent Bit alongside your containers.
Docker Compose example
version: '3.8'
services:
app:
image: your-app:latest
logging:
driver: fluentd
options:
fluentd-address: localhost:24224
tag: app.logs
fluent-bit:
image: fluent/fluent-bit:latest
ports:
- "24224:24224"
volumes:
- ./fluent-bit.yaml:/fluent-bit/etc/fluent-bit.yaml
command: ["/fluent-bit/bin/fluent-bit", "-c", "/fluent-bit/etc/fluent-bit.yaml"]Fluent Bit configuration
service:
flush: 5
log_level: info
pipeline:
inputs:
- name: forward
listen: 0.0.0.0
port: 24224
outputs:
- name: http
match: '*'
host: parseable
port: 8000
uri: /api/v1/ingest
format: json
header: X-API-Key <parseable-api-key>
header: X-P-Stream docker-logsOption 2: Docker log driver
Use Docker's built-in logging drivers.
Fluentd Driver
version: '3.8'
services:
app:
image: your-app:latest
logging:
driver: fluentd
options:
fluentd-address: "fluent-bit:24224"
fluentd-async: "true"
tag: "docker.{{.Name}}"JSON file driver with tail
Collect logs from Docker's default JSON file driver:
# fluent-bit.yaml
service:
flush: 5
log_level: info
pipeline:
inputs:
- name: tail
path: /var/lib/docker/containers/*/*.log
parser: docker
tag: docker.*
refresh_interval: 5
mem_buf_limit: 5MB
skip_long_lines: on
parsers:
- name: docker
format: json
time_key: time
time_format: "%Y-%m-%dT%H:%M:%S.%L"
filters:
- name: modify
match: docker.*
add: source docker
outputs:
- name: http
match: '*'
host: parseable
port: 8000
uri: /api/v1/ingest
format: json
header: X-API-Key <parseable-api-key>
header: X-P-Stream docker-logsDocker Compose with log collection
version: '3.8'
services:
fluent-bit:
image: fluent/fluent-bit:latest
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./fluent-bit.yaml:/fluent-bit/etc/fluent-bit.yaml
command: ["/fluent-bit/bin/fluent-bit", "-c", "/fluent-bit/etc/fluent-bit.yaml"]
parseable:
image: quay.io/parseablehq/parseable:latest
ports:
- "8000:8000"
environment:
- P_USERNAME=admin
- P_PASSWORD=adminOption 3: Direct HTTP logging
Send logs directly from your application.
Python example
import logging
import requests
import os
from datetime import datetime
class ParseableHandler(logging.Handler):
def __init__(self, url, dataset, api_key):
super().__init__()
self.url = f"{url}/api/v1/ingest"
self.dataset = dataset
self.api_key = api_key
self.buffer = []
self.batch_size = 100
def emit(self, record):
log_entry = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"level": record.levelname.lower(),
"message": self.format(record),
"logger": record.name,
"container": os.environ.get("HOSTNAME", "unknown")
}
self.buffer.append(log_entry)
if len(self.buffer) >= self.batch_size:
self.flush()
def flush(self):
if not self.buffer:
return
try:
requests.post(
self.url,
json=self.buffer,
headers={
"X-API-Key": self.api_key,
"X-P-Stream": self.dataset,
}
)
except Exception as e:
print(f"Failed to send logs: {e}")
finally:
self.buffer = []
# Usage
handler = ParseableHandler(
url="http://parseable:8000",
dataset="app-logs",
api_key=os.environ["PARSEABLE_API_KEY"]
)
logging.getLogger().addHandler(handler)Option 4: Docker events
Collect Docker daemon events.
Event collector script
#!/usr/bin/env python3
import docker
import requests
import os
from datetime import datetime
PARSEABLE_URL = "http://parseable:8000"
PARSEABLE_API_KEY = os.environ["PARSEABLE_API_KEY"]
STREAM = "docker-events"
client = docker.from_env()
for event in client.events(decode=True):
log_entry = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"event_type": event.get("Type"),
"action": event.get("Action"),
"actor_id": event.get("Actor", {}).get("ID"),
"actor_attributes": event.get("Actor", {}).get("Attributes"),
"status": event.get("status"),
"from": event.get("from")
}
try:
requests.post(
f"{PARSEABLE_URL}/api/v1/ingest",
json=[log_entry],
headers={
"X-API-Key": PARSEABLE_API_KEY,
"X-P-Stream": STREAM,
}
)
except Exception as e:
print(f"Error: {e}")Container Labels
Add metadata using Docker labels:
version: '3.8'
services:
app:
image: your-app:latest
labels:
- "logging.parseable.dataset=app-logs"
- "logging.parseable.service=my-app"
- "logging.parseable.environment=production"Use Labels in Fluent Bit
filters:
- name: modify
match: docker.*
add: service ${LABEL_logging.parseable.service}
add: environment ${LABEL_logging.parseable.environment}Querying Docker Logs
-- Recent container logs
SELECT timestamp, container_name, message, level
FROM "docker-logs"
ORDER BY timestamp DESC
LIMIT 100
-- Error logs by container
SELECT container_name, COUNT(*) as error_count
FROM "docker-logs"
WHERE level = 'error'
AND timestamp > NOW() - INTERVAL '1 hour'
GROUP BY container_name
ORDER BY error_count DESC
-- Container events
SELECT timestamp, event_type, action, actor_id
FROM "docker-events"
ORDER BY timestamp DESC
LIMIT 50Docker Monitoring dashboard
The reusable Docker Monitoring dashboard is available in the parseablehq/dashboards repository.
Import docker-monitoring-mixed.json, then set Docker Metrics Dataset to the dataset configured in X-P-Stream. The default is docker-metrics. The dashboard includes container CPU, memory, network, storage, task state, health, inventory, cAdvisor scrape health, and metric inventory.
The Project and Service filters are populated from Docker Compose labels. Containers started outside Compose can still be filtered by Node and Container.




Best Practices
- Use Labels - Add metadata for filtering
- Identify Hosts - Assign a stable
nodelabel to each cAdvisor scrape target - Buffer Logs - Batch logs for efficiency
- Handle Backpressure - Configure memory limits
- Monitor Collectors - Watch Prometheus, cAdvisor, and Fluent Bit health
- Rotate Logs - Configure Docker log rotation
Troubleshooting
Missing Logs
- Verify logging driver is configured
- Check Fluent Bit is running
- Verify Parseable endpoint is accessible
- Check container permissions
Missing Metrics
- Open the Prometheus Targets page and confirm that cAdvisor is UP
- Check
docker compose logs cadvisor prometheusfor scrape or remote-write errors - Verify that Prometheus can reach
/v1/prometheus/writeon the Parseable ingestor - Confirm the
X-P-Stream: docker-metricsandX-P-Log-Source: otel-metricsheaders - Confirm that the cAdvisor container can read the Docker runtime paths mounted in the Compose file
Some metric families are conditional. Health-state metrics require Docker health checks, project and service labels require Docker Compose, and resource-limit metrics require limits on the container.
High Memory Usage
- Configure
mem_buf_limitin Fluent Bit - Enable Docker log rotation
- Reduce batch sizes
Next Steps
- Configure Kubernetes for orchestration
- Set up alerts for container events
- Import the Docker Monitoring dashboard
Was this page helpful?