ESPHome 2025.5.0
Loading...
Searching...
No Matches
logger.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdarg>
4#include <map>
5#ifdef USE_ESP32
6#include <pthread.h>
7#endif
12#include "esphome/core/log.h"
13
14#ifdef USE_ESPHOME_TASK_LOG_BUFFER
15#include "task_log_buffer.h"
16#endif
17
18#ifdef USE_ARDUINO
19#if defined(USE_ESP8266) || defined(USE_ESP32)
20#include <HardwareSerial.h>
21#endif // USE_ESP8266 || USE_ESP32
22#ifdef USE_RP2040
23#include <HardwareSerial.h>
24#include <SerialUSB.h>
25#endif // USE_RP2040
26#endif // USE_ARDUINO
27
28#ifdef USE_ESP_IDF
29#include <driver/uart.h>
30#endif // USE_ESP_IDF
31
32namespace esphome {
33
34namespace logger {
35
36// Color and letter constants for log levels
37static const char *const LOG_LEVEL_COLORS[] = {
38 "", // NONE
39 ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), // ERROR
40 ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_YELLOW), // WARNING
41 ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_GREEN), // INFO
42 ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_MAGENTA), // CONFIG
43 ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_CYAN), // DEBUG
44 ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_GRAY), // VERBOSE
45 ESPHOME_LOG_COLOR(ESPHOME_LOG_COLOR_WHITE), // VERY_VERBOSE
46};
47
48static const char *const LOG_LEVEL_LETTERS[] = {
49 "", // NONE
50 "E", // ERROR
51 "W", // WARNING
52 "I", // INFO
53 "C", // CONFIG
54 "D", // DEBUG
55 "V", // VERBOSE
56 "VV", // VERY_VERBOSE
57};
58
59#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY)
65#ifdef USE_LIBRETINY
68#else
70#endif
72#if defined(USE_LIBRETINY) || defined(USE_ESP32_VARIANT_ESP32)
74#endif
75#ifdef USE_LOGGER_USB_CDC
77#endif
78#ifdef USE_LOGGER_USB_SERIAL_JTAG
80#endif
81#ifdef USE_ESP8266
83#endif // USE_ESP8266
84};
85#endif // USE_ESP32 || USE_ESP8266 || USE_RP2040 || USE_LIBRETINY
86
104class Logger : public Component {
105 public:
106 explicit Logger(uint32_t baud_rate, size_t tx_buffer_size);
107#ifdef USE_ESPHOME_TASK_LOG_BUFFER
108 void init_log_buffer(size_t total_buffer_size);
109#endif
110#if defined(USE_LOGGER_USB_CDC) || defined(USE_ESP32)
111 void loop() override;
112#endif
114 void set_baud_rate(uint32_t baud_rate);
115 uint32_t get_baud_rate() const { return baud_rate_; }
116#ifdef USE_ARDUINO
117 Stream *get_hw_serial() const { return hw_serial_; }
118#endif
119#ifdef USE_ESP_IDF
120 uart_port_t get_uart_num() const { return uart_num_; }
121#endif
122#ifdef USE_ESP32
123 void create_pthread_key() { pthread_key_create(&log_recursion_key_, nullptr); }
124#endif
125#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY)
126 void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; }
128 UARTSelection get_uart() const;
129#endif
130
132 void set_log_level(int level);
134 void set_log_level(const std::string &tag, int log_level);
135 int get_log_level() { return this->current_level_; }
136
137 // ========== INTERNAL METHODS ==========
138 // (In most use cases you won't need these)
140 void pre_setup();
141 void dump_config() override;
142
143 inline int level_for(const char *tag);
144
146 void add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback);
147
148 // add a listener for log level changes
149 void add_listener(std::function<void(int)> &&callback) { this->level_callback_.add(std::move(callback)); }
150
151 float get_setup_priority() const override;
152
153 void log_vprintf_(int level, const char *tag, int line, const char *format, va_list args); // NOLINT
154#ifdef USE_STORE_LOG_STR_IN_FLASH
155 void log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format, va_list args); // NOLINT
156#endif
157
158 protected:
159 void call_log_callbacks_(int level, const char *tag, const char *msg);
160 void write_msg_(const char *msg);
161
162 // Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator
163 // It's the caller's responsibility to initialize buffer_at (typically to 0)
164 inline void HOT format_log_to_buffer_with_terminator_(int level, const char *tag, int line, const char *format,
165 va_list args, char *buffer, int *buffer_at, int buffer_size) {
166#if defined(USE_ESP32) || defined(USE_LIBRETINY)
167 this->write_header_to_buffer_(level, tag, line, this->get_thread_name_(), buffer, buffer_at, buffer_size);
168#else
169 this->write_header_to_buffer_(level, tag, line, nullptr, buffer, buffer_at, buffer_size);
170#endif
171 this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, args);
172 this->write_footer_to_buffer_(buffer, buffer_at, buffer_size);
173
174 // Always ensure the buffer has a null terminator, even if we need to
175 // overwrite the last character of the actual content
176 if (*buffer_at >= buffer_size) {
177 buffer[buffer_size - 1] = '\0'; // Truncate and ensure null termination
178 } else {
179 buffer[*buffer_at] = '\0'; // Normal case, append null terminator
180 }
181 }
182
183 // Helper to format and send a log message to both console and callbacks
184 inline void HOT log_message_to_buffer_and_send_(int level, const char *tag, int line, const char *format,
185 va_list args) {
186 // Format to tx_buffer and prepare for output
187 this->tx_buffer_at_ = 0; // Initialize buffer position
188 this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, this->tx_buffer_, &this->tx_buffer_at_,
189 this->tx_buffer_size_);
190
191 if (this->baud_rate_ > 0) {
192 this->write_msg_(this->tx_buffer_); // If logging is enabled, write to console
193 }
194 this->call_log_callbacks_(level, tag, this->tx_buffer_);
195 }
196
197 // Write the body of the log message to the buffer
198 inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, int *buffer_at, int buffer_size) {
199 // Calculate available space
200 const int available = buffer_size - *buffer_at;
201 if (available <= 0)
202 return;
203
204 // Determine copy length (minimum of remaining capacity and string length)
205 const size_t copy_len = (length < static_cast<size_t>(available)) ? length : available;
206
207 // Copy the data
208 if (copy_len > 0) {
209 memcpy(buffer + *buffer_at, value, copy_len);
210 *buffer_at += copy_len;
211 }
212 }
213
214 // Format string to explicit buffer with varargs
215 inline void printf_to_buffer_(const char *format, char *buffer, int *buffer_at, int buffer_size, ...) {
216 va_list arg;
217 va_start(arg, buffer_size);
218 this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, arg);
219 va_end(arg);
220 }
221
222#ifndef USE_HOST
223 const char *get_uart_selection_();
224#endif
225
226 uint32_t baud_rate_;
227 char *tx_buffer_{nullptr};
230#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
232#endif
233#ifdef USE_LIBRETINY
235#endif
236#ifdef USE_ARDUINO
237 Stream *hw_serial_{nullptr};
238#endif
239#ifdef USE_ESP_IDF
240 uart_port_t uart_num_;
241#endif
242 std::map<std::string, int> log_levels_{};
243 CallbackManager<void(int, const char *, const char *)> log_callback_{};
244 int current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
245#ifdef USE_ESPHOME_TASK_LOG_BUFFER
246 std::unique_ptr<logger::TaskLogBuffer> log_buffer_; // Will be initialized with init_log_buffer
247#endif
248#ifdef USE_ESP32
249 // Task-specific recursion guards:
250 // - Main task uses a dedicated member variable for efficiency
251 // - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
253 pthread_key_t log_recursion_key_;
254#else
255 bool global_recursion_guard_{false}; // Simple global recursion guard for single-task platforms
256#endif
258
259#if defined(USE_ESP32) || defined(USE_LIBRETINY)
260 void *main_task_ = nullptr; // Only used for thread name identification
261 const char *HOT get_thread_name_() {
262 TaskHandle_t current_task = xTaskGetCurrentTaskHandle();
263 if (current_task == main_task_) {
264 return nullptr; // Main task
265 } else {
266#if defined(USE_ESP32)
267 return pcTaskGetName(current_task);
268#elif defined(USE_LIBRETINY)
269 return pcTaskGetTaskName(current_task);
270#endif
271 }
272 }
273#endif
274
275#ifdef USE_ESP32
276 inline bool HOT check_and_set_task_log_recursion_(bool is_main_task) {
277 if (is_main_task) {
278 const bool was_recursive = main_task_recursion_guard_;
280 return was_recursive;
281 }
282
283 intptr_t current = (intptr_t) pthread_getspecific(log_recursion_key_);
284 if (current != 0)
285 return true;
286
287 pthread_setspecific(log_recursion_key_, (void *) 1);
288 return false;
289 }
290
291 inline void HOT reset_task_log_recursion_(bool is_main_task) {
292 if (is_main_task) {
294 return;
295 }
296
297 pthread_setspecific(log_recursion_key_, (void *) 0);
298 }
299#endif
300
301 inline void HOT write_header_to_buffer_(int level, const char *tag, int line, const char *thread_name, char *buffer,
302 int *buffer_at, int buffer_size) {
303 // Format header
304 if (level < 0)
305 level = 0;
306 if (level > 7)
307 level = 7;
308
309 const char *color = esphome::logger::LOG_LEVEL_COLORS[level];
310 const char *letter = esphome::logger::LOG_LEVEL_LETTERS[level];
311
312#if defined(USE_ESP32) || defined(USE_LIBRETINY)
313 if (thread_name != nullptr) {
314 // Non-main task with thread name
315 this->printf_to_buffer_("%s[%s][%s:%03u]%s[%s]%s: ", buffer, buffer_at, buffer_size, color, letter, tag, line,
316 ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), thread_name, color);
317 return;
318 }
319#endif
320 // Main task or non ESP32/LibreTiny platform
321 this->printf_to_buffer_("%s[%s][%s:%03u]: ", buffer, buffer_at, buffer_size, color, letter, tag, line);
322 }
323
324 inline void HOT format_body_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format,
325 va_list args) {
326 // Get remaining capacity in the buffer
327 const int remaining = buffer_size - *buffer_at;
328 if (remaining <= 0)
329 return;
330
331 const int ret = vsnprintf(buffer + *buffer_at, remaining, format, args);
332
333 if (ret < 0) {
334 return; // Encoding error, do not increment buffer_at
335 }
336
337 // Update buffer_at with the formatted length (handle truncation)
338 int formatted_len = (ret >= remaining) ? remaining : ret;
339 *buffer_at += formatted_len;
340
341 // Remove all trailing newlines right after formatting
342 while (*buffer_at > 0 && buffer[*buffer_at - 1] == '\n') {
343 (*buffer_at)--;
344 }
345 }
346
347 inline void HOT write_footer_to_buffer_(char *buffer, int *buffer_at, int buffer_size) {
348 static const int RESET_COLOR_LEN = strlen(ESPHOME_LOG_RESET_COLOR);
349 this->write_body_to_buffer_(ESPHOME_LOG_RESET_COLOR, RESET_COLOR_LEN, buffer, buffer_at, buffer_size);
350 }
351};
352extern Logger *global_logger; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
353
354class LoggerMessageTrigger : public Trigger<int, const char *, const char *> {
355 public:
356 explicit LoggerMessageTrigger(Logger *parent, int level) {
357 this->level_ = level;
358 parent->add_on_log_callback([this](int level, const char *tag, const char *message) {
359 if (level <= this->level_) {
360 this->trigger(level, tag, message);
361 }
362 });
363 }
364
365 protected:
367};
368
369} // namespace logger
370
371} // namespace esphome
Logger component for all ESPHome logging.
Definition logger.h:104
UARTSelection uart_
Definition logger.h:231
void call_log_callbacks_(int level, const char *tag, const char *msg)
Definition logger.cpp:132
int level_for(const char *tag)
Definition logger.cpp:125
void HOT write_footer_to_buffer_(char *buffer, int *buffer_at, int buffer_size)
Definition logger.h:347
const char *HOT get_thread_name_()
Definition logger.h:261
void dump_config() override
Definition logger.cpp:223
uint32_t get_baud_rate() const
Definition logger.h:115
const char * get_uart_selection_()
void log_vprintf_(int level, const char *tag, int line, const char *format, va_list args)
Definition logger.cpp:27
bool HOT check_and_set_task_log_recursion_(bool is_main_task)
Definition logger.h:276
void loop() override
Definition logger.cpp:159
Stream * get_hw_serial() const
Definition logger.h:117
void pre_setup()
Set up this component.
CallbackManager< void(int, const char *, const char *)> log_callback_
Definition logger.h:243
void HOT log_message_to_buffer_and_send_(int level, const char *tag, int line, const char *format, va_list args)
Definition logger.h:184
void printf_to_buffer_(const char *format, char *buffer, int *buffer_at, int buffer_size,...)
Definition logger.h:215
float get_setup_priority() const override
Definition logger.cpp:220
UARTSelection get_uart() const
Get the UART used by the logger.
Definition logger.cpp:214
uart_port_t uart_num_
Definition logger.h:240
std::unique_ptr< logger::TaskLogBuffer > log_buffer_
Definition logger.h:246
pthread_key_t log_recursion_key_
Definition logger.h:253
uart_port_t get_uart_num() const
Definition logger.h:120
void init_log_buffer(size_t total_buffer_size)
Definition logger.cpp:153
void HOT write_header_to_buffer_(int level, const char *tag, int line, const char *thread_name, char *buffer, int *buffer_at, int buffer_size)
Definition logger.h:301
void set_baud_rate(uint32_t baud_rate)
Manually set the baud rate for serial, set to 0 to disable.
Definition logger.cpp:210
void set_uart_selection(UARTSelection uart_selection)
Definition logger.h:126
void HOT format_log_to_buffer_with_terminator_(int level, const char *tag, int line, const char *format, va_list args, char *buffer, int *buffer_at, int buffer_size)
Definition logger.h:164
Logger(uint32_t baud_rate, size_t tx_buffer_size)
Definition logger.cpp:145
std::map< std::string, int > log_levels_
Definition logger.h:242
void HOT format_body_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, va_list args)
Definition logger.h:324
void write_body_to_buffer_(const char *value, size_t length, char *buffer, int *buffer_at, int buffer_size)
Definition logger.h:198
void HOT reset_task_log_recursion_(bool is_main_task)
Definition logger.h:291
void write_msg_(const char *msg)
CallbackManager< void(int)> level_callback_
Definition logger.h:257
bool main_task_recursion_guard_
Definition logger.h:252
void add_on_log_callback(std::function< void(int, const char *, const char *)> &&callback)
Register a callback that will be called for every log message sent.
Definition logger.cpp:217
void set_log_level(int level)
Set the default log level for this logger.
Definition logger.cpp:242
void add_listener(std::function< void(int)> &&callback)
Definition logger.h:149
LoggerMessageTrigger(Logger *parent, int level)
Definition logger.h:356
UARTSelection
Enum for logging UART selection.
Definition logger.h:64
@ UART_SELECTION_UART0_SWAP
Definition logger.h:82
@ UART_SELECTION_UART2
Definition logger.h:73
@ UART_SELECTION_USB_SERIAL_JTAG
Definition logger.h:79
@ UART_SELECTION_DEFAULT
Definition logger.h:66
@ UART_SELECTION_USB_CDC
Definition logger.h:76
@ UART_SELECTION_UART0
Definition logger.h:67
@ UART_SELECTION_UART1
Definition logger.h:71
Logger * global_logger
Definition logger.cpp:251
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint16_t length
Definition tt21100.cpp:0