Conversation
multiWriteSyncer.Write documents that it returns the smallest number of
bytes any of its syncers wrote, but the running minimum was reset by the
next syncer whenever it held zero:
if nWritten == 0 && n != 0 {
nWritten = n
} else if n < nWritten {
A syncer that writes nothing -- the usual result of writing to a closed
or full file -- is therefore masked by any later syncer, and Write
reports a complete write.
Seed the minimum from the first syncer instead, so a zero is carried
through like any other value. An empty multiWriteSyncer still returns 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1590 +/- ##
==========================================
+ Coverage 98.85% 98.88% +0.03%
==========================================
Files 53 53
Lines 3047 3045 -2
==========================================
- Hits 3012 3011 -1
+ Misses 35 34 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A
WriteSyncerbuilt from several sinks reports a full write even when one ofthe sinks wrote nothing.
Writing to a closed or full file returns
(0, err), which is the normalshort-write signal.
multiWriteSyncerdrops it:ncomes back as the countfrom whichever sink happened to be listed later. Callers that use the syncer as
the plain
io.Writerit embeds —io.Copy,fmt.Fprint— then account forbytes that were never written.
Cause
Writeis documented directly above its own definition:nWritten == 0is used to mean "nothing recorded yet", but 0 is also alegitimate minimum. Once the running minimum is 0, the first branch matches
again on the next syncer and overwrites it. So a 0 only survives if it comes
from the last syncer:
Fix
Seed the minimum from the first syncer instead of from the zero value, so 0 is
carried through like any other count. An empty
multiWriteSyncerstill returns0, unchanged.
Tests
TestMultiWriteSyncerReturnsSmallestWritecovers the five rows above.Before, on unmodified master:
After, all five pass, and so do the existing tests that pin the current
behaviour —
TestMultiWriteSyncerFailsShortWrite,TestMultiWriteSyncerWritesBoth,TestMultiWriteSyncerFailsWrite,TestNewMultiWriteSyncerWorksForSingleWriter,TestWritestoAllSyncs_EvenIfFirstErrorsand the threeTestMultiWriteSyncerSync_*tests.Benchmarks
Writeis on the logging hot path when more than one output is configured, soI benchmarked three no-op syncers writing 128 bytes, before and after,
interleaved over two rounds (
-benchtime=1s -count=6, three fastest ns/op perrun):
The ordering flips between rounds, so there is no measurable difference on this
machine — as expected, since the change swaps two comparisons for one. Both
versions are 0 B/op, 0 allocs/op.
Verification
go test ./...produces the same set of failures before and after:TestConfig,TestConfigWithSamplingHook,TestOpen,TestOpenOtherErrors,TestStacktraceFiltersVendorZapandzapcore.TestIOCore. All are pre-existingand Windows-only on this machine (
t.TempDir()cleanup cannot delete a file zapstill holds open; the stacktrace test needs symlink privileges) and fail
identically on an unmodified checkout.
🤖 Generated with Claude Code