From d9c3df4a04a57659a0ba5d1b4208ab9cd69a2866 Mon Sep 17 00:00:00 2001
From: Jonas Larsen <jlarsen@gitlab.com>
Date: Wed, 17 Jan 2024 08:02:26 +0000
Subject: [PATCH] Expose category in internal events

---
 lib/gitlab/internal_events.rb           | 12 ++++++------
 scripts/internal_events/monitor.rb      |  4 +++-
 spec/lib/gitlab/internal_events_spec.rb | 15 +++++++++++++--
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/lib/gitlab/internal_events.rb b/lib/gitlab/internal_events.rb
index eb2ba3449fb0..12609e9be35f 100644
--- a/lib/gitlab/internal_events.rb
+++ b/lib/gitlab/internal_events.rb
@@ -10,7 +10,7 @@ class << self
       include Gitlab::Tracking::Helpers
       include Gitlab::Utils::StrongMemoize
 
-      def track_event(event_name, send_snowplow_event: true, **kwargs)
+      def track_event(event_name, category: nil, send_snowplow_event: true, **kwargs)
         raise UnknownEventError, "Unknown event: #{event_name}" unless EventDefinitions.known_event?(event_name)
 
         validate_property!(kwargs, :user, User)
@@ -23,7 +23,7 @@ def track_event(event_name, send_snowplow_event: true, **kwargs)
         increase_total_counter(event_name)
         increase_weekly_total_counter(event_name)
         update_unique_counter(event_name, kwargs)
-        trigger_snowplow_event(event_name, kwargs) if send_snowplow_event
+        trigger_snowplow_event(event_name, category, kwargs) if send_snowplow_event
 
         if Feature.enabled?(:internal_events_for_product_analytics)
           send_application_instrumentation_event(event_name, kwargs)
@@ -76,7 +76,7 @@ def update_unique_counter(event_name, kwargs)
         UsageDataCounters::HLLRedisCounter.track_event(event_name, values: unique_value)
       end
 
-      def trigger_snowplow_event(event_name, kwargs)
+      def trigger_snowplow_event(event_name, category, kwargs)
         user = kwargs[:user]
         project = kwargs[:project]
         namespace = kwargs[:namespace]
@@ -93,11 +93,11 @@ def trigger_snowplow_event(event_name, kwargs)
           event: event_name
         ).to_context
 
-        track_struct_event(event_name, contexts: [standard_context, service_ping_context])
+        track_struct_event(event_name, category, contexts: [standard_context, service_ping_context])
       end
 
-      def track_struct_event(event_name, contexts:)
-        category = 'InternalEventTracking'
+      def track_struct_event(event_name, category, contexts:)
+        category ||= 'InternalEventTracking'
         tracker = Gitlab::Tracking.tracker
         tracker.event(category, event_name, context: contexts)
       rescue StandardError => error
diff --git a/scripts/internal_events/monitor.rb b/scripts/internal_events/monitor.rb
index e9ba1dbfbb7a..03f17ed257da 100644
--- a/scripts/internal_events/monitor.rb
+++ b/scripts/internal_events/monitor.rb
@@ -59,6 +59,7 @@ def extract_standard_context(event)
     next unless context['schema'].start_with?('iglu:com.gitlab/gitlab_standard/jsonschema')
 
     return {
+
       user_id: context["data"]["user_id"],
       namespace_id: context["data"]["namespace_id"],
       project_id: context["data"]["project_id"],
@@ -73,7 +74,7 @@ def generate_snowplow_table
   @initial_max_timestamp ||= events.map { |e| e['rawEvent']['parameters']['dtm'].to_i }.max || 0
 
   rows = []
-  rows << ['Event Name', 'Collector Timestamp', 'user_id', 'namespace_id', 'project_id', 'plan']
+  rows << ['Event Name', 'Collector Timestamp', 'Category', 'user_id', 'namespace_id', 'project_id', 'plan']
   rows << :separator
 
   events.each do |event|
@@ -82,6 +83,7 @@ def generate_snowplow_table
     row = [
       event['event']['se_action'],
       event['event']['collector_tstamp'],
+      event['event']['se_category'],
       standard_context[:user_id],
       standard_context[:namespace_id],
       standard_context[:project_id],
diff --git a/spec/lib/gitlab/internal_events_spec.rb b/spec/lib/gitlab/internal_events_spec.rb
index 7ac583b24ce6..4e475cf9a1d6 100644
--- a/spec/lib/gitlab/internal_events_spec.rb
+++ b/spec/lib/gitlab/internal_events_spec.rb
@@ -51,8 +51,8 @@ def expect_snowplow_tracking(expected_namespace = nil)
     expect(SnowplowTracker::SelfDescribingJson).to have_received(:new)
       .with(service_ping_context[:schema], service_ping_context[:data]).at_least(:once)
 
-    expect(fake_snowplow).to have_received(:event) do |category, provided_event_name, args|
-      expect(category).to eq('InternalEventTracking')
+    expect(fake_snowplow).to have_received(:event) do |provided_category, provided_event_name, args|
+      expect(provided_category).to eq(category)
       expect(provided_event_name).to eq(event_name)
 
       contexts = args[:context]&.map(&:to_json)
@@ -92,6 +92,7 @@ def validate_service_ping_context(service_ping_context)
   let(:redis) { instance_double('Redis') }
   let(:fake_snowplow) { instance_double(Gitlab::Tracking::Destinations::Snowplow) }
   let(:event_name) { 'g_edit_by_web_ide' }
+  let(:category) { 'InternalEventTracking' }
   let(:unique_property) { :user }
   let(:unique_value) { user.id }
   let(:redis_arguments) { [event_name, Date.today.strftime('%G-%V')] }
@@ -134,6 +135,16 @@ def validate_service_ping_context(service_ping_context)
     end
   end
 
+  context 'when category is passed' do
+    let(:category) { 'SomeCategory' }
+
+    it 'is sent to Snowplow' do
+      described_class.track_event(event_name, category: category, user: user, project: project)
+
+      expect_snowplow_tracking
+    end
+  end
+
   context 'when arguments are invalid' do
     context 'when user is not an instance of User' do
       let(:user) { 'a_string' }
-- 
GitLab