From 054716fa5192b6a87048856f3622927c47eab528 Mon Sep 17 00:00:00 2001 From: Tomasz Duda Date: Wed, 11 Feb 2026 12:54:35 +0100 Subject: [PATCH] fix --- esphome/components/logger/__init__.py | 2 +- esphome/components/logger/logger.cpp | 21 +++++++------------ esphome/components/logger/logger.h | 2 +- .../logger/task_log_buffer_zephyr.cpp | 7 +++---- .../logger/task_log_buffer_zephyr.h | 4 ++-- .../logger/test.nrf52-adafruit.yaml | 1 + 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py index 8de52db0cb9..b2952d79956 100644 --- a/esphome/components/logger/__init__.py +++ b/esphome/components/logger/__init__.py @@ -326,7 +326,6 @@ async def to_code(config): cg.add_define("USE_ESPHOME_TASK_LOG_BUFFER") cg.add(log.init_log_buffer(task_log_buffer_size)) if CORE.using_zephyr: - zephyr_add_prj_conf("THREAD_LOCAL_STORAGE", True) zephyr_add_prj_conf("MPSC_PBUF", True) elif CORE.is_host: cg.add(log.create_pthread_key()) @@ -427,6 +426,7 @@ async def to_code(config): pass if CORE.is_nrf52: + zephyr_add_prj_conf("THREAD_LOCAL_STORAGE", True) if config[CONF_HARDWARE_UART] == UART0: zephyr_add_overlay("""&uart0 { status = "okay";};""") if config[CONF_HARDWARE_UART] == UART1: diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index ab7957b3302..74d93daed38 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -10,7 +10,7 @@ namespace esphome::logger { static const char *const TAG = "logger"; -#ifdef USE_ESPHOME_TASK_LOG_BUFFER +#if defined(USE_ESP32) || defined(USE_HOST) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR) // Implementation for multi-threaded platforms (ESP32 with FreeRTOS, Host with pthreads, LibreTiny with FreeRTOS, // Zephyr) Main thread/task always uses direct buffer access for console output and callbacks // @@ -80,6 +80,7 @@ void Logger::log_vprintf_non_main_thread_(uint8_t level, const char *tag, int li auto guard = this->make_non_main_task_guard_(); bool message_sent = false; +#ifdef USE_ESPHOME_TASK_LOG_BUFFER // For non-main threads/tasks, queue the message for callbacks message_sent = this->log_buffer_->send_message_thread_safe(level, tag, static_cast(line), thread_name, format, args); @@ -88,7 +89,7 @@ void Logger::log_vprintf_non_main_thread_(uint8_t level, const char *tag, int li // This is safe to call from any context including ISRs this->enable_loop_soon_any_context(); } - +#endif // Emergency console logging for non-main threads when ring buffer is full or disabled // This is a fallback mechanism to ensure critical log messages are visible // Note: This may cause interleaved/corrupted console output if multiple threads @@ -115,22 +116,16 @@ void Logger::log_vprintf_non_main_thread_(uint8_t level, const char *tag, int li // RAII guard automatically resets on return } #else -// Implementation for single-task platforms (ESP8266, RP2040, Zephyr) -// TODO: Zephyr may have multiple threads (work queues, etc.) but uses this single-task path. +// Implementation for single-task platforms (ESP8266, RP2040) // Logging calls are NOT thread-safe: global_recursion_guard_ is a plain bool and tx_buffer_ has no locking. // Not a problem in practice yet since Zephyr has no API support (logs are console-only). 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; -#ifdef USE_ZEPHYR - char tmp[MAX_POINTER_REPRESENTATION]; - this->log_message_to_buffer_and_send_(global_recursion_guard_, level, tag, line, format, args, - this->get_thread_name_(tmp)); -#else // Other single-task platforms don't have thread names, so pass nullptr + // Other single-task platforms don't have thread names, so pass nullptr this->log_message_to_buffer_and_send_(global_recursion_guard_, level, tag, line, format, args, nullptr); -#endif } -#endif // USE_ESP32 / USE_HOST / USE_LIBRETINY +#endif // USE_ESPHOME_TASK_LOG_BUFFER #ifdef USE_STORE_LOG_STR_IN_FLASH // Implementation for ESP8266 with flash string support. @@ -176,7 +171,7 @@ void Logger::init_log_buffer(size_t total_buffer_size) { this->log_buffer_ = new logger::TaskLogBuffer(total_buffer_size); // Zephyr needs loop working to check when CDC port is open -#if !(defined(USE_ZEPHYR) || defined(USE_LOGGER_USB_CDC)) +#if defined(USE_ESPHOME_TASK_LOG_BUFFER) && !(defined(USE_ZEPHYR) || defined(USE_LOGGER_USB_CDC)) // Start with loop disabled when using task buffer (unless using USB CDC on ESP32) // The loop will be enabled automatically when messages arrive this->disable_loop_when_buffer_empty_(); @@ -210,7 +205,7 @@ void Logger::process_messages_() { } } // Zephyr needs loop working to check when CDC port is open -#if !(defined(USE_ZEPHYR) || defined(USE_LOGGER_USB_CDC)) +#if defined(USE_ESPHOME_TASK_LOG_BUFFER) && !(defined(USE_ZEPHYR) || defined(USE_LOGGER_USB_CDC)) else { // No messages to process, disable loop if appropriate // This reduces overhead when there's no async logging activity diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index aa349a29144..4c50acf2874 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -222,7 +222,7 @@ class Logger : public Component { bool &flag_; }; -#ifdef USE_ESPHOME_TASK_LOG_BUFFER +#if defined(USE_ESP32) || defined(USE_HOST) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR) // Handles non-main thread logging only (~0.1% of calls) // thread_name is resolved by the caller from the task handle, avoiding redundant lookups void log_vprintf_non_main_thread_(uint8_t level, const char *tag, int line, const char *format, va_list args, diff --git a/esphome/components/logger/task_log_buffer_zephyr.cpp b/esphome/components/logger/task_log_buffer_zephyr.cpp index 50b9ca984de..3fc0eabf813 100644 --- a/esphome/components/logger/task_log_buffer_zephyr.cpp +++ b/esphome/components/logger/task_log_buffer_zephyr.cpp @@ -2,12 +2,12 @@ #include "task_log_buffer_zephyr.h" -#ifdef USE_ESPHOME_TASK_LOG_BUFFER - namespace esphome::logger { __thread bool non_main_task_recursion_guard_; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +#ifdef USE_ESPHOME_TASK_LOG_BUFFER + static inline uint32_t total_size_in_32bit_words(uint16_t text_length) { // Calculate total size in 32-bit words needed (header + text length + null terminator + 3(4 bytes alignment) return (sizeof(TaskLogBuffer::LogMessage) + text_length + 1 + 3) / sizeof(uint32_t); @@ -109,7 +109,6 @@ void TaskLogBuffer::release_message_main_loop() { mpsc_pbuf_free(&this->log_buffer_, this->current_token_); this->current_token_ = nullptr; } +#endif } // namespace esphome::logger - -#endif #endif diff --git a/esphome/components/logger/task_log_buffer_zephyr.h b/esphome/components/logger/task_log_buffer_zephyr.h index f5487a1c970..0e82aaf5b7a 100644 --- a/esphome/components/logger/task_log_buffer_zephyr.h +++ b/esphome/components/logger/task_log_buffer_zephyr.h @@ -11,10 +11,10 @@ namespace esphome::logger { // "0x" + 2 hex digits per byte + '\0' static constexpr size_t MAX_POINTER_REPRESENTATION = 2 + sizeof(void *) * 2 + 1; -#ifdef USE_ESPHOME_TASK_LOG_BUFFER - extern __thread bool non_main_task_recursion_guard_; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +#ifdef USE_ESPHOME_TASK_LOG_BUFFER + class TaskLogBuffer { public: // Structure for a log message header (text data follows immediately after) diff --git a/tests/components/logger/test.nrf52-adafruit.yaml b/tests/components/logger/test.nrf52-adafruit.yaml index 70b485daac2..821a1362507 100644 --- a/tests/components/logger/test.nrf52-adafruit.yaml +++ b/tests/components/logger/test.nrf52-adafruit.yaml @@ -5,3 +5,4 @@ esphome: logger: level: DEBUG + task_log_buffer_size: 0