From 62a10c3a045eba9df0348959c51e96f2b573e574 Mon Sep 17 00:00:00 2001 From: Piotr Skorupa <pskorupa@gitlab.com> Date: Tue, 21 Nov 2023 03:16:37 +0000 Subject: [PATCH] Rename application_instrumentation feature flag Rename `application_instrumentation` FF to `internal_events_for_product_analytics`. --- Gemfile | 2 + Gemfile.checksum | 1 + Gemfile.lock | 5 ++ .../internal_events_for_product_analytics.yml | 8 +++ lib/gitlab/internal_events.rb | 24 ++++++++ spec/lib/gitlab/internal_events_spec.rb | 60 +++++++++++++++++++ .../editor_unique_counter_spec.rb | 10 ++-- 7 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 config/feature_flags/development/internal_events_for_product_analytics.yml diff --git a/Gemfile b/Gemfile index 30d8bc7622a44..e428a545780ab 100644 --- a/Gemfile +++ b/Gemfile @@ -638,3 +638,5 @@ gem 'net-protocol', '~> 0.1.3' # rubocop:todo Gemfile/MissingFeatureCategory gem 'net-http', '= 0.1.1' # rubocop:todo Gemfile/MissingFeatureCategory gem 'duo_api', '~> 1.3' # rubocop:todo Gemfile/MissingFeatureCategory + +gem 'gitlab-sdk', feature_category: :application_instrumentation diff --git a/Gemfile.checksum b/Gemfile.checksum index bd22ef4e64c0e..905ce96746bf5 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -218,6 +218,7 @@ {"name":"gitlab-mail_room","version":"0.0.23","platform":"ruby","checksum":"23564fa4dab24ec5011d4c64a801fc0228301d5b0f046a26a1d8e96e36c19997"}, {"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"}, {"name":"gitlab-net-dns","version":"0.9.2","platform":"ruby","checksum":"f726d978479d43810819f12a45c0906d775a07e34df111bbe693fffbbef3059d"}, +{"name":"gitlab-sdk","version":"0.2.3","platform":"ruby","checksum":"e891278a20860ab1f861312813dce5f2e73081bcc10def2ae4ee138b10a2d0d6"}, {"name":"gitlab-styles","version":"11.0.0","platform":"ruby","checksum":"0dd8ec066ce9955ac51d3616c6bfded30f75bb526f39ff392ece6f43d5b9406b"}, {"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"}, {"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"}, diff --git a/Gemfile.lock b/Gemfile.lock index 809d2a19eac5a..c1742a91fc115 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -703,6 +703,10 @@ GEM oauth2 (>= 1.4.4, < 3) gitlab-markup (1.9.0) gitlab-net-dns (0.9.2) + gitlab-sdk (0.2.3) + activesupport (>= 5.2.0) + rake (~> 13.0) + snowplow-tracker (~> 0.8.0) gitlab-styles (11.0.0) rubocop (~> 1.57.1) rubocop-graphql (~> 0.18) @@ -1883,6 +1887,7 @@ DEPENDENCIES gitlab-rspec! gitlab-safe_request_store! gitlab-schema-validation! + gitlab-sdk gitlab-secret_detection! gitlab-sidekiq-fetcher! gitlab-styles (~> 11.0.0) diff --git a/config/feature_flags/development/internal_events_for_product_analytics.yml b/config/feature_flags/development/internal_events_for_product_analytics.yml new file mode 100644 index 0000000000000..0ed4f0cf7445a --- /dev/null +++ b/config/feature_flags/development/internal_events_for_product_analytics.yml @@ -0,0 +1,8 @@ +--- +name: internal_events_for_product_analytics +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136154 +rollout_issue_url: +milestone: '16.7' +type: development +group: group::analytics instrumentation +default_enabled: false diff --git a/lib/gitlab/internal_events.rb b/lib/gitlab/internal_events.rb index c775182fb4063..c4fddede4b85b 100644 --- a/lib/gitlab/internal_events.rb +++ b/lib/gitlab/internal_events.rb @@ -8,6 +8,7 @@ module InternalEvents class << self include Gitlab::Tracking::Helpers + include Gitlab::Utils::StrongMemoize def track_event(event_name, send_snowplow_event: true, **kwargs) raise UnknownEventError, "Unknown event: #{event_name}" unless EventDefinitions.known_event?(event_name) @@ -23,6 +24,10 @@ def track_event(event_name, send_snowplow_event: true, **kwargs) increase_weekly_total_counter(event_name) update_unique_counter(event_name, kwargs) trigger_snowplow_event(event_name, kwargs) if send_snowplow_event + + if Feature.enabled?(:internal_events_for_product_analytics) + send_application_instrumentation_event(event_name, kwargs) + end rescue StandardError => e Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, event_name: event_name, kwargs: kwargs) nil @@ -93,6 +98,25 @@ def track_struct_event(event_name, contexts:) Gitlab::ErrorTracking .track_and_raise_for_dev_exception(error, snowplow_category: category, snowplow_action: event_name) end + + def send_application_instrumentation_event(event_name, kwargs) + return if gitlab_sdk_client.nil? + + user = kwargs[:user] + + gitlab_sdk_client.identify(user&.id) + gitlab_sdk_client.track(event_name) + end + + def gitlab_sdk_client + app_id = ENV['GITLAB_ANALYTICS_ID'] + host = ENV['GITLAB_ANALYTICS_URL'] + + return unless app_id.present? && host.present? + + GitlabSDK::Client.new(app_id: app_id, host: host) + end + strong_memoize_attr :gitlab_sdk_client end end end diff --git a/spec/lib/gitlab/internal_events_spec.rb b/spec/lib/gitlab/internal_events_spec.rb index 68d6f3700af5e..26c2421e6499b 100644 --- a/spec/lib/gitlab/internal_events_spec.rb +++ b/spec/lib/gitlab/internal_events_spec.rb @@ -267,4 +267,64 @@ def validate_service_ping_context(service_ping_context) expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to have_received(:track_event) end end + + describe 'Product Analytics tracking' do + let(:app_id) { 'foobar' } + let(:url) { 'http://localhost:4000' } + + before do + described_class.clear_memoization(:gitlab_sdk_client) + + stub_env('GITLAB_ANALYTICS_ID', app_id) + stub_env('GITLAB_ANALYTICS_URL', url) + end + + subject(:track_event) { described_class.track_event(event_name, user: user) } + + shared_examples 'does not send a Product Analytics event' do + it 'does not call the Product Analytics Ruby SDK' do + expect(GitlabSDK::Client).not_to receive(:new) + + track_event + end + end + + context 'when internal_events_for_product_analytics FF is enabled' do + before do + stub_feature_flags(internal_events_for_product_analytics: true) + end + + it 'calls Product Analytics Ruby SDK', :aggregate_failures do + expect_next_instance_of(GitlabSDK::Client) do |sdk_client| + expect(sdk_client).to receive(:identify).with(user.id) + expect(sdk_client).to receive(:track).with(event_name) + end + + track_event + end + + context 'when GITLAB_ANALYTICS_ID is nil' do + let(:app_id) { nil } + + it_behaves_like 'does not send a Product Analytics event' + end + + context 'when GITLAB_ANALYTICS_URL is nil' do + let(:url) { nil } + + it_behaves_like 'does not send a Product Analytics event' + end + end + + context 'when internal_events_for_product_analytics FF is disabled' do + let(:app_id) { 'foobar' } + let(:url) { 'http://localhost:4000' } + + before do + stub_feature_flags(internal_events_for_product_analytics: false) + end + + it_behaves_like 'does not send a Product Analytics event' + end + end end diff --git a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb index 71e9e7a8e7dfb..cbf4d3c82619a 100644 --- a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb @@ -19,9 +19,9 @@ specify do aggregate_failures do - expect(track_action(author: user, project: project)).to be_truthy - expect(track_action(author: user2, project: project)).to be_truthy - expect(track_action(author: user3, project: project)).to be_truthy + track_action(author: user, project: project) + track_action(author: user2, project: project) + track_action(author: user3, project: project) expect(count_unique(date_from: time.beginning_of_week, date_to: 1.week.from_now)).to eq(3) end @@ -30,7 +30,9 @@ it_behaves_like 'internal event tracking' it 'does not track edit actions if author is not present' do - expect(track_action(author: nil, project: project)).to be_nil + track_action(author: nil, project: project) + + expect(count_unique(date_from: time.beginning_of_week, date_to: 1.week.from_now)).to eq(0) end end -- GitLab