Minimal footprint OTLP node metrics exporter (x86_64 + aarch64)
C
2
1 commits
updated Sep 24, 2026
pico_exporter is a system metrics exporter written in C that runs in about 120 kiB of memory. It is a drop-in replacement for the Prometheus node_exporter, but instead of waiting to be scraped it pushes the metrics to an OTLP gateway over TLS, so there is no need for an extra piece of software to pick the metrics up and forward them to the gateway.
I wanted system metrics from a Raspberry Pi, and every alternative I came across seemed to use an absurd amount of resources for the work it had to do. So I built my own. What I did not expect was to win three orders of magnitude of memory doing it. For the full story, see JOURNEY.md.
malloc on the hot cycle path.Compared with the usual alternatives, Grafana Alloy and the Prometheus node_exporter:
| Grafana Alloy | node_exporter | pico_exporter | |
|---|---|---|---|
| Delivery | push (OTLP) and pull | pull based | push only |
| Metrics scope | Full OpenTelemetry ecosystem | system metrics (extensible) | core system metrics + textfile |
| Logs & traces | yes | no | no |
| Configuration | declarative config file | many flags | a few env vars |
| Extensibility | large component catalog | collector plugins | fixed set |
| Language | Go | Go | C11 |
| Binary | ~530 MB | ~22 MB | ~100 kB |
Only Grafana Alloy is compared here, because it is the one that does everything and can be measured head-to-head with pico_exporter. Measured on my machine, over the same running window:
| Grafana Alloy | pico_exporter | Ratio | |
|---|---|---|---|
| Binary size | 530 000 kB | 100 kB | 5300× smaller |
| Steady RSS | 400 000 kB | 132 kB | 3000× less memory |
| CPU per day | 516 s | 6 s | 86× less CPU |
| Scrape time | 50 ms | 6 ms | 8× faster |
curl -fsSL -o pico_exporter \
https://github.com/dpaneda/pico_exporter/releases/latest/download/pico_exporter-aarch64
chmod +x pico_exporter
GW_URL=https://otlp-gateway-prod/otlp/v1/metrics \
GW_USER=12345 GW_PASS=glc_... \
./pico_exporter
For building from source and the host prerequisites, see DEVELOPMENT.md.
Configuration is environment-based:
| Env | Required | Default | Meaning |
|---|---|---|---|
GW_URL | yes (push mode) | none | push endpoint, https://host[:port]/path or http://… |
GW_USER / GW_PASS | no | empty | HTTP Basic-auth (Grafana Cloud: stack id / glc_…) |
JOB | no | integrations/node_exporter | OTel service.name → Prometheus job |
INSTANCE | no | uname -n | OTel service.instance.id → Prometheus instance. Set it when two exporters share a host so they do not collide into one series |
INTERVAL | no | 15 | collection/push cycle in seconds |
BATCH | no | 100 | samples per OTLP request |
TEXTFILE_DIR | no | unset | directory of *.prom files to fold into each push; unset disables the collector |
Drop the binary on the host, point it at your gateway and run it under
whatever supervises your services. There is a ready unit in
contrib/pico_exporter.service.
Every push writes a line to the log, so the journal is the whole health check: if it is working, you will see it say so each cycle.
There is no CA bundle on disk to point at: the root certificate is baked into the binary, and the default is DigiCert G2, the CA behind Grafana Cloud's gateway. Any endpoint signed by something else fails validation, and the fix is a rebuild rather than a flag. Point the build at the endpoint and it captures and compiles in the chain that endpoint serves:
make GW_URL=https://your-gateway:443/
INSECURE=1 skips validation altogether. It is not recommended: the binary
then trusts any well-formed certificate, so anyone on the path can read and
rewrite what you push.
1 commits
C
70.4%
Shell
22.7%
Makefile
5.7%
Python
1.2%
Minimal footprint OTLP node metrics exporter (x86_64 + aarch64)
C
2
1 commits
updated Sep 24, 2026
pico_exporter is a system metrics exporter written in C that runs in about 120 kiB of memory. It is a drop-in replacement for the Prometheus node_exporter, but instead of waiting to be scraped it pushes the metrics to an OTLP gateway over TLS, so there is no need for an extra piece of software to pick the metrics up and forward them to the gateway.
I wanted system metrics from a Raspberry Pi, and every alternative I came across seemed to use an absurd amount of resources for the work it had to do. So I built my own. What I did not expect was to win three orders of magnitude of memory doing it. For the full story, see JOURNEY.md.
malloc on the hot cycle path.Compared with the usual alternatives, Grafana Alloy and the Prometheus node_exporter:
| Grafana Alloy | node_exporter | pico_exporter | |
|---|---|---|---|
| Delivery | push (OTLP) and pull | pull based | push only |
| Metrics scope | Full OpenTelemetry ecosystem | system metrics (extensible) | core system metrics + textfile |
| Logs & traces | yes | no | no |
| Configuration | declarative config file | many flags | a few env vars |
| Extensibility | large component catalog | collector plugins | fixed set |
| Language | Go | Go | C11 |
| Binary | ~530 MB | ~22 MB | ~100 kB |
Only Grafana Alloy is compared here, because it is the one that does everything and can be measured head-to-head with pico_exporter. Measured on my machine, over the same running window:
| Grafana Alloy | pico_exporter | Ratio | |
|---|---|---|---|
| Binary size | 530 000 kB | 100 kB | 5300× smaller |
| Steady RSS | 400 000 kB | 132 kB | 3000× less memory |
| CPU per day | 516 s | 6 s | 86× less CPU |
| Scrape time | 50 ms | 6 ms | 8× faster |
curl -fsSL -o pico_exporter \
https://github.com/dpaneda/pico_exporter/releases/latest/download/pico_exporter-aarch64
chmod +x pico_exporter
GW_URL=https://otlp-gateway-prod/otlp/v1/metrics \
GW_USER=12345 GW_PASS=glc_... \
./pico_exporter
For building from source and the host prerequisites, see DEVELOPMENT.md.
Configuration is environment-based:
| Env | Required | Default | Meaning |
|---|---|---|---|
GW_URL | yes (push mode) | none | push endpoint, https://host[:port]/path or http://… |
GW_USER / GW_PASS | no | empty | HTTP Basic-auth (Grafana Cloud: stack id / glc_…) |
JOB | no | integrations/node_exporter | OTel service.name → Prometheus job |
INSTANCE | no | uname -n | OTel service.instance.id → Prometheus instance. Set it when two exporters share a host so they do not collide into one series |
INTERVAL | no | 15 | collection/push cycle in seconds |
BATCH | no | 100 | samples per OTLP request |
TEXTFILE_DIR | no | unset | directory of *.prom files to fold into each push; unset disables the collector |
Drop the binary on the host, point it at your gateway and run it under
whatever supervises your services. There is a ready unit in
contrib/pico_exporter.service.
Every push writes a line to the log, so the journal is the whole health check: if it is working, you will see it say so each cycle.
There is no CA bundle on disk to point at: the root certificate is baked into the binary, and the default is DigiCert G2, the CA behind Grafana Cloud's gateway. Any endpoint signed by something else fails validation, and the fix is a rebuild rather than a flag. Point the build at the endpoint and it captures and compiles in the chain that endpoint serves:
make GW_URL=https://your-gateway:443/
INSECURE=1 skips validation altogether. It is not recommended: the binary
then trusts any well-formed certificate, so anyone on the path can read and
rewrite what you push.
1 commits
C
70.4%
Shell
22.7%
Makefile
5.7%
Python
1.2%