Skip to content

Record HTTP status code on blob-hydration failure telemetry - #2085

Merged
tyrielv merged 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/blob-hydration-telemetry
Aug 14, 2026
Merged

Record HTTP status code on blob-hydration failure telemetry#2085
tyrielv merged 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/blob-hydration-telemetry

Conversation

@tyrielv

@tyrielv tyrielv commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Problem

When an on-demand loose-blob download fails, GVFS emits a terminal telemetry error TryCopyBlobContentStream: Failed to provide blob contents tagged with a BlobHydrationFailureCategory. The DownloadFailed category is the transient/unclassified bucket, so it collapses both genuine auth failures (HTTP 401/400/302) and transient failures (timeout 408, 5xx, connection-pool-exhaustion 503) into one value.

The HTTP status of the failing download is already known inside the code, but it is only written to the on-box GVFS log (an Informational event that is not shipped). It never reaches shipped telemetry. As a result, you cannot tell from telemetry whether blob failures were real 401s or transient failures.

Change

Carry the HTTP status of the last download attempt through to the point where the terminal failure telemetry is emitted, and add it to that event's metadata:

  • A new internal DownloadAttemptResult type carries both the existing DownloadAndSaveObjectResult outcome and the HttpStatusCode? of the last attempt.
  • DoDownloadAndSaveObject and the private coalescing TryDownloadAndSaveObject now return the richer type; the inflightDownloads coalescing dictionary holds Lazy<DownloadAttemptResult>.
  • The public DownloadAndSaveObjectResult TryDownloadAndSaveObject(...) overload is unchanged, so callers in InProcessMount and GVFSVerb are unaffected.
  • The terminal-failure OnFailure handler adds HttpStatusCode (int) and HttpStatusName (string) to the event metadata only when the failure is attributable to the download itself (category DownloadFailed or ObjectNotOnServer). On the exception (LocalIO/NetworkUnavailable) and LocalCopyFailed paths the status is suppressed, so an earlier attempt's status cannot attach to a later, differently-caused terminal event. When no HTTP response was received (exhausted-retry exception, or a failure carrying no status), no status keys are emitted. Existing BlobHydrationFailureCategory bucketing is preserved and the new keys are purely additive.

No credential/auth logic, HttpRequestor, or RetryWrapper behavior changes.

Tests

GVFSGitObjectsTests (23/23 pass):

  • 401 (auth): a download failing with Unauthorized produces a terminal event containing "HttpStatusCode":401 / "HttpStatusName":"Unauthorized", still bucketed DownloadFailed.
  • 503 (transient): a download failing with ServiceUnavailable produces "HttpStatusCode":503 / "HttpStatusName":"ServiceUnavailable" — directly exercising the auth-vs-transient split.
  • No status: a download that fails without an HTTP response emits no HttpStatusCode/HttpStatusName keys (guards against ever emitting "HttpStatusCode":0).

When an on-demand loose-blob download fails, GVFS emits a terminal
telemetry error with a BlobHydrationFailureCategory. The DownloadFailed
category is the transient or unclassified bucket. It collapses genuine
auth failures (401, 400, 302) and transient failures (timeout 408, 5xx,
pool-exhaustion 503) into one value.

The HTTP status of the failing download is known in the code, but it
only reaches the on-box log, not shipped telemetry. So telemetry cannot
tell a real auth failure apart from a transient one.

Carry the HTTP status of the last download attempt to the terminal
failure event through an internal DownloadAttemptResult type. Add
HttpStatusCode and HttpStatusName to the event metadata only when the
failure is attributable to the download itself (DownloadFailed or
ObjectNotOnServer), so an earlier attempt's status cannot attach to a
later local-IO or copy failure. The public TryDownloadAndSaveObject
return type does not change.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv
tyrielv force-pushed the tyrielv/blob-hydration-telemetry branch from a90a1d0 to 64b0dbe Compare August 13, 2026 17:08
@tyrielv
tyrielv marked this pull request as ready for review August 13, 2026 20:49
@tyrielv
tyrielv enabled auto-merge August 13, 2026 20:50
@tyrielv
tyrielv merged commit a5327b7 into microsoft:master Aug 14, 2026
35 checks passed
@tyrielv tyrielv mentioned this pull request Aug 14, 2026
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.

2 participants