Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Analytics middleware & recording #11681

Closed
wants to merge 12 commits into from
73 changes: 61 additions & 12 deletions app/services/analytics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,56 @@ class Analytics
include AnalyticsEvents
prepend Idv::AnalyticsEventsEnhancer

attr_reader :user, :request, :sp, :session, :ahoy
# Analytics middleware that sends the event to Ahoy
class AhoyMiddleware
attr_reader :ahoy

def initialize(ahoy: nil, request: nil)
@ahoy = ahoy || Ahoy::Tracker.new(request:)
end

def call(event)
event.tap do |event|
ahoy.track(event[:name], event[:properties])
end
end
end

# Analytics middleware that augments NewRelic APM trace with additional metadata.
class NewRelicMiddleware
def call(event)
event.tap do
# Tag NewRelic APM trace with a handful of useful metadata
# https://www.rubydoc.info/github/newrelic/rpm/NewRelic/Agent#add_custom_attributes-instance_method
::NewRelic::Agent.add_custom_attributes(
user_id: event.dig(:properties, :user_id),
user_ip: event.dig(:properties, :user_ip),
service_provider: event.dig(:properties, :service_provider),
event_name: event[:name],
git_sha: IdentityConfig::GIT_SHA,
)
end
end
end
Comment on lines +7 to +37
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ideally these would live in app/services/analytics/ and ApplicationController would add them when it's creating its own Analytics instance


class << self
# @return [Proc[]] The set of middleware Procs added to all new Analytics instances by default.
def default_middleware
@default_middleware ||= []
end

# @param [Proc[]] middlewares Middleware procs to add while block executes.
# Added for use in specs only
def with_default_middleware(*middlewares, &block)
matthinz marked this conversation as resolved.
Show resolved Hide resolved
middlewares.each { |m| default_middleware << m }
block.call
ensure
middlewares.each { |m| default_middleware.delete(m) }
end
end

attr_reader :user, :request, :sp, :session
attr_reader :middleware

# @param [User] user
# @param [ActionDispatch::Request,nil] request
Expand All @@ -16,7 +65,10 @@ def initialize(user:, request:, sp:, session:, ahoy: nil)
@request = request
@sp = sp
@session = session
@ahoy = ahoy || Ahoy::Tracker.new(request: request)
@middleware = Analytics.default_middleware.dup

middleware << AhoyMiddleware.new(ahoy:, request:)
middleware << NewRelicMiddleware.new
end

def track_event(event, attributes = {})
Expand All @@ -36,17 +88,14 @@ def track_event(event, attributes = {})
analytics_hash.merge!(sp_request_attributes) if sp_request_attributes
analytics_hash.merge!(ab_test_attributes(event))

ahoy.track(event, analytics_hash)
event_for_middleware = {
name: event,
properties: analytics_hash,
}.freeze

# Tag NewRelic APM trace with a handful of useful metadata
# https://www.rubydoc.info/github/newrelic/rpm/NewRelic/Agent#add_custom_attributes-instance_method
::NewRelic::Agent.add_custom_attributes(
user_id: analytics_hash[:user_id],
user_ip: request&.remote_ip,
service_provider: sp,
event_name: event,
git_sha: IdentityConfig::GIT_SHA,
)
middleware.each do |m|
event_for_middleware = m.call(event_for_middleware)
end
end

def update_session_events_and_paths_visited_for_analytics(event)
Expand Down
1 change: 1 addition & 0 deletions spec/features/idv/end_to_end_idv_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
RSpec.describe 'Identity verification', :js do
include IdvStepHelper
include InPersonHelper
include AnalyticsRecordingHelper

let(:sp) { :oidc }
let(:sp_name) { 'Test SP' }
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading