ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
logger.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdarg>
4#include <map>
5#include <span>
6#include <type_traits>
7#if defined(USE_ESP32) || defined(USE_HOST)
8#include <pthread.h>
9#endif
14#include "esphome/core/log.h"
16
17#include "log_buffer.h"
22
23#ifdef USE_ARDUINO
24#if defined(USE_ESP8266)
25#include <HardwareSerial.h>
26#endif // USE_ESP8266
27#ifdef USE_RP2
28#include <HardwareSerial.h>
29#include <SerialUSB.h>
30#endif // USE_RP2
31#endif // USE_ARDUINO
32
33#ifdef USE_ESP32
34#include <driver/uart.h>
35#endif // USE_ESP32
36
37#ifdef USE_ZEPHYR
38#include <zephyr/kernel.h>
39struct device;
40#endif
41
42namespace esphome::logger {
43
58 void *instance;
59 void (*fn)(void *, uint8_t, const char *, const char *, size_t);
60 void invoke(uint8_t level, const char *tag, const char *message, size_t message_len) const {
61 this->fn(this->instance, level, tag, message, message_len);
62 }
63};
64
65#ifdef USE_LOGGER_LEVEL_LISTENERS
84 public:
85 virtual void on_log_level_change(uint8_t level) = 0;
86};
87#endif
88
89// RAM map keys compared with a tag that may be in PROGMEM, without copying it
90struct FlashTag {
91 const char *tag;
92};
94 using is_transparent = void;
95 bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; }
96 bool operator()(const char *key, FlashTag t) const { return ESPHOME_strcmp_P(key, t.tag) < 0; }
97 bool operator()(FlashTag t, const char *key) const { return ESPHOME_strcmp_P(key, t.tag) > 0; }
98};
99
100// Stack buffer size for retrieving thread/task names from the OS
101// macOS allows up to 64 bytes, Linux up to 16
102static constexpr size_t THREAD_NAME_BUF_SIZE = 64;
103
104#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
109enum UARTSelection : uint8_t {
110#ifdef USE_LIBRETINY
113#else
115#endif
117#if defined(USE_LIBRETINY) || defined(USE_ESP32_VARIANT_ESP32)
119#endif
120#ifdef USE_LOGGER_USB_CDC
122#endif
123#ifdef USE_LOGGER_USB_SERIAL_JTAG
125#endif
126#ifdef USE_ESP8266
128#endif // USE_ESP8266
129};
130#endif // USE_ESP32 || USE_ESP8266 || USE_RP2 || USE_LIBRETINY || USE_ZEPHYR
131
149class Logger final : public Component {
150 public:
151 explicit Logger(uint32_t baud_rate);
152#if defined(USE_ESPHOME_TASK_LOG_BUFFER) || (defined(USE_ZEPHYR) && defined(USE_LOGGER_UART_SELECTION_USB_CDC))
153 void loop() override;
154#endif
156 void set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; }
158#if defined(USE_ARDUINO) && !defined(USE_ESP32)
159 Stream *get_hw_serial() const { return hw_serial_; }
160#endif
161#ifdef USE_ESP32
162 uart_port_t get_uart_num() const { return uart_num_; }
163 void create_pthread_key() { pthread_key_create(&log_recursion_key_, nullptr); }
164#endif
165#ifdef USE_HOST
166 void create_pthread_key() { pthread_key_create(&log_recursion_key_, nullptr); }
167#endif
168#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
169 void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; }
171 UARTSelection get_uart() const { return this->uart_; }
172#endif
173
175 void set_log_level(uint8_t level);
176#ifdef USE_LOGGER_RUNTIME_TAG_LEVELS
178 void set_log_level(const char *tag, uint8_t log_level);
179#endif
180 uint8_t get_log_level() { return this->current_level_; }
182 uint8_t get_log_level(const char *tag);
183
184 // ========== INTERNAL METHODS ==========
185 // (In most use cases you won't need these)
187 void pre_setup();
188 void dump_config() override;
189
190 inline uint8_t level_for(const char *tag);
191
192#ifdef USE_LOG_LISTENERS
194 void add_log_callback(void *instance, void (*fn)(void *, uint8_t, const char *, const char *, size_t)) {
195 this->log_callbacks_.push_back(LogCallback{instance, fn});
196 }
197#else
199 void add_log_callback(void *instance, void (*fn)(void *, uint8_t, const char *, const char *, size_t)) {}
200#endif
201
202#ifdef USE_LOGGER_LEVEL_LISTENERS
204 void add_level_listener(LoggerLevelListener *listener) { this->level_listeners_.push_back(listener); }
205#endif
206
207 float get_setup_priority() const override { return setup_priority::BUS + 500.0f; }
208
209 void log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args); // NOLINT
210#ifdef USE_ESP8266
211 // NOLINTNEXTLINE(readability-identifier-naming)
212 void log_vprintf_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format, va_list args);
213#endif
214
215 protected:
216 // RAII guard for recursion flags - sets flag on construction, clears on destruction
218 public:
219 explicit RecursionGuard(bool &flag) : flag_(flag) { flag_ = true; }
220 ~RecursionGuard() { flag_ = false; }
225
226 private:
227 bool &flag_;
228 };
229
230#if defined(USE_ESP32) || defined(USE_HOST) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
231 // Handles non-main thread logging only (~0.1% of calls)
232 // thread_name is resolved by the caller from the task handle, avoiding redundant lookups
233 void log_vprintf_non_main_thread_(uint8_t level, const char *tag, int line, const char *format, va_list args,
234 const char *thread_name);
235#endif
236#if defined(USE_ZEPHYR) && defined(USE_LOGGER_UART_SELECTION_USB_CDC)
237 void cdc_loop_();
238#endif
239 void process_messages_();
240#if defined(USE_HOST) || defined(USE_ZEPHYR)
241 void write_msg_(const char *msg, uint16_t len);
242#else
243 inline void write_msg_(const char *msg, uint16_t len); // Defined in platform-specific logger_*.h
244#endif
245
246 // Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator
247 // thread_name: name of the calling thread/task, or nullptr for main task (callers already know which task they're on)
248 inline void HOT format_log_to_buffer_with_terminator_(uint8_t level, const char *tag, int line, const char *format,
249 va_list args, LogBuffer &buf, const char *thread_name) {
250 buf.write_header(level, tag, line, thread_name);
251 buf.format_body(format, args);
252 }
253
254#ifdef USE_ESP8266
255 // Format a log message with flash string format and write it to a buffer with header, footer, and null terminator
256 // ESP8266-only (single-task), thread_name is always nullptr
257 inline void HOT format_log_to_buffer_with_terminator_p_(uint8_t level, const char *tag, int line,
258 const __FlashStringHelper *format, va_list args,
259 LogBuffer &buf) {
260 buf.write_header(level, tag, line, nullptr);
261 buf.format_body_p(reinterpret_cast<PGM_P>(format), args);
262 }
263#endif
264
265 // Helper to notify log callbacks
266 inline void HOT notify_listeners_(uint8_t level, const char *tag, const LogBuffer &buf) {
267#ifdef USE_LOG_LISTENERS
268 for (auto &cb : this->log_callbacks_)
269 cb.invoke(level, tag, buf.data, buf.pos);
270#endif
271 }
272
273 // Helper to write log buffer to console (replaces null terminator with newline and writes)
274 inline void HOT write_to_console_(LogBuffer &buf) {
276 this->write_msg_(buf.data, buf.pos);
277 }
278
279 // Helper to write log buffer to console if logging is enabled
281 if (this->baud_rate_ > 0)
282 this->write_to_console_(buf);
283 }
284
285 // Helper to format and send a log message to both console and listeners
286 // Template handles both const char* (RAM) and __FlashStringHelper* (flash) format strings
287 // thread_name: name of the calling thread/task, or nullptr for main task
288 template<typename FormatType>
289 inline void HOT log_message_to_buffer_and_send_(bool &recursion_guard, uint8_t level, const char *tag, int line,
290 FormatType format, va_list args, const char *thread_name) {
291 RecursionGuard guard(recursion_guard);
292 LogBuffer buf{this->tx_buffer_, ESPHOME_LOGGER_TX_BUFFER_SIZE};
293#ifdef USE_ESP8266
294 if constexpr (std::is_same_v<FormatType, const __FlashStringHelper *>) {
295 this->format_log_to_buffer_with_terminator_p_(level, tag, line, format, args, buf);
296 } else
297#endif
298 {
299 this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, buf, thread_name);
300 }
301 this->notify_listeners_(level, tag, buf);
303 }
304
305#ifdef USE_ESPHOME_TASK_LOG_BUFFER
306 // Helper to format a pre-formatted message from the task log buffer and notify listeners
307 // Used by process_messages_ to avoid code duplication between ESP32 and host platforms
308 inline void HOT format_buffered_message_and_notify_(uint8_t level, const char *tag, uint16_t line,
309 const char *thread_name, const char *text, uint16_t text_length,
310 LogBuffer &buf) {
311 buf.write_header(level, tag, line, thread_name);
312 buf.write_body(text, text_length);
313 this->notify_listeners_(level, tag, buf);
314 }
315#endif
316
317#ifndef USE_HOST
318 const LogString *get_uart_selection_();
319#endif
320
321 // Group 4-byte aligned members first
323#if defined(USE_ARDUINO) && !defined(USE_ESP32)
324 Stream *hw_serial_{nullptr};
325#endif
326#if defined(USE_ZEPHYR)
327 void dump_crash_();
328 const device *uart_dev_{nullptr};
329#endif
330#if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
331 void *main_task_{nullptr}; // Main thread/task for fast path comparison
332#endif
333#ifdef USE_HOST
334 pthread_t main_thread_{}; // Main thread for pthread_equal() comparison
335#endif
336#ifdef USE_ESP32
337 // Task-specific recursion guards:
338 // - Main task uses a dedicated member variable for efficiency
339 // - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
340 pthread_key_t log_recursion_key_; // 4 bytes
341 uart_port_t uart_num_; // 4 bytes (enum defaults to int size)
342#endif
343#ifdef USE_HOST
344 // Thread-specific recursion guards using pthread TLS
345 pthread_key_t log_recursion_key_;
346#endif
347
348 // Large objects (internally aligned)
349#ifdef USE_LOGGER_RUNTIME_TAG_LEVELS
350 std::map<const char *, uint8_t, CStrCompare> log_levels_{};
351#endif
352#ifdef USE_LOG_LISTENERS
354 log_callbacks_; // Log message callbacks (API, MQTT, syslog, etc.)
355#endif
356#ifdef USE_LOGGER_LEVEL_LISTENERS
357 std::vector<LoggerLevelListener *> level_listeners_; // Log level change listeners
358#endif
359 // Group smaller types together at the end
360 uint8_t current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
361#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_ZEPHYR)
362 UARTSelection uart_{UART_SELECTION_UART0}; // Must match cpp_default_uart in __init__.py
363#endif
364#ifdef USE_LIBRETINY
365 UARTSelection uart_{UART_SELECTION_DEFAULT}; // Must match cpp_default_uart in __init__.py
366#endif
367#if defined(USE_ESP32) || defined(USE_HOST) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
369#ifdef USE_LIBRETINY
370 bool non_main_task_recursion_guard_{false}; // Shared guard for all non-main tasks on LibreTiny
371#endif
372#else
373 bool global_recursion_guard_{false}; // Simple global recursion guard for single-task platforms
374#endif
375
376 // Large buffers placed last to keep frequently-accessed member offsets small
377 char tx_buffer_[ESPHOME_LOGGER_TX_BUFFER_SIZE + 1]; // +1 for null terminator
378#ifdef USE_ESPHOME_TASK_LOG_BUFFER
379 logger::TaskLogBuffer log_buffer_; // Embedded in Logger (no separate heap allocation)
380#endif
381
382 // --- get_thread_name_ overloads (per-platform) ---
383
384#if defined(USE_ESP32) || defined(USE_LIBRETINY)
385 // Primary overload - takes a task handle directly to avoid redundant xTaskGetCurrentTaskHandle() calls
386 // when the caller already has the handle (e.g. from the main task check in log_vprintf_)
387 const char *get_thread_name_(TaskHandle_t task) {
388 if (task == this->main_task_) {
389 return nullptr; // Main task
390 }
391#if defined(USE_ESP32)
392 return pcTaskGetName(task);
393#elif defined(USE_LIBRETINY)
394 return pcTaskGetTaskName(task);
395#endif
396 }
397
398 // Convenience overload - gets the current task handle and delegates
399 const char *HOT get_thread_name_() { return this->get_thread_name_(xTaskGetCurrentTaskHandle()); }
400
401#elif defined(USE_HOST)
402 // Takes a caller-provided buffer for the thread name (stack-allocated for thread safety)
403 const char *HOT get_thread_name_(std::span<char> buff) {
404 pthread_t current_thread = pthread_self();
405 if (pthread_equal(current_thread, main_thread_)) {
406 return nullptr; // Main thread
407 }
408 // For non-main threads, get the thread name into the caller-provided buffer
409 if (pthread_getname_np(current_thread, buff.data(), buff.size()) == 0) {
410 return buff.data();
411 }
412 return nullptr;
413 }
414
415#elif defined(USE_ZEPHYR)
416 const char *HOT get_thread_name_(std::span<char> buff, k_tid_t current_task = nullptr) {
417 if (current_task == nullptr) {
418 current_task = k_current_get();
419 }
420 if (current_task == main_task_) {
421 return nullptr; // Main task
422 }
423 const char *name = k_thread_name_get(current_task);
424 if (name) {
425 // zephyr print task names only if debug component is present
426 return name;
427 }
428 std::snprintf(buff.data(), buff.size(), "%p", current_task);
429 return buff.data();
430 }
431#endif
432
433 // --- Non-main task recursion guards (per-platform) ---
434
435#if defined(USE_ESP32) || defined(USE_HOST)
436 // RAII guard for non-main task recursion using pthread TLS
438 public:
439 explicit NonMainTaskRecursionGuard(pthread_key_t key) : key_(key) {
440 pthread_setspecific(key_, reinterpret_cast<void *>(1));
441 }
442 ~NonMainTaskRecursionGuard() { pthread_setspecific(key_, nullptr); }
447
448 private:
449 pthread_key_t key_;
450 };
451
452 // Check if non-main task is already in recursion (via TLS)
453 inline bool HOT is_non_main_task_recursive_() const { return pthread_getspecific(log_recursion_key_) != nullptr; }
454
455 // Create RAII guard for non-main task recursion
457
458#elif defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
459 // LibreTiny doesn't have FreeRTOS TLS, so use a simple approach:
460 // - Main task uses dedicated boolean (same as ESP32)
461 // - Non-main tasks share a single recursion guard
462 // This is safe because:
463 // - Recursion from logging within logging is the main concern
464 // - Cross-task "recursion" is prevented by the buffer mutex anyway
465 // - Missing a recursive call from another task is acceptable (falls back to direct output)
466 //
467 // Zephyr use __thread as TLS
468
469 // Check if non-main task is already in recursion
471
472 // Create RAII guard for non-main task recursion (uses shared boolean for all non-main tasks)
474#endif
475
476#if defined(USE_ESPHOME_TASK_LOG_BUFFER) && !(defined(USE_ZEPHYR) && defined(USE_LOGGER_UART_SELECTION_USB_CDC))
477 // Disable loop when task buffer is empty
478 // Zephyr with USB CDC needs loop active to poll port readiness via cdc_loop_()
480 // Thread safety note: This is safe even if another task calls enable_loop_soon_any_context()
481 // concurrently. If that happens between our check and disable_loop(), the enable request
482 // will be processed on the next main loop iteration since:
483 // - disable_loop() takes effect immediately
484 // - enable_loop_soon_any_context() sets a pending flag that's checked at loop start
485 this->disable_loop();
486 }
487#endif
488};
489extern Logger *global_logger; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
490
491class LoggerMessageTrigger final : public Trigger<uint8_t, const char *, const char *> {
492 public:
493 explicit LoggerMessageTrigger(Logger *parent, uint8_t level) : level_(level) {
494 parent->add_log_callback(this,
495 [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
496 auto *trigger = static_cast<LoggerMessageTrigger *>(self);
497 if (level <= trigger->level_) {
498#ifdef USE_ESP8266
499 // User lambdas may strcmp the tag, which may be in PROGMEM. The copy lives in
500 // the trigger so an automation that suspends (delay) still sees a valid tag.
501 ESPHOME_strncpy_P(trigger->ram_tag_, tag, MAX_TAG_LENGTH);
502 tag = trigger->ram_tag_;
503#endif
504 trigger->trigger(level, tag, message);
505 }
506 });
507 }
508
509 protected:
510 uint8_t level_;
511#ifdef USE_ESP8266
512 char ram_tag_[MAX_TAG_LENGTH + 1]{};
513#endif
514};
515
516#ifdef USE_CRASH_HANDLER
518bool crash_log_pending();
522#endif
523
524} // namespace esphome::logger
525
526// Platform-specific inline implementations of write_msg_()
527// Must be included after the Logger class definition is complete
528#if defined(USE_ESP32)
529#include "logger_esp32.h"
530#elif defined(USE_ESP8266)
531#include "logger_esp8266.h"
532#elif defined(USE_RP2)
533#include "logger_rp2.h"
534#elif defined(USE_LIBRETINY)
535#include "logger_libretiny.h"
536#endif
void disable_loop()
Disable this component's loop.
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:286
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Definition automation.h:556
NonMainTaskRecursionGuard & operator=(const NonMainTaskRecursionGuard &)=delete
NonMainTaskRecursionGuard & operator=(NonMainTaskRecursionGuard &&)=delete
NonMainTaskRecursionGuard(const NonMainTaskRecursionGuard &)=delete
NonMainTaskRecursionGuard(NonMainTaskRecursionGuard &&)=delete
RecursionGuard & operator=(const RecursionGuard &)=delete
RecursionGuard(const RecursionGuard &)=delete
RecursionGuard & operator=(RecursionGuard &&)=delete
RecursionGuard(RecursionGuard &&)=delete
Logger component for all ESPHome logging.
Definition logger.h:149
void add_level_listener(LoggerLevelListener *listener)
Register a listener for log level changes.
Definition logger.h:204
void HOT notify_listeners_(uint8_t level, const char *tag, const LogBuffer &buf)
Definition logger.h:266
UARTSelection uart_
Definition logger.h:362
void HOT format_log_to_buffer_with_terminator_p_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format, va_list args, LogBuffer &buf)
Definition logger.h:257
void write_msg_(const char *msg, uint16_t len)
Definition logger_esp32.h:9
const char *HOT get_thread_name_()
Definition logger.h:399
void dump_config() override
Definition logger.cpp:219
const char * get_thread_name_(TaskHandle_t task)
Definition logger.h:387
bool HOT is_non_main_task_recursive_() const
Definition logger.h:453
uint32_t get_baud_rate() const
Definition logger.h:157
const char *HOT get_thread_name_(std::span< char > buff, k_tid_t current_task=nullptr)
Definition logger.h:416
NonMainTaskRecursionGuard make_non_main_task_guard_()
Definition logger.h:456
const LogString * get_uart_selection_()
uint8_t level_for(const char *tag)
Definition logger.cpp:147
StaticVector< LogCallback, ESPHOME_LOG_MAX_LISTENERS > log_callbacks_
Definition logger.h:354
void loop() override
Definition logger.cpp:170
uint8_t get_log_level()
Definition logger.h:180
Stream * get_hw_serial() const
Definition logger.h:159
void log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args)
Definition logger.cpp:26
void HOT log_message_to_buffer_and_send_(bool &recursion_guard, uint8_t level, const char *tag, int line, FormatType format, va_list args, const char *thread_name)
Definition logger.h:289
void pre_setup()
Set up this component.
char tx_buffer_[ESPHOME_LOGGER_TX_BUFFER_SIZE+1]
Definition logger.h:377
void HOT format_buffered_message_and_notify_(uint8_t level, const char *tag, uint16_t line, const char *thread_name, const char *text, uint16_t text_length, LogBuffer &buf)
Definition logger.h:308
void write_msg_(const char *msg, uint16_t len)
float get_setup_priority() const override
Definition logger.h:207
std::map< const char *, uint8_t, CStrCompare > log_levels_
Definition logger.h:350
const char *HOT get_thread_name_(std::span< char > buff)
Definition logger.h:403
UARTSelection get_uart() const
Get the UART used by the logger.
Definition logger.h:171
pthread_t main_thread_
Definition logger.h:334
std::vector< LoggerLevelListener * > level_listeners_
Definition logger.h:357
bool non_main_task_recursion_guard_
Definition logger.h:370
void disable_loop_when_buffer_empty_()
Definition logger.h:479
uart_port_t uart_num_
Definition logger.h:341
void HOT format_log_to_buffer_with_terminator_(uint8_t level, const char *tag, int line, const char *format, va_list args, LogBuffer &buf, const char *thread_name)
Definition logger.h:248
pthread_key_t log_recursion_key_
Definition logger.h:340
RecursionGuard make_non_main_task_guard_()
Definition logger.h:473
void HOT write_log_buffer_to_console_(LogBuffer &buf)
Definition logger.h:280
uart_port_t get_uart_num() const
Definition logger.h:162
void set_log_level(uint8_t level)
Set the default log level for this logger.
Definition logger.cpp:263
void set_baud_rate(uint32_t baud_rate)
Manually set the baud rate for serial, set to 0 to disable.
Definition logger.h:156
void set_uart_selection(UARTSelection uart_selection)
Definition logger.h:169
void add_log_callback(void *instance, void(*fn)(void *, uint8_t, const char *, const char *, size_t))
Register a log callback to receive log messages.
Definition logger.h:194
void HOT write_to_console_(LogBuffer &buf)
Definition logger.h:274
void log_vprintf_non_main_thread_(uint8_t level, const char *tag, int line, const char *format, va_list args, const char *thread_name)
Definition logger.cpp:72
logger::TaskLogBuffer log_buffer_
Definition logger.h:379
bool main_task_recursion_guard_
Definition logger.h:368
const device * uart_dev_
Definition logger.h:328
Logger(uint32_t baud_rate)
Definition logger.cpp:159
Interface for receiving log level changes without std::function overhead.
Definition logger.h:83
virtual void on_log_level_change(uint8_t level)=0
char ram_tag_[MAX_TAG_LENGTH+1]
Definition logger.h:512
LoggerMessageTrigger(Logger *parent, uint8_t level)
Definition logger.h:493
Task log buffer for ESP32 platform using FreeRTOS ring buffer.
const LogString * message
Definition component.cpp:35
const char * key
const char * format
bool crash_log_pending()
Whether a crash record from before this boot is waiting to be reported.
UARTSelection
Enum for logging UART selection.
Definition logger.h:109
@ UART_SELECTION_UART0_SWAP
Definition logger.h:127
@ UART_SELECTION_UART2
Definition logger.h:118
@ UART_SELECTION_USB_SERIAL_JTAG
Definition logger.h:124
@ UART_SELECTION_DEFAULT
Definition logger.h:111
@ UART_SELECTION_USB_CDC
Definition logger.h:121
@ UART_SELECTION_UART0
Definition logger.h:112
@ UART_SELECTION_UART1
Definition logger.h:116
Logger * global_logger
Definition logger.cpp:276
void log_crash_to_client()
Log the previous crash for a client that just subscribed to the logs.
constexpr float BUS
For communication buses like i2c/spi.
Definition component.h:39
const void size_t len
Definition hal.h:68
static void uint32_t
bool operator()(const char *a, const char *b) const
Definition logger.h:95
bool operator()(FlashTag t, const char *key) const
Definition logger.h:97
bool operator()(const char *key, FlashTag t) const
Definition logger.h:96
void HOT format_body_p(PGM_P format, va_list args)
Definition log_buffer.h:112
void write_body(const char *text, uint16_t text_length)
Definition log_buffer.h:117
void HOT write_header(uint8_t level, const char *tag, int line, const char *thread_name)
Definition log_buffer.h:54
void HOT format_body(const char *format, va_list args)
Definition log_buffer.h:107
Lightweight callback for receiving log messages without virtual dispatch overhead.
Definition logger.h:57
void invoke(uint8_t level, const char *tag, const char *message, size_t message_len) const
Definition logger.h:60
void(* fn)(void *, uint8_t, const char *, const char *, size_t)
Definition logger.h:59