feat: report $release_id from POSTHOG_RELEASE_ID on exceptions - #301
Closed
ablaszkiewicz wants to merge 1 commit into
Closed
feat: report $release_id from POSTHOG_RELEASE_ID on exceptions#301ablaszkiewicz wants to merge 1 commit into
ablaszkiewicz wants to merge 1 commit into
Conversation
Report a `$release_id` on `$exception` events when `POSTHOG_RELEASE_ID` is set in the environment. This is the native, deploy-time counterpart to injecting `$release_id` into a web bundle: a build tool creates the release with `posthog-cli release resolve`, launches the app with the printed id in `POSTHOG_RELEASE_ID`, and the SDK stamps it on each exception, so the server resolves that exception's release by a direct id lookup — no release name or version has to match anything the app reports. The id is read once (cached), added on both the v0 (`APIfy`) and v1 (`apifyEvent`) exception paths, and only on `$exception` events (that is where a release is resolved). An unset or blank value changes nothing. No binary patching and no code signing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
posthog-go Compliance ReportDate: 2026-08-27 12:22:20 UTC ✅ All Tests Passed!111/111 tests passed Capture_V1 Tests✅ 94/94 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
dustinbyrne
reviewed
Aug 27, 2026
Comment on lines
+16
to
+30
| const releaseIDEnvVar = "POSTHOG_RELEASE_ID" | ||
|
|
||
| var ( | ||
| releaseIDOnce sync.Once | ||
| releaseIDValue *string | ||
| ) | ||
|
|
||
| // releaseIDFromEnv returns the release id from POSTHOG_RELEASE_ID, read once. It returns nil when | ||
| // the variable is unset or blank, so no $release_id is sent. | ||
| func releaseIDFromEnv() *string { | ||
| releaseIDOnce.Do(func() { | ||
| releaseIDValue = normalizeReleaseID(os.Getenv(releaseIDEnvVar)) | ||
| }) | ||
| return releaseIDValue | ||
| } |
Contributor
There was a problem hiding this comment.
similar to my comment on the rust PR, should this come from ldflags instead? otherwise this is a runtime requirement instead of a build time requirement
Author
|
We wont be migrating go/rust to the new release system |
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
A compiled Go binary carries no release. A JavaScript build injects
$release_idinto its bundle, but a Go binary has neither.Change
Report a
$release_idon$exceptionevents whenPOSTHOG_RELEASE_IDis set in the environment — the native, deploy-time counterpart to the web$release_id:posthog-cli release resolveto create the release and print its id.POSTHOG_RELEASE_ID.$release_idon each exception.The server then resolves each exception's release by a direct id lookup, so no release name or version has to match anything the app reports.
Only
$exceptionevents carry the property — that is the only event the server resolves a release from, so a normalCapturedoes not need it. The id is read once (cached) and added on both the v0 (APIfy) and v1 (apifyEvent) exception paths, so it is consistent across capture modes. An unset or blank value changes nothing. No binary patching and no code signing.Contract: the variable is
POSTHOG_RELEASE_ID, holding the release id (a UUID) thatposthog-cli release resolveprints. Upload the Go binary's symbols release-independent withsymbol-sets upload --release-mode=event(PostHog/posthog#89834), so one symbol set serves every release.This mirrors the Rust SDK change (PostHog/posthog-rs#239): the env-var flow is SDK-agnostic — any native SDK that reads
POSTHOG_RELEASE_IDparticipates.How did you test this code?
go test ./...— new unit tests for the value normalization (unset → none, blank → none, surrounding whitespace trimmed) and for the exception scoping: a$release_idlands on an$exception(verified on both the v0APIfyand the v1apifyEventwire paths), not on a non-exceptionCapture, and not at all when unset. The full suite stays green;go vetandgofmtclean.new tests
The positive env-read path is exercised through the wire-format structs (
ExceptionInApi/ the v1 event) rather than by faking the env: the variable is read behind async.Once, so a test pins the cached value directly.End to end against a local PostHog stack, run by the agent (Claude). A minimal
go-release-envexample (a plain posthog-go app,alpha → beta → gamma→ capture) is built against this branch, its symbols upload release-independent, its exception resolves its release purely from the reported$release_id, and its frames show Go source context.posthog-cli — release-independent
symbol-sets uploadof the Go binary, thenrelease resolvethe app, launched with the resolved id in
POSTHOG_RELEASE_IDRead back server-side (a dev-login session over the local API): the
$exception($lib = posthog-go) carries the reported$release_id, cymbal resolved it into a$exception_release, and the app frames symbolicate to source off the uploaded symbol set:$release_idThe binary carries no release-specific code — only
POSTHOG_RELEASE_IDin the environment names the release. This matches the Rust pair (PostHog/posthog-rs#239); the two SDKs produce the identical$exceptionshape.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Authored by Claude in Claude Code, directed by @ablaszkiewicz (DRI). This brings the env-variable
$release_idapproach (already done for Rust in PostHog/posthog-rs#239, with the CLI side in PostHog/posthog#89834) to the Go SDK. The repo was cloned locally for this change. The end-to-end verification above was run by the agent against a local PostHog dev stack (ingestion + cymbal), with screenshots uploaded viahogli pr:upload-image; the example data is invented (go-release-env) and draws on no customer material.🤖 Generated with Claude Code