diff options
Diffstat (limited to 'lib/gitlab/alerting')
-rw-r--r-- | lib/gitlab/alerting/alert.rb | 167 | ||||
-rw-r--r-- | lib/gitlab/alerting/alert_annotation.rb | 11 |
2 files changed, 178 insertions, 0 deletions
diff --git a/lib/gitlab/alerting/alert.rb b/lib/gitlab/alerting/alert.rb new file mode 100644 index 00000000000..531307b93d4 --- /dev/null +++ b/lib/gitlab/alerting/alert.rb @@ -0,0 +1,167 @@ +# 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 diff --git a/lib/gitlab/alerting/alert_annotation.rb b/lib/gitlab/alerting/alert_annotation.rb new file mode 100644 index 00000000000..a4b3a97b08c --- /dev/null +++ b/lib/gitlab/alerting/alert_annotation.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Gitlab + module Alerting + class AlertAnnotation + include ActiveModel::Model + + attr_accessor :label, :value + end + end +end |