From a8734370b8ac0579a71ffc441b8b4501c9bf4c6b Mon Sep 17 00:00:00 2001 From: Karan Sharma Date: Wed, 13 Mar 2024 11:10:30 +0530 Subject: [PATCH] feat: make threaded replies optional fixes https://github.com/mr-karan/calert/issues/74 --- cmd/init.go | 21 ++++----- config.sample.toml | 2 + internal/providers/google_chat/google_chat.go | 43 ++++++++++--------- internal/providers/google_chat/message.go | 9 +++- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/cmd/init.go b/cmd/init.go index ce6d6a5..622cee6 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -95,16 +95,17 @@ func initProviders(ko *koanf.Koanf, lo *slog.Logger, metrics *metrics.Manager) ( case "google_chat": gchat, err := google_chat.NewGoogleChat( google_chat.GoogleChatOpts{ - Log: lo, - Timeout: ko.MustDuration(fmt.Sprintf("%s.timeout", cfgKey)), - MaxIdleConn: ko.MustInt(fmt.Sprintf("%s.max_idle_conns", cfgKey)), - ProxyURL: ko.String(fmt.Sprintf("%s.proxy_url", cfgKey)), - Endpoint: ko.MustString(fmt.Sprintf("%s.endpoint", cfgKey)), - Room: name, - Template: ko.MustString(fmt.Sprintf("%s.template", cfgKey)), - ThreadTTL: ko.MustDuration(fmt.Sprintf("%s.thread_ttl", cfgKey)), - Metrics: metrics, - DryRun: ko.Bool(fmt.Sprintf("%s.dry_run", cfgKey)), + Log: lo, + Timeout: ko.MustDuration(fmt.Sprintf("%s.timeout", cfgKey)), + MaxIdleConn: ko.MustInt(fmt.Sprintf("%s.max_idle_conns", cfgKey)), + ProxyURL: ko.String(fmt.Sprintf("%s.proxy_url", cfgKey)), + Endpoint: ko.MustString(fmt.Sprintf("%s.endpoint", cfgKey)), + Room: name, + Template: ko.MustString(fmt.Sprintf("%s.template", cfgKey)), + ThreadTTL: ko.MustDuration(fmt.Sprintf("%s.thread_ttl", cfgKey)), + ThreadedReplies: ko.Bool(fmt.Sprintf("%s.threaded_replies", cfgKey)), + Metrics: metrics, + DryRun: ko.Bool(fmt.Sprintf("%s.dry_run", cfgKey)), }, ) if err != nil { diff --git a/config.sample.toml b/config.sample.toml index e4cf026..987586d 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -12,6 +12,7 @@ timeout = "30s" # Timeout for making requests to Provider. # proxy_url = "http://internal-squid-proxy.com:3128" # Specify `proxy_url` as your proxy endpoint to route all HTTP requests to the provider via a proxy. template = "static/message.tmpl" # Path to specify the message template path. thread_ttl = "12h" # Timeout to keep active alerts in memory. Once this TTL expires, a new thread will be created. +threaded_replies = true # Whether to send threaded replies or not. dry_run = false [providers.dev_alerts] @@ -22,4 +23,5 @@ timeout = "30s" # proxy_url = "http://internal-squid-proxy.com:3128" template = "static/message.tmpl" thread_ttl = "12h" +threaded_replies = false # Whether to send threaded replies or not. dry_run = false diff --git a/internal/providers/google_chat/google_chat.go b/internal/providers/google_chat/google_chat.go index 11faa31..953c84d 100644 --- a/internal/providers/google_chat/google_chat.go +++ b/internal/providers/google_chat/google_chat.go @@ -17,27 +17,29 @@ import ( ) type GoogleChatManager struct { - lo *slog.Logger - metrics *metrics.Manager - activeAlerts *ActiveAlerts - endpoint string - room string - client *http.Client - msgTmpl *template.Template - dryRun bool + lo *slog.Logger + metrics *metrics.Manager + activeAlerts *ActiveAlerts + endpoint string + room string + client *http.Client + msgTmpl *template.Template + dryRun bool + threadedReplies bool } type GoogleChatOpts struct { - Log *slog.Logger - Metrics *metrics.Manager - DryRun bool - MaxIdleConn int - Timeout time.Duration - ProxyURL string - Endpoint string - Room string - Template string - ThreadTTL time.Duration + Log *slog.Logger + Metrics *metrics.Manager + DryRun bool + MaxIdleConn int + Timeout time.Duration + ProxyURL string + Endpoint string + Room string + Template string + ThreadTTL time.Duration + ThreadedReplies bool } // NewGoogleChat initializes a Google Chat provider object. @@ -92,8 +94,9 @@ func NewGoogleChat(opts GoogleChatOpts) (*GoogleChatManager, error) { lo: opts.Log, metrics: opts.Metrics, }, - msgTmpl: tmpl, - dryRun: opts.DryRun, + msgTmpl: tmpl, + dryRun: opts.DryRun, + threadedReplies: opts.ThreadedReplies, } // Start a background worker to cleanup alerts based on TTL mechanism. go mgr.activeAlerts.startPruneWorker(1*time.Hour, opts.ThreadTTL) diff --git a/internal/providers/google_chat/message.go b/internal/providers/google_chat/message.go index 20511ac..8e00667 100644 --- a/internal/providers/google_chat/message.go +++ b/internal/providers/google_chat/message.go @@ -66,8 +66,13 @@ func (m *GoogleChatManager) sendMessage(msg ChatMessage, threadKey string) error return err } q := u.Query() - q.Set("threadKey", threadKey) - q.Set("messageReplyOption", "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD") + // Default behaviour is to start a new thread for every alert. + q.Set("messageReplyOption", "MESSAGE_REPLY_OPTION_UNSPECIFIED") + if m.threadedReplies { + // If threaded replies are enabled, use the threadKey to reply to the same thread. + q.Set("messageReplyOption", "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD") + q.Set("threadKey", threadKey) + } u.RawQuery = q.Encode() endpoint := u.String()