diff --git a/README.md b/README.md index 5e02ace..350861f 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ DFTE is a lightweight C++ template engine tailored for Arduino-class hardware (E - `isComplete(const TemplateContext&)`, `hasError(const TemplateContext&)` – convenience checks. - `DeviceFrameworkTemplateEngineDebug` - - Optional logging interface; create a `DeviceFrameworkTemplateEngineLogger` subclass and call `deviceFrameworkTemplateEngineEnableLogging(&logger)`. + - Optional logging interface; create a `DeviceFrameworkTemplateEngineLogger` subclass and call `deviceFrameworkTemplateEngineEnableLogging(&logger)` (or the two-argument overload with an owner tag, e.g. `this`, for `deviceFrameworkTemplateEngineDisableLoggingForOwner`). All public headers are re-exported from `TemplateEngine.h`, so typical sketches only include that file. @@ -313,11 +313,11 @@ SerialLogger logger; void setup() { Serial.begin(115200); - deviceFrameworkTemplateEngineEnableLogging(&logger); + deviceFrameworkTemplateEngineEnableLogging(&logger, static_cast(&logger)); } ``` -Use `deviceFrameworkTemplateEngineDisableLogging()` to silence output or `deviceFrameworkTemplateEngineIsLoggingEnabled()` to inspect the current state. +Use `deviceFrameworkTemplateEngineDisableLogging()` to silence output, `deviceFrameworkTemplateEngineDisableLoggingForOwner(tag)` to tear down only the registration made with that owner (for example WiFiManager’s server instance), or `deviceFrameworkTemplateEngineIsLoggingEnabled()` to inspect the current state. ## License diff --git a/include/DeviceFrameworkTemplateEngineDebug.h b/include/DeviceFrameworkTemplateEngineDebug.h index 23553b9..dd378fa 100644 --- a/include/DeviceFrameworkTemplateEngineDebug.h +++ b/include/DeviceFrameworkTemplateEngineDebug.h @@ -41,6 +41,9 @@ public: // Global logger pointer - set by user or defaults to nullptr (disabled) extern DeviceFrameworkTemplateEngineLogger* deviceFrameworkTemplateEngineLogger; +/** Opaque owner tag for the active logger (set on enable). Used to disable without clobbering another host. */ +extern const void* deviceFrameworkTemplateEngineLoggerOwner; + // ============================================================================ // LOGGING MACROS - NO-OPS BY DEFAULT // ============================================================================ @@ -86,6 +89,13 @@ extern DeviceFrameworkTemplateEngineLogger* deviceFrameworkTemplateEngineLogger; } \ } while(0) +/** Optional verbose trace (compile with -DDFTE_ENABLE_TRACE). Maps to debug() on the active logger. */ +#if defined(DFTE_ENABLE_TRACE) +#define DFTE_LOG_TRACE(msg) DFTE_LOG_DEBUG(String(F("[TRACE] ")) + String(msg)) +#else +#define DFTE_LOG_TRACE(msg) do { (void)0; } while(0) +#endif + // ============================================================================ // LOGGING CONFIGURATION FUNCTIONS // ============================================================================ @@ -98,12 +108,21 @@ extern DeviceFrameworkTemplateEngineLogger* deviceFrameworkTemplateEngineLogger; */ bool deviceFrameworkTemplateEngineEnableLogging(DeviceFrameworkTemplateEngineLogger* logger); +/** + * Enable logging and record an owner tag (e.g. `this` of WiFiManagerServer). + * If ownerTag is nullptr, the logger pointer is used as the tag. + */ +bool deviceFrameworkTemplateEngineEnableLogging(DeviceFrameworkTemplateEngineLogger* logger, const void* ownerTag); + /** * Disable all logging * Sets logger to nullptr, making all DFTE_LOG_* macros no-ops */ void deviceFrameworkTemplateEngineDisableLogging(); +/** Disable only if the current logger was registered with this owner tag. Returns true if disabled. */ +bool deviceFrameworkTemplateEngineDisableLoggingForOwner(const void* ownerTag); + /** * Check if logging is currently enabled * @@ -118,4 +137,6 @@ bool deviceFrameworkTemplateEngineIsLoggingEnabled(); */ DeviceFrameworkTemplateEngineLogger* deviceFrameworkTemplateEngineGetLogger(); +const void* deviceFrameworkTemplateEngineGetLoggerOwner(); + #endif // DEVICEFRAMEWORK_TEMPLATE_ENGINE_DEBUG_H \ No newline at end of file diff --git a/src/DeviceFrameworkTemplateEngineDebug.cpp b/src/DeviceFrameworkTemplateEngineDebug.cpp index 8a413ad..44dcc13 100644 --- a/src/DeviceFrameworkTemplateEngineDebug.cpp +++ b/src/DeviceFrameworkTemplateEngineDebug.cpp @@ -2,21 +2,39 @@ // Global logger pointer - starts as nullptr (disabled by default) DeviceFrameworkTemplateEngineLogger* deviceFrameworkTemplateEngineLogger = nullptr; +const void* deviceFrameworkTemplateEngineLoggerOwner = nullptr; // ============================================================================ // LOGGING CONFIGURATION IMPLEMENTATIONS // ============================================================================ bool deviceFrameworkTemplateEngineEnableLogging(DeviceFrameworkTemplateEngineLogger* logger) { + return deviceFrameworkTemplateEngineEnableLogging(logger, nullptr); +} + +bool deviceFrameworkTemplateEngineEnableLogging(DeviceFrameworkTemplateEngineLogger* logger, const void* ownerTag) { if (logger == nullptr) { return false; } deviceFrameworkTemplateEngineLogger = logger; + deviceFrameworkTemplateEngineLoggerOwner = ownerTag ? ownerTag : static_cast(logger); return true; } void deviceFrameworkTemplateEngineDisableLogging() { deviceFrameworkTemplateEngineLogger = nullptr; + deviceFrameworkTemplateEngineLoggerOwner = nullptr; +} + +bool deviceFrameworkTemplateEngineDisableLoggingForOwner(const void* ownerTag) { + if (deviceFrameworkTemplateEngineLogger == nullptr || ownerTag == nullptr) { + return false; + } + if (deviceFrameworkTemplateEngineLoggerOwner != ownerTag) { + return false; + } + deviceFrameworkTemplateEngineDisableLogging(); + return true; } bool deviceFrameworkTemplateEngineIsLoggingEnabled() { @@ -25,4 +43,8 @@ bool deviceFrameworkTemplateEngineIsLoggingEnabled() { DeviceFrameworkTemplateEngineLogger* deviceFrameworkTemplateEngineGetLogger() { return deviceFrameworkTemplateEngineLogger; +} + +const void* deviceFrameworkTemplateEngineGetLoggerOwner() { + return deviceFrameworkTemplateEngineLoggerOwner; } \ No newline at end of file diff --git a/src/DeviceFrameworkTemplateRenderer.cpp b/src/DeviceFrameworkTemplateRenderer.cpp index 24cee77..68543e4 100644 --- a/src/DeviceFrameworkTemplateRenderer.cpp +++ b/src/DeviceFrameworkTemplateRenderer.cpp @@ -261,18 +261,24 @@ static DeviceFrameworkTemplateRenderer::RenderOutcome processIteratorContext(Dev } // namespace -// Helper function to convert RenderingContextType to string -static String getContextTypeString(RenderingContextType type) { - switch (type) { - case RenderingContextType::TEMPLATE: return "TEMPLATE"; - case RenderingContextType::PLACEHOLDER_DATA: return "PLACEHOLDER_DATA"; - case RenderingContextType::PLACEHOLDER_TEMPLATE: return "PLACEHOLDER_TEMPLATE"; - default: return "UNKNOWN"; - } -} - // Helper function to log state transitions with stack state static void logStateTransition(DeviceFrameworkTemplateContext& ctx, const String& fromState, const String& toState, const String& reason = "") { +#if !defined(DFTE_ENABLE_TRACE) + (void)ctx; + (void)fromState; + (void)toState; + (void)reason; + return; +#else + auto getContextTypeString = [](RenderingContextType type) -> String { + switch (type) { + case RenderingContextType::TEMPLATE: return "TEMPLATE"; + case RenderingContextType::PLACEHOLDER_DATA: return "PLACEHOLDER_DATA"; + case RenderingContextType::PLACEHOLDER_TEMPLATE: return "PLACEHOLDER_TEMPLATE"; + default: return "UNKNOWN"; + } + }; + if (!deviceFrameworkTemplateEngineLogger) { return; } @@ -287,6 +293,7 @@ static void logStateTransition(DeviceFrameworkTemplateContext& ctx, const String msg += " | Current: " + String(currentCtx->name) + " (type=" + getContextTypeString(currentCtx->type) + ")"; } deviceFrameworkTemplateEngineLogger->debug(msg); +#endif } static String getStateName(TemplateRenderState state) { @@ -887,6 +894,8 @@ void DeviceFrameworkTemplateRenderer::initializeContext(DeviceFrameworkTemplateC ctx.state = TemplateRenderState::TEXT; logStateTransition(ctx, "INIT", "TEXT", "Initialized template context"); + DFTE_LOG_TRACE("initializeContext len=" + String(rootCtx->context.templateCtx.templateLen) + " progmem=" + + String(templateInProgmem ? 1 : 0)); } bool DeviceFrameworkTemplateRenderer::isComplete(const DeviceFrameworkTemplateContext& ctx) {