Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api/error_tracking/collector.rb')
-rw-r--r--lib/api/error_tracking/collector.rb135
1 files changed, 135 insertions, 0 deletions
diff --git a/lib/api/error_tracking/collector.rb b/lib/api/error_tracking/collector.rb
new file mode 100644
index 00000000000..22fbd3a1118
--- /dev/null
+++ b/lib/api/error_tracking/collector.rb
@@ -0,0 +1,135 @@
+# frozen_string_literal: true
+
+module API
+ # This API is responsible for collecting error tracking information
+ # from sentry client. It allows us to use GitLab as an alternative to
+ # sentry backend. For more details see https://gitlab.com/gitlab-org/gitlab/-/issues/329596.
+ class ErrorTracking::Collector < ::API::Base
+ feature_category :error_tracking
+
+ content_type :envelope, 'application/x-sentry-envelope'
+ content_type :json, 'application/json'
+ content_type :txt, 'text/plain'
+ default_format :envelope
+
+ before do
+ not_found!('Project') unless project
+ not_found! unless feature_enabled?
+ not_found! unless active_client_key?
+ end
+
+ helpers do
+ def project
+ @project ||= find_project(params[:id])
+ end
+
+ def feature_enabled?
+ project.error_tracking_setting&.enabled? &&
+ project.error_tracking_setting&.integrated_client?
+ end
+
+ def find_client_key(public_key)
+ return unless public_key.present?
+
+ project.error_tracking_client_keys.active.find_by_public_key(public_key)
+ end
+
+ def active_client_key?
+ public_key = extract_public_key
+
+ find_client_key(public_key)
+ end
+
+ def extract_public_key
+ # Some SDK send public_key as a param. In this case we don't need to parse headers.
+ return params[:sentry_key] if params[:sentry_key].present?
+
+ begin
+ ::ErrorTracking::Collector::SentryAuthParser.parse(request)[:public_key]
+ rescue StandardError
+ bad_request!('Failed to parse sentry request')
+ end
+ end
+ end
+
+ desc 'Submit error tracking event to the project as envelope' do
+ detail 'This feature was introduced in GitLab 14.1.'
+ end
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ post 'error_tracking/collector/api/:id/envelope' do
+ # There is a reason why we have such uncommon path.
+ # We depend on a client side error tracking software which
+ # modifies URL for its own reasons.
+ #
+ # When we give user a URL like this
+ # HOST/api/v4/error_tracking/collector/123
+ #
+ # Then error tracking software will convert it like this:
+ # HOST/api/v4/error_tracking/collector/api/123/envelope/
+
+ begin
+ parsed_request = ::ErrorTracking::Collector::SentryRequestParser.parse(request)
+ rescue StandardError
+ bad_request!('Failed to parse sentry request')
+ end
+
+ type = parsed_request[:request_type]
+
+ # Sentry sends 2 requests on each exception: transaction and event.
+ # Everything else is not a desired behavior.
+ unless type == 'transaction' || type == 'event'
+ render_api_error!('400 Bad Request', 400)
+
+ break
+ end
+
+ # We don't have use for transaction request yet,
+ # so we record only event one.
+ if type == 'event'
+ ::ErrorTracking::CollectErrorService
+ .new(project, nil, event: parsed_request[:event])
+ .execute
+ end
+
+ # Collector should never return any information back.
+ # Because DSN and public key are designed for public use,
+ # it is safe only for submission of new events.
+ no_content!
+ end
+
+ desc 'Submit error tracking event to the project' do
+ detail 'This feature was introduced in GitLab 14.1.'
+ end
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ post 'error_tracking/collector/api/:id/store' do
+ # There is a reason why we have such uncommon path.
+ # We depend on a client side error tracking software which
+ # modifies URL for its own reasons.
+ #
+ # When we give user a URL like this
+ # HOST/api/v4/error_tracking/collector/123
+ #
+ # Then error tracking software will convert it like this:
+ # HOST/api/v4/error_tracking/collector/api/123/store/
+
+ begin
+ parsed_body = Gitlab::Json.parse(request.body.read)
+ rescue StandardError
+ bad_request!('Failed to parse sentry request')
+ end
+
+ ::ErrorTracking::CollectErrorService
+ .new(project, nil, event: parsed_body)
+ .execute
+
+ # Collector should never return any information back.
+ # Because DSN and public key are designed for public use,
+ # it is safe only for submission of new events.
+ no_content!
+ end
+ end
+end