# 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