168 lines
3.8 KiB
Ruby
168 lines
3.8 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
module Gitlab
|
||
|
module Alerting
|
||
|
class Alert
|
||
|
include ActiveModel::Model
|
||
|
include Gitlab::Utils::StrongMemoize
|
||
|
include Presentable
|
||
|
|
||
|
attr_accessor :project, :payload
|
||
|
|
||
|
def gitlab_alert
|
||
|
strong_memoize(:gitlab_alert) do
|
||
|
parse_gitlab_alert_from_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def metric_id
|
||
|
strong_memoize(:metric_id) do
|
||
|
payload&.dig('labels', 'gitlab_alert_id')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def title
|
||
|
strong_memoize(:title) do
|
||
|
gitlab_alert&.title || parse_title_from_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def description
|
||
|
strong_memoize(:description) do
|
||
|
parse_description_from_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def environment
|
||
|
strong_memoize(:environment) do
|
||
|
gitlab_alert&.environment || parse_environment_from_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def annotations
|
||
|
strong_memoize(:annotations) do
|
||
|
parse_annotations_from_payload || []
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def starts_at
|
||
|
strong_memoize(:starts_at) do
|
||
|
parse_datetime_from_payload('startsAt')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def starts_at_raw
|
||
|
strong_memoize(:starts_at_raw) do
|
||
|
payload&.dig('startsAt')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def ends_at
|
||
|
strong_memoize(:ends_at) do
|
||
|
parse_datetime_from_payload('endsAt')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def full_query
|
||
|
strong_memoize(:full_query) do
|
||
|
gitlab_alert&.full_query || parse_expr_from_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def alert_markdown
|
||
|
strong_memoize(:alert_markdown) do
|
||
|
parse_alert_markdown_from_payload
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def status
|
||
|
strong_memoize(:status) do
|
||
|
payload&.dig('status')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def firing?
|
||
|
status == 'firing'
|
||
|
end
|
||
|
|
||
|
def resolved?
|
||
|
status == 'resolved'
|
||
|
end
|
||
|
|
||
|
def gitlab_managed?
|
||
|
metric_id.present?
|
||
|
end
|
||
|
|
||
|
def valid?
|
||
|
payload.respond_to?(:dig) && project && title && starts_at
|
||
|
end
|
||
|
|
||
|
def present
|
||
|
super(presenter_class: Projects::Prometheus::AlertPresenter)
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def parse_environment_from_payload
|
||
|
environment_name = payload&.dig('labels', 'gitlab_environment_name')
|
||
|
|
||
|
return unless environment_name
|
||
|
|
||
|
EnvironmentsFinder.new(project, nil, { name: environment_name })
|
||
|
.find
|
||
|
&.first
|
||
|
end
|
||
|
|
||
|
def parse_gitlab_alert_from_payload
|
||
|
return unless metric_id
|
||
|
|
||
|
Projects::Prometheus::AlertsFinder
|
||
|
.new(project: project, metric: metric_id)
|
||
|
.execute
|
||
|
.first
|
||
|
end
|
||
|
|
||
|
def parse_title_from_payload
|
||
|
payload&.dig('annotations', 'title') ||
|
||
|
payload&.dig('annotations', 'summary') ||
|
||
|
payload&.dig('labels', 'alertname')
|
||
|
end
|
||
|
|
||
|
def parse_description_from_payload
|
||
|
payload&.dig('annotations', 'description')
|
||
|
end
|
||
|
|
||
|
def parse_annotations_from_payload
|
||
|
payload&.dig('annotations')&.map do |label, value|
|
||
|
Alerting::AlertAnnotation.new(label: label, value: value)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def parse_datetime_from_payload(field)
|
||
|
value = payload&.dig(field)
|
||
|
return unless value
|
||
|
|
||
|
Time.rfc3339(value)
|
||
|
rescue ArgumentError
|
||
|
end
|
||
|
|
||
|
# Parses `g0.expr` from `generatorURL`.
|
||
|
#
|
||
|
# Example: http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1
|
||
|
def parse_expr_from_payload
|
||
|
url = payload&.dig('generatorURL')
|
||
|
return unless url
|
||
|
|
||
|
uri = URI(url)
|
||
|
|
||
|
Rack::Utils.parse_query(uri.query).fetch('g0.expr')
|
||
|
rescue URI::InvalidURIError, KeyError
|
||
|
end
|
||
|
|
||
|
def parse_alert_markdown_from_payload
|
||
|
payload&.dig('annotations', 'gitlab_incident_markdown')
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|