FEATURE: Add firing count to topic titles, and bump when count changes

FEATURE: Add firing count to topic titles, and bump when count changes

diff --git a/app/jobs/concerns/alert_post_mixin.rb b/app/jobs/concerns/alert_post_mixin.rb
index 0c19e21..017754b 100644
--- a/app/jobs/concerns/alert_post_mixin.rb
+++ b/app/jobs/concerns/alert_post_mixin.rb
@@ -115,6 +115,15 @@ module AlertPostMixin
     "[Previous alert](#{Discourse.base_url}/t/#{topic_id}) #{local_date(created_at.to_s)}\n\n"
   end
 
+  def generate_title(base_title, alert_history)
+    firing_count = alert_history&.count { |alert| is_firing?(alert["status"]) }
+    if firing_count > 0
+      I18n.t("prom_alert_receiver.topic_title.firing", base_title: base_title, count: firing_count)
+    else
+      I18n.t("prom_alert_receiver.topic_title.not_firing", base_title: base_title)
+    end
+  end
+
   def first_post_body(receiver:,
                       topic_body: "",
                       alert_history:,
@@ -162,6 +171,10 @@ module AlertPostMixin
         skip_validations: true,
         validate_topic: true # This is a very weird API
       )
+      if firing && title_changed
+        topic.update_column(:bumped_at, Time.now)
+        TopicTrackingState.publish_latest(topic)
+      end
     end
   end
 
diff --git a/app/jobs/regular/process_alert.rb b/app/jobs/regular/process_alert.rb
index 798bb28..74cb354 100644
--- a/app/jobs/regular/process_alert.rb
+++ b/app/jobs/regular/process_alert.rb
@@ -47,9 +47,11 @@ module Jobs
           prev_topic_id: topic.custom_fields[::DiscoursePrometheusAlertReceiver::PREVIOUS_TOPIC_CUSTOM_FIELD]
         )
 
-        title = params["commonAnnotations"]["topic_title"] ||
+        base_title = params["commonAnnotations"]["topic_title"] ||
           "#{params["groupLabels"].to_hash.map { |k, v| "#{k}: #{v}" }.join(", ")}"
 
+        title = generate_title(base_title, alert_history)
+
         revise_topic(
           topic: topic,
           title: title,
@@ -84,9 +86,11 @@ module Jobs
     end
 
     def create_new_topic(receiver, params, alert_history)
-      topic_title = params["commonAnnotations"]["topic_title"] ||
+      base_title = params["commonAnnotations"]["topic_title"] ||
         "#{params["groupLabels"].to_hash.map { |k, v| "#{k}: #{v}" }.join(", ")}"
 
+      topic_title = generate_title(base_title, alert_history)
+
       datacenter = params["commonLabels"]["datacenter"]
       topic_body = params["commonAnnotations"]["topic_body"]
 
diff --git a/app/jobs/regular/process_grouped_alerts.rb b/app/jobs/regular/process_grouped_alerts.rb
index 3e0a8fe..ac187d4 100644
--- a/app/jobs/regular/process_grouped_alerts.rb
+++ b/app/jobs/regular/process_grouped_alerts.rb
@@ -119,7 +119,7 @@ module Jobs
 
                 revise_topic(
                   topic: topic,
-                  title: annotations["topic_title"],
+                  title: generate_title(annotations["topic_title"], stored_alerts),
                   raw: raw,
                   datacenters: datacenters(stored_alerts),
                   firing: stored_alerts.any? { |alert| is_firing?(alert["status"]) }
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index d39b524..958aa5d 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -10,3 +10,7 @@ en:
         firing: "Firing Alerts"
         history: "Alert History"
         stale: "Stale Alerts"
+    topic_title: 
+      not_firing: "%{base_title}"
+      firing: "%{base_title} (%{count} firing)"
+      
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 1327021..4768fdc 100644
--- a/spec/integration/discourse_prometheus_alert_receiver/receiver_controller_spec.rb
+++ b/spec/integration/discourse_prometheus_alert_receiver/receiver_controller_spec.rb
@@ -450,7 +450,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
           )
 
           expect(topic.title).to eq(
-            "Alert investigation required: AnAlert is on the loose"
+            "Alert investigation required: AnAlert is on the loose (1 firing)"
           )
 
           expect(receiver["topic_map"][alert_name]).to eq(topic.id)
@@ -510,7 +510,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
             post "/prometheus/receiver/#{token}", params: payload
           end.to change { Topic.count }.by(1)
 
-          expect(topic.title).to eq("foo: bar, baz: wombat")
+          expect(topic.title).to eq("foo: bar, baz: wombat (1 firing)")
 
           expect(topic.tags.pluck(:name)).to contain_exactly(
             datacenter,
@@ -591,7 +591,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
           expect(messages.first.data[:firing_alerts_count]).to eq(1)
 
           expect(topic.title).to eq(
-            "Alert investigation required: AnAlert is on the loose"
+            "Alert investigation required: AnAlert is on the loose (1 firing)"
           )
 
           expect(topic.tags.pluck(:name)).to contain_exactly(
@@ -692,7 +692,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
           topic.reload
 
           expect(topic.title).to eq(
-            "Alert investigation required: AnAlert is on the loose"
+            "Alert investigation required: AnAlert is on the loose (2 firing)"
           )
 
           expect(topic.tags.pluck(:name)).to contain_exactly(
@@ -730,6 +730,40 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
           expect(raw).to match(/newalert.*date=2020-12-31 time=23:59:59/)
         end
 
+        it "bumps the existing topic correctly" do
+          freeze_time(1.hour.from_now) do
+            expect do
+              post "/prometheus/receiver/#{token}", params: payload
+            end.to change { topic.reload.bumped_at }
+
+            expect(topic.reload.title).to eq(
+              "Alert investigation required: AnAlert is on the loose (2 firing)"
+            )
+          end
+
+          freeze_time(2.hours.from_now) do
+            payload["alerts"][0]["status"] = "stale"
+            expect do
+              post "/prometheus/receiver/#{token}", params: payload
+            end.to change { topic.reload.bumped_at }
+
+            expect(topic.reload.title).to eq(
+              "Alert investigation required: AnAlert is on the loose (1 firing)"
+            )
+          end
+
+          freeze_time(3.hours.from_now) do
+            payload["alerts"][1]["status"] = "stale"
+            expect do
+              post "/prometheus/receiver/#{token}", params: payload
+            end.to_not change { topic.reload.bumped_at }
+
+            expect(topic.reload.title).to eq(
+              "Alert investigation required: AnAlert is on the loose"
+            )
+          end
+        end
+
         describe 'from another datacenter' do
           let(:datacenter2) { "datacenter-2" }
           let(:external_url2) { "supposed.be.a.url.2" }
@@ -761,7 +795,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
             topic.reload
 
             expect(topic.title).to eq(
-              "Alert investigation required: AnAlert is on the loose"
+              "Alert investigation required: AnAlert is on the loose (2 firing)"
             )
 
             expect(topic.tags.pluck(:name)).to contain_exactly(
@@ -948,7 +982,7 @@ RSpec.describe DiscoursePrometheusAlertReceiver::ReceiverController do
           )
 
           expect(keyed_topic.title).to eq(
-            "Alert investigation required: AnAlert is on the loose"
+            "Alert investigation required: AnAlert is on the loose (1 firing)"
           )
 
           expect(keyed_topic.tags.pluck(:name)).to contain_exactly(

GitHub sha: 78b2c5d0

2 Likes