Skip to content

Commit 4aa5e5e

Browse files
DavidCozensclaude
andcommitted
feat: install the SolidSyslog error handler
Nothing in the library fails loudly. A _Create that cannot succeed returns a Null object and carries on, so a logger that has silently stopped looks exactly like one with nothing to say. The handler is what tells them apart, and it goes in before the first _Create rather than after something looks wrong. Flash +404 B RAM +8 B The handler prints to the same console as everything else, so a fault lands in the run report next to the rest of what the device did. It names the four lifecycle categories a misconfigured integration raises and prints the rest numerically — a device reacting to those would switch on the range, not the text. That is 404 bytes for something this device may never use. It buys the difference between a silent failure and a sentence, which is worth more than the bytes on anything that has to be trusted to report. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 3461555 commit 4aa5e5e

8 files changed

Lines changed: 145 additions & 19 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ add_executable(baseline
130130
${APP_DIR}/net/EthernetIf.c
131131
${APP_DIR}/storage/diskio.c
132132
${APP_DIR}/storage/SemihostingDisk.c
133+
${APP_DIR}/syslog/SyslogErrorHandler.c
133134
$<TARGET_OBJECTS:baseline_upstream>
134135
)
135136

@@ -150,6 +151,7 @@ target_include_directories(baseline PRIVATE
150151
${APP_DIR}/net/smsc9220
151152
${APP_DIR}/platform # CmsdkUart.h, SemihostingExit.h, SemihostingIo.h
152153
${APP_DIR}/storage # SemihostingDisk.h
154+
${APP_DIR}/syslog # SyslogErrorHandler.h
153155
${FREERTOS_KERNEL_PATH}/include
154156
${FREERTOS_PORT_DIR}
155157
${LWIP_DIR}/src/include

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ It builds on a baseline that simulates the sort of device you might be adding th
1010
measures itself: see [docs/baseline.md](docs/baseline.md) for what the baseline is, how the
1111
figures are made, and how to run it.
1212

13-
## This stage — Linked
13+
## This stage — Error handler
1414

15-
SolidSyslog is in the build with the lwIP platform selected: the core library, plus the components
16-
that integrate lwIP in raw mode. Nothing calls it yet, so the linker strips it all back out.
15+
The device installs its own handler on SolidSyslog's error slot, before creating anything. A
16+
`_Create` that cannot succeed returns a Null object rather than failing, so without this a
17+
mis-wired logger and a quiet one look identical.
1718

1819
<!-- STAGE-COST:START (generated by scripts/gen-cost-table.py — do not edit by hand) -->
1920

20-
**Cost above baseline: Flash +0 B, RAM +0 B.**
21+
**Cost above baseline: Flash +404 B, RAM +8 B.**
2122

2223
<!-- STAGE-COST:END -->
2324

@@ -32,6 +33,7 @@ committed as [`run-report.md`](run-report.md), and rewritten by every stage.
3233
|---|---|---|---|
3334
| Baseline | a device that already networks, stores, and holds an mTLS session — before any syslog |||
3435
| Linked | the core library and lwIP raw-mode networking, linked but not yet called | +0 | +0 |
36+
| Error handler | a fault inside the logger reaches the console instead of being silent | +404 | +8 |
3537

3638
*Deltas are bytes above the baseline, which is itself Flash 350,308 B, RAM 111,192 B.*
3739

app/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "SemihostingExit.h"
1010
#include "ServiceTask.h"
1111
#include "SimulatedExistingApp.h"
12+
#include "SyslogErrorHandler.h"
1213

1314
#include "lwip/tcpip.h"
1415

@@ -93,6 +94,9 @@ int main(void)
9394
CmsdkUart_Init(&UART_ACCESS, DEVICE_UART0_BASE);
9495
(void) printf("[device] solid-syslog-example (FreeRTOS + lwIP + mbedTLS + FatFs)\n");
9596

97+
/* Before the first _Create — see SyslogErrorHandler.h for why that matters. */
98+
SyslogErrorHandler_Install();
99+
96100
/* lwIP tcpip thread + core-lock mutex + mbox. Pre-scheduler safe. */
97101
tcpip_init(NULL, NULL);
98102

app/syslog/SyslogErrorHandler.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* See SyslogErrorHandler.h. Prints to the same console as the rest of the
2+
* device, so a fault shows up in the run report next to everything else. */
3+
4+
#include "SyslogErrorHandler.h"
5+
6+
#include "SolidSyslogError.h"
7+
#include "SolidSyslogErrorCategory.h"
8+
#include "SolidSyslogPrival.h"
9+
10+
#include <stdint.h>
11+
#include <stdio.h>
12+
13+
static const char* SeverityName(enum SolidSyslogSeverity severity)
14+
{
15+
switch (severity)
16+
{
17+
case SOLIDSYSLOG_SEVERITY_EMERGENCY:
18+
return "EMERGENCY";
19+
case SOLIDSYSLOG_SEVERITY_ALERT:
20+
return "ALERT";
21+
case SOLIDSYSLOG_SEVERITY_CRITICAL:
22+
return "CRITICAL";
23+
case SOLIDSYSLOG_SEVERITY_ERROR:
24+
return "ERROR";
25+
case SOLIDSYSLOG_SEVERITY_WARNING:
26+
return "WARNING";
27+
case SOLIDSYSLOG_SEVERITY_NOTICE:
28+
return "NOTICE";
29+
case SOLIDSYSLOG_SEVERITY_INFORMATIONAL:
30+
return "INFO";
31+
case SOLIDSYSLOG_SEVERITY_DEBUG:
32+
return "DEBUG";
33+
}
34+
return "?";
35+
}
36+
37+
/* The four a misconfigured integration raises. Role-specific categories sit in
38+
* ranges above 0x0100 and print numerically. */
39+
static const char* CategoryName(uint16_t category)
40+
{
41+
switch (category)
42+
{
43+
case SOLIDSYSLOG_CAT_BAD_CONFIG:
44+
return "bad-config";
45+
case SOLIDSYSLOG_CAT_BAD_ARGUMENT:
46+
return "bad-argument";
47+
case SOLIDSYSLOG_CAT_POOL_EXHAUSTED:
48+
return "pool-exhausted";
49+
case SOLIDSYSLOG_CAT_UNKNOWN_DESTROY:
50+
return "unknown-destroy";
51+
default:
52+
return NULL;
53+
}
54+
}
55+
56+
static void OnSyslogError(void* context, const struct SolidSyslogErrorEvent* event)
57+
{
58+
(void) context;
59+
60+
if (event == NULL)
61+
{
62+
return;
63+
}
64+
65+
/* Sources are matched by pointer identity — Name is only ever a label, which
66+
* is all it is used for here. */
67+
const char* source = ((event->Source != NULL) && (event->Source->Name != NULL)) ? event->Source->Name : "?";
68+
const char* category = CategoryName(event->Category);
69+
70+
if (category != NULL)
71+
{
72+
(void) printf("[syslog] %s %s %s (detail %ld)\n", SeverityName(event->Severity), source, category, (long) event->Detail);
73+
}
74+
else
75+
{
76+
(void) printf(
77+
"[syslog] %s %s category 0x%04X (detail %ld)\n",
78+
SeverityName(event->Severity),
79+
source,
80+
(unsigned int) event->Category,
81+
(long) event->Detail
82+
);
83+
}
84+
}
85+
86+
void SyslogErrorHandler_Install(void)
87+
{
88+
SolidSyslog_SetErrorHandler(OnSyslogError, NULL);
89+
}

app/syslog/SyslogErrorHandler.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* The device's reaction to a SolidSyslog internal fault.
2+
*
3+
* Nothing in the library fails loudly — a _Create that cannot succeed returns a
4+
* Null object instead — so a logger that has silently stopped looks exactly like
5+
* one with nothing to say. This is the only thing that tells them apart, which
6+
* is why it goes in before the first _Create and not after something looks
7+
* wrong. */
8+
#ifndef SYSLOG_ERROR_HANDLER_H
9+
#define SYSLOG_ERROR_HANDLER_H
10+
11+
/** Install the handler on the library's single global slot. Call once, at
12+
* startup, before any SolidSyslog object is created. */
13+
void SyslogErrorHandler_Install(void);
14+
15+
#endif /* SYSLOG_ERROR_HANDLER_H */

measurements/error-handler.csv

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# error-handler figures (bytes) — captured by scripts/run.sh (CAPTURE=1).
2+
# The device reads measurements/Baseline.csv as its frozen baseline and reports current-minus-Baseline.
3+
flash_text,350392
4+
flash_data,320
5+
static_bss,110880
6+
heap_used,4440
7+
mbedtls_peak,21336
8+
mbedtls_free,11432
9+
lwip_mem_free,7576
10+
lwip_pbufs_free,14
11+
stack_log,120
12+
stack_service,52
13+
stack_harness,2840

measurements/stages.tsv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@
1111
# after it, and this history has already had one inserted.
1212
Baseline Baseline a device that already networks, stores, and holds an mTLS session — before any syslog
1313
linked Linked the core library and lwIP raw-mode networking, linked but not yet called
14+
error-handler Error handler a fault inside the logger reaches the console instead of being silent

run-report.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# solid-syslog-example — run (linked)
1+
# solid-syslog-example — run (error-handler)
22

33
## Device (self-measured)
44

@@ -9,14 +9,14 @@
99
[device] sim app (lwIP up, FatFs mounted, broker session held over mTLS): ready
1010
[report] --- SolidSyslog cost above baseline (simulated existing application) ---
1111
[report] key,current,baseline,used_above_baseline
12-
[report] flash_text,349992,349992,0
13-
[report] flash_data,316,316,0
14-
[report] static_bss,110876,110876,0
12+
[report] flash_text,350392,349992,400
13+
[report] flash_data,320,316,4
14+
[report] static_bss,110880,110876,4
1515
[report] heap_used,4440,4440,0
16-
[report] mbedtls_peak,21328,21332,-4
17-
[report] mbedtls_free,11440,11436,4
16+
[report] mbedtls_peak,21208,21332,-124
17+
[report] mbedtls_free,11560,11436,124
1818
[report] lwip_mem_free,7576,7576,0
19-
[report] lwip_pbufs_free,14,14,0
19+
[report] lwip_pbufs_free,13,14,-1
2020
[report] stack_log,120,120,0
2121
[report] stack_service,52,52,0
2222
[report] stack_harness,2840,2840,0
@@ -28,7 +28,7 @@
2828

2929
```text
3030
text data bss dec hex filename
31-
349984 324 110876 461184 70980 /w/build/baseline-cross/baseline.elf
31+
350384 328 110880 461592 70b18 /w/build/baseline-cross/baseline.elf
3232
```
3333

3434
## Listeners (proved before the device ran)
@@ -49,17 +49,17 @@
4949
(nothing — this device sends no records yet)
5050
```
5151

52-
## Self-check (vs measurements/linked.csv)
52+
## Self-check (vs measurements/error-handler.csv)
5353

5454
```text
55-
OK flash_text: 349992 (expected 349992, Δ0)
56-
OK flash_data: 316 (expected 316, Δ0)
57-
OK static_bss: 110876 (expected 110876, Δ0)
55+
OK flash_text: 350392 (expected 350392, Δ0)
56+
OK flash_data: 320 (expected 320, Δ0)
57+
OK static_bss: 110880 (expected 110880, Δ0)
5858
OK heap_used: 4440 (expected 4440, Δ0)
59-
OK mbedtls_peak: 21328 (expected 21332, Δ4)
60-
OK mbedtls_free: 11440 (expected 11436, Δ4)
59+
OK mbedtls_peak: 21208 (expected 21336, Δ128)
60+
OK mbedtls_free: 11560 (expected 11432, Δ128)
6161
OK lwip_mem_free: 7576 (expected 7576, Δ0)
62-
OK lwip_pbufs_free: 14 (expected 14, Δ0)
62+
OK lwip_pbufs_free: 13 (expected 14, Δ1)
6363
OK stack_log: 120 (expected 120, Δ0)
6464
OK stack_service: 52 (expected 52, Δ0)
6565
OK stack_harness: 2840 (expected 2840, Δ0)

0 commit comments

Comments
 (0)