Skip to content

[Step 1] Update Gitlab::UsageDataCounters::TrackUniqueActions to track new actions

In !35580 (merged), the service module Gitlab::UsageDataCounters::TrackUniqueActions was introduced to track events that later will be consumed by Usage Data.

Nevertheless, this service class is very tight to the Event model to a point in which it validates that the action to track is a valid action defined in that model.

The actions we want to track are quite particular since we don't create a real Event when the action is executed. Specifically, we want to track when a commit is performed:

  • Through the web IDE
  • Through the Single File Editor
  • Through the Snippets editor

Therefore, we cannot fully rely on the Gitlab::UsageDataCounters::TrackUniqueActions service class because we need a custom set of actions and a payload that is different from the existing behavior.

That's why I'd proposed to create a service class named like Gitlab::UsageDataCounters::TrackUniqueVirtualActions that would extend the Gitlab::UsageDataCounters::TrackUniqueActions module.

This new service could be something like:

module Gitlab
  module UsageDataCounters
    module TrackUniqueVirtualActions
      VIRTUAL_ACTIONS = %i[edit_by_web_ide edit_by_sfe edit_by_snippet_editor]

      class << self
        def track_action(event_action:, author_id:, time: Time.zone.now)
          return unless Gitlab::CurrentSettings.usage_ping_enabled
          return unless Feature.enabled?(FEATURE_FLAG)          
          return unless valid_action?(event_action)
          
          target_key = key(event_action, time)

          Gitlab::Redis::HLL.add(key: target_key, value: author_id, expiry: KEY_EXPIRY_LENGTH)
        end

        def count_unique_events(event_action:, date_from:, date_to:)
          keys = (date_from.to_date..date_to.to_date).map { |date| key(event_action, date) }

          Gitlab::Redis::HLL.count(keys: keys)
        end

        private                      

        def valid_action?(action)
          VIRTUAL_ACTIONS.key?(action)
        end

        def key(event_action, date)
          year_day = date.strftime('%G-%j')
          "#{year_day}-{#{event_action}}"
        end
      end
    end
  end
end

This is a quick approach to what would we need to achieve. We would need to think more about the action names and whether it's the best way for reusing it with other events.

Basically, this way we can store unique events related to virtual actions, we just need to figure out the programming nuances.

Edited by Francisco Javier López