diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 21e2b4480..474eb9ec3 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -65,8 +65,8 @@ void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const ch 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); - // Add newline if platform needs it (ESP32 doesn't add via write_msg_) - this->add_newline_to_buffer_if_needed_(console_buffer, &buffer_at, MAX_CONSOLE_LOG_MSG_SIZE); + // Add newline before writing to console + this->add_newline_to_buffer_(console_buffer, &buffer_at, MAX_CONSOLE_LOG_MSG_SIZE); this->write_msg_(console_buffer, buffer_at); } diff --git a/esphome/components/logger/logger.h b/esphome/components/logger/logger.h index 2cedd7a76..ba8d4667b 100644 --- a/esphome/components/logger/logger.h +++ b/esphome/components/logger/logger.h @@ -117,17 +117,6 @@ static constexpr uint16_t MAX_HEADER_SIZE = 128; // "0x" + 2 hex digits per byte + '\0' static constexpr size_t MAX_POINTER_REPRESENTATION = 2 + sizeof(void *) * 2 + 1; -// Platform-specific: does write_msg_ add its own newline? -// false: Caller must add newline to buffer before calling write_msg_ (ESP32, ESP8266, RP2040, LibreTiny, Zephyr) -// Allows single write call with newline included for efficiency -// true: write_msg_ adds newline itself via puts()/println() (other platforms) -// Newline should NOT be added to buffer -#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR) -static constexpr bool WRITE_MSG_ADDS_NEWLINE = false; -#else -static constexpr bool WRITE_MSG_ADDS_NEWLINE = true; -#endif - #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR) /** Enum for logging UART selection * @@ -259,22 +248,20 @@ class Logger : public Component { } } - // Helper to add newline to buffer for platforms that need it + // Helper to add newline to buffer before writing to console // Modifies buffer_at to include the newline - inline void HOT add_newline_to_buffer_if_needed_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) { - if constexpr (!WRITE_MSG_ADDS_NEWLINE) { - // Add newline - don't need to maintain null termination - // write_msg_ now always receives explicit length, so we can safely overwrite the null terminator - // This is safe because: - // 1. Callbacks already received the message (before we add newline) - // 2. write_msg_ receives the length explicitly (doesn't need null terminator) - if (*buffer_at < buffer_size) { - buffer[(*buffer_at)++] = '\n'; - } else if (buffer_size > 0) { - // Buffer was full - replace last char with newline to ensure it's visible - buffer[buffer_size - 1] = '\n'; - *buffer_at = buffer_size; - } + inline void HOT add_newline_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) { + // Add newline - don't need to maintain null termination + // write_msg_ receives explicit length, so we can safely overwrite the null terminator + // This is safe because: + // 1. Callbacks already received the message (before we add newline) + // 2. write_msg_ receives the length explicitly (doesn't need null terminator) + if (*buffer_at < buffer_size) { + buffer[(*buffer_at)++] = '\n'; + } else if (buffer_size > 0) { + // Buffer was full - replace last char with newline to ensure it's visible + buffer[buffer_size - 1] = '\n'; + *buffer_at = buffer_size; } } @@ -283,7 +270,7 @@ class Logger : public Component { inline void HOT write_tx_buffer_to_console_(uint16_t offset = 0, uint16_t *length = nullptr) { if (this->baud_rate_ > 0) { uint16_t *len_ptr = length ? length : &this->tx_buffer_at_; - this->add_newline_to_buffer_if_needed_(this->tx_buffer_ + offset, len_ptr, this->tx_buffer_size_ - offset); + this->add_newline_to_buffer_(this->tx_buffer_ + offset, len_ptr, this->tx_buffer_size_ - offset); this->write_msg_(this->tx_buffer_ + offset, *len_ptr); } } diff --git a/esphome/components/logger/logger_host.cpp b/esphome/components/logger/logger_host.cpp index c5e1e6f86..cbca06e43 100644 --- a/esphome/components/logger/logger_host.cpp +++ b/esphome/components/logger/logger_host.cpp @@ -3,16 +3,23 @@ namespace esphome::logger { -void HOT Logger::write_msg_(const char *msg, size_t) { - time_t rawtime; - struct tm *timeinfo; - char buffer[80]; +void HOT Logger::write_msg_(const char *msg, size_t len) { + static constexpr size_t TIMESTAMP_LEN = 10; // "[HH:MM:SS]" + // tx_buffer_size_ defaults to 512, so 768 covers default + headroom + char buffer[TIMESTAMP_LEN + 768]; + time_t rawtime; time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(buffer, sizeof buffer, "[%H:%M:%S]", timeinfo); - fputs(buffer, stdout); - puts(msg); + struct tm *timeinfo = localtime(&rawtime); + size_t pos = strftime(buffer, TIMESTAMP_LEN + 1, "[%H:%M:%S]", timeinfo); + + // Copy message (with newline already included by caller) + size_t copy_len = std::min(len, sizeof(buffer) - pos); + memcpy(buffer + pos, msg, copy_len); + pos += copy_len; + + // Single write for everything + fwrite(buffer, 1, pos, stdout); } void Logger::pre_setup() { global_logger = this; }