Skip to content

Commit 9c080cf

Browse files
DavidCozensclaude
andcommitted
feat: create the logger, wired to nothing, and watch it say so
The logger is created with both collaborators absent, deliberately. Create never fails and never returns NULL — a missing collaborator is substituted with its Null object — so the only evidence is what the handler prints, and the run report now carries three of them: [syslog] CRITICAL SolidSyslog bad-config (detail 1) [syslog] CRITICAL SolidSyslog bad-config (detail 2) [syslog] CRITICAL SolidSyslog bad-config (detail 3) Flash +1,052 B RAM +184 B One each for the buffer, the sender and the store, named in Detail as values of the emitting class's own error enum. Doing it in this order is the point. An integrator who wires everything at once and sees nothing cannot tell a working logger from a silent one; seeing the faults first, and then watching them go quiet as collaborators arrive, is the difference between believing it works and knowing. NULL is "not supplied" and is reported. A collaborator deliberately done without is passed as its Null object instead — the library tells those two apart, and so should anyone reading this wiring later. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 0b1af20 commit 9c080cf

8 files changed

Lines changed: 111 additions & 34 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
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/Syslog.c
133134
${APP_DIR}/syslog/SyslogErrorHandler.c
134135
$<TARGET_OBJECTS:baseline_upstream>
135136
)
@@ -151,7 +152,7 @@ target_include_directories(baseline PRIVATE
151152
${APP_DIR}/net/smsc9220
152153
${APP_DIR}/platform # CmsdkUart.h, SemihostingExit.h, SemihostingIo.h
153154
${APP_DIR}/storage # SemihostingDisk.h
154-
${APP_DIR}/syslog # SyslogErrorHandler.h
155+
${APP_DIR}/syslog # Syslog.h, SyslogErrorHandler.h
155156
${FREERTOS_KERNEL_PATH}/include
156157
${FREERTOS_PORT_DIR}
157158
${LWIP_DIR}/src/include

README.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,45 @@ 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 — Error handler
13+
## This stage — Logger created
1414

15-
Install the handler before any other call into SolidSyslog.
15+
Create the logger with both collaborators absent, deliberately, and read what the handler prints.
1616

1717
```c
18-
SolidSyslog_SetErrorHandler(OnSyslogError, NULL);
18+
struct SolidSyslogConfig config = {
19+
.Buffer = NULL,
20+
.Sender = NULL,
21+
};
22+
23+
struct SolidSyslog* logger = SolidSyslog_Create(&config);
24+
```
25+
26+
No `_Create` fails or returns `NULL` — a missing collaborator is substituted with its Null object
27+
and reported — so the only evidence is what the handler says:
28+
29+
```text
30+
[syslog] CRITICAL SolidSyslog bad-config (detail 1)
31+
[syslog] CRITICAL SolidSyslog bad-config (detail 2)
32+
[syslog] CRITICAL SolidSyslog bad-config (detail 3)
1933
```
2034

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.
35+
Three, for the buffer, the sender and the store. Each names the collaborator in `Detail`, as a
36+
value of the emitting class's own error enum.
2637

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.
38+
The order matters. Wire everything at once and see nothing, and you cannot tell a working logger
39+
from a silent one. Seeing the faults first, then watching them go quiet as each collaborator
40+
arrives, is the difference between believing it works and knowing.
3241

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.
42+
A convention worth adopting now: `NULL` as a parameter means "not supplied" and is reported, while
43+
a collaborator you have deliberately done without is passed as its Null object. The library
44+
distinguishes the two, and so should anyone reading the wiring later.
3545

36-
**When you need it.** Every device, and first. It is the only thing standing between a
37-
misconfigured logger and a silent one.
46+
**When you need it.** As a step rather than a destination. It costs one build to prove the handler
47+
is connected and the library is reachable, before anything can be blamed on the network.
3848

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

41-
**Cost above baseline: Flash +404 B, RAM +8 B.**
51+
**Cost above baseline: Flash +1,052 B, RAM +184 B.**
4252

4353
<!-- STAGE-COST:END -->
4454

@@ -54,6 +64,7 @@ committed as [`run-report.md`](run-report.md), and rewritten by every stage.
5464
| Baseline | a device that already networks, stores, and holds an mTLS session — before any syslog |||
5565
| Linked | the core library and lwIP raw-mode networking, linked but not yet called | +0 | +0 |
5666
| Error handler | a fault inside the logger reaches the console instead of being silent | +404 | +8 |
67+
| Logger created | the logger object, reporting exactly what is still missing from it | +1,052 | +184 |
5768

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

app/main.c

Lines changed: 3 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 "Syslog.h"
1213
#include "SyslogErrorHandler.h"
1314

1415
#include "lwip/tcpip.h"
@@ -97,6 +98,8 @@ int main(void)
9798
/* Before the first _Create — see SyslogErrorHandler.h for why that matters. */
9899
SyslogErrorHandler_Install();
99100

101+
Syslog_Start();
102+
100103
/* lwIP tcpip thread + core-lock mutex + mbox. Pre-scheduler safe. */
101104
tcpip_init(NULL, NULL);
102105

app/syslog/Syslog.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* See Syslog.h. Created with nothing wired into it, on purpose: a missing
2+
* collaborator is substituted with its Null object and reported, and the run
3+
* report is where that shows. */
4+
5+
#include "Syslog.h"
6+
7+
#include "SolidSyslogConfig.h"
8+
9+
#include <stddef.h>
10+
11+
static struct SolidSyslog* s_logger = NULL;
12+
13+
void Syslog_Start(void)
14+
{
15+
/* Buffer and Sender decide where a record goes. NULL is "not supplied" and
16+
* is reported; a collaborator deliberately done without is passed as its
17+
* Null object instead, which is how the library tells the two apart. */
18+
struct SolidSyslogConfig config = {
19+
.Buffer = NULL,
20+
.Sender = NULL,
21+
};
22+
23+
/* No null check — Create returns a shared null instance rather than NULL. */
24+
s_logger = SolidSyslog_Create(&config);
25+
}
26+
27+
struct SolidSyslog* Syslog_Handle(void)
28+
{
29+
return s_logger;
30+
}

app/syslog/Syslog.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* The device's SolidSyslog wiring — the one place that knows how the logger is
2+
* assembled. Everything else in the application just logs. */
3+
#ifndef SYSLOG_H
4+
#define SYSLOG_H
5+
6+
struct SolidSyslog;
7+
8+
/** Build the config and create the logger. Call once at startup, after
9+
* SyslogErrorHandler_Install so any fault in here is reported. */
10+
void Syslog_Start(void);
11+
12+
/** The logger, for the tasks that log from it and drain it. */
13+
struct SolidSyslog* Syslog_Handle(void);
14+
15+
#endif /* SYSLOG_H */

measurements/logger.csv

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# logger 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,350976
4+
flash_data,384
5+
static_bss,110992
6+
heap_used,4440
7+
mbedtls_peak,21300
8+
mbedtls_free,11468
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
@@ -12,3 +12,4 @@
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
1414
error-handler Error handler a fault inside the logger reaches the console instead of being silent
15+
logger Logger created the logger object, reporting exactly what is still missing from it

run-report.md

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

33
## Device (self-measured)
44

55
```text
66
[device] solid-syslog-example (FreeRTOS + lwIP + mbedTLS + FatFs)
7+
[syslog] CRITICAL SolidSyslog bad-config (detail 1)
8+
[syslog] CRITICAL SolidSyslog bad-config (detail 2)
9+
[syslog] CRITICAL SolidSyslog bad-config (detail 3)
710
[device] starting simulated existing application...
811
[sim] broker session to 10.0.2.2:8883: TLSv1.3, TLS1-3-CHACHA20-POLY1305-SHA256
912
[device] sim app (lwIP up, FatFs mounted, broker session held over mTLS): ready
1013
[report] --- SolidSyslog cost above baseline (simulated existing application) ---
1114
[report] key,current,baseline,used_above_baseline
12-
[report] flash_text,350392,349992,400
13-
[report] flash_data,320,316,4
14-
[report] static_bss,110880,110876,4
15+
[report] flash_text,350976,349992,984
16+
[report] flash_data,384,316,68
17+
[report] static_bss,110992,110876,116
1518
[report] heap_used,4440,4440,0
16-
[report] mbedtls_peak,21336,21332,4
17-
[report] mbedtls_free,11432,11436,-4
19+
[report] mbedtls_peak,21276,21332,-56
20+
[report] mbedtls_free,11492,11436,56
1821
[report] lwip_mem_free,7576,7576,0
19-
[report] lwip_pbufs_free,13,14,-1
22+
[report] lwip_pbufs_free,14,14,0
2023
[report] stack_log,120,120,0
2124
[report] stack_service,52,52,0
2225
[report] stack_harness,2840,2840,0
@@ -28,7 +31,7 @@
2831

2932
```text
3033
text data bss dec hex filename
31-
350384 328 110880 461592 70b18 /w/build/baseline-cross/baseline.elf
34+
350968 392 110992 462352 70e10 /w/build/baseline-cross/baseline.elf
3235
```
3336

3437
## Listeners (proved before the device ran)
@@ -49,17 +52,17 @@
4952
(nothing — this device sends no records yet)
5053
```
5154

52-
## Self-check (vs measurements/error-handler.csv)
55+
## Self-check (vs measurements/logger.csv)
5356

5457
```text
55-
OK flash_text: 350392 (expected 350392, Δ0)
56-
OK flash_data: 320 (expected 320, Δ0)
57-
OK static_bss: 110880 (expected 110880, Δ0)
58+
OK flash_text: 350976 (expected 350976, Δ0)
59+
OK flash_data: 384 (expected 384, Δ0)
60+
OK static_bss: 110992 (expected 110992, Δ0)
5861
OK heap_used: 4440 (expected 4440, Δ0)
59-
OK mbedtls_peak: 21336 (expected 21296, Δ40)
60-
OK mbedtls_free: 11432 (expected 11472, Δ40)
62+
OK mbedtls_peak: 21276 (expected 21300, Δ24)
63+
OK mbedtls_free: 11492 (expected 11468, Δ24)
6164
OK lwip_mem_free: 7576 (expected 7576, Δ0)
62-
OK lwip_pbufs_free: 13 (expected 13, Δ0)
65+
OK lwip_pbufs_free: 14 (expected 13, Δ1)
6366
OK stack_log: 120 (expected 120, Δ0)
6467
OK stack_service: 52 (expected 52, Δ0)
6568
OK stack_harness: 2840 (expected 2840, Δ0)

0 commit comments

Comments
 (0)