1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// SPDX-License-Identifier: MPL-2.0
//! Logger backend trait and global state.
use ;
use Once;
use ;
static LOGGER: = new;
/// Registers the global logger backend.
///
/// The function may be called only once; subsequent calls take no effect.
/// Returns the registered logger, if any.
pub
/// Writes a log record to the registered logger,
/// or falls back to early console output
/// if no logger has been registered yet.
///
/// Called by the `log!` macro. Not intended for direct use.
/// The logger backend trait.
///
/// Implement this trait and register it with [`inject_logger()`] to receive log
/// records from the OSTD logging macros.
///
/// # Implementation guidelines
///
/// The logging macros can be called from **any context**: interrupt handlers,
/// early boot, OOM handlers, or panic handlers. An implementation should
/// be designed to work correctly in all of these contexts. In practice:
///
/// - **The ring buffer write must be heapless and lock-free (or IRQ-safe).**
/// The part of `log()` that records the message must not allocate from the
/// heap and must use either a lock-free data structure or an IRQ-disabled
/// spinlock, so that it is safe from any context.
///
/// - **Console flushing is best-effort.** After recording the message,
/// the implementation may attempt to flush pending messages to console
/// devices synchronously. In contended or non-blockable contexts
/// (e.g., scheduler code), the implementation should skip or defer
/// flushing rather than blocking.
///
/// - **The implementation should be short.** Long-running work can stall the
/// calling CPU. Implementations should bound the work per `log()` call.
/// A single log record carrying level, message, and source location.
///
/// Records are created by the logging macros
/// and passed to the [`Log`] backend.
/// They are transient —
/// the backend must consume all data during the `log()` call.
// -- Maximum log level --
/// Compile-time maximum log level.
// TODO: Add cargo features (e.g., `log_max_level_info`) to
// set `STATIC_MAX_LEVEL` at compile time
// so that log calls above the chosen level are eliminated entirely.
// The same feature should activate the corresponding `log` crate feature
// (e.g., `log/max_level_info`)
// so that both OSTD macros and third-party `log::info!()` calls are filtered uniformly.
pub const STATIC_MAX_LEVEL: LevelFilter = Debug;
/// Run-time maximum log level.
static DYNAMIC_MAX_LEVEL: AtomicU8 = ;
/// Sets the runtime maximum log level.
///
/// If the given `filter` argument is greater than [`STATIC_MAX_LEVEL`],
/// then the runtime maximum log level is set to `STATIC_MAX_LEVEL`.
///
/// This function also updates the `log` crate's max level
/// so that third-party crates using `log::info!()` etc. are filtered consistently.
///
/// # Requirements
///
/// This function is intended to be called sequentially:
/// concurrent calls to this function may cause the maximum levels
/// kept by OSTD and `log` to diverge.
/// Returns the current runtime maximum log level.