Conversation
…gging A client that stops reading a server-streaming call (Process.Start most visibly) makes the handler return context.Canceled, and the stream interceptor logged that at ERROR with error_code=2 (Unknown) — identical to a real failure. On a short-lived sandbox this is routine: the client got what it needed and moved on, or a sibling task/timeout cancelled it, while the process keeps running to completion on its own context. The noisy line was "Process start (server stream end) error=context canceled error_code=2", which says nothing about why it was cancelled and drowns real errors. Three changes, all observability, no behaviour change: - getErrDebugLogEvent now picks the level by the error: nil->Debug, context.Canceled->Info (client went away, expected), DeadlineExceeded-> Warn, everything else stays Error. Client cancellations stop being logged next to genuine failures. - codeOf maps context.Canceled->CodeCanceled and DeadlineExceeded-> CodeDeadlineExceeded instead of letting connect.CodeOf report them as Unknown(2), so error_code aggregates meaningfully. Used at the three error_code emission sites. - The three <-ctx.Done() branches in process Start now cancel with a cause that names the phase (before start / while streaming / before end) and wraps context.Cause(ctx), so the end log carries why and where rather than a bare "context canceled". Adds interceptor_test.go covering the level classification (incl. wrapped errors) and the code mapping.
AdaAibaby
requested review from
ValentaTomas,
dobrac and
jakubno
as code owners
September 17, 2026 06:35
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.
Problem
When a client stops reading a server-streaming call, the handler returns
context.Canceled, and the stream interceptor logged it at ERROR witherror_code=2(Unknown) — indistinguishable from a genuine failure.Process.Startmakes this routine and noisy. The process runs on its own context (context.Background()-derivedprocCtx), decoupled from the stream, so cancelling the stream does not kill the process — it runs to completion. Yet a client that fires a command and moves on (got its result, timed out, or a sibling task cancelled it) produces:This says nothing about why it was cancelled, and buries real errors at the same level. On short-lived sandboxes it is a constant source of scary-looking-but-benign ERROR lines.
Changes (observability only, no behaviour change)
getErrDebugLogEventpicks the level by the error:nil→Debug,context.Canceled→Info (client went away, expected),context.DeadlineExceeded→Warn, everything else stays Error. Client cancellations stop sitting next to genuine failures.codeOfmaps the context sentinelscontext.Canceled→CodeCanceledandcontext.DeadlineExceeded→CodeDeadlineExceeded, instead of lettingconnect.CodeOfreport them asUnknown(2). Applied at the threeerror_codeemission sites so downstream aggregation is meaningful.The three
<-ctx.Done()branches inprocess.Startnow cancel with a cause that names the phase (before start / while streaming output / before end) and wrapscontext.Cause(ctx), so the "server stream end" line carries where and why the stream ended rather than a barecontext canceled.Testing
internal/logs/interceptor_test.go(new): level classification incl. wrapped errors (fmt.Errorf(... %w, context.Canceled)), and thecodeOfmapping (canceled/deadline/plain/preserved connect code).go build ./...,go vet, fullinternal/logstests, andgolangci-lint(v2, pinned) all clean.Note
This is the server side of the picture. The client SDK is the party that actually knows why it cancelled (request timeout, sibling failure, caller exit, explicit kill); a companion SDK change to log that local cause and correlate via
operation_idwould complete the diagnosis, and can follow separately.