[CFX-6266] feat(telemetry): add TrackWithShared for unified Amplitude property groups#513
Draft
ajalon1 wants to merge 13 commits into
Draft
[CFX-6266] feat(telemetry): add TrackWithShared for unified Amplitude property groups#513ajalon1 wants to merge 13 commits into
ajalon1 wants to merge 13 commits into
Conversation
…roups TrackWithShared is like TrackWith but declares keys as 'shared' — keys that appear on every telemetry event (as "" when not applicable) so Amplitude sees a single unified property rather than N per-event-type properties. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Client.Track now iterates sharedPropKeys and ensures each declared shared key is present in every event's properties (defaulting to ""). Commands that registered a TrackWithShared extractor override these defaults via their EventProperties, so Amplitude sees one property across all event types. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Covers four cases: - annotation is set and keys are registered in sharedPropKeys - shared extractor output appears in EventFor's EventProperties - TrackWithShared coexists correctly with TrackWith on the same command - non-registered commands do not get shared props in EventFor (seeding is Client.Track's responsibility, validated via sharedPropKeys state) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
task_name is now a shared telemetry property so Amplitude sees it as a single unified property across all event types, not a per-event-type key. Non-task events get task_name seeded as "". Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Aligns dr run with dr task so both contribute to the same shared Amplitude property. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…omplexity EventFor was exceeding cyclop's max cyclomatic complexity of 10. Extract the sync.Map load-and-invoke pattern into a shared helper so both the per-command and shared extractor paths stay readable. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
template_name, template_id, and template_version will be added as shared properties once CFX-6052 exposes them from the TUI model. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…e preference Changed Client.Track to delete shared properties with empty-string values instead of seeding them. This applies to both extractors that returned empty strings (e.g., FirstArg with no args) and keys registered via TrackWithShared that were not set on a given event. Amplitude prefers properties to be omitted entirely when not set, rather than sent with empty values.
…e preference Changed Client.Track to delete shared properties with empty-string values instead of seeding them. This applies to both extractors that returned empty strings (e.g., FirstArg with no args) and keys registered via TrackWithShared that were not set on a given event. Amplitude prefers properties to be omitted entirely when not set, rather than sent with empty values. Refactored Track method to extract property merging and omission logic into separate helper functions (mergeCommonProperties and omitEmptySharedProperties) to reduce nesting complexity and improve testability. Updated documentation comments for sharedExtractors, sharedPropKeys, TrackWithShared, and EventFor to reflect the new omission behavior. Renamed TestTrackWithShared_NonRegisteredCommandGetsEmptyKey to TestTrackWithShared_NonRegisteredCommandOmitsKey and added two new tests: - TestTrackWithShared_EmptyExtractorValueOmitsKey - TestTrackWithShared_NonEmptyValueIsIncluded Added integration-level tests to telemetry_test.go.
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.
RATIONALE
Currently, Amplitude scopes event properties to their event type. This means that when
task_nameis registered as an event property ondr task,dr run, anddr task runseparately, Amplitude treats them as three distinct properties —dr task › task_name,dr run › task_name, anddr task run › task_name— rather than a single unified one. Any cross-command question like "which tasks are most commonly run?" requires manually aggregating three separate Amplitude properties, and any filtering or funnel built ontask_namesilently misses events from the other two commands.This property-scoping limitation applies to any logical "property group" that spans multiple commands: we have the same problem with
plugin_nameacross install/uninstall/update, andmissing_depsacross check and install.This PR introduces
TrackWithShared: a registration function identical toTrackWithin its closure-invocation contract (thanks @taras-pokornyy!), but which additionally declares a set of property keys that belong to a unified Amplitude property.Client.Trackseeds those keys as `` on all events, and commands that registered a shared extractor override the default via theirEventProperties.CHANGES
Before
flowchart LR A[dr task dev] -->|TrackWith| B[task event\ntask_name: dev] C[dr run dev] -->|TrackWith| D[run event\ntask_name: dev] E[dr auth set-url] --> F[auth event\nno task_name] B --> G[Amplitude\ndr task.task_name] D --> H[Amplitude\ndr run.task_name]After
flowchart LR R[TrackWithShared] -->|registers key| S[sharedPropKeys] A[dr task dev] -->|shared extractor| B[task event\ntask_name: dev] C[dr run dev] -->|shared extractor| D[run event\ntask_name: dev] E[dr auth set-url] -->|Client.Track seeds| F[auth event\ntask_name: empty] B --> G[Amplitude\ntask_name unified] D --> G F --> GTrackWithShared(cmd, keys, extract)and backing sync.Maps (internal/telemetry/wire.go) — marks the command as tracked, stores the extractor insharedExtractors, and records each declared key insharedPropKeys. The extractor is invoked atcobra.OnFinalizetime (afterRunE), so closures over local variables populated during command execution work identically toTrackWith.mergeExtractorPropshelper (internal/telemetry/wire.go) — refactors the load-and-invoke pattern shared bycommandPropertiesandsharedExtractorsinto a single function. (Appeases the linter.)internal/telemetry/telemetry.go) —Client.TrackiteratessharedPropKeysand inserts""for any key not already in the common-property map before merging event-specific properties.task_nametoTrackWithShared(cmd/task/cmd.go,cmd/task/run/cmd.go) — no change to task events; non-task events now additionally carrytask_name: "".cmd/templates/setup/cmd.go) — markstemplate_name,template_id, andtemplate_versionfor the same migration once that work exposes those values from the TUI model. (I think Vol this is something we can use for template_name, if you haven't already ...)TESTING
TestTrackWithShared_SetsAnnotationAndRegistersKeyssharedPropKeysTestTrackWithShared_PassesPropertiesFromExtractorEventForinvokes the shared extractor and includes its output inEventPropertiesTestTrackWithShared_CoexistsWithTrackWithTrackWithandTrackWithSharedproduces all properties correctlyTestTrackWithShared_NonRegisteredCommandGetsEmptyKeysharedPropKeysis populated after registration;EventFordoes not seed (seeding isClient.Track's responsibility)Run with
task test.TODO
template_name,template_id,template_versiontoTrackWithSharedonce the template setup TUI exposes those valuescomponent_name,plugin_name,missing_deps/wrong_version_depsusing the same patternNOTES
TrackWithSharedis intentionally a separate registration path fromTrackWithrather than a flag on the existing function. The distinction matters: per-command properties (e.g.parallel,output_format) should not appear on every event as empty strings — only properties that span a logical group of commands benefit from that treatment.PR Automation
Comment-Commands: Trigger CI by commenting on the PR:
/trigger-smoke-testor/trigger-test-smoke- Run smoke tests/trigger-install-testor/trigger-test-install- Run installation testsLabels: Apply labels to trigger workflows:
run-smoke-testsorgo- Run smoke tests on demand (only works for non-forked PRs)Important
For Forked PRs: The
run-smoke-testslabel won't work. A required Smoke Tests check will block merge until a maintainer acts:/approve-smoke-teststo run smoke tests (results will set the check)/skip-smoke-teststo bypass the check without running testsPlease comment requesting a maintainer review if you need smoke tests to run.