mirror of
https://github.com/esphome/esphome.git
synced 2026-10-04 18:11:29 +00:00
[log] Detect early log calls before logger init and optimize hot path (#14538)
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
"""Tests for the logger component."""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def test_logger_pre_setup_before_other_components(generate_main):
|
||||
"""Logger::pre_setup() must be called before any other component is created.
|
||||
|
||||
Log functions call global_logger->log_vprintf_() without a null check,
|
||||
so global_logger must be set before anything can log.
|
||||
"""
|
||||
main_cpp = generate_main("tests/component_tests/logger/test_logger.yaml")
|
||||
|
||||
# Find the logger's pre_setup() call specifically
|
||||
logger_pre_setup = re.search(r"logger_logger->pre_setup\(\)", main_cpp)
|
||||
if logger_pre_setup is None:
|
||||
# Fall back to finding any logger-related pre_setup
|
||||
logger_pre_setup = re.search(r"logger\w*->pre_setup\(\)", main_cpp)
|
||||
assert logger_pre_setup is not None, (
|
||||
"Logger pre_setup() not found in generated code"
|
||||
)
|
||||
|
||||
# Find all "new " allocations (component creation)
|
||||
new_allocations = list(re.finditer(r"\bnew [\w:]+", main_cpp))
|
||||
assert len(new_allocations) > 0, "No component allocations found"
|
||||
|
||||
# Separate logger and non-logger allocations
|
||||
logger_allocs = [a for a in new_allocations if "logger" in a.group().lower()]
|
||||
non_logger_allocs = [
|
||||
a
|
||||
for a in new_allocations
|
||||
if "logger" not in a.group().lower()
|
||||
# Skip placement new for App
|
||||
and "(&App)" not in main_cpp[max(0, a.start() - 5) : a.start()]
|
||||
]
|
||||
|
||||
assert len(logger_allocs) > 0, (
|
||||
f"Logger allocation not found in: {[a.group() for a in new_allocations]}"
|
||||
)
|
||||
assert len(non_logger_allocs) > 0, (
|
||||
"No non-logger component allocations found — "
|
||||
"add a component to test_logger.yaml so the ordering check is meaningful"
|
||||
)
|
||||
|
||||
# All non-logger allocations must appear after logger pre_setup()
|
||||
for alloc in non_logger_allocs:
|
||||
assert alloc.start() > logger_pre_setup.start(), (
|
||||
f"Component allocation '{alloc.group()}' at position {alloc.start()} "
|
||||
f"appears before logger pre_setup() at position {logger_pre_setup.start()}"
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp8266:
|
||||
board: d1_mini_lite
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
# Need at least one non-logger component so the ordering test
|
||||
# can verify that logger pre_setup() comes before other allocations.
|
||||
preferences:
|
||||
flash_write_interval: 1min
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "esphome/components/logger/logger.h"
|
||||
|
||||
/*
|
||||
This special main.cpp replaces the default one.
|
||||
It will run all the Google Tests found in all compiled cpp files and then exit with the result
|
||||
@@ -18,6 +20,12 @@ void original_setup() {
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Log functions call global_logger->log_vprintf_() without a null check,
|
||||
// so we must set up a Logger before any test that triggers logging.
|
||||
static esphome::logger::Logger test_logger(0);
|
||||
test_logger.set_log_level(ESPHOME_LOG_LEVEL);
|
||||
test_logger.pre_setup();
|
||||
|
||||
::testing::InitGoogleTest();
|
||||
int exit_code = RUN_ALL_TESTS();
|
||||
exit(exit_code);
|
||||
|
||||
@@ -193,6 +193,7 @@ async def yaml_config(request: pytest.FixtureRequest, unused_tcp_port: int) -> s
|
||||
" platformio_options:\n"
|
||||
" build_flags:\n"
|
||||
' - "-DDEBUG" # Enable assert() statements\n'
|
||||
' - "-DESPHOME_DEBUG" # Enable ESPHOME_DEBUG_ASSERT checks\n'
|
||||
' - "-DESPHOME_DEBUG_API" # Enable API protocol asserts\n'
|
||||
' - "-g" # Add debug symbols',
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user