Skip to content

perf: use slf4j placeholders instead of string interpolation in logging - #3537

Merged
pjfanning merged 1 commit into
apache:mainfrom
pjfanning:slf4j-lazy-logging
Sep 11, 2026
Merged

pjfanning merged 1 commit into
apache:mainfrom
pjfanning:slf4j-lazy-logging

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Motivation

Several slf4j log calls in main sources built their message with Scala string interpolation, so the message was formatted eagerly even when the level was disabled. A few others carried an s prefix on a literal with no interpolation at all, which is misleading next to the {} placeholders in the same string.

Modification

  • Replaced interpolated log messages with slf4j {} placeholders and lazily formatted arguments in persistence-typed BehaviorSetup (both the event-sourced and durable-state variants), EventSourcedBehaviorImpl, and the testkit LogCapturing / LogCapturingExtension rules.
  • Dropped the redundant s prefix from log literals that contain no interpolation in Running and RequestingRecoveryPermit (both variants).
  • BehaviorSetup.onSignal now passes the signal as a placeholder argument and keeps the throwable as the trailing slf4j argument, so the stack trace is still logged without rendering the exception into the message eagerly.

Result

Log message rendering is deferred to the logging backend and only happens when the level is enabled. Rendered output is unchanged apart from onSignal, where the exception toString is no longer duplicated in the message text; it remains available via the logged throwable.

Tests

  • sbt "actor-testkit-typed/compile" "persistence-typed/compile" - pass
  • scalafmt on changed files - pass
  • No behaviour change beyond log formatting; existing EventSourcedBehaviorLoggingSpec assertions on "Handled command" cover the unchanged message text. Full test run left to CI.

References

None - internal logging cleanup

Motivation:
Several slf4j log calls in main sources built their message with Scala
string interpolation, so the message was formatted eagerly even when the
level was disabled. A few others carried an `s` prefix on a literal that
had no interpolation at all, which is misleading next to the `{}`
placeholders in the same string.

Modification:
- Replaced interpolated log messages with slf4j `{}` placeholders and
  lazily formatted arguments in persistence-typed `BehaviorSetup` (both
  the event-sourced and durable-state variants),
  `EventSourcedBehaviorImpl`, and the testkit `LogCapturing` /
  `LogCapturingExtension` rules.
- Dropped the redundant `s` prefix from log literals that contain no
  interpolation in `Running` and `RequestingRecoveryPermit` (both
  variants).
- `BehaviorSetup.onSignal` now passes the signal as a placeholder
  argument and keeps the throwable as the trailing slf4j argument, so
  the stack trace is still logged without rendering the exception into
  the message eagerly.

Result:
Log message rendering is deferred to the logging backend and only
happens when the level is enabled. Rendered output is unchanged apart
from `onSignal`, where the exception `toString` is no longer duplicated
in the message text; it remains available via the logged throwable.

Tests:
- sbt "actor-testkit-typed/compile" "persistence-typed/compile" - pass
- scalafmt on changed files - pass
- No behavior change beyond log formatting; covered by existing
  EventSourcedBehaviorLoggingSpec assertions on "Handled command"

References:
None - internal logging cleanup
@pjfanning
pjfanning merged commit b765c5b into apache:main Sep 11, 2026
10 checks passed
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