1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# frozen_string_literal: true
module Gitlab
module ErrorTracking
class ErrorRepository
class ActiveRecordStrategy
def initialize(project)
@project = project
end
def report_error(
name:, description:, actor:, platform:,
environment:, level:, occurred_at:, payload:
)
error = project_errors.report_error(
name: name, # Example: ActionView::MissingTemplate
description: description, # Example: Missing template posts/show in...
actor: actor, # Example: PostsController#show
platform: platform, # Example: ruby
timestamp: occurred_at
)
# The payload field contains all the data on error including stacktrace in jsonb.
# Together with occurred_at these are 2 main attributes that we need to save here.
error.events.create!(
environment: environment,
description: description,
level: level,
occurred_at: occurred_at,
payload: payload
)
rescue ActiveRecord::ActiveRecordError => e
handle_exceptions(e)
end
def find_error(id)
project_error(id).to_sentry_detailed_error
rescue ActiveRecord::ActiveRecordError => e
handle_exceptions(e)
end
def list_errors(filters:, sort:, limit:, cursor:)
errors = project_errors
errors = filter_by_status(errors, filters[:status])
errors = sort(errors, sort)
errors = errors.keyset_paginate(cursor: cursor, per_page: limit)
pagination = ErrorRepository::Pagination.new(errors.cursor_for_next_page, errors.cursor_for_previous_page)
[errors.map(&:to_sentry_error), pagination]
end
def last_event_for(id)
project_error(id).last_event&.to_sentry_error_event
rescue ActiveRecord::ActiveRecordError => e
handle_exceptions(e)
end
def update_error(id, **attributes)
project_error(id).update(attributes)
end
private
attr_reader :project
def project_errors
::ErrorTracking::Error.where(project: project) # rubocop:disable CodeReuse/ActiveRecord
end
def project_error(id)
project_errors.find(id)
end
def filter_by_status(errors, status)
return errors unless ::ErrorTracking::Error.statuses.key?(status)
errors.for_status(status)
end
def sort(errors, sort)
return errors.order_id_desc unless sort
errors.sort_by_attribute(sort)
end
def handle_exceptions(exception)
case exception
when ActiveRecord::RecordInvalid
raise RecordInvalidError, exception.message
else
raise DatabaseError, exception.message
end
end
end
end
end
end
|