Skip to content

feat(frontend,ad,payment): propagate enduser.id as span attribute and W3C baggage - #3366

Merged
julianocosta89 merged 6 commits into
open-telemetry:mainfrom
dpacheconr:feat/enduser-id-attribute
May 26, 2026
Merged

feat(frontend,ad,payment): propagate enduser.id as span attribute and W3C baggage#3366
julianocosta89 merged 6 commits into
open-telemetry:mainfrom
dpacheconr:feat/enduser-id-attribute

Conversation

@dpacheconr

@dpacheconr dpacheconr commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • AttributeNames.ts — adds ENDUSER_ID = 'enduser.id' enum value alongside the existing SESSION_ID
  • SessionIdProcessor.ts — stamps enduser.id on every browser span in onStart, using the same per-browser UUID already used for session.id
  • Api.gateway.ts — chains .setEntry(AttributeNames.ENDUSER_ID, { value: userId }) onto the baggage Proxy wrapper, injecting enduser.id into the W3C baggage header on every outgoing /api/* call
  • AdService.java — inside the existing if (baggage != null) block, extracts "enduser.id" from baggage and calls span.setAttribute("enduser.id", enduserId) when present
  • charge.js — after the existing synthetic_request baggage check, extracts 'enduser.id' from baggage and stamps it on the charge span when present

Motivation

enduser.id is the OTel-recommended semantic convention attribute for identifying the end user associated with a request. Populating it consistently across browser and backend spans enables observability backends to correlate traces to individual users, power "impacted users" counts in error views, and filter/group by user out of the box — without any custom attribute naming.

The demo already had a stable per-browser UUID in localStorage used as session.id. This change re-uses that same value for enduser.id so there is no new data collection, and the attribute flows end-to-end: browser spans carry it directly, and the ad and payment services extract it from the propagated W3C baggage and stamp their own spans.

Test plan

  • TypeScript compilation clean (npm run build in src/frontend/)
  • Compiled Next.js bundle contains ENDUSER_ID="enduser.id" enum, setEntry(ENDUSER_ID) baggage call, and setAttribute(ENDUSER_ID) span call
  • Ad and payment Docker images build successfully with our changes
  • Browser request headers confirm baggage: session.id=<uuid>,enduser.id=<uuid> on every /api/* call
  • Jaeger confirms enduser.id=<uuid> on payment charge spans for browser-initiated checkouts

Note on ad service: the service currently crashes on startup with a gRPC internal API mismatch (AbstractMethodError in NettyServerBuilder) introduced by the recent Gradle dependency bump in commit cf3ba5c. This is unrelated to this PR — our Java change compiled successfully, and the baggage extraction logic follows the same pattern already used for session.id in the same file.

@dpacheconr dpacheconr changed the title feat(frontend): add enduser.id attribute to browser spans and baggage feat(frontend,ad,payment): propagate enduser.id as span attribute and W3C baggage May 14, 2026
… W3C baggage

Add enduser.id (the existing per-browser UUID) as a span attribute on
every browser span via SessionIdProcessor, propagate it in W3C baggage
on all outgoing API requests via the ApiGateway Proxy, and extract it
in the ad and payment backend services to stamp their own spans.
@dpacheconr
dpacheconr force-pushed the feat/enduser-id-attribute branch from 6834e1a to edc7c47 Compare May 14, 2026 10:24
@dpacheconr
dpacheconr marked this pull request as ready for review May 14, 2026 10:25
@dpacheconr
dpacheconr requested a review from a team as a code owner May 14, 2026 10:25

@osullivandonal osullivandonal 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.

Hey thanks for the contribution, can you please add a changelog entry as per the contributing guidelines. Thanks.

@dpacheconr

Copy link
Copy Markdown
Contributor Author

Hey thanks for the contribution, can you please add a changelog entry as per the contributing guidelines. Thanks.

changelog entry added

@puckpuck

Copy link
Copy Markdown
Contributor

There is a semantic convention for a user that we should use. We should be using user.id instead of enduser.id.

Can you change all references and attribute names to show this as user instead of enduser?

@danielgblanco

Copy link
Copy Markdown
Contributor

Both user.* and enduser.* namespaces are active, and it will depend what we want to represent. Although initially the enduser.* namespace was deprecated in favour of user.* when ECS was imported, later discussions brought it back. The general consensus is that describing end users of a system (unathenticated or not) has different constraints than internal users and should live in separate namespace managed by client-side SIG.

In this case, according to this PR, I believe we're trying to describe end users of the Astronomy Shop, and propagate that ID via Baggage. IMO this is a great use case to showcase client-side semconv.

I think it's fine right now to have session.id and user.id be the same value, however in the future as session.id (and tooling related to sessions) stabilises we may want to use some of that tooling here and make a distinction between session and user ID which are generally different things (cc @martinkuba @breedx-splk @bidetofevil).

@danielgblanco

Copy link
Copy Markdown
Contributor

I'd add that the fact that this is a common source of confusion means we could make semconv clearer about these two attributes. One should not need to know the lore to reason about this. I'll open an issue.

@puckpuck

Copy link
Copy Markdown
Contributor

TIL: Enduser is in the spec.

@julianocosta89

Copy link
Copy Markdown
Member

Hey @dpacheconr thanks for that, would you be able to also add an entry on the telemetry schema for this?
https://github.com/open-telemetry/opentelemetry-demo/tree/main/telemetry-schema

Add enduser.id (OTel semconv) to the telemetry schema service refs for
frontend, ad, and payment — the three services that instrument this
attribute per the enduser.id propagation PR.
Keep enduser.id alongside upstream's renamed demo.user_context.loyalty_level
in payment service schema; preserve both CHANGELOG entries.
@julianocosta89
julianocosta89 enabled auto-merge May 26, 2026 09:26
@julianocosta89
julianocosta89 added this pull request to the merge queue May 26, 2026
Merged via the queue into open-telemetry:main with commit c144654 May 26, 2026
39 checks passed
swanpyaetun pushed a commit to swanpyaetun/swan_opentelemetry-demo that referenced this pull request Jun 8, 2026
… W3C baggage (open-telemetry#3366)

* feat(frontend,ad,payment): propagate enduser.id as span attribute and W3C baggage

Add enduser.id (the existing per-browser UUID) as a span attribute on
every browser span via SessionIdProcessor, propagate it in W3C baggage
on all outgoing API requests via the ApiGateway Proxy, and extract it
in the ad and payment backend services to stamp their own spans.

* docs: add changelog entry for enduser.id propagation (open-telemetry#3366)

* feat(telemetry-schema): add enduser.id to service attribute refs

Add enduser.id (OTel semconv) to the telemetry schema service refs for
frontend, ad, and payment — the three services that instrument this
attribute per the enduser.id propagation PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants