mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'logger_memory' into integration
This commit is contained in:
		| @@ -184,7 +184,9 @@ CONFIG_SCHEMA = cv.All( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Logger), | ||||
|             cv.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int, | ||||
|             cv.Optional(CONF_TX_BUFFER_SIZE, default=512): cv.validate_bytes, | ||||
|             cv.Optional(CONF_TX_BUFFER_SIZE, default=512): cv.All( | ||||
|                 cv.validate_bytes, cv.int_range(min=160, max=65535) | ||||
|             ), | ||||
|             cv.Optional(CONF_DEASSERT_RTS_DTR, default=False): cv.boolean, | ||||
|             cv.SplitDefault( | ||||
|                 CONF_TASK_LOG_BUFFER_SIZE, | ||||
|   | ||||
| @@ -24,7 +24,7 @@ static const char *const TAG = "logger"; | ||||
| //    - Messages are serialized through main loop for proper console output | ||||
| //    - Fallback to emergency console logging only if ring buffer is full | ||||
| //  - WITHOUT task log buffer: Only emergency console output, no callbacks | ||||
| void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) {  // NOLINT | ||||
| void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args) {  // NOLINT | ||||
|   if (level > this->level_for(tag)) | ||||
|     return; | ||||
|  | ||||
| @@ -63,7 +63,7 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char * | ||||
|     // Maximum size for console log messages (includes null terminator) | ||||
|     static const size_t MAX_CONSOLE_LOG_MSG_SIZE = 144; | ||||
|     char console_buffer[MAX_CONSOLE_LOG_MSG_SIZE];  // MUST be stack allocated for thread safety | ||||
|     int buffer_at = 0;                              // Initialize buffer position | ||||
|     uint16_t buffer_at = 0;                         // Initialize buffer position | ||||
|     this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, console_buffer, &buffer_at, | ||||
|                                                 MAX_CONSOLE_LOG_MSG_SIZE); | ||||
|     this->write_msg_(console_buffer); | ||||
| @@ -74,7 +74,7 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char * | ||||
| } | ||||
| #else | ||||
| // Implementation for all other platforms | ||||
| void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) {  // NOLINT | ||||
| void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args) {  // NOLINT | ||||
|   if (level > this->level_for(tag) || global_recursion_guard_) | ||||
|     return; | ||||
|  | ||||
| @@ -90,7 +90,7 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char * | ||||
| #ifdef USE_STORE_LOG_STR_IN_FLASH | ||||
| // Implementation for ESP8266 with flash string support. | ||||
| // Note: USE_STORE_LOG_STR_IN_FLASH is only defined for ESP8266. | ||||
| void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format, | ||||
| void Logger::log_vprintf_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format, | ||||
|                           va_list args) {  // NOLINT | ||||
|   if (level > this->level_for(tag) || global_recursion_guard_) | ||||
|     return; | ||||
| @@ -127,7 +127,7 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr | ||||
| } | ||||
| #endif  // USE_STORE_LOG_STR_IN_FLASH | ||||
|  | ||||
| inline int Logger::level_for(const char *tag) { | ||||
| inline uint8_t Logger::level_for(const char *tag) { | ||||
|   auto it = this->log_levels_.find(tag); | ||||
|   if (it != this->log_levels_.end()) | ||||
|     return it->second; | ||||
| @@ -208,13 +208,13 @@ void Logger::loop() { | ||||
| #endif | ||||
|  | ||||
| void Logger::set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; } | ||||
| void Logger::set_log_level(const std::string &tag, int log_level) { this->log_levels_[tag] = log_level; } | ||||
| void Logger::set_log_level(const std::string &tag, uint8_t log_level) { this->log_levels_[tag] = log_level; } | ||||
|  | ||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) | ||||
| UARTSelection Logger::get_uart() const { return this->uart_; } | ||||
| #endif | ||||
|  | ||||
| void Logger::add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback) { | ||||
| void Logger::add_on_log_callback(std::function<void(uint8_t, const char *, const char *)> &&callback) { | ||||
|   this->log_callback_.add(std::move(callback)); | ||||
| } | ||||
| float Logger::get_setup_priority() const { return setup_priority::BUS + 500.0f; } | ||||
| @@ -243,7 +243,7 @@ void Logger::dump_config() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Logger::set_log_level(int level) { | ||||
| void Logger::set_log_level(uint8_t level) { | ||||
|   if (level > ESPHOME_LOG_LEVEL) { | ||||
|     level = ESPHOME_LOG_LEVEL; | ||||
|     ESP_LOGW(TAG, "Cannot set log level higher than pre-compiled %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]); | ||||
|   | ||||
| @@ -61,7 +61,7 @@ static const char *const LOG_LEVEL_LETTERS[] = { | ||||
|  * | ||||
|  * Advanced configuration (pin selection, etc) is not supported. | ||||
|  */ | ||||
| enum UARTSelection { | ||||
| enum UARTSelection : uint8_t { | ||||
| #ifdef USE_LIBRETINY | ||||
|   UART_SELECTION_DEFAULT = 0, | ||||
|   UART_SELECTION_UART0, | ||||
| @@ -129,10 +129,10 @@ class Logger : public Component { | ||||
| #endif | ||||
|  | ||||
|   /// Set the default log level for this logger. | ||||
|   void set_log_level(int level); | ||||
|   void set_log_level(uint8_t level); | ||||
|   /// Set the log level of the specified tag. | ||||
|   void set_log_level(const std::string &tag, int log_level); | ||||
|   int get_log_level() { return this->current_level_; } | ||||
|   void set_log_level(const std::string &tag, uint8_t log_level); | ||||
|   uint8_t get_log_level() { return this->current_level_; } | ||||
|  | ||||
|   // ========== INTERNAL METHODS ========== | ||||
|   // (In most use cases you won't need these) | ||||
| @@ -140,19 +140,20 @@ class Logger : public Component { | ||||
|   void pre_setup(); | ||||
|   void dump_config() override; | ||||
|  | ||||
|   inline int level_for(const char *tag); | ||||
|   inline uint8_t level_for(const char *tag); | ||||
|  | ||||
|   /// Register a callback that will be called for every log message sent | ||||
|   void add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback); | ||||
|   void add_on_log_callback(std::function<void(uint8_t, const char *, const char *)> &&callback); | ||||
|  | ||||
|   // add a listener for log level changes | ||||
|   void add_listener(std::function<void(int)> &&callback) { this->level_callback_.add(std::move(callback)); } | ||||
|   void add_listener(std::function<void(uint8_t)> &&callback) { this->level_callback_.add(std::move(callback)); } | ||||
|  | ||||
|   float get_setup_priority() const override; | ||||
|  | ||||
|   void log_vprintf_(int level, const char *tag, int line, const char *format, va_list args);  // NOLINT | ||||
|   void log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args);  // NOLINT | ||||
| #ifdef USE_STORE_LOG_STR_IN_FLASH | ||||
|   void log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format, va_list args);  // NOLINT | ||||
|   void log_vprintf_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format, | ||||
|                     va_list args);  // NOLINT | ||||
| #endif | ||||
|  | ||||
|  protected: | ||||
| @@ -160,8 +161,9 @@ class Logger : public Component { | ||||
|  | ||||
|   // Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator | ||||
|   // It's the caller's responsibility to initialize buffer_at (typically to 0) | ||||
|   inline 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) { | ||||
|   inline void HOT format_log_to_buffer_with_terminator_(uint8_t level, const char *tag, int line, const char *format, | ||||
|                                                         va_list args, char *buffer, uint16_t *buffer_at, | ||||
|                                                         uint16_t buffer_size) { | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|     this->write_header_to_buffer_(level, tag, line, this->get_thread_name_(), buffer, buffer_at, buffer_size); | ||||
| #else | ||||
| @@ -180,7 +182,7 @@ class Logger : public Component { | ||||
|   } | ||||
|  | ||||
|   // Helper to format and send a log message to both console and callbacks | ||||
|   inline void HOT log_message_to_buffer_and_send_(int level, const char *tag, int line, const char *format, | ||||
|   inline void HOT log_message_to_buffer_and_send_(uint8_t level, const char *tag, int line, const char *format, | ||||
|                                                   va_list args) { | ||||
|     // Format to tx_buffer and prepare for output | ||||
|     this->tx_buffer_at_ = 0;  // Initialize buffer position | ||||
| @@ -194,11 +196,12 @@ class Logger : public Component { | ||||
|   } | ||||
|  | ||||
|   // Write the body of the log message to the buffer | ||||
|   inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, int *buffer_at, int buffer_size) { | ||||
|   inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, uint16_t *buffer_at, | ||||
|                                     uint16_t buffer_size) { | ||||
|     // Calculate available space | ||||
|     const int available = buffer_size - *buffer_at; | ||||
|     if (available <= 0) | ||||
|     if (*buffer_at >= buffer_size) | ||||
|       return; | ||||
|     const uint16_t available = buffer_size - *buffer_at; | ||||
|  | ||||
|     // Determine copy length (minimum of remaining capacity and string length) | ||||
|     const size_t copy_len = (length < static_cast<size_t>(available)) ? length : available; | ||||
| @@ -211,7 +214,7 @@ class Logger : public Component { | ||||
|   } | ||||
|  | ||||
|   // Format string to explicit buffer with varargs | ||||
|   inline void printf_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, ...) { | ||||
|   inline void printf_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format, ...) { | ||||
|     va_list arg; | ||||
|     va_start(arg, format); | ||||
|     this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, arg); | ||||
| @@ -222,41 +225,50 @@ class Logger : public Component { | ||||
|   const char *get_uart_selection_(); | ||||
| #endif | ||||
|  | ||||
|   // Group 4-byte aligned members first | ||||
|   uint32_t baud_rate_; | ||||
|   char *tx_buffer_{nullptr}; | ||||
|   int tx_buffer_at_{0}; | ||||
|   int tx_buffer_size_{0}; | ||||
| #ifdef USE_ARDUINO | ||||
|   Stream *hw_serial_{nullptr}; | ||||
| #endif | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|   void *main_task_ = nullptr;  // Only used for thread name identification | ||||
| #endif | ||||
| #ifdef USE_ESP32 | ||||
|   // Task-specific recursion guards: | ||||
|   // - Main task uses a dedicated member variable for efficiency | ||||
|   // - Other tasks use pthread TLS with a dynamically created key via pthread_key_create | ||||
|   pthread_key_t log_recursion_key_;  // 4 bytes | ||||
| #endif | ||||
| #ifdef USE_ESP_IDF | ||||
|   uart_port_t uart_num_;  // 4 bytes (enum defaults to int size) | ||||
| #endif | ||||
|  | ||||
|   // Large objects (internally aligned) | ||||
|   std::map<std::string, uint8_t> log_levels_{}; | ||||
|   CallbackManager<void(uint8_t, const char *, const char *)> log_callback_{}; | ||||
|   CallbackManager<void(uint8_t)> level_callback_{}; | ||||
| #ifdef USE_ESPHOME_TASK_LOG_BUFFER | ||||
|   std::unique_ptr<logger::TaskLogBuffer> log_buffer_;  // Will be initialized with init_log_buffer | ||||
| #endif | ||||
|  | ||||
|   // Group smaller types together at the end | ||||
|   uint16_t tx_buffer_at_{0}; | ||||
|   uint16_t tx_buffer_size_{0}; | ||||
|   uint8_t current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE}; | ||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) | ||||
|   UARTSelection uart_{UART_SELECTION_UART0}; | ||||
| #endif | ||||
| #ifdef USE_LIBRETINY | ||||
|   UARTSelection uart_{UART_SELECTION_DEFAULT}; | ||||
| #endif | ||||
| #ifdef USE_ARDUINO | ||||
|   Stream *hw_serial_{nullptr}; | ||||
| #endif | ||||
| #ifdef USE_ESP_IDF | ||||
|   uart_port_t uart_num_; | ||||
| #endif | ||||
|   std::map<std::string, int> log_levels_{}; | ||||
|   CallbackManager<void(int, const char *, const char *)> log_callback_{}; | ||||
|   int current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE}; | ||||
| #ifdef USE_ESPHOME_TASK_LOG_BUFFER | ||||
|   std::unique_ptr<logger::TaskLogBuffer> log_buffer_;  // Will be initialized with init_log_buffer | ||||
| #endif | ||||
| #ifdef USE_ESP32 | ||||
|   // Task-specific recursion guards: | ||||
|   // - Main task uses a dedicated member variable for efficiency | ||||
|   // - Other tasks use pthread TLS with a dynamically created key via pthread_key_create | ||||
|   bool main_task_recursion_guard_{false}; | ||||
|   pthread_key_t log_recursion_key_; | ||||
| #else | ||||
|   bool global_recursion_guard_{false};  // Simple global recursion guard for single-task platforms | ||||
| #endif | ||||
|   CallbackManager<void(int)> level_callback_{}; | ||||
|  | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|   void *main_task_ = nullptr;  // Only used for thread name identification | ||||
|   const char *HOT get_thread_name_() { | ||||
|     TaskHandle_t current_task = xTaskGetCurrentTaskHandle(); | ||||
|     if (current_task == main_task_) { | ||||
| @@ -297,11 +309,10 @@ class Logger : public Component { | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   inline 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) { | ||||
|   inline void HOT write_header_to_buffer_(uint8_t level, const char *tag, int line, const char *thread_name, | ||||
|                                           char *buffer, uint16_t *buffer_at, uint16_t buffer_size) { | ||||
|     // Format header | ||||
|     if (level < 0) | ||||
|       level = 0; | ||||
|     // uint8_t level is already bounded 0-255, just ensure it's <= 7 | ||||
|     if (level > 7) | ||||
|       level = 7; | ||||
|  | ||||
| @@ -320,12 +331,12 @@ class Logger : public Component { | ||||
|     this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]: ", color, letter, tag, line); | ||||
|   } | ||||
|  | ||||
|   inline void HOT format_body_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, | ||||
|   inline void HOT format_body_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format, | ||||
|                                          va_list args) { | ||||
|     // Get remaining capacity in the buffer | ||||
|     const int remaining = buffer_size - *buffer_at; | ||||
|     if (remaining <= 0) | ||||
|     if (*buffer_at >= buffer_size) | ||||
|       return; | ||||
|     const uint16_t remaining = buffer_size - *buffer_at; | ||||
|  | ||||
|     const int ret = vsnprintf(buffer + *buffer_at, remaining, format, args); | ||||
|  | ||||
| @@ -334,7 +345,7 @@ class Logger : public Component { | ||||
|     } | ||||
|  | ||||
|     // Update buffer_at with the formatted length (handle truncation) | ||||
|     int formatted_len = (ret >= remaining) ? remaining : ret; | ||||
|     uint16_t formatted_len = (ret >= remaining) ? remaining : ret; | ||||
|     *buffer_at += formatted_len; | ||||
|  | ||||
|     // Remove all trailing newlines right after formatting | ||||
| @@ -343,8 +354,8 @@ class Logger : public Component { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   inline void HOT write_footer_to_buffer_(char *buffer, int *buffer_at, int buffer_size) { | ||||
|     static const int RESET_COLOR_LEN = strlen(ESPHOME_LOG_RESET_COLOR); | ||||
|   inline void HOT write_footer_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) { | ||||
|     static const uint16_t RESET_COLOR_LEN = strlen(ESPHOME_LOG_RESET_COLOR); | ||||
|     this->write_body_to_buffer_(ESPHOME_LOG_RESET_COLOR, RESET_COLOR_LEN, buffer, buffer_at, buffer_size); | ||||
|   } | ||||
|  | ||||
| @@ -370,11 +381,11 @@ class Logger : public Component { | ||||
| }; | ||||
| extern Logger *global_logger;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|  | ||||
| class LoggerMessageTrigger : public Trigger<int, const char *, const char *> { | ||||
| class LoggerMessageTrigger : public Trigger<uint8_t, const char *, const char *> { | ||||
|  public: | ||||
|   explicit LoggerMessageTrigger(Logger *parent, int level) { | ||||
|   explicit LoggerMessageTrigger(Logger *parent, uint8_t level) { | ||||
|     this->level_ = level; | ||||
|     parent->add_on_log_callback([this](int level, const char *tag, const char *message) { | ||||
|     parent->add_on_log_callback([this](uint8_t level, const char *tag, const char *message) { | ||||
|       if (level <= this->level_) { | ||||
|         this->trigger(level, tag, message); | ||||
|       } | ||||
| @@ -382,7 +393,7 @@ class LoggerMessageTrigger : public Trigger<int, const char *, const char *> { | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   int level_; | ||||
|   uint8_t level_; | ||||
| }; | ||||
|  | ||||
| }  // namespace logger | ||||
|   | ||||
| @@ -29,7 +29,7 @@ void HOT esp_log_vprintf_(int level, const char *tag, int line, const char *form | ||||
|   if (log == nullptr) | ||||
|     return; | ||||
|  | ||||
|   log->log_vprintf_(level, tag, line, format, args); | ||||
|   log->log_vprintf_(static_cast<uint8_t>(level), tag, line, format, args); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @@ -41,7 +41,7 @@ void HOT esp_log_vprintf_(int level, const char *tag, int line, const __FlashStr | ||||
|   if (log == nullptr) | ||||
|     return; | ||||
|  | ||||
|   log->log_vprintf_(level, tag, line, format, args); | ||||
|   log->log_vprintf_(static_cast<uint8_t>(level), tag, line, format, args); | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user