DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
logbuf.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file logbuf.cpp
6 * @brief Fixed-RAM rotating log ring + severity trap - implementation (pure).
7 */
8
10
11#if DETWS_ENABLE_LOGBUF
12
13#include <stdio.h>
14#include <string.h>
15
16namespace
17{
18// All log-ring state, owned by one instance (internal linkage): the line/severity ring, its
19// head/count cursors, and the severity trap, grouped so it is one named owner, unreachable
20// from any other translation unit.
21struct LogbufCtx
22{
23 char lines[DETWS_LOG_LINES][DETWS_LOG_LINE_LEN]; // ring storage (BSS)
24 uint8_t level[DETWS_LOG_LINES]; // per-line severity
25 uint16_t head = 0; // index of the oldest line
26 uint16_t count = 0; // lines currently held
27 uint8_t trap_threshold = 0xFF; // 0xFF = trap disabled
28 detws_log_trap_fn trap = nullptr;
29};
30LogbufCtx s_log;
31
32char level_letter(uint8_t level)
33{
34 switch (level)
35 {
36 case DetwsLogLevel::DETWS_LOG_ERROR:
37 return 'E';
38 case DetwsLogLevel::DETWS_LOG_WARN:
39 return 'W';
40 case DetwsLogLevel::DETWS_LOG_INFO:
41 return 'I';
42 default:
43 return 'D';
44 }
45}
46} // namespace
47
48void detws_logbuf_reset(void)
49{
50 s_log.head = 0;
51 s_log.count = 0;
52}
53
54void detws_log(uint8_t level, const char *msg)
55{
56 uint16_t slot;
57 if (s_log.count < DETWS_LOG_LINES)
58 {
59 slot = (uint16_t)((s_log.head + s_log.count) % DETWS_LOG_LINES);
60 s_log.count++;
61 }
62 else // full: overwrite the oldest and advance head
63 {
64 slot = s_log.head;
65 s_log.head = (uint16_t)((s_log.head + 1) % DETWS_LOG_LINES);
66 }
67 snprintf(s_log.lines[slot], DETWS_LOG_LINE_LEN, "%c %s", level_letter(level), msg ? msg : "");
68 s_log.level[slot] = level;
69
70 if (s_log.trap && level >= s_log.trap_threshold)
71 s_log.trap(level, s_log.lines[slot]);
72}
73
74uint16_t detws_log_count(void)
75{
76 return s_log.count;
77}
78
79const char *detws_log_at(uint16_t i)
80{
81 if (i >= s_log.count)
82 return nullptr;
83 return s_log.lines[(s_log.head + i) % DETWS_LOG_LINES];
84}
85
86int detws_log_dump(char *out, size_t cap)
87{
88 if (!out || cap == 0)
89 return 0;
90 out[0] = '\0';
91 size_t pos = 0;
92 for (uint16_t i = 0; i < s_log.count; i++)
93 {
94 const char *line = s_log.lines[(s_log.head + i) % DETWS_LOG_LINES];
95 size_t n = strnlen(line, cap);
96 size_t need = n + (i + 1 < s_log.count ? 1 : 0); // +1 for the '\n' separator
97 if (pos + need >= cap) // keep room for the null terminator
98 {
99 out[0] = '\0';
100 return 0;
101 }
102 memcpy(out + pos, line, n);
103 pos += n;
104 if (i + 1 < s_log.count)
105 out[pos++] = '\n';
106 }
107 out[pos] = '\0';
108 return (int)pos;
109}
110
111void detws_log_set_trap(uint8_t threshold, detws_log_trap_fn cb)
112{
113 s_log.trap_threshold = threshold;
114 s_log.trap = cb;
115}
116
117#endif // DETWS_ENABLE_LOGBUF
#define DETWS_LOG_LINE_LEN
Maximum length of one stored log line (bytes, including null).
#define DETWS_LOG_LINES
Number of log lines retained in the ring.
Fixed-RAM rotating log buffer with severity traps (DETWS_ENABLE_LOGBUF).