A worked integration of SolidSyslog, built up in stages — from a device with no syslog at all to one whose records are authenticated and encrypted.
Each stage is one commit. It says what it does, what it changes, what it gives you, and what it costs. The costs are measured by the device itself, not estimated.
It builds on a baseline that simulates the sort of device you might be adding this to, and that measures itself: see docs/baseline.md for what the baseline is, how the figures are made, and how to run it.
The device logs one RFC 5424 record carrying four SD elements — sequence and uptime, time quality, origin, and a private element naming the protection its own log pipeline is under. The record goes to the collector over mutual TLS and is spooled to a local store encrypted with AES-256-GCM, so records survive a failed send and a disk that leaves the device gives nothing away.
Cost above baseline: Flash +13,780 B, RAM +37,748 B.
Most devices want less than that. The table below prices every stage, and the cheapest row that does anything useful — a valid, timestamped record on the wire — is a fraction of it.
Read it as a sequence. Start at the Baseline commit and step forward: git show on any stage
gives you the diff to apply to your own build, the reasoning behind it, and the measured cost of
applying it — each stage's run is committed alongside it as run-report.md. Stop
where your device's threat model does.
| Stage | What it gives you | Flash | RAM |
|---|---|---|---|
| Baseline | a device that already networks, stores, and holds an mTLS session — before any syslog | — | — |
| Linked | the core library and lwIP raw-mode networking, linked but not yet called | +0 | +0 |
| Error handler | a fault inside the logger reaches the console instead of being silent | +404 | +8 |
| Logger created | the logger object, reporting exactly what is still missing from it | +1,036 | +180 |
| First record | a valid RFC 5424 record on the wire, over UDP | +4,716 | +372 |
| Header fields | a timestamped record naming the device, instead of nil values | +5,100 | +372 |
| Sequence numbers | every record numbered, so a gap in the sequence is visible | +6,032 | +436 |
| Message cap | a bounded record size, so a long message truncates instead of being dropped | +6,032 | +1,956 |
| Buffered | logging that returns immediately, with the send moved off the logging task | +6,788 | +5,676 |
| TCP | records the network retransmits instead of dropping, and a send that fails when the collector is gone | +7,320 | +5,856 |
| Time quality | a timestamp the collector knows how far to trust, and an uptime that tells a reboot from a counter wrap | +7,612 | +5,880 |
| File store | records that survive a failed send, spooled to disk with a checksum at rest | +11,576 | +7,092 |
| Origin | the device named in the record itself, not inferred from the source address | +11,972 | +7,136 |
| Larger cap | headroom for the grown record, so full-width counters cannot push it into truncation | +11,980 | +9,440 |
| Smaller ring | most of the cap rise given back, now the store rather than the ring holds a backlog | +11,980 | +7,384 |
| Origin address | the device's own address in the record, which a relay or NAT between it and the collector cannot rewrite | +12,388 | +7,384 |
| TLS | a collector the device authenticates, and records no longer readable on the wire | +13,076 | +35,664 |
| HMAC at rest | stored records that cannot be edited undetected, not merely checked for corruption | +13,424 | +35,684 |
| Private SD-ELEMENT | a record that states the protection its own log pipeline was under | +13,548 | +35,688 |
| Mutual TLS | a collector that knows which device sent the record, not just that one did | +13,624 | +37,740 |
| AES-GCM at rest | spooled records unreadable to anyone holding the disk, not just unforgeable | +13,780 | +37,748 |
Deltas are bytes above the baseline, which is itself Flash 350,308 B, RAM 111,192 B.
This example's own code is 0BSD — completely open, no conditions.
Third-party code keeps its own license: the vendored Arm SMSC9220 driver (app/net/smsc9220/) is
Apache-2.0 (see its LICENSE). FreeRTOS, lwIP, mbedTLS, and FatFs are consumed from the build
container under their own upstream licenses and are not redistributed here.