Skip to content

Commit 697c5e2

Browse files
DavidCozensclaude
andcommitted
feat: install the SolidSyslog error handler
Nothing in the library fails loudly. A _Create that cannot succeed substitutes a Null object and reports it rather than returning NULL, 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 +412 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 category, not the text. It is more than an integration aid. The handler is the seam into the device's own error and health reporting, and later stages use it at run time: an edge-triggered warning when the collector becomes unreachable, a notice when delivery recovers. The build gains one source file and its include directory. Nothing about how SolidSyslog enters the build changes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 261e79e commit 697c5e2

8 files changed

Lines changed: 163 additions & 31 deletions

File tree

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ APP_SRCS := \
5050
$(APP_DIR)/platform/SemihostingIo.c \
5151
$(APP_DIR)/net/EthernetIf.c \
5252
$(APP_DIR)/storage/diskio.c \
53-
$(APP_DIR)/storage/SemihostingDisk.c
53+
$(APP_DIR)/storage/SemihostingDisk.c \
54+
$(APP_DIR)/syslog/SyslogErrorHandler.c
5455

5556
UPSTREAM_SRCS := \
5657
$(FREERTOS_SRCS) \
@@ -71,6 +72,7 @@ APP_INCLUDES := \
7172
-I$(APP_DIR)/net/smsc9220 \
7273
-I$(APP_DIR)/platform \
7374
-I$(APP_DIR)/storage \
75+
-I$(APP_DIR)/syslog \
7476
$(FREERTOS_INCLUDES) $(LWIP_INCLUDES) $(FATFS_INCLUDES) $(MBEDTLS_INCLUDES) \
7577
$(SOLIDSYSLOG_INCLUDES)
7678

README.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,35 @@ 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 linked into the application without any of it being called. The stage is broken out
16-
for clarity: it separates getting the build to accept the library from getting the device to use
17-
it, so anything that goes wrong here is a build problem and nothing else.
15+
Install the handler before any other call into SolidSyslog.
1816

19-
The library ships `solidsyslog.mk`, so `make/solidsyslog.mk` names the platforms and includes it,
20-
and gets the source lists and include sets back. `SOLIDSYSLOG_PLATFORMS` names the platforms rather
21-
than letting the library infer them from the environment — lwIP alone, because nothing at this
22-
stage reaches any other pack. What is left is this build's own architecture: Core compiles against
23-
the library's own headers into an archive, and the platform sources compile with this device's
24-
flags and config headers.
17+
```c
18+
SolidSyslog_SetErrorHandler(OnSyslogError, NULL);
19+
```
2520
26-
`--gc-sections` discards what nothing calls, so a platform pack that is linked but unused does not
27-
reach the image.
21+
Nothing in the library fails loudly. A `_Create` that cannot succeed substitutes a Null object and
22+
reports it rather than returning `NULL`, so a logger that has silently stopped looks exactly like
23+
one with nothing to say. The handler is what tells the two apart, which is why it goes in before
24+
the first `_Create` and not after something looks wrong. It reports many misconfiguration errors,
25+
and can save significant time while integrating.
2826
29-
For now you need only the core and a network platform. The library has no release tag yet, so the
30-
pin is a commit.
27+
This is not only an integration aid. The handler is the seam into the device's own error and health
28+
reporting, and it stays valuable at run time: later stages raise an edge-triggered warning when the
29+
collector becomes unreachable and a notice when delivery recovers. Route it wherever the device
30+
already routes faults — here, the same console as everything else, so a fault lands in the run
31+
report next to the rest of what the device did.
32+
33+
The handler names the four lifecycle categories a misconfigured integration raises and prints the
34+
rest numerically. A device reacting to a fault would switch on the category rather than the text.
35+
36+
**When you need it.** Every device, and first. It is the only thing standing between a
37+
misconfigured logger and a silent one.
3138
3239
<!-- STAGE-COST:START (generated by scripts/gen-cost-table.py — do not edit by hand) -->
3340
34-
**Cost above baseline: Flash +0 B, RAM +0 B.**
41+
**Cost above baseline: Flash +412 B, RAM +8 B.**
3542
3643
<!-- STAGE-COST:END -->
3744
@@ -46,6 +53,7 @@ committed as [`run-report.md`](run-report.md), and rewritten by every stage.
4653
|---|---|---|---|
4754
| Baseline | a device that already networks, stores, and holds an mTLS session — before any syslog | — | — |
4855
| Linked | the core library and lwIP raw-mode networking, linked but not yet called | +0 | +0 |
56+
| Error handler | a fault inside the logger reaches the console instead of being silent | +412 | +8 |
4957
5058
*Deltas are bytes above the baseline, which is itself Flash 350,124 B, RAM 111,192 B.*
5159

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,350216
4+
flash_data,320
5+
static_bss,110880
6+
heap_used,4440
7+
mbedtls_peak,21304
8+
mbedtls_free,11464
9+
lwip_mem_free,7576
10+
lwip_pbufs_free,13
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.
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,349808,349808,0
13-
[report] flash_data,316,316,0
14-
[report] static_bss,110876,110876,0
12+
[report] flash_text,350216,349808,408
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,21244,21328,-84
17-
[report] mbedtls_free,11524,11440,84
16+
[report] mbedtls_peak,21220,21328,-108
17+
[report] mbedtls_free,11548,11440,108
1818
[report] lwip_mem_free,7576,7576,0
19-
[report] lwip_pbufs_free,13,13,0
19+
[report] lwip_pbufs_free,14,13,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-
349800 324 110876 461000 708c8 /w/build/baseline.elf
31+
350208 328 110880 461416 70a68 /w/build/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: 349808 (expected 349808, Δ0)
56-
OK flash_data: 316 (expected 316, Δ0)
57-
OK static_bss: 110876 (expected 110876, Δ0)
55+
OK flash_text: 350216 (expected 350216, Δ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: 21244 (expected 21284, Δ40)
60-
OK mbedtls_free: 11524 (expected 11484, Δ40)
59+
OK mbedtls_peak: 21220 (expected 21304, Δ84)
60+
OK mbedtls_free: 11548 (expected 11464, Δ84)
6161
OK lwip_mem_free: 7576 (expected 7576, Δ0)
62-
OK lwip_pbufs_free: 13 (expected 13, Δ0)
62+
OK lwip_pbufs_free: 14 (expected 13, Δ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)