Fix handling of partial log lines#290
Merged
jasonopslevel merged 1 commit intomainfrom Apr 22, 2026
Merged
Conversation
271c30f to
acaf2f8
Compare
jasonopslevel
approved these changes
Apr 22, 2026
Contributor
jasonopslevel
left a comment
There was a problem hiding this comment.
tested locally, lgtm!
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.
The k8s stdout/stderr streamer is byte oriented and does not particularly care about newline boundaries. This means that it will sometimes feed us half a line in one payload and then the other half of that line in a subsequent payload. If the timing worked out, the log processor would see a partial line and (due to incomplete error handling) simply discard it, breaking the structure of the logs.
First Part
The most critical part of the change is switching the loops from
to
Basically, instead of looping until all the bytes are consumed, we loop until there are no more newlines in the buffer, thus potentially leaving a partial line in the buffer to be completed later. Because we now know that there must be a newline by the time we call
ReadStringwe can skip its error-handling (from the golang docs:ReadString returns err != nil if and only if the returned data does not end in delim.).Second Part
While working on this Claude pointed out that we were not handling the final line properly in
Flushif it didn't itself end in a newline. Previously we would have just dropped it inRun, but since we were no longer dropping partial lines,Flushwould time out waiting for the buffers to empty.The fix is similar: instead of polling until the buffer is empty, poll until it has no more newlines. Then
Flushitself processes any remaining partial lines as if they were a complete line.Third Part
We ended up with four almost-identical blocks of code to process a log line (for Stdout-vs-Stderr and Flush-vs-Run). Refactored those into a helper method and
logStreamstruct.Changelog
changieentryTophatting