Skip to content

BP-69: Allow caller to pass a parent slog Logger to created/opened ledgers#4766

Open
merlimat wants to merge 1 commit intoapache:masterfrom
merlimat:bp-69-client-logger-ctx
Open

BP-69: Allow caller to pass a parent slog Logger to created/opened ledgers#4766
merlimat wants to merge 1 commit intoapache:masterfrom
merlimat:bp-69-client-logger-ctx

Conversation

@merlimat
Copy link
Copy Markdown
Contributor

Summary

Add withLoggerContext(Logger parentLogger) to CreateBuilder and OpenBuilder so an application that already has a per-request / per-tenant slog Logger can pass it as the parent of the per-handle Logger that bookkeeper builds. The LedgerHandle's logger inherits the parent's context via slog's LoggerBuilder.ctx(Logger), then layers on the always-present ledgerId.

// Application's per-request logger, built once at the top of a request.
Logger requestLog = Logger.get(MyService.class).with()
        .attr("requestId", requestId)
        .attr("tenant", tenantId)
        .build();

WriteHandle writer = bk.newCreateLedgerOp()
        .withEnsembleSize(3).withWriteQuorumSize(3).withAckQuorumSize(2)
        .withPassword(pw)
        .withLoggerContext(requestLog)   // ← new
        .execute().get();

// Every log statement emitted by the writer (and the create-time machinery
// that produced it) now carries requestId, tenant, and ledgerId.

Passing a Logger (vs. a Map<String, Object>) avoids the need to extract / serialize attrs out of slog: the application's Logger is the natural source of context.

Implementation

  • New default no-op method on the @Public / @Unstable CreateBuilder and OpenBuilder interfaces — preserves source compatibility for any out-of-tree implementor.
  • CreateBuilderImpl and OpenBuilderBase store the parent Logger and pass it through to LedgerCreateOp / LedgerOpenOp, which forward it to the LedgerHandle / LedgerHandleAdv / ReadOnlyLedgerHandle constructor.
  • New constructor overloads on the three handle types take a Logger parentLogger; existing constructors delegate with null.
  • LedgerOpenOp's own contextual log is built with the same parent so log events emitted during the open path also carry the attrs.

Test plan

New LoggerContextTest covers:

  • Compile-time API contract: withLoggerContext(Logger) on both builders is chainable and returns the same builder type.

  • Runtime: passing null is a no-op; non-null context map executes cleanly through to WriteHandle.getId().

  • Open-on-non-existent-ledger end-to-end test under a log4j2 capturing appender.

  • Deterministic unit test of the slog LoggerBuilder.ctx(parent).attr("ledgerId", ...).build() chain — verifies the parent's attrs and ledgerId both appear in event.getContextData() on the resulting Logger.

  • mvn -pl bookkeeper-server compile checkstyle:check clean

  • LoggerContextTest (5 tests) pass locally

  • Existing BookKeeperBuildersTest / BookKeeperBuildersOpenLedgerTest (33 tests) unaffected

  • Full CI matrix green

…dgers

Add CreateBuilder.withLoggerContext(io.github.merlimat.slog.Logger) and
OpenBuilder.withLoggerContext(io.github.merlimat.slog.Logger) so an
application that already has a per-request / per-tenant slog Logger can
pass it as the parent of the per-handle Logger that bookkeeper builds.
The LedgerHandle's logger inherits the parent's context via slog's
LoggerBuilder.ctx(Logger), then layers on the always-present `ledgerId`.

Passing a Logger (vs. a Map<String, Object>) avoids the need to
extract/serialize attrs out of slog: the application's Logger is
typically the natural source of context already.

Implementation:
- New default no-op method on the @Public/@unstable CreateBuilder /
  OpenBuilder interfaces to keep source compatibility for any
  out-of-tree implementor.
- CreateBuilderImpl, OpenBuilderBase store the parent Logger and pass
  it through to LedgerCreateOp / LedgerOpenOp, which forward it to
  LedgerHandle / LedgerHandleAdv / ReadOnlyLedgerHandle constructor.
- New constructor overloads on the three handle types take a
  parentLogger; existing constructors delegate with null.
- LedgerOpenOp's own contextual log is built with the same parent so
  log events emitted during the open path also carry the attrs.

Tests: new LoggerContextTest covers compile-time API contract
(chainable, accepts a Logger), runtime happy-path (null is no-op,
non-null context map executes cleanly), and a deterministic check via
a log4j2 capturing appender that the parent's attrs flow into the
event's ContextData on the resulting handle's Logger via the
LoggerBuilder.ctx(Logger) hook.
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.

1 participant