Skip to content

count registry sockets and requests, and export them to otel - #971

Merged
mzihlmann merged 1 commit into
mainfrom
mz961-registry-connection-metrics
Aug 12, 2026
Merged

count registry sockets and requests, and export them to otel#971
mzihlmann merged 1 commit into
mainfrom
mz961-registry-connection-metrics

Conversation

@mzihlmann

@mzihlmann mzihlmann commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Groundwork for #961, no behaviour change to how builds talk to registries.

Kaniko builds a fresh http.Transport for every registry operation, so almost nothing shares a connection pool. The evidence in #961 came from a counting TCP proxy in front of a plaintext local registry, which is a dead end for anything real: a proxy cannot see through TLS, so the numbers cannot be reproduced against the registry a user actually builds against. Before changing the pooling, kaniko should be able to count its own sockets.

Two hooks, because neither sees what the other does. Opens, closes, still-open-at-exit and peak concurrency come from wrapping Transport.DialContext and counting Close() on the conn it hands back, since net/http never reports a socket close to its caller and httptrace has no close hook. Reuse, idle time before reuse and handshake cost come from httptrace.ClientTrace, which the dialer cannot see, because a reuse is precisely a dial that never happened.

A build with KANIKO_TELEMETRY_ENDPOINT set gets ten numbers as attributes on the root span, where the per-build rollup reads them, and the same numbers go to one debug line for anyone without a collector. Five step build against a local registry: 26 sockets carrying 109 requests, 17 of them open at once, 15 still open when the process exits, which is the shape the proxy reported in the issue.

Cost is a ClientTrace and a few atomics per request, plus an atomic per socket. The conn wrapper only overrides Close, so reads and writes stay untouched.

Summary by CodeRabbit

  • New Features

    • Added registry connection and request telemetry, including socket usage, dialing time, connection reuse, idle time, and TLS handshakes.
    • Registry metrics are now captured in build tracing and debug logs.
    • Registry connection details are logged after image pushes, cache warming, and command errors.
  • Documentation

    • Expanded telemetry documentation with registry connection and request attributes.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@mzihlmann, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ebc79f53-6b7b-4aa7-8a67-627db224b972

📥 Commits

Reviewing files that changed from the base of the PR and between 77f4fad and 93b811c.

📒 Files selected for processing (7)
  • cmd/executor/cmd/root.go
  • cmd/warmer/cmd/root.go
  • docs/telemetry.md
  • pkg/connstats/connstats.go
  • pkg/tracing/tracing.go
  • pkg/util/transport_util.go
  • pkg/util/transport_util_test.go
📝 Walkthrough

Walkthrough

Registry transports now collect connection and request metrics. Tracing exports aggregate metrics. Executor and warmer commands log registry statistics on success and error paths. Telemetry documentation lists the new Build span attributes.

Changes

Registry connection telemetry

Layer / File(s) Summary
Connection instrumentation
pkg/connstats/connstats.go
Adds dialer and round-tripper instrumentation for socket lifecycle, requests, TLS handshakes, connection reuse, dialing, and idle time.
Transport instrumentation and logging
pkg/util/transport_util.go, pkg/util/transport_util_test.go
Wraps registry transports with connection statistics and adds registry connection logging. Tests read TLS configuration from the concrete transport helper.
Trace metric export
pkg/tracing/tracing.go
Adds registry statistics as root-span attributes during tracing shutdown.
Command lifecycle and telemetry documentation
cmd/executor/cmd/root.go, cmd/warmer/cmd/root.go, docs/telemetry.md
Logs registry statistics on executor and warmer success and error paths. Documents the new Build span attributes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: babs, nejch, bobdu, 0hlov3

Sequence Diagram(s)

sequenceDiagram
  participant BuildCommand
  participant RegistryTransport
  participant connstats
  participant Registry
  participant tracing
  BuildCommand->>RegistryTransport: Create instrumented registry transport
  RegistryTransport->>connstats: Wrap dialing and HTTP requests
  connstats->>Registry: Open sockets and send requests
  Registry-->>connstats: Return connection and request events
  BuildCommand->>tracing: Shut down tracing
  tracing->>connstats: Snapshot registry statistics
  tracing-->>BuildCommand: Export registry attributes and end root span
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: counting registry sockets and requests and exporting the metrics to OpenTelemetry.
Description check ✅ Passed The description clearly explains the implementation, tracked metrics, telemetry behavior, cost, and lack of registry communication changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mz961-registry-connection-metrics

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mzihlmann
mzihlmann marked this pull request as draft August 2, 2026 17:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (7)
docs/telemetry.md (1)

51-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document that socket spans require a configured collector.

The section describes the spans but not the condition that produces them. pkg/tracing/tracing.go emits them only during Shutdown, and only when KANIKO_TELEMETRY_ENDPOINT is set and the build talked to a registry. Without the endpoint, connstats still keeps up to 256 records but nothing exports them.

All documented attribute names match socketSpans in pkg/tracing/tracing.go lines 180-193.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/telemetry.md` around lines 51 - 66, Update the “Registry socket spans”
documentation to state that socket spans are emitted during Shutdown only when
KANIKO_TELEMETRY_ENDPOINT is configured and the build communicated with a
registry; without the endpoint, connstats may retain up to 256 records but
exports none.
pkg/tracing/tracing.go (2)

170-195: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

socketSpans reads rootSpan without a nil check.

Line 173 guards tracer, but line 178 dereferences rootSpan. The only caller checks rootSpan != nil first, so this is correct today. The doc comment records the mu precondition but not the rootSpan precondition, so a future second caller can panic here.

State both preconditions, or guard rootSpan directly.

🛡️ Guard `rootSpan`
 func socketSpans() {
-	if tracer == nil {
+	if tracer == nil || rootSpan == nil {
 		return
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/tracing/tracing.go` around lines 170 - 195, Update socketSpans to guard
rootSpan before calling SetAttributes, or explicitly document rootSpan as a
required precondition alongside the existing mu precondition. Prefer a direct
nil check in socketSpans so future callers cannot trigger a panic.

241-244: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Socket spans compete with the root span for the shutdown flush budget.

socketSpans() can add up to 256 spans to the batch processor. provider.Shutdown then flushes everything under shutdownFlushTimeout. If the collector is slow, the added volume raises the chance that the flush times out and the root span never arrives. The root span carries the aggregate attributes that most consumers read, so losing it is worse than losing the per-socket detail.

Consider one of:

  • Raise shutdownFlushTimeout when socket spans are emitted.
  • Lower the 256 cap.
  • Make the per-socket export opt-in with a separate environment variable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/tracing/tracing.go` around lines 241 - 244, Adjust the tracing
shutdown/export behavior around socketSpans so emitting per-socket spans cannot
starve the root span within shutdownFlushTimeout. Prefer making socket-span
export opt-in through a separate environment variable, or otherwise reduce the
socket span cap or increase the flush timeout; preserve root-span delivery and
existing aggregate registryAttrs behavior.
pkg/util/transport_util_test.go (1)

166-170: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test covers the new instrumentation.

The test only unwraps the transport to reach the existing TLS assertions. Nothing verifies that MakeTransport wrapped DialContext, or that connstats counts a socket and a request.

A test against httptest.NewServer would cover the whole path: one request, then connstats.Snapshot() reports one socket opened and one request. That test needs a reset hook in connstats, because the counters are package globals with no way to clear them.

Do you want me to generate the test and the reset hook?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/util/transport_util_test.go` around lines 166 - 170, The transport tests
around MakeTransport currently verify only TLS configuration; add an
httptest.NewServer integration test that performs one request through the
instrumented transport and asserts connstats.Snapshot reports one socket opened
and one request. Add and use a connstats reset hook to clear the package-level
counters before the test so results are isolated.
pkg/util/transport_util.go (1)

123-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

LogRegistryConnections belongs closer to connstats.

The function reads only connstats state and writes a log line. It does not use anything from util. Placing it in pkg/connstats would remove the util import from cmd/warmer/cmd/root.go for callers that need nothing else from util.

This is a placement preference only. Keep it here if util is the established entry point for command-level helpers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/util/transport_util.go` around lines 123 - 129, Move
LogRegistryConnections from pkg/util into the connstats package, since it only
reads connstats state and logs the snapshot. Update its callers, including
cmd/warmer/cmd/root.go, to use the new package location and remove the
now-unneeded util import where applicable; preserve the existing logging
behavior.
pkg/connstats/connstats.go (2)

81-123: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Dial failures are not counted.

WrapDial returns early on error. Failed dials add nothing to dialTime and are not counted anywhere. A build that spends most of its time on failing dials reports dial.ms near zero, which is misleading for the pooling work this instrumentation supports.

Consider counting failed dials and their duration in separate counters.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/connstats/connstats.go` around lines 81 - 123, Update WrapDial to record
every dial attempt’s elapsed time, including failures, by adding the duration to
a dedicated failed-dial counter before returning the error. Keep successful dial
metrics and connection registration unchanged, and expose the separate failure
metric through the existing connstats counters/reporting mechanism.

176-216: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

GotConn attribution silently drops HTTP/2 and proxied requests.

lookup matches on info.Conn.LocalAddr().String(). Two cases return nil and lose the per-socket attribution without any signal:

  • HTTP/2 requests, where info.Conn can be the underlying TCP connection but many requests share it. Per-socket counts stay correct here, so this case is fine.
  • Any connection not created through the wrapped dialer, for example one produced by a proxy DialContext replacement.

The aggregate counters still increment, so only the per-socket records diverge from the totals. Consider counting the unattributed requests so the socket-span sum can be reconciled against kaniko.registry.requests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/connstats/connstats.go` around lines 176 - 216, Update the GotConn
callback in tracedTransport.RoundTrip to record requests when lookup(info.Conn)
returns nil, covering HTTP/2 and connections created outside the wrapped dialer.
Add or reuse an unattributed-request counter associated with the aggregate
connection statistics so per-socket totals can be reconciled with the overall
requests count, while preserving the existing per-socket attribution path when
lookup succeeds.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/warmer/cmd/root.go`:
- Around line 106-109: Ensure util.LogRegistryConnections() runs when cache
warming fails as well as on success by moving it into the exit() helper or
invoking it immediately before exit in the warmer error path. Update the warmer
command flow around warmer.WarmCache and exit, avoiding duplicate logging on
successful execution.

In `@docs/telemetry.md`:
- Line 35: Update the telemetry table entry so kaniko.registry.tls.ms has its
own table row, while keeping kaniko.registry.tls.handshakes in a separate row
with its existing description and documenting the duration metric in the new
row.

In `@pkg/connstats/connstats.go`:
- Around line 160-174: Update tracedTransport to implement CloseIdleConnections
by forwarding the call to its wrapped inner transport when it supports that
method, preserving registry clients’ ability to clean up idle connections
through the Trace wrapper.

---

Nitpick comments:
In `@docs/telemetry.md`:
- Around line 51-66: Update the “Registry socket spans” documentation to state
that socket spans are emitted during Shutdown only when
KANIKO_TELEMETRY_ENDPOINT is configured and the build communicated with a
registry; without the endpoint, connstats may retain up to 256 records but
exports none.

In `@pkg/connstats/connstats.go`:
- Around line 81-123: Update WrapDial to record every dial attempt’s elapsed
time, including failures, by adding the duration to a dedicated failed-dial
counter before returning the error. Keep successful dial metrics and connection
registration unchanged, and expose the separate failure metric through the
existing connstats counters/reporting mechanism.
- Around line 176-216: Update the GotConn callback in tracedTransport.RoundTrip
to record requests when lookup(info.Conn) returns nil, covering HTTP/2 and
connections created outside the wrapped dialer. Add or reuse an
unattributed-request counter associated with the aggregate connection statistics
so per-socket totals can be reconciled with the overall requests count, while
preserving the existing per-socket attribution path when lookup succeeds.

In `@pkg/tracing/tracing.go`:
- Around line 170-195: Update socketSpans to guard rootSpan before calling
SetAttributes, or explicitly document rootSpan as a required precondition
alongside the existing mu precondition. Prefer a direct nil check in socketSpans
so future callers cannot trigger a panic.
- Around line 241-244: Adjust the tracing shutdown/export behavior around
socketSpans so emitting per-socket spans cannot starve the root span within
shutdownFlushTimeout. Prefer making socket-span export opt-in through a separate
environment variable, or otherwise reduce the socket span cap or increase the
flush timeout; preserve root-span delivery and existing aggregate registryAttrs
behavior.

In `@pkg/util/transport_util_test.go`:
- Around line 166-170: The transport tests around MakeTransport currently verify
only TLS configuration; add an httptest.NewServer integration test that performs
one request through the instrumented transport and asserts connstats.Snapshot
reports one socket opened and one request. Add and use a connstats reset hook to
clear the package-level counters before the test so results are isolated.

In `@pkg/util/transport_util.go`:
- Around line 123-129: Move LogRegistryConnections from pkg/util into the
connstats package, since it only reads connstats state and logs the snapshot.
Update its callers, including cmd/warmer/cmd/root.go, to use the new package
location and remove the now-unneeded util import where applicable; preserve the
existing logging behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 23929f0a-147f-4c56-83ad-c3e03d1e5d43

📥 Commits

Reviewing files that changed from the base of the PR and between 990272f and b1e8320.

📒 Files selected for processing (7)
  • cmd/executor/cmd/root.go
  • cmd/warmer/cmd/root.go
  • docs/telemetry.md
  • pkg/connstats/connstats.go
  • pkg/tracing/tracing.go
  • pkg/util/transport_util.go
  • pkg/util/transport_util_test.go

Comment thread cmd/warmer/cmd/root.go
Comment thread docs/telemetry.md Outdated
Comment thread pkg/connstats/connstats.go
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.23404% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/util/transport_util.go 56.00% 10 Missing and 1 partial ⚠️
cmd/warmer/cmd/root.go 50.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@mzihlmann
mzihlmann force-pushed the mz961-registry-connection-metrics branch 7 times, most recently from 5f46f5a to d943b17 Compare August 2, 2026 21:44
@mzihlmann
mzihlmann marked this pull request as ready for review August 2, 2026 21:45
@mzihlmann
mzihlmann requested review from 0hlov3, BobDu, babs and nejch August 2, 2026 21:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/util/transport_util.go`:
- Line 118: Initialize tr.TLSClientConfig before the Certificates assignment in
the transport setup, ensuring the RegistriesClientCertificates-only path creates
a non-nil tls.Config while preserving existing configuration when already
initialized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f9ba9cea-383c-4965-a620-1e337954ac6b

📥 Commits

Reviewing files that changed from the base of the PR and between b1e8320 and d943b17.

📒 Files selected for processing (7)
  • cmd/executor/cmd/root.go
  • cmd/warmer/cmd/root.go
  • docs/telemetry.md
  • pkg/connstats/connstats.go
  • pkg/tracing/tracing.go
  • pkg/util/transport_util.go
  • pkg/util/transport_util_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • cmd/executor/cmd/root.go
  • cmd/warmer/cmd/root.go

Comment thread pkg/util/transport_util.go
@mzihlmann
mzihlmann force-pushed the mz961-registry-connection-metrics branch from d943b17 to 77f4fad Compare August 2, 2026 22:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/util/transport_util.go`:
- Around line 82-91: The connstats.Trace wrapper must preserve the wrapped
transport’s lifecycle behavior. Update tracedTransport and its construction in
MakeTransport to forward lifecycle methods such as CloseIdleConnections to the
inner http.RoundTripper, while retaining the existing RoundTrip tracing
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 88131c1d-cb08-4044-aa34-a54ac72c10c3

📥 Commits

Reviewing files that changed from the base of the PR and between d943b17 and 77f4fad.

📒 Files selected for processing (7)
  • cmd/executor/cmd/root.go
  • cmd/warmer/cmd/root.go
  • docs/telemetry.md
  • pkg/connstats/connstats.go
  • pkg/tracing/tracing.go
  • pkg/util/transport_util.go
  • pkg/util/transport_util_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • cmd/executor/cmd/root.go
  • docs/telemetry.md
  • pkg/tracing/tracing.go
  • cmd/warmer/cmd/root.go
  • pkg/util/transport_util_test.go
  • pkg/connstats/connstats.go

Comment thread pkg/util/transport_util.go
@mzihlmann
mzihlmann force-pushed the mz961-registry-connection-metrics branch from 77f4fad to 93b811c Compare August 2, 2026 22:29
@mzihlmann mzihlmann added the telemetry Everything related to our OTEL exporter label Aug 4, 2026

@0hlov3 0hlov3 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mzihlmann
mzihlmann merged commit abe9431 into main Aug 12, 2026
13 checks passed
@mzihlmann
mzihlmann deleted the mz961-registry-connection-metrics branch August 12, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

telemetry Everything related to our OTEL exporter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants