This commit is contained in:
Tomasz Duda
2026-02-11 12:54:35 +01:00
parent eee83b0edf
commit 054716fa51
6 changed files with 16 additions and 21 deletions
+1 -1
View File
@@ -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:
+8 -13
View File
@@ -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<uint16_t>(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
+1 -1
View File
@@ -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,
@@ -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
@@ -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)
@@ -5,3 +5,4 @@ esphome:
logger:
level: DEBUG
task_log_buffer_size: 0