Skip to main content
This page ships container logs from a Linux host to Rootprint over OTLP. Vector reads the Docker daemon socket: it auto-discovers containers and attaches container.name, container.image.name, and friends with no extra wiring.
This page collects every container’s stdout — Vector via the Docker daemon socket, the Collector via on-disk container logs. To run an agent as a container that tails specific files you bind-mount in, see the agent pages: Vector, OpenTelemetry Collector, Fluent Bit.

Prerequisites

  • A running Rootprint instance and its base URL — you’ll substitute it for <your-rootprint>.
  • A Linux host with Docker (and Docker Compose for the examples below).
  • A log agent: Vector or the OpenTelemetry Collector.
  • An ingest API key scoped to your target index. See API keys.
Mounting /var/run/docker.sock into a container lets it enumerate and inspect every container on the host. This is standard for log collectors that use the Docker API. The mount below is read-only (:ro).
1

Create the Vector config

Save this as vector.yaml next to your docker-compose.yml. Replace <your-rootprint> with your Rootprint base URL and <your-ingest-token> with the API key.
2

Add the Vector service to your compose file

Drop this service alongside your existing ones. The Vector container reads every other container’s logs through the Docker socket. No changes needed to your application services.
The container_name and the exclude_containers value in vector.yaml must match. That’s how Vector skips its own logs. Change one, change the other.
3

Start the Vector service

4

Send a test log line

Run a throwaway container that prints one line and exits. Vector picks it up from the daemon and ships it with service.name set to the container’s name.
5

Verify in Rootprint

Open Search, pick otel-logs-v0_9 from the index selector, and query for hello from rootprint. The record typically arrives within 5 seconds (one batch interval). service.name reads rootprint-smoke-test; attributes.container.image.name reads alpine.

What the remap does

Two remap transforms run in sequence. enrich infers a severity level from the message body. to_otlp packs the message and the Docker-supplied metadata into the OTLP wire format that Rootprint’s ingest endpoint expects.

Severity inference

The message body is lowercased and matched against two pattern families:
  • error, fatal, panic, or exception (word-boundary) → severityText: ERROR (severity number 17).
  • warn / warning, deprecated, or retryseverityText: WARN (13).
  • Everything else → severityText: INFO (9).
DEBUG is not inferred. \bdebug\b against arbitrary container output false-positives constantly. Apps that need debug-level visibility should emit it via an OpenTelemetry SDK that sets severityNumber itself; the OTLP record will carry that through unchanged because the SDK writes to the same endpoint.

Apps that emit JSON

If a container writes structured JSON to stdout, the body arrives as a string but its content is JSON. Add a parse_json step in enrich and assign parsed fields to attributes. The OTLP attribute list takes them as-is.

What you get in Rootprint

service.name is derived from the container’s name (with the leading / Docker prefixes stripped) when using Vector; it is not set automatically by the OTEL Collector path. Per-event attributes by agent:
OTLP keyVectorOpenTelemetry Collector
container.idfull 64-char IDfull 64-char ID (from filepath)
container.namename without leading /not populated
container.image.nameimage reference (e.g., nginx:latest)not populated
container.image.idimage digestnot populated
container.runtimeliteral dockerliteral docker
log.iostreamstdout or stderrnot populated
severityinferred from message bodyinferred from message body
The Vector path populates all rows. The OTEL Collector path populates container.id, container.runtime, and severity only; it cannot resolve container.name or container.image.name from the json-file path without the Docker socket. Container labels are not promoted by default. They’re user-defined and unbounded, and adding all of them risks attribute-cardinality issues. To promote a specific label with Vector, add one line to the to_otlp remap before the . = { ... } assignment:

Troubleshooting

  • 401 from Rootprint: the Authorization header is missing or the token is wrong. Check the token value in your config.
  • 403 from Rootprint: the API key exists but is not scoped to otel-logs-v0_9. Create a new key scoped to that index.
  • 413 from Rootprint: the batch is too large. Lower max_bytes (Vector) or add send_batch_max_size to the batch processor (OTEL Collector).
  • 415 from Rootprint: the Content-Type is not application/x-protobuf. Both agents set this automatically; if you see a 415, check for a proxy stripping headers.