summaryrefslogtreecommitdiff
path: root/lib/product_analytics
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-17 00:09:37 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-17 00:09:37 +0000
commitd5cf5cf4f77eec07a04604b1a0298452029df16f (patch)
tree7fafba2450f0cc0160fbacfbd94a0b11ab47dc12 /lib/product_analytics
parent831b6108d2aa46aca9bdce39a9bda33718d61fa7 (diff)
downloadgitlab-ce-d5cf5cf4f77eec07a04604b1a0298452029df16f.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/product_analytics')
-rw-r--r--lib/product_analytics/collector_app.rb40
-rw-r--r--lib/product_analytics/event_params.rb51
2 files changed, 91 insertions, 0 deletions
diff --git a/lib/product_analytics/collector_app.rb b/lib/product_analytics/collector_app.rb
new file mode 100644
index 00000000000..cf971eef4b6
--- /dev/null
+++ b/lib/product_analytics/collector_app.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module ProductAnalytics
+ class CollectorApp
+ def call(env)
+ request = Rack::Request.new(env)
+ params = request.params
+
+ return not_found unless EventParams.has_required_params?(params)
+
+ # Product analytics feature is behind a flag and is disabled by default.
+ # We expect limited amount of projects with this feature enabled in first release.
+ # Since collector has no authentication we temporary prevent recording of events
+ # for project without the feature enabled. During increase of feature adoption, this
+ # check will be removed for better performance.
+ project = Project.find(params['aid'].to_i)
+ return not_found unless Feature.enabled?(:product_analytics, project, default_enabled: false)
+
+ # Snowplow tracker has own format of events.
+ # We need to convert them to match the schema of our database.
+ event_params = EventParams.parse_event_params(params)
+
+ if ProductAnalyticsEvent.create(event_params)
+ ok
+ else
+ not_found
+ end
+ rescue ActiveRecord::InvalidForeignKey, ActiveRecord::RecordNotFound
+ not_found
+ end
+
+ def ok
+ [200, {}, []]
+ end
+
+ def not_found
+ [404, {}, []]
+ end
+ end
+end
diff --git a/lib/product_analytics/event_params.rb b/lib/product_analytics/event_params.rb
new file mode 100644
index 00000000000..d938fe1f594
--- /dev/null
+++ b/lib/product_analytics/event_params.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module ProductAnalytics
+ # Converts params from Snowplow tracker to one compatible with
+ # GitLab ProductAnalyticsEvent model. The field naming corresponds
+ # with snowplow event model. Only project_id is GitLab specific.
+ #
+ # For information on what each field is you can check next resources:
+ # * Snowplow tracker protocol: https://github.com/snowplow/snowplow/wiki/snowplow-tracker-protocol
+ # * Canonical event model: https://github.com/snowplow/snowplow/wiki/canonical-event-model
+ class EventParams
+ def self.parse_event_params(params)
+ {
+ project_id: params['aid'],
+ platform: params['p'],
+ collector_tstamp: Time.zone.now,
+ event_id: params['eid'],
+ v_tracker: params['tv'],
+ v_collector: Gitlab::VERSION,
+ v_etl: Gitlab::VERSION,
+ os_timezone: params['tz'],
+ name_tracker: params['tna'],
+ br_lang: params['lang'],
+ doc_charset: params['cs'],
+ br_features_pdf: Gitlab::Utils.to_boolean(params['f_pdf']),
+ br_features_flash: Gitlab::Utils.to_boolean(params['f_fla']),
+ br_features_java: Gitlab::Utils.to_boolean(params['f_java']),
+ br_features_director: Gitlab::Utils.to_boolean(params['f_dir']),
+ br_features_quicktime: Gitlab::Utils.to_boolean(params['f_qt']),
+ br_features_realplayer: Gitlab::Utils.to_boolean(params['f_realp']),
+ br_features_windowsmedia: Gitlab::Utils.to_boolean(params['f_wma']),
+ br_features_gears: Gitlab::Utils.to_boolean(params['f_gears']),
+ br_features_silverlight: Gitlab::Utils.to_boolean(params['f_ag']),
+ br_colordepth: params['cd'],
+ br_cookies: Gitlab::Utils.to_boolean(params['cookie']),
+ dvce_created_tstamp: params['dtm'],
+ br_viewheight: params['vp'],
+ domain_sessionidx: params['vid'],
+ domain_sessionid: params['sid'],
+ domain_userid: params['duid'],
+ user_fingerprint: params['fp'],
+ page_referrer: params['refr'],
+ page_url: params['url']
+ }
+ end
+
+ def self.has_required_params?(params)
+ params['aid'].present? && params['eid'].present?
+ end
+ end
+end