Skip to content

feat(logger): make the tag's mutability a compile-time option (off on ESP-IDF) - #882

Merged
finger563 merged 5 commits into
mainfrom
feat/logger-immutable-tag
Nov 5, 2026
Merged

finger563 merged 5 commits into
mainfrom
feat/logger-immutable-tag

Conversation

@finger563

Copy link
Copy Markdown
Contributor

Description

On ESP-IDF every std::mutex allocates its FreeRTOS semaphore when it is constructed. That is about 116 B of internal RAM (a new std::mutex measured 140 B with heap overhead). Every espp::Logger has one, to guard its tag against set_tag(), and every espp component has a Logger. Almost nothing changes a tag after construction: in this repo only RtspSession and PersistentData did, both from their constructors.

This PR makes the tag's mutability a compile-time option:

  • New Kconfig option CONFIG_ESPP_LOGGER_MUTABLE_TAG (menuconfig: ESPP Logger → Mutable tag), default n.
    • Off: the Logger has no mutex, and the log calls lock nothing. Logger::set_tag() and BaseComponent::set_log_tag() become templates that fail to compile with a static_assert naming the option, so existing users see what to turn on to keep building.
    • On: behaves as before.
  • Host / Python builds keep the mutable tag by default, since the Python bindings expose set_log_tag(). Defining ESPP_LOGGER_MUTABLE_TAG to 0 or 1 overrides that.
  • RtspSession and PersistentData now set their tags in the constructor. RtspSession delegates to a new constructor that takes the session ID, because the tag is set before the members are. generate_session_id() is now static, since it uses no members.
  • With the option off, copy and move assignment of a Logger still replace the tag. They are not thread-safe against another thread logging through the same Logger, just like assigning any other object.

Measured

M5Stack Tab5 example on ESP-IDF 6.1, internal RAM free at the same point, with main's Logger vs this branch's:

Point main this PR Difference
before initialize_audio() 287,315 289,743 +2,428
after initialize_audio() 222,999 225,879 +2,880

Possible follow-up

A seqlock-guarded fixed-size tag would allow a mutable tag without a mutex. It would have compile-time options for the tag length, and perhaps std::array vs std::string storage.

Testing

  • Default (tag immutable): the logger, persistent_data and rtsp examples build with no warnings (esp32s3, ESP-IDF 6.1).
  • set_tag() with the option off: fails with static assertion failed: Logger::set_tag() needs CONFIG_ESPP_LOGGER_MUTABLE_TAG (menuconfig: ESPP Logger -> Mutable tag); or set the tag in the Logger's Config.
  • set_tag() with CONFIG_ESPP_LOGGER_MUTABLE_TAG=y: builds.
  • Host build: not run locally (the Mac's SDK is missing). CI's desktop, library, wheel and sanitizer jobs cover it, and the host default is the mutable tag, as before.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SFCMzomCZ5wRHJN4sxwkvY

… ESP-IDF)

Changing a Logger's tag after construction needs a mutex, and on ESP-IDF
every std::mutex allocates its FreeRTOS semaphore: about 116 B of
internal RAM for every Logger, which every espp component has. Almost
nothing changes the tag after construction, so:

- New Kconfig option CONFIG_ESPP_LOGGER_MUTABLE_TAG (default n). With it
  off the Logger has no mutex, and Logger::set_tag() /
  BaseComponent::set_log_tag() fail to compile with a message naming the
  option, so existing users can turn it on and keep building.
- Host / python builds keep the mutable tag (the python bindings expose
  set_log_tag()); define ESPP_LOGGER_MUTABLE_TAG to 0 / 1 to choose.
- RtspSession and PersistentData set their tags in the constructor
  instead of with set_tag() / set_log_tag().

M5Stack Tab5 example: about 2.9 KB more internal RAM free after
initialize_audio().

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFCMzomCZ5wRHJN4sxwkvY
Copilot AI balanced review requested due to automatic review settings November 4, 2026 17:04
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

✅Static analysis result - no issues found! ✅

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

No open issues 🎉

What changed in this PR

This PR makes Logger tag mutability a compile-time option (off by default on ESP-IDF) to eliminate per-Logger mutex RAM overhead, and updates components that previously changed tags post-construction to set tags during construction instead.

Changes:

  • Add CONFIG_ESPP_LOGGER_MUTABLE_TAG Kconfig option to control whether tags can change after construction.
  • Update Logger/BaseComponent to compile-time enable/disable set_tag() / set_log_tag() (with static_assert when disabled), and remove tag mutex usage when disabled.
  • Update RtspSession and PersistentData to include additional context in the constructor tag rather than calling set_tag() later.
File Description
components/​rtsp/​src/​rtsp_session.cpp Set RTSP session logger tag during base construction via a delegating constructor.
components/​rtsp/​include/​rtsp_session.hpp Add protected ctor for injected session id; make generate_session_id() static.
components/​persistent_data/​include/​persistent_data.hpp Bake file name into the logger tag at construction time (no runtime tag mutation).
components/​logger/​include/​logger.hpp Add compile-time mutable-tag switch and remove tag mutex/locking when disabled.
components/​logger/​Kconfig Add ESPP_LOGGER_MUTABLE_TAG Kconfig option (default off).
components/​base_component/​include/​base_component.hpp Gate set_log_tag() behind the mutable-tag option with a clear compile-time failure when disabled.

Review effort: Lite

- iperf_menu example: add base_component to EXTRA_COMPONENT_DIRS. Without
  it the component manager pulls the published espp/base_component, whose
  set_log_tag() calls Logger::set_tag(), which the local logger now rejects
  when CONFIG_ESPP_LOGGER_MUTABLE_TAG is off.
- motorgo-mini: default_motor{1,2}_config copied motor{1,2}_driver_ and
  encoder{1,2}_, members declared (so constructed) after it - copying
  shared_ptrs that do not exist yet. init_motor_channel_{1,2}() always set
  both, so the defaults now hold nullptr. GCC 15 reports it
  (-Werror=uninitialized) since the Logger change alters inlining of the
  MotorGoMini constructor, failing the bldc_motor, bldc_haptics and
  motorgo-mini examples.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFCMzomCZ5wRHJN4sxwkvY

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

2 open issues

Review effort: Lite

Comment thread components/logger/include/logger.hpp Resolved
…ds guard

It sat inside #if !defined(ESPP_LOGGER_CURSOR_COMMANDS_ENABLED), so a build
that defines ESPP_LOGGER_CURSOR_COMMANDS_ENABLED itself left it undefined -
which the #if checks read as 0, silently making the tag immutable.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFCMzomCZ5wRHJN4sxwkvY
@finger563
finger563 requested a balanced review from Copilot November 4, 2026 22:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

2 open issues
2 resolved since last review

Review effort: Lite

Comment thread components/logger/include/logger.hpp Resolved
@finger563
finger563 merged commit 927a6fa into main Nov 5, 2026
180 checks passed
@finger563
finger563 deleted the feat/logger-immutable-tag branch November 5, 2026 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants