Add per-request image count to logs and metrics - #201
Merged
Conversation
Gatekeeper sends all of a pod's images in a single external-data request. Capture that count so we can (1) analyze the distribution of images per request and (2) trace a failed image fetch back to whether it was a solo or a large multi-image request. - metrics: add aaop_attestations_request_images histogram, observed once per request. - provider: generate a per-request request_id and thread request_id/image_count/image_index through the per-image log lines via slog.With, so a single failure line (e.g. a canceled/timeout fetch) self-describes its request context. - promote github.com/google/uuid to a direct dependency. - add tests and document the metric and log fields in the README. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1b5c800-5c7c-466d-83f4-c1aaa75967e5
Contributor
There was a problem hiding this comment.
Pull request overview
Adds per-request image-count observability for validation and timeout troubleshooting.
Changes:
- Adds an image-count histogram.
- Correlates request and per-image logs using UUIDs and image indexes.
- Adds tests and documentation for the new telemetry.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents metrics and log fields. |
go.mod |
Promotes the UUID dependency. |
pkg/metrics/prom.go |
Defines the image-count histogram. |
pkg/provider/provider.go |
Records metrics and structured request context. |
pkg/provider/provider_test.go |
Tests histogram and log correlation behavior. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Balanced
- Promote github.com/prometheus/client_model to a direct dependency; the test imports it directly for the DTO type, so it should not be marked indirect (go mod tidy would otherwise rewrite go.mod). - Assert the per-image failure line's image_index is exactly 2 (the second image) instead of merely non-nil, covering the 1-based position semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c1b5c800-5c7c-466d-83f4-c1aaa75967e5
bdehamer
marked this pull request as ready for review
August 19, 2026 15:28
piceri
approved these changes
Aug 19, 2026
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.
Summary
When Gatekeeper's admission controller validates a pod, it sends all of the pod's image references in a single external-data request. Today we have no visibility into how many images ride along in each request. This PR captures that count to support two goals:
canceled/timeout(context_cancelled), trace that specific failure back to determine whether it was a solo validation or one image in a larger, multi-image request that ran out of time.The provider processes images sequentially in one loop that shares the request context/deadline, so later images in a big request are the ones most likely to time out — which is exactly the pattern these fields surface.
Changes
pkg/metrics/prom.go— new histogramaaop_attestations_request_images(buckets1, 2, 3, 5, 10, 20, 50), observed once per request. A histogram (not a counter or a label) is the right tool: it yields the distribution (_bucket{le="1"} / _countfor the single-image fraction,histogram_quantilefor percentiles,_sum/_countfor the average) without exploding metric label cardinality.pkg/provider/provider.go— inValidate, generate a per-requestrequest_id(UUID) and threadrequest_id+image_count+image_indexthrough the per-image log lines viaslog.With. Every per-image line (success and failure) now self-describes its request context, so a singlereason="canceled"/"timeout"line reads e.g.image_count=17, image_index=14→ "image 14 of a 17-image request ran out of time."go.mod— promotegithub.com/google/uuidfrom an indirect to a direct dependency (already in the module graph).pkg/provider/provider_test.go— a histogram test (_count+1,_sum+N) and a log-correlation test asserting a failure line'srequest_idmatches the request entry line and carriesimage_count/image_index.README.md— document the new metric and log fields.Pure observability — no change to the provider's request/response contract or verification behavior.
Example log line after this change
{"level":"ERROR","msg":"validate: error fetching bundles","request_id":"…", "image_count":17,"image_index":14,"image":"…","reason":"canceled",…}Validation
go build ./...go test ./...(all packages pass)golangci-lint runon changed packages — cleanNotes / trade-offs