Skip to content

[pull] main from livekit:main - #481

Merged
pull[bot] merged 1 commit into
erickirt:mainfrom
livekit:main
Sep 10, 2026
Merged

[pull] main from livekit:main#481
pull[bot] merged 1 commit into
erickirt:mainfrom
livekit:main

Conversation

@pull

@pull pull Bot commented Sep 10, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

* logger/zaputil: replay deferred writes through Check

Deferrer.write and Deferrer.flush called the wrapped core's Write directly,
bypassing Check. zapcore.multiCore.Write fans out to every child
unconditionally, so a destination that filters in Check rather than in Write
received entries it never enabled. encoderCore was immune because it re-checks
each out's level inside Write; nothing else is, including zaptest/observer.

testCore now registers itself in Check. It overrides Write but not Check, so
its Write only ever ran because the deferred path skipped Check.

* logger: replace WithTap with WithTee

WithTap took a WriteSyncer, so a tap could only ever receive bytes encoded by
a zaputil-chosen encoder: Encoder.Core took two destinations and
DevelopmentEncoder carried a second JSON encoder that existed only to format
tap output. WithTee hands the duplicate stream a zapcore.Core instead, which
brings its own encoder and sees the structured entry.

A Tee builds its core from the derived logger's resolved enabler, so it shares
the console's level rather than widening what the logger emits, and the
component leveler no longer has to OR a tap's level in. Fields do not arrive on
their own: WithValues bakes them into the encoder and replaces the whole core,
and the sugared path never calls Core.With, so a Tee accumulates them itself.

Benchmarks cover objects allocated per WithValues and WithDeferredValues, with
and without a tee.

* logger/zaputil: replace encoderCore with zapcore.NewCore

With one destination per core, encoderCore is zapcore.ioCore plus a
per-destination level re-check on write, and that check became redundant once
the deferred path started replaying through Check.

* logger/zaputil: drop the Encoder type parameter

Encoder was generic because WithValues returned a concrete type, and there were
two concrete types because DevelopmentEncoder needed a second encoder for the
tap. Both are now one encoder and one destination, so the interface and its two
implementations collapse into a struct with two constructors, and zapLogger,
newZapLogger and zapLoggerComponentLeveler stop being generic.

* logger: make the component leveler replaceable per branch

Component levels resolved through one process-global sharedConfig, so the only
per-tenant knob was WithMinLevel: a flat floor that also bypassed the
write-enabler cache and allocated a WriteEnabler on every derivation.

zaputil.ComponentLeveler now owns both the per-component level and the
write-enabler cache, and WithComponentLeveler attaches one to a branch of the
logger tree. A derived leveler can only widen its parent, which is what lets a
global config change reach every branch without the root holding references to
its children.

Replaces WithMinLevel.

* changeset: cover WithComponentLeveler

* logger: tighten the tee comments
@pull pull Bot locked and limited conversation to collaborators Sep 10, 2026
@pull pull Bot added the ⤵️ pull label Sep 10, 2026
@pull
pull Bot merged commit 271d9cd into erickirt:main Sep 10, 2026
1 check was pending
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant