How Promtail reads the Docker API and pushes logs to Loki

Short answer: Promtail does not open Docker’s log files. It connects to the local Docker socket, lists container ids, and calls the engine logs API with follow. It splits stdout from stderr, removes Docker’s timestamp prefix, and POSTs the lines to Loki at /loki/api/v1/push. This page assumes that push URL is already reachable.


What Promtail asks the Docker API

docker_sd_configs with host: unix:///var/run/docker.sock talks to the engine on that socket. On each refresh it lists containers that are running then. A container that exits between refreshes is not added. The discovery labels that matter are __meta_docker_container_id and __meta_docker_container_name. The name label has a leading /.

For each new id, Promtail calls inspect to learn whether the container has a TTY, then logs: stdout and stderr, follow, timestamps on, and since taken from the saved cursor. A missing cursor is since=0. Docker then returns the retained log from the start.

A container without a TTY sends a multiplexed stream. Each frame starts with an 8-byte header: the first byte is stdout or stderr, and the last four bytes are the frame length. A TTY container has no header. Promtail reads that stream as stdout.


What the socket is, and what Loki receives

The socket is the engine HTTP API. Promtail’s own calls are list, inspect, and logs. A read-only bind mount does not remove the other methods: start, stop, and create are still requests on the same socket. The socket still has to stay on that host.

Loki receives a push. It does not scrape Promtail. Promtail strips the Docker timestamp off the front of each line, uses that time as the entry time, and POSTs batches to /loki/api/v1/push. The default body is snappy-compressed protobuf. Before that push, Promtail sets __meta_docker_container_log_stream to stdout or stderr and runs relabel. Labels that still start with __ are dropped, so a relabel rule has to copy the stream onto stream if you want to keep it.


The working path

  1. docker_sd_configs.host is unix:///var/run/docker.sock.
  2. In relabel_configs, map __meta_docker_container_name with /(.*) onto container, and copy __meta_docker_container_log_stream onto stream. Promtail does not keep the stream label unless that copy is configured.
  3. Promtail inspects the container id, then follows its logs from the saved cursor.
  4. It demuxes non-TTY frames into stdout and stderr.
  5. It stores cursor-<container id> as the Unix second of each shipped line. The id is the container id, not the name.
  6. It POSTs to a reachable Loki URL, for example http://loki.example:3100/loki/api/v1/push.

The cursor is whole seconds. After a restart, lines from that same second can be sent again. Stop Promtail before you write cursors into its positions file, or its flush overwrites them.

A process that logs only to a file, and never to stdout, is a different pipeline.


Approaches that look simpler and fail

Approach Why it fails
Tail Docker’s json log files on disk That file belongs to the json-file driver. Other drivers store logs elsewhere. The logs API is the same call for all of them.
Run docker logs -f in a loop No cursor, no labels, and a restart repeats or skips lines
Publish the socket to the Loki host The far side gets the engine control API
Mount the socket read-only and treat that as a log-only API The read-only flag does not filter API methods
Start with an empty positions file since=0 ships the retained backlog

A login in front of Loki protects queries. It does not replace keeping the Docker socket on the container host.


When you can drop Promtail

Drop Promtail when the reader already runs on the Docker host and can call the logs API itself. Also drop it when you only ship one known application file, and you do not need every container’s stdout.

Keep it when many containers on a host should appear in Loki and the socket must stay on that host. If Promtail cannot route to the push URL, fix that path first. This page assumes the URL is reachable.


Why this stays published

We hit this while sending container stdout from several hosts into one Loki. Promtail lists containers on the local Docker socket, follows the engine logs API, and pushes the lines. It does not open Docker’s log files, and the socket stays on that host.

本文由 HoHo 與 AI 協作整理,最後更新於 2026 年 10 月 3 日。

Leave a Reply

Your email address will not be published. Required fields are marked *