An example of integrating SolidSyslog into an application that already exists, starting from a realistic device rather than an empty one.
Each pull request merged to main is one stage of that integration, and each raises the security
posture of the logging path. A stage states what it changes, what it gives you, and what it costs,
measured by the device itself rather than estimated.
The purpose is to show the process of integration, the cost of each step and the benefit it brings, so that all three can be set against your own threat model when you plan your own.
The baseline is the sort of device this might be added to: it already networks, mounts a filesystem and holds a mutual-TLS session to its broker before any syslog exists. See docs/baseline.md for what it is, how the figures are made, and how to run it.
The device logs one RFC 5424 record carrying four SD-ELEMENTs: sequence number 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,788 B, RAM +36,048 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 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.
This history is rebuilt against each SolidSyslog release, which means a force-push. An existing clone or fork needs re-cloning rather than pulling.
| 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,052 | +184 |
| First record | a valid RFC 5424 record on the wire, over UDP | +4,724 | +1,912 |
| Header fields | a timestamped record naming the device, instead of nil values | +5,116 | +1,912 |
| Sequence numbers | every record numbered, so a gap in the sequence is visible | +6,048 | +1,976 |
| Buffered | logging that returns immediately, with the send moved off the logging task | +6,804 | +7,488 |
| TCP | records the network retransmits instead of dropping, and a send that fails when the collector is gone | +7,336 | +7,668 |
| Time quality | a timestamp the collector knows how far to trust, and an uptime that tells a reboot from a counter wrap | +7,628 | +7,692 |
| File store | records that survive a failed send, spooled to disk with a checksum at rest | +11,584 | +9,128 |
| Origin | the device named in the record itself, not inferred from the source address | +11,988 | +9,172 |
| Origin address | the device's own address in the record, which a relay or NAT between it and the collector cannot rewrite | +12,380 | +9,172 |
| TLS | a collector the device authenticates, and records no longer readable on the wire | +13,084 | +37,452 |
| HMAC at rest | stored records that cannot be edited undetected, not merely checked for corruption | +13,416 | +37,472 |
| Private SD-ELEMENT | a record that states the protection its own log pipeline was under | +13,556 | +37,476 |
| Mutual TLS | a collector that knows which device sent the record, not just that one did | +13,632 | +39,528 |
| AES-GCM at rest | spooled records unreadable to anyone holding the disk, not just unforgeable | +13,788 | +39,536 |
| Right-sized | the pools, the ring and the task stacks fitted to what this device uses | +13,788 | +36,048 |
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.
SolidSyslog is fetched at build time and is likewise not redistributed here. It is offered under three alternative licenses, which its own LICENSE.md sets out.