Repository navigation
Conversation
The controller and writer take a constructor instead of S2 credentials, so a second backend can share their lifecycle and fork gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When BTEL_STORAGE_PATH is set, stored telemetry is posted in batches to the metro-api relay with the instance JWT instead of appended to S2 with a credential baked into the VM. Direct S2 stays available when only the S2 credentials are set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retry temporary transport errors like the OTLP exporter, count batches cut off by Close as shutdown drops, keep the post-deadline wait short, and refuse a relay path with no host to reach it on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
Serve browser telemetry storage through the metro-api relay instead of baking S2 credentials into VMs. This PR adds the in-VM sink.
When
BTEL_STORAGE_PATHis set, stored telemetry is posted to the metro-api relay instead of appended to S2. Direct S2 (S2_BASINplusS2_ACCESS_TOKEN) is unchanged and still used when the path is unset. The relay wins when both are set.Each record body is
json.Marshal(envelope), exactly what the direct sink appended, so S2 contents and the read path are unchanged. It is sent with the event time converted from microseconds to milliseconds.The sink follows the OTLP sink's semantics:
Retry-After, for up to 30s per batch.The bearer token (instance JWT) and relay host are resolved per batch, so a fork posts with its own identity to the metro-api it was handed. Host order:
BTEL_OTLP_ENDPOINT, withBTEL_OTLP_INSECUREpicking the scheme.The token goes only on requests to that URL, and redirects are refused.
The storage controller now takes a storage constructor. The relay controller shares the S2 controller's start/stop/once-only lifecycle and its fork gate: nothing opens until
S2_STREAM(or the applied fork identity's stream) resolves. The telemetry handler is unchanged.Config:
BTEL_STORAGE_PATH,BTEL_STORAGE_MAX_RECORDS(200),BTEL_STORAGE_MAX_BYTES(786432),BTEL_STORAGE_LINGER(100ms),BTEL_STORAGE_MAX_QUEUE(8192). When the path is set, values are validated against S2's batch limits and a relay host is required. Documented inserver/README.md.Metrics:
kernel_btel_relay_exported_total,_dropped_total{reason},_retries_total,_failed_total{status},_queue_depth.Rollout
Release this image before provisioning sets
BTEL_STORAGE_PATH. Images without this sink provisioned without S2 credentials store nothing.Validation
lib/eventsrelay sink tests againsthttptest:json.Marshal(envelope)byte for byte, including HTML and line-separator escapes.tsis in milliseconds.Retry-Afteris honoured.Controller contract tests run against both the S2 and relay controllers: lifecycle, the fork gate, and rollback when start is cancelled.
cmd/api/api/telemetry_test.go: the storage toggle runs against both real controllers. Storage opens once, refuses to turn off (409), and stays closed while no stream resolves.Config validation cases, the metrics collector, and the relay base URL fallback.
e2e, run locally against a freshly built headless image:
TestRelayStorage: relay plus direct S2 credentials; records reach a mock relay with the instance JWT and valid envelopes.TestRelayStorageForkIdentity: a fork boots with no JWT and a dead endpoint. After the identity handoff, storage reaches the handed metro-api with the fresh JWT.Both pass, as does the existing
TestOTLPExport. Locally, testcontainers neededTESTCONTAINERS_RYUK_DISABLED=trueandTESTCONTAINERS_HOST_OVERRIDE=127.0.0.1because of this machine's DNS.go test ./...outside e2e passes. One devtoolsproxy test flaked once on Chromium temp-dir cleanup and passed on rerun.Not tested: a real metro-api relay and S2.
🤖 Generated with Claude Code