Add a link to grafana dashboard with time range filter.

Add a link to grafana dashboard with time range filter.

diff --git a/app/controllers/discourse_prometheus_alert_receiver/receiver_controller.rb b/app/controllers/discourse_prometheus_alert_receiver/receiver_controller.rb
index 4c1cdf1..1c7fa48 100644
--- a/app/controllers/discourse_prometheus_alert_receiver/receiver_controller.rb
+++ b/app/controllers/discourse_prometheus_alert_receiver/receiver_controller.rb
@@ -69,7 +69,8 @@ module DiscoursePrometheusAlertReceiver
         token: @token,
         data: params[:data].to_json,
         graph_url: params[:graphURL],
-        logs_url: params[:logsURL]
+        logs_url: params[:logsURL],
+        grafana_url: params[:grafanaURL]
       )
 
       render json: success_json
diff --git a/app/jobs/concerns/alert_post_mixin.rb b/app/jobs/concerns/alert_post_mixin.rb
index a126039..f15973b 100644
--- a/app/jobs/concerns/alert_post_mixin.rb
+++ b/app/jobs/concerns/alert_post_mixin.rb
@@ -78,7 +78,13 @@ module AlertPostMixin
       item += " #{description} |"
     end
 
-    item += " [:file_folder:](#{logs_link(alert)}) |"
+    link = logs_link(alert)
+    item += " [:file_folder:](#{link})" if link.present?
+
+    link = grafana_link(alert)
+    item += " [:bar_chart:](#{link})" if link.present?
+
+    item += " |"
 
     item
   end
@@ -116,6 +122,8 @@ module AlertPostMixin
   end
 
   def logs_link(alert)
+    return if alert['logs_url'].blank?
+
     url = "#{alert['logs_url']}#/discover"
     begin_t = Time.parse(alert['starts_at'])
     end_t   = Time.parse(alert['ends_at']) rescue Time.zone.now
@@ -123,6 +131,29 @@ module AlertPostMixin
     "#{url}?_g=(time:(from:'#{begin_t.to_s(:iso8601)}',mode:absolute,to:'#{end_t.to_s(:iso8601)}'))"
   end
 
+  def grafana_link(alert)
+    return if alert['grafana_url'].blank?
+
+    url = URI(alert['grafana_url'])
+    url_params = CGI.parse(url.query || "")
+
+    begin_t = Time.parse(alert['starts_at'])
+    end_t   = Time.parse(alert['ends_at']) rescue Time.zone.now
+    url_params['from'] = "#{begin_t.to_i}000"
+    url_params['to'] = "#{end_t.to_i}000"
+    url.query = URI.encode_www_form(url_params)
+    url.to_s
+  end
+
+  def get_grafana_dashboard_url(alert, grafana_url)
+    return if grafana_url.blank?
+
+    dashboard_path = alert.dig('annotations', 'grafana_dashboard_path')
+    return if dashboard_path.blank?
+
+    "#{grafana_url}#{dashboard_path}"
+  end
+
   def prev_topic_link(topic_id)
     return "" if topic_id.nil?
     created_at = Topic.where(id: topic_id).pluck(:created_at).first
diff --git a/app/jobs/regular/process_alert.rb b/app/jobs/regular/process_alert.rb
index 7a08d82..192be02 100644
--- a/app/jobs/regular/process_alert.rb
+++ b/app/jobs/regular/process_alert.rb
@@ -39,7 +39,9 @@ module Jobs
 
         alert_history = update_alert_history(prev_alert_history, params["alerts"],
           datacenter: params["commonLabels"]["datacenter"],
-          external_url: params["externalURL"]
+          external_url: params["externalURL"],
+          logs_url: params["logsURL"],
+          grafana_url: params["grafanaURL"]
         )
 
         raw = first_post_body(
@@ -70,7 +72,9 @@ module Jobs
       else
         alert_history = update_alert_history([], params["alerts"],
           datacenter: params["commonLabels"]["datacenter"],
-          external_url: params["externalURL"]
+          external_url: params["externalURL"],
+          logs_url: params["logsURL"],
+          grafana_url: params["grafanaURL"]
         )
 
         topic = create_new_topic(receiver, params, alert_history)
@@ -193,7 +197,9 @@ module Jobs
 
     def update_alert_history(previous_history, active_alerts,
                              datacenter:,
-                             external_url:)
+                             external_url:,
+                             logs_url:,
+                             grafana_url:)
 
       # Sadly, this is the easiest way to get a deep dup
       JSON.parse(previous_history.to_json).tap do |new_history|
@@ -206,6 +212,7 @@ module Jobs
           end
 
           alert_description = alert.dig('annotations', 'description')
+          grafana_dashboard_url = get_grafana_dashboard_url(alert, grafana_url)
           firing = is_firing?(alert['status'])
 
           if stored_alert.nil? && firing
@@ -218,6 +225,8 @@ module Jobs
               'datacenter' => datacenter,
               'external_url' => external_url
             }
+            stored_alert['logs_url'] = logs_url if logs_url.present?
+            stored_alert['grafana_url'] = grafana_dashboard_url if grafana_dashboard_url.present?
 
             new_history << stored_alert
           elsif stored_alert
@@ -226,6 +235,8 @@ module Jobs
             stored_alert['datacenter'] = datacenter
             stored_alert['external_url'] = external_url
             stored_alert.delete('ends_at') if firing
+            stored_alert['logs_url'] = logs_url if logs_url.present?
+            stored_alert['grafana_url'] = grafana_dashboard_url if grafana_dashboard_url.present?
           end
 
           if alert['status'] == "resolved" && stored_alert && stored_alert['ends_at'].nil?
diff --git a/app/jobs/regular/process_grouped_alerts.rb b/app/jobs/regular/process_grouped_alerts.rb
index 487a89f..dfd1344 100644
--- a/app/jobs/regular/process_grouped_alerts.rb
+++ b/app/jobs/regular/process_grouped_alerts.rb
@@ -11,8 +11,6 @@ module Jobs
     def execute(args)
       token = args[:token]
       data = JSON.parse(args[:data])
-      graph_url = args[:graph_url]
-      logs_url = args[:logs_url]
 
       receiver = PluginStore.get(
         ::DiscoursePrometheusAlertReceiver::PLUGIN_NAME,
@@ -27,7 +25,7 @@ module Jobs
         current_alerts = data
       end
 
-      update_open_alerts(receiver, current_alerts, graph_url, logs_url)
+      update_open_alerts(receiver, current_alerts, args.slice(:graph_url, :logs_url, :grafana_url))
     end
 
     private
@@ -55,7 +53,7 @@ module Jobs
       status
     end
 
-    def update_open_alerts(receiver, active_alerts, graph_url, logs_url)
+    def update_open_alerts(receiver, active_alerts, opts)
       Topic.open_alerts.each do |topic|
         DistributedMutex.synchronize("prom_alert_receiver_topic_#{topic.id}") do
           alertname = receiver["topic_map"].key(topic.id)
@@ -65,11 +63,14 @@ module Jobs
           updated = false
 
           stored_alerts&.each do |stored_alert|
-            stored_alert['logs_url'] ||= logs_url if logs_url.present?
+            stored_alert['logs_url'] ||= opts[:logs_url] if opts[:logs_url].present?
 
-            if stored_alert['graph_url'].include?(graph_url) && stored_alert['status'] != 'resolved'
+            if stored_alert['graph_url'].include?(opts[:graph_url]) && stored_alert['status'] != 'resolved'
               active_alert = active_alerts.find { |a| a['labels']['id'] == stored_alert['id'] && a['labels']['alertname'] == alertname }
 
+              grafana_dashboard_url = get_grafana_dashboard_url(active_alert, opts[:grafana_url])
+              stored_alert['grafana_url'] = grafana_dashboard_url if grafana_dashboard_url.present?
+
               if !active_alert && stored_alert["status"] != "stale" &&
                   STALE_DURATION.minute.ago > DateTime.parse(stored_alert["starts_at"])
                 stored_alert["status"] = "stale"
diff --git a/spec/integration/discourse_prometheus_alert_receiver/receiver_controller_spec.rb b/spec/integration/discourse_prometheus_alert_receiver/receiver_controller_spec.rb
index b68bae1..457d217 100644
--- a/spec/integration/discourse_prometheus_alert_receiver/receiver_controller_spec.rb
+++ b/spec/integration/discourse_prometheus_alert_receiver/receiver_controller_spec.rb
@@ -884,6 +884,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
                 'starts_at' => "2020-01-02T03:04:05.12345678Z",
                 'graph_url' => "http://alerts.example.com/graph?g0.expr=lolrus",
                 'logs_url' => "http://logs.example.com/app",
+                'grafana_url' => "http://graphs.example.com/d/xyzabcefg",

[... diff too long, it was truncated ...]

GitHub sha: c3dd088a

1 Like