Skip to content

nri-prelude: thread session id through LogHandler#153

Draft
ArthurJordao wants to merge 1 commit into
haskell-analytics-trackingfrom
haskell-analytics-tracking-session-id
Draft

nri-prelude: thread session id through LogHandler#153
ArthurJordao wants to merge 1 commit into
haskell-analytics-trackingfrom
haskell-analytics-tracking-session-id

Conversation

@ArthurJordao
Copy link
Copy Markdown
Contributor

Summary

Builds on @juliano's analytics handler design (this branch's base) by adding a per-request session id slot to LogHandler, so request-context metadata rides alongside the analytics callback rather than each event constructor declaring its own sessionId field.

  • New field sessionIdRef :: IORef (Maybe Text) on LogHandler.
  • mkHandler and rootTracingSpanIO thread it the same way they thread trackAnalyticsEventIO — IORef minted once at the request root, shared with every child / new-root handler via closure capture.
  • New public surface in Platform.hs:
    • sessionId :: Task e (Maybe Text)
    • setSessionIdIO :: LogHandler -> Maybe Text -> IO ()
  • Platform.Analytics.Internal.trackEvent reads the ref and shallow-merges { "session_id": ... } onto the event JSON before invoking trackAnalyticsEventIO. So every event automatically carries the session id without per-event schemas declaring it (mirrors how event_id/event_timestamp are stamped centrally in nri-analytics).

Companion PR

  • NoRedInk: haskell-analytics-tracking-session-id — adds the rostering WAI middleware that calls setSessionIdIO, the Ruby header injection on RosteringService, and drops the per-event sessionId props from Analytics.Event.

Test plan

  • cabal --project-file=cabal.project test from nri-prelude/: 279 pass, 1 unrelated pre-existing failure (debug-todo-stacktrace golden line-number drift in TestSpec.hs)
  • 3 new tests in PlatformSpec.hs:
    • trackEvent stamps the current request's session_id onto the payload
    • Platform.sessionId reflects the value written by setSessionIdIO
    • child handlers see the session id set on the root

🤖 Generated with Claude Code

Adds a per-request session-id slot to LogHandler with the same
plumbing pattern as trackAnalyticsEventIO: an IORef created by
rootTracingSpanIO and shared across child / new-root handlers via
closure capture in mkHandler.

Public surface:
  - Platform.sessionId :: Task e (Maybe Text)
  - Platform.setSessionIdIO :: LogHandler -> Maybe Text -> IO ()

The intended use is a WAI middleware on the application root: read an
incoming X-NRI-Session-Id header, call setSessionIdIO once on the
per-request LogHandler, and let every Analytics.track call inside the
request stamp it automatically.

Platform.Analytics.Internal.trackEvent reads the ref and shallow-merges
{ "session_id": ... } onto the event's JSON before invoking the
analytics callback, so per-event schemas don't need a session_id
field. Mirrors how event_id/event_timestamp are stamped centrally in
nri-analytics.

Tests cover four cases:
  - trackEvent stamps session_id when set
  - existing trackEvent test (no session id) still passes unchanged
  - sessionId reflects setSessionIdIO writes
  - child handlers see the session id set on the root

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ArthurJordao ArthurJordao marked this pull request as draft May 8, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant