ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
logbuf.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file logbuf.h
6 * @brief Fixed-RAM rotating log buffer with severity traps (PROTOCORE_ENABLE_LOGBUF).
7 *
8 * Keeps the last PROTOCORE_LOG_LINES log lines in a fixed ring (the oldest is pruned
9 * on overflow - no heap, bounded latency), each line stored as `<L> message`
10 * where L is the severity letter. Dump the ring oldest-first for a `/logs`
11 * endpoint, and register a trap callback that fires when a line is logged at or
12 * above a severity threshold (forward criticals as an SNMP trap / webhook). Pure
13 * and fully host-tested - no vendor dependency.
14 *
15 * @author Douglas Quigg (dstroy0)
16 * @date 2026
17 */
18
19#ifndef PROTOCORE_LOGBUF_H
20#define PROTOCORE_LOGBUF_H
21
22#include "protocore_config.h" // the entry point: protocore_types.h for the widths
23
24#if PROTOCORE_ENABLE_LOGBUF
25
27
28/** @brief Severity levels (ordered low -> high). Compared (level >= threshold) and passed through the
29 * uint8_t trap-callback ABI, so integer constants in a namespacing struct - cast-free. */
30#define PROTOCORE_LOG_DEBUG 0
31#define PROTOCORE_LOG_INFO 1
32#define PROTOCORE_LOG_WARN 2
33#define PROTOCORE_LOG_ERROR 3
34
35/** @brief Trap callback: fired for a line logged at level >= the threshold. */
36typedef void (*protocore_log_trap_fn)(uint8_t level, const char *line);
37
38/** @brief What one append carries. */
39typedef struct
40{
41 uint8_t level; ///< severity; the line is stored as `<L> msg`
42 const char *msg; ///< the message; NULL renders empty
43} LogLineArgs;
44
45/** @brief Where a dump writes, and the line a lookup names. */
46typedef struct
47{
48 char *out; ///< where a dump writes the held lines, oldest-first, newline-separated
49 size_t cap; ///< how much room it has
50 uint16_t i; ///< the line a lookup names (0 = oldest .. count-1 = newest)
51} LogReadArgs;
52
53/** @brief What a trap fires on. */
54typedef struct
55{
56 uint8_t threshold; ///< fire for a line logged at this level or above; 0xFF disables
57 protocore_log_trap_fn cb; ///< what fires; NULL leaves the trap off
58} LogTrapArgs;
59
60/**
61 * @brief The in-memory log ring.
62 *
63 * A caller sets the members a call takes, invokes it through ::Logbuf, and reads the outcome off the
64 * same handle. The ring itself is behind @ref internal.
65 *
66 * @var LogbufNs::line what one append carries
67 * @var LogbufNs::read where a dump writes, and the line a lookup names
68 * @var LogbufNs::trap what a trap fires on
69 * @var LogbufNs::count lines currently held (0 .. PROTOCORE_LOG_LINES)
70 * @var LogbufNs::text the line a lookup reports, or NULL when the index is out of range
71 * @var LogbufNs::n characters a dump wrote, or 0 when the buffer is too small
72 * @var LogbufNs::reset empty the ring and clear the line count
73 * @var LogbufNs::put append one line, truncated to fit
74 * @var LogbufNs::held how many lines are held
75 * @var LogbufNs::at one held line by index
76 * @var LogbufNs::dump every held line, oldest-first, newline-separated
77 * @var LogbufNs::set_trap install the severity trap
78 *
79 * dump fails closed: a buffer that cannot hold every line writes nothing and reports 0.
80 */
81typedef struct
82{
83 LogLineArgs line;
84 LogReadArgs read;
85 LogTrapArgs trap;
86 uint16_t count;
87 const char *text;
88 int n;
89} LogbufVars;
90
91/** @brief The operands and the outcome. */
92extern LogbufVars LogbufV;
93
94/** @brief The entries. */
95typedef struct
96{
97 void (*const reset)(uint8_t *work);
98 void (*const put)(uint8_t *work);
99 void (*const held)(uint8_t *work);
100 void (*const at)(uint8_t *work);
101 void (*const dump)(uint8_t *work);
102 void (*const set_trap)(uint8_t *work);
103} LogbufNs;
104
105// What the table binds, defined once in the .c and taking one parameter each: everything
106// else an entry needs is an operand in LogbufV or a region of the borrow at a fixed offset.
107void protocore_logbuf_reset(uint8_t *work);
108void protocore_logbuf_put(uint8_t *work);
109void protocore_logbuf_held(uint8_t *work);
110void protocore_logbuf_at(uint8_t *work);
111void protocore_logbuf_dump(uint8_t *work);
112void protocore_logbuf_set_trap(uint8_t *work);
113
114// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
115// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
116// `Logbuf.reset(work)` resolves to a named function and becomes a DIRECT call. An extern table
117// leaves the call indirect and the symbol live at every level, -O2 -flto included.
118static const LogbufNs Logbuf __attribute__((unused)) = {
119 .reset = protocore_logbuf_reset,
120 .put = protocore_logbuf_put,
121 .held = protocore_logbuf_held,
122 .at = protocore_logbuf_at,
123 .dump = protocore_logbuf_dump,
124 .set_trap = protocore_logbuf_set_trap,
125};
126
127/**
128 * @brief The PROTOCORE_LOGBUF_BORROW bytes this module's state lives in.
129 *
130 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
131 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
132 * walks, so the state lasts the life of the program.
133 *
134 * @return the span.
135 */
136uint8_t *protocore_logbuf_span(void);
137
139
140#endif // PROTOCORE_ENABLE_LOGBUF
141
142#endif // PROTOCORE_LOGBUF_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
#define PROTOCORE_END_DECLS
Definition types.h:97