[OPINION] Almost all community drivers and apps don't implement logs properly, wasting hub's CPU and Memory

Guilty as charged.

ChatGPT's take for thought....

Yes, you’re exactly right — Option 1 favors readability and developer convenience, while Option 2 avoids unnecessary work when logging is disabled, especially if constructing the log message involves costly operations (like method calls or string interpolations).

:white_check_mark: Option 3: Lazy Evaluation with Closure

You can strike a better balance using closures (lambdas) for lazy evaluation:

void logDebug(Closure msg) {
    if (logEnable) {
        log.debug "${device.displayName} ${msg()}"
    }
}

Then you call it like this:

logDebug { "current state.deviceProfile=${state.deviceProfile}, settings.forcedProfile=${settings?.forcedProfile}, getProfileKey()=${getProfileKey(settings?.forcedProfile)}" }

:white_check_mark: Benefits of Option 3

  • Performance: The string interpolation and method calls in the closure are only evaluated if logEnable is true.
  • Developer-friendly: It preserves the readability of Option 1, without needing to wrap every log call in a conditional.
  • No performance hit: Behaves like Option 2 when logging is off, because the closure isn’t invoked.

:white_check_mark: Optional Variant: Support Both String and Closure

You can even make logDebug more flexible by supporting both a String and a Closure:

void logDebug(Object msg) {
    if (logEnable) {
        def text = (msg instanceof Closure) ? msg() : msg
        log.debug "${device.displayName} ${text}"
    }
}

Then you can call it either way:

logDebug "This is a simple message"
logDebug { "Complex message with ${expensiveCall()}" }

This is a clean, idiomatic Groovy solution with minimal trade-offs.

4 Likes