Skip to content
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
Copy Markdown
Contributor 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)
Comment thread
matthinz marked this conversation as 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