With 1,000 tracked files, the OpenTelemetry Collector's File Log receiver was burning roughly 77 ms of CPU every second just recording where it had stopped reading. Starting with Collector Contrib v0.164.0 that checkpoint is written as protobuf, the cost drops to about 16 ms and the file shrinks by 35%. No config change is needed, but it's worth knowing what moves under the hood before you roll it out to your DaemonSets.
What the checkpoint is and why it was expensive
When filelog runs with a storage extension (usually file_storage), the receiver keeps one record per tracked file: a fingerprint made of the file's first 1,000 bytes, the read offset, the record number, file attributes and some state for partial lines. That whole list is serialized and written at the end of every poll cycle. With the default poll_interval of 200 ms, that's five writes per second for as long as the process lives, while the checkpoint is only read once, at startup.
On a Kubernetes node with hundreds of container logs, that adds up. The change traces back to a report from October 2025: a user saw their Collector shipping Kubernetes logs with file_storage using noticeably more resources than Fluent Bit doing similar work, and profiling pointed straight at JSON encoding of the checkpoint.
JSON was a poor fit on three counts. The fingerprint is raw bytes, so JSON had to turn it into text, making it about a third bigger and redoing that work on every save. Every record repeated the same field names. And numbers and timestamps were stored as text. Nobody reads this file except the receiver, so JSON was paying for readability no one used.
The numbers
The maintainers used the benchmarks in pkg/stanza/fileconsumer, with 1,000 files, 1,000-byte fingerprints and five attributes per file, on a 4 vCPU VM:
| Operation (1,000 files) | JSON | Protobuf | Change |
|---|---|---|---|
| Save | 15.38 ms | 3.21 ms | −79% |
| Load | 28.18 ms | 5.01 ms | −82% |
| Checkpoint size | 1.740 MiB | 1.139 MiB | −35% |
| Memory allocated per save | 5.807 MiB | 2.919 MiB | −50% |
The speedup holds at 4 to 6.5x from a single file up to a thousand, so it isn't a scale artifact. Save time is the number that matters in production because it runs five times a second: that CPU goes back to parsing and exporting logs, and the node's disk sees less write traffic. The one trade-off is 10–13% more allocations per save, though they're smaller and total bytes allocated are halved.
The archive kept by the polls_to_archive setting uses the same encoding, so it gets the same gains.
What changes in your config
Nothing. On startup, v0.164.0 still reads existing JSON checkpoints and rewrites them as protobuf on the next save, so you keep your offsets and don't lose or duplicate logs. Protobuf is no longer opt-in: it's the only format written from this version on.
This is the setup that's affected. If your filelog has no storage, offsets live in memory and this change doesn't apply to you (though then every restart re-reads or skips logs, which is a bigger problem):
extensions:
file_storage:
directory: /var/lib/otelcol/file_storage
receivers:
filelog:
include: [/var/log/pods/*/*/*.log]
storage: file_storage
service:
extensions: [file_storage]Upgrading to v0.164.0
filelog isn't part of the core Collector image; it ships in the Contrib and Kubernetes distributions. With Docker:
docker pull otel/opentelemetry-collector-contrib:0.164.0With the official Helm chart, refresh the repo and check that the chart's app version is 0.164.0 or later before you upgrade your release:
helm repo update open-telemetry
helm search repo open-telemetry/opentelemetry-collectorValidating it before production
- Roll it out to a node or test environment that already has JSON checkpoints in
file_storage, so you exercise the conversion rather than a clean start. - Restart the pod a couple of times and check your backend for duplicated lines or gaps around each restart.
- Compare Collector CPU before and after on the nodes with the most files, which is where the difference shows.
- Watch the size of the
file_storagedirectory: it should drop by about a third.
The real caveat here is rolling back. The announcement covers moving from JSON to protobuf, but it doesn't say an older version can read a protobuf checkpoint. If your deployment pipeline includes automatic rollback, test it in that environment before trusting it to keep your offsets.
Sources
- Faster, smaller checkpoints: the File Log receiver now uses protobuf (OpenTelemetry blog, October 28, 2026)
- Install the Collector with Docker (OpenTelemetry docs)
- OpenTelemetry Collector Chart (OpenTelemetry docs)