diff --git a/ee/config/feature_flags/experiment/ai_tracking_data_gathering.yml b/ee/config/feature_flags/experiment/ai_tracking_data_gathering.yml new file mode 100644 index 0000000000000000000000000000000000000000..4cf88435b6477f7edbf09803a93e573325411b36 --- /dev/null +++ b/ee/config/feature_flags/experiment/ai_tracking_data_gathering.yml @@ -0,0 +1,9 @@ +--- +name: ai_tracking_data_gathering +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/441485 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146918 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/454106 +milestone: '16.11' +group: group::optimize +type: experiment +default_enabled: false diff --git a/ee/lib/api/code_suggestions.rb b/ee/lib/api/code_suggestions.rb index b424bdb3d973394f2b07974a6cb55a3f5e4afa56..b1e09d1f1f254b2a483d8be27ca3d51d7501dc46 100644 --- a/ee/lib/api/code_suggestions.rb +++ b/ee/lib/api/code_suggestions.rb @@ -96,6 +96,7 @@ def saas_headers 'code_suggestions_requested', user: current_user ) + Gitlab::Tracking::AiTracking.track_event('code_suggestions_requested', user_id: current_user.id) workhorse_headers = Gitlab::Workhorse.send_url( diff --git a/ee/lib/gitlab/tracking/ai_tracking.rb b/ee/lib/gitlab/tracking/ai_tracking.rb new file mode 100644 index 0000000000000000000000000000000000000000..8659461b65c457a37c0749f1ecfd2698740205ac --- /dev/null +++ b/ee/lib/gitlab/tracking/ai_tracking.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Gitlab + module Tracking + module AiTracking + EVENTS = { + 'code_suggestions_requested' => 1 + }.freeze + + class << self + def track_event(event_name, context_hash = {}) + return unless Feature.enabled?(:ai_tracking_data_gathering) + + ::ClickHouse::WriteBuffer.write_event(context_hash.merge(event: EVENTS[event_name], timestamp: Time.zone.now)) + end + end + end + end +end diff --git a/ee/spec/lib/gitlab/tracking/ai_tracking_spec.rb b/ee/spec/lib/gitlab/tracking/ai_tracking_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..db75244c33a52149add73b32f7f594ef98bc05a0 --- /dev/null +++ b/ee/spec/lib/gitlab/tracking/ai_tracking_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Tracking::AiTracking, feature_category: :value_stream_management do + describe '.track_event', :freeze_time do + subject(:track_event) { described_class.track_event(event_name, event_context) } + + let(:event_context) { { user_id: 1, language: 'ruby' } } + let(:event_name) { 'code_suggestions_requested' } + + it 'writes to ClickHouse buffer with event data' do + expect(::ClickHouse::WriteBuffer) + .to receive(:write_event).with(event_context.merge(event: 1, timestamp: Time.zone.now)).once + + track_event + end + + context 'when :ai_tracking_data_gathering feature flag is disabled' do + before do + stub_feature_flags(ai_tracking_data_gathering: false) + end + + it 'does not write to ClickHouse buffer' do + expect(::ClickHouse::WriteBuffer).not_to receive(:write_event) + + track_event + end + end + end +end diff --git a/ee/spec/requests/api/code_suggestions_spec.rb b/ee/spec/requests/api/code_suggestions_spec.rb index 0526ab5cf0bea4d1a1923c281211467530da01ad..5b1f5135bf48f897de2e52158451fa74c0050141 100644 --- a/ee/spec/requests/api/code_suggestions_spec.rb +++ b/ee/spec/requests/api/code_suggestions_spec.rb @@ -30,6 +30,7 @@ .and_return(false) allow(Gitlab::InternalEvents).to receive(:track_event) + allow(Gitlab::Tracking::AiTracking).to receive(:track_event) end shared_examples 'a response' do |case_name| @@ -239,6 +240,14 @@ def request ) end + it 'tracks code_suggestions_requested ai event' do + post_api + + expect(Gitlab::Tracking::AiTracking) + .to have_received(:track_event) + .with('code_suggestions_requested', user_id: current_user.id) + end + context 'with telemetry headers' do let(:headers) do { @@ -394,8 +403,8 @@ def request let(:current_user) { authorized_user } let(:prefix) do <<~PREFIX - def is_even(n: int) -> - # A function that outputs the first 20 fibonacci numbers + def is_even(n: int) -> + # A function that outputs the first 20 fibonacci numbers PREFIX end @@ -550,8 +559,8 @@ def get_user(session): let(:current_user) { authorized_user } let(:prefix) do <<~PREFIX - def is_even(n: int) -> - # A function that outputs the first 20 fibonacci numbers + def is_even(n: int) -> + # A function that outputs the first 20 fibonacci numbers PREFIX end diff --git a/lib/click_house/write_buffer.rb b/lib/click_house/write_buffer.rb new file mode 100644 index 0000000000000000000000000000000000000000..691363d5509aa5f9db93f73da075af0560adfc3b --- /dev/null +++ b/lib/click_house/write_buffer.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module ClickHouse + module WriteBuffer + BUFFER_KEY = 'clickhouse_write_buffer' + + class << self + def write_event(event_hash) + Gitlab::Redis::SharedState.with do |redis| + redis.lpush(BUFFER_KEY, event_hash.to_json) + end + end + end + end +end diff --git a/spec/lib/click_house/write_buffer_spec.rb b/spec/lib/click_house/write_buffer_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..31a6f9caedc981f0c9a13ff9108d1f1e6f4b2bed --- /dev/null +++ b/spec/lib/click_house/write_buffer_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ClickHouse::WriteBuffer, :clean_gitlab_redis_shared_state, feature_category: :database do + describe '.write_event' do + subject(:write_event) { described_class.write_event(event_hash) } + + let(:event_hash) { { foo: 'bar' } } + + it 'saves ClickHouse event to Redis' do + expect do + write_event + end.to change { + Gitlab::Redis::SharedState.with do |redis| + redis.lrange(described_class::BUFFER_KEY, 0, 10) + end + }.from([]).to([event_hash.to_json]) + end + end +end