Skip to content

poc: analytics tracking#152

Draft
omnibs wants to merge 5 commits into
trunkfrom
haskell-analytics-tracking
Draft

poc: analytics tracking#152
omnibs wants to merge 5 commits into
trunkfrom
haskell-analytics-tracking

Conversation

@omnibs
Copy link
Copy Markdown
Member

@omnibs omnibs commented May 8, 2026

This is a proof of concept claude wrote for me. Don't merge it.

omnibs and others added 5 commits May 7, 2026 18:25
Adds an opaque (Aeson.Value -> IO ()) callback to LogHandler,
propagated by mkHandler to every child handler. rootTracingSpanIO
gains a new parameter for the callback; nullHandler defaults to
silentTrack. Re-exports silentTrack from Platform for callers.

This is a breaking change to rootTracingSpanIO and mkHandler. See
the design doc at NoRedInk/event-platform/docs/2026-05-07-haskell-analytics-tracking-design.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
trackEvent opens an analytics.track child span, attaches the JSON
payload as span details, and invokes the LogHandler's analytics
callback. The .Internal suffix signals do-not-import from product
code; consumers should wrap this in a typed entry point.

Bump to 0.7.0.0 (breaking: rootTracingSpanIO signature changed in
the previous commit). Bump nri-prelude upper bound to <0.8 in the
sibling packages so the workspace builds, and refresh hard-coded
package strings in the test-suite golden files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Initial nri-analytics package. Provides a Settings type read from
ANALYTICS_EVENTS_* env vars, an AnalyticsHandler with a sendEvent
callback that POSTs application/json to {eventsServiceUrl}/events
with bearer auth and a bounded timeout, and a silentHandler for
tests and non-tracking platforms.

The handler is sync (one outbound request per track call) and
log-and-drops on failure so analytics outages never affect the
surrounding request. Wire format is provisional pending the events
service contract.
The envelope fields required by the events service contract are added
by the wire layer at sendEvent time, not by the typed Event in NoRedInk.
This keeps the domain Event type pure data and removes the need to lift
IO into Task in callers.
The auth token is now Log.Secret Text so accidental Show/logging
doesn't leak it. buildRequest unwraps it at the HTTP-header
boundary; the decoder uses Environment.secret to wrap on read.

Also adds a test that sendEventIO swallows exceptions when
delivery fails (unreachable URL), exercising the non-throwing
contract that the surrounding request depends on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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