Agent
Server collector
Runs under systemd as an unprivileged user with a strict filesystem policy
Technical overviewData engineering and observability
A streaming telemetry pipeline from host collectors to a day-partitioned archive.
Source code
The repository is private. The architecture, engineering decisions, and verified evidence are documented below.
01
Sentinel collects operational telemetry from two self-hosted machines and moves it through Kafka into a day-partitioned HDFS archive that a public dashboard reads back. Collectors publish system, container, and endpoint readings every ten seconds, buffer to local disk whenever the broker is unreachable, and replay in order once it returns. It is live at sentinel.pesanth.com.
02
Agent
Runs under systemd as an unprivileged user with a strict filesystem policy
Agent
Registered as a scheduled task that starts at logon
Durability
Bounded local buffer holding readings the broker could not accept
Message broker
Single node in KRaft mode with separate listeners for local, container, and remote clients
Streams
System metrics, container inventory, and endpoint checks, each on its own topic
Consumer
Batches readings and commits stream offsets only once the files land
Coordinator
Namespace and block metadata for the archive
Archive
Immutable newline-delimited JSON, partitioned by the day each reading was taken
Web interface
Host cards, endpoint checks, and archive coverage, each row carrying its own age
Public ingress
Outbound-only ingress publishing the dashboard without opening a router port
03
Readings are filed under the day they were taken rather than the day they arrived, so a collector that buffered through an outage restores the correct history instead of concentrating it on the day the broker returned.
The sink writes its partition files before committing stream offsets, so an interruption repeats a batch rather than losing it. Duplicates remain identifiable by host, kind, and timestamp; a missing interval would not be recoverable.
The broker runs on a machine that is not always available, so each collector keeps a bounded local buffer and replays it in order. The buffer file is claimed by rename before a replay begins, which prevents an asynchronous producer from discarding readings whose failure has not yet been reported.
The interface reads the HDFS archive rather than the live stream. A page fed by the stream would look the same whether or not anything had been stored, so reading from storage makes the archive demonstrable. Readings appear one batch behind live, and every row shows its own age.
04
$ python -m collector --once
5 readings · 0 delivered · 5 failed
$ docker compose start kafka
10 delivered · 5 replayed from disk
✓ /sentinel/raw/system/dt=2026-08-1505