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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
# frozen_string_literal: true
module Gitlab
module AlertManagement
module Payload
# Attribute mapping for alerts via prometheus alerting integration.
class Prometheus < Base
attribute :alert_markdown, paths: %w(annotations gitlab_incident_markdown)
attribute :annotations, paths: 'annotations'
attribute :description, paths: %w(annotations description)
attribute :ends_at, paths: 'endsAt', type: :time
attribute :environment_name, paths: %w(labels gitlab_environment_name)
attribute :generator_url, paths: %w(generatorURL)
attribute :gitlab_y_label,
paths: [%w(annotations gitlab_y_label),
%w(annotations title),
%w(annotations summary),
%w(labels alertname)]
attribute :runbook, paths: %w(annotations runbook)
attribute :starts_at,
paths: 'startsAt',
type: :time,
fallback: -> { Time.current.utc }
attribute :status, paths: 'status'
attribute :title,
paths: [%w(annotations title),
%w(annotations summary),
%w(labels alertname)]
attribute :starts_at_raw,
paths: [%w(startsAt)]
private :starts_at_raw
attribute :severity_raw, paths: %w(labels severity)
private :severity_raw
METRIC_TIME_WINDOW = 30.minutes
SEVERITY_MAP = {
'critical' => :critical,
'high' => :high,
'medium' => :medium,
'low' => :low,
'info' => :info,
's1' => :critical,
's2' => :high,
's3' => :medium,
's4' => :low,
's5' => :info,
'p1' => :critical,
'p2' => :high,
'p3' => :medium,
'p4' => :low,
'p5' => :info,
'debug' => :info,
'information' => :info,
'notice' => :info,
'warn' => :low,
'warning' => :low,
'minor' => :low,
'error' => :medium,
'major' => :high,
'emergency' => :critical,
'fatal' => :critical,
'alert' => :medium,
'page' => :high
}.freeze
# Handle an unmapped severity value the same way we treat missing values
# so we can fallback to alert's default severity `critical`.
UNMAPPED_SEVERITY = nil
def monitoring_tool
Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
end
# Parses `g0.expr` from `generatorURL`.
#
# Example: http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1
def full_query
return unless generator_url
uri = URI(generator_url)
Rack::Utils.parse_query(uri.query).fetch('g0.expr')
rescue URI::InvalidURIError, KeyError
end
def metrics_dashboard_url
return unless environment && full_query && title
metrics_dashboard_project_environment_url(
project,
environment,
embed_json: dashboard_json,
embedded: true,
**alert_embed_window_params
)
end
def has_required_attributes?
project && title && starts_at_raw
end
def severity
return unless severity_raw
SEVERITY_MAP.fetch(severity_raw.to_s.downcase, UNMAPPED_SEVERITY)
end
private
def plain_gitlab_fingerprint
[starts_at_raw, title, full_query].join('/')
end
# Formatted for parsing by JS
def alert_embed_window_params
{
start: (starts_at - METRIC_TIME_WINDOW).utc.strftime('%FT%TZ'),
end: (starts_at + METRIC_TIME_WINDOW).utc.strftime('%FT%TZ')
}
end
def dashboard_json
{
panel_groups: [{
panels: [{
type: 'area-chart',
title: title,
y_label: gitlab_y_label,
metrics: [{
query_range: full_query
}]
}]
}]
}.to_json
end
end
end
end
end
|