From fc03e99167e3901b3eccc5994cf79438f830be38 Mon Sep 17 00:00:00 2001 From: jverger Date: Mon, 3 Feb 2025 19:17:22 +0100 Subject: [PATCH 1/9] Add card feature to msteamsv2_config Signed-off-by: jverger Signed-off-by: Tossaporn Jiw --- config/notifiers.go | 1 + docs/configuration.md | 5 +++ examples/msteamsv2/card.tmpl | 75 ++++++++++++++++++++++++++++++++ notify/msteamsv2/msteamsv2.go | 81 +++++++++++++++++++++-------------- 4 files changed, 129 insertions(+), 33 deletions(-) create mode 100644 examples/msteamsv2/card.tmpl diff --git a/config/notifiers.go b/config/notifiers.go index 87f806aa27..5b5d90b50b 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -872,6 +872,7 @@ type MSTeamsV2Config struct { Title string `yaml:"title,omitempty" json:"title,omitempty"` Text string `yaml:"text,omitempty" json:"text,omitempty"` + Card string `yaml:"card,omitempty" json:"card,omitempty"` } func (c *MSTeamsV2Config) UnmarshalYAML(unmarshal func(interface{}) error) error { diff --git a/docs/configuration.md b/docs/configuration.md index 01b16a8868..594df1dd10 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -992,6 +992,11 @@ Microsoft Teams v2 notifications using the new message format with adaptive card # Message body template. [ text: | default = '{{ template "msteamsv2.default.text" . }}' ] +# Message body card. +# If not null, it will override title and text values (no need to configure these values) +# You can find a complete sample file template here 'examples/msteamsv2/card.tmpl' and provide '{{ template "msteams.card" . }}' in the card value to test. +[ card: ] + # The HTTP client's configuration. [ http_config: | default = global.http_config ] ``` diff --git a/examples/msteamsv2/card.tmpl b/examples/msteamsv2/card.tmpl new file mode 100644 index 0000000000..af086213a9 --- /dev/null +++ b/examples/msteamsv2/card.tmpl @@ -0,0 +1,75 @@ +{{ define "msteams.card" }} +{ + "Type": "message", + "Attachments": [ + { + "contentType": "application/vnd.microsoft.card.adaptive", + "content": { + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "type": "AdaptiveCard", + "version": "1.4", + "msteams": { + "width": "Full" + }, + "body": [ + { + "type": "ColumnSet", + "style": "{{ if eq .Status "firing" }}attention{{ else if eq .Status "resolved" }}good{{ else }}warning{{ end }}", + "columns": [ + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "weight": "Bolder", + "size": "ExtraLarge", + "color": "{{ if eq .Status "firing" }}attention{{ else if eq .Status "resolved" }}good{{ else }}warning{{ end }}", + "text": "{{ if eq .Status "firing" }}🔥{{ else if eq .Status "resolved" }}✅{{ else }}⚠️{{ end }} Prometheus alert {{ if eq .Status "resolved" }}(Resolved){{ else if eq .Status "firing" }}(Firing){{ else if eq .Status "unknown" }}(Unknown){{ else }}(Warning){{ end }}" + }, + { + "type": "TextBlock", + "weight": "Bolder", + "size": "ExtraLarge", + "text": "{{ if eq .Status "resolved" }}(Resolved) {{ end }}{{ .CommonAnnotations.summary }}", + "wrap": true + } + ] + } + ] + }, + { + "type": "FactSet", + "facts": [ + { "title": "Status", "value": "{{ .Status }} {{ if eq .Status "firing" }}🔥{{ else if eq .Status "resolved" }}✅{{ else }}⚠️{{ end }}" } + {{ if .CommonLabels.alertname }}, { "title": "Alert", "value": "{{ .CommonLabels.alertname }}" }{{ end }} + {{ if .CommonLabels.instance }}, { "title": "In host", "value": "{{ .CommonLabels.instance }}" }{{ end }} + {{ if .CommonLabels.severity }}, { "title": "Severity", "value": "{{ .CommonLabels.severity }} {{ if eq .CommonLabels.severity "critical" }}❌{{ else if eq .CommonLabels.severity "error" }}❗️{{ else if eq .CommonLabels.severity "warning" }}⚠️{{ else if eq .CommonLabels.severity "info" }}ℹ️{{ else }}❓{{ end }}" }{{ end }} + {{ if .CommonAnnotations.description }}, { "title": "Description", "value": "{{ .CommonAnnotations.description }}" }{{ end }} + {{- range $key, $value := .CommonLabels }} + {{- if and (ne $key "alertname") (ne $key "instance") (ne $key "severity") }} + , { "title": "{{ $key }}", "value": "{{ $value }}" } + {{- end }} + {{- end }} + {{- range $key, $value := .CommonAnnotations }} + {{- if and (ne $key "summary") (ne $key "description") }} + , { "title": "{{ $key }}", "value": "{{ $value }}" } + {{- end }} + {{- end }} + ] + } + ] + {{ if .CommonAnnotations.runbook_url }}, + "actions": [ + { + "type": "Action.OpenUrl", + "title": "View details", + "url": "{{ .CommonAnnotations.runbook_url }}" + } + ] + {{ end }} + } + } + ] +} +{{ end }} \ No newline at end of file diff --git a/notify/msteamsv2/msteamsv2.go b/notify/msteamsv2/msteamsv2.go index f013bc3bdc..6e670130dc 100644 --- a/notify/msteamsv2/msteamsv2.go +++ b/notify/msteamsv2/msteamsv2.go @@ -125,6 +125,10 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) if err != nil { return false, err } + card := tmpl(n.conf.Card) + if err != nil { + return false, err + } alerts := types.Alerts(as...) color := colorGrey @@ -146,44 +150,55 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) url = strings.TrimSpace(string(content)) } - // A message as referenced in https://learn.microsoft.com/en-us/connectors/teams/?tabs=text1%2Cdotnet#request-body-schema - t := teamsMessage{ - Type: "message", - Attachments: []Attachment{ - { - ContentType: "application/vnd.microsoft.card.adaptive", - ContentURL: nil, - Content: Content{ - Schema: "http://adaptivecards.io/schemas/adaptive-card.json", - Type: "AdaptiveCard", - Version: "1.2", - Body: []Body{ - { - Type: "TextBlock", - Text: title, - Weight: "Bolder", - Size: "Medium", - Wrap: true, - Style: "heading", - Color: color, + // If the card is empty, use title and text otherwise use card. + var payload bytes.Buffer + if card == "" { + // A message as referenced in https://learn.microsoft.com/en-us/connectors/teams/?tabs=text1%2Cdotnet#request-body-schema + t := teamsMessage{ + Type: "message", + Attachments: []Attachment{ + { + ContentType: "application/vnd.microsoft.card.adaptive", + ContentURL: nil, + Content: Content{ + Schema: "http://adaptivecards.io/schemas/adaptive-card.json", + Type: "AdaptiveCard", + Version: "1.2", + Body: []Body{ + { + Type: "TextBlock", + Text: title, + Weight: "Bolder", + Size: "Medium", + Wrap: true, + Style: "heading", + Color: color, + }, + { + Type: "TextBlock", + Text: text, + }, }, - { - Type: "TextBlock", - Text: text, - Wrap: true, + Msteams: Msteams{ + Width: "full", }, }, - Msteams: Msteams{ - Width: "full", - }, }, }, - }, - } - - var payload bytes.Buffer - if err = json.NewEncoder(&payload).Encode(t); err != nil { - return false, err + } + + if err = json.NewEncoder(&payload).Encode(t); err != nil { + return false, err + } + } else { + // Transform card string into object + var jsonMap map[string]interface{} + json.Unmarshal([]byte(card), &jsonMap) + n.logger.Debug("jsonMap", "jsonMap", jsonMap) + + if err = json.NewEncoder(&payload).Encode(jsonMap); err != nil { + return false, err + } } resp, err := n.postJSONFunc(ctx, n.client, url, &payload) From 8fd0f8d7e6f69ddc2f09ced9d72a5097afeda8f6 Mon Sep 17 00:00:00 2001 From: jverger Date: Mon, 3 Feb 2025 19:29:38 +0100 Subject: [PATCH 2/9] Fix gofmt error Signed-off-by: jverger Signed-off-by: Tossaporn Jiw --- notify/msteamsv2/msteamsv2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/msteamsv2/msteamsv2.go b/notify/msteamsv2/msteamsv2.go index 6e670130dc..f5ae9b8b04 100644 --- a/notify/msteamsv2/msteamsv2.go +++ b/notify/msteamsv2/msteamsv2.go @@ -186,7 +186,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) }, }, } - + if err = json.NewEncoder(&payload).Encode(t); err != nil { return false, err } @@ -195,7 +195,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) var jsonMap map[string]interface{} json.Unmarshal([]byte(card), &jsonMap) n.logger.Debug("jsonMap", "jsonMap", jsonMap) - + if err = json.NewEncoder(&payload).Encode(jsonMap); err != nil { return false, err } From 09624f411fad8472ca8175703c9265e11b2a05d3 Mon Sep 17 00:00:00 2001 From: Anastasios_Dados Date: Wed, 19 Feb 2025 11:28:34 +0100 Subject: [PATCH 3/9] header for slack config (#4247) Signed-off-by: Anastasios_Dados Signed-off-by: Tossaporn Jiw --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 594df1dd10..69fbd9d193 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1366,7 +1366,7 @@ The fields are documented in the [Rocketchat API api models](https://github.com/ [ msg: ] ``` -### `` +#### `` Slack notifications can be sent via [Incoming webhooks](https://api.slack.com/messaging/webhooks) or [Bot tokens](https://api.slack.com/authentication/token-types). From cb9185d92fe501976922f87b8f1623f135ad070a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Naveiras?= Date: Wed, 19 Feb 2025 15:55:38 +0000 Subject: [PATCH 4/9] fix(ci): update promci to v0.4.6 to handle artifact actions deprecation (#4258) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The update addresses failing GitHub Actions caused by the deprecation of v3 actions/upload-artifact and actions/download-artifact APIs. This change: - Updates promci from previous version to v0.4.6 - I hope resolves CI failures in artifact upload/download steps Signed-off-by: Raúl Naveiras Signed-off-by: Tossaporn Jiw --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish.yml | 4 ++-- .github/workflows/release.yml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6c37510d2..860a3a30a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - thread: [ 0, 1, 2 ] + thread: [0, 1, 2] steps: - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: prometheus/promci@c3c93a50d581b928af720f0134b2b2dad32a6c41 # v0.4.6 - uses: ./.github/promci/actions/build with: promu_opts: "-p linux/amd64 -p windows/amd64 -p linux/arm64 -p darwin/amd64 -p darwin/arm64 -p linux/386" @@ -40,7 +40,7 @@ jobs: image: quay.io/prometheus/golang-builder:1.23-base steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: prometheus/promci@c3c93a50d581b928af720f0134b2b2dad32a6c41 # v0.4.6 - uses: ./.github/promci/actions/setup_environment - run: make - run: git diff --exit-code diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d7ef97f1d2..54dc2487fd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - thread: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ] + thread: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] needs: ci steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -29,7 +29,7 @@ jobs: needs: build steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: prometheus/promci@c3c93a50d581b928af720f0134b2b2dad32a6c41 # v0.4.6 - uses: ./.github/promci/actions/publish_main with: docker_hub_login: ${{ secrets.docker_hub_login }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01f31883a9..91da7d117a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,11 +14,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - thread: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ] + thread: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] needs: ci steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: prometheus/promci@c3c93a50d581b928af720f0134b2b2dad32a6c41 # v0.4.6 - uses: ./.github/promci/actions/build with: parallelism: 12 @@ -29,7 +29,7 @@ jobs: needs: build steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: prometheus/promci@c3c93a50d581b928af720f0134b2b2dad32a6c41 # v0.4.6 - uses: ./.github/promci/actions/publish_release with: docker_hub_login: ${{ secrets.docker_hub_login }} From 9c0626c2d84a9490b8e7c587d45425f1afcaa93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Naveiras?= Date: Wed, 19 Feb 2025 20:32:25 +0000 Subject: [PATCH 5/9] fix(ci): update promci to v0.4.6 to handle artifact actions deprecation (#4259) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same as #4258 The update addresses failing GitHub Actions caused by the deprecation of v3 actions/upload-artifact and actions/download-artifact APIs. This change: - Updates promci from previous version to v0.4.6 - I hope resolves CI failures in artifact upload/download steps https://github.com/prometheus/promci/releases/tag/v0.4.6 https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/ Signed-off-by: Raúl Naveiras Signed-off-by: Tossaporn Jiw --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 54dc2487fd..db6ddfc6c3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,7 +18,7 @@ jobs: needs: ci steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0 + - uses: prometheus/promci@c3c93a50d581b928af720f0134b2b2dad32a6c41 # v0.4.6 - uses: ./.github/promci/actions/build with: parallelism: 12 From 5fc0b575a50a49517f26addccd3d0b6af7a77627 Mon Sep 17 00:00:00 2001 From: Tossaporn Jiw Date: Wed, 26 Feb 2025 22:45:12 +0700 Subject: [PATCH 6/9] feat: update default card template for msteamsv2_configs receiver Signed-off-by: Tossaporn Jiw --- notify/msteamsv2/msteamsv2.go | 159 ++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 19 deletions(-) diff --git a/notify/msteamsv2/msteamsv2.go b/notify/msteamsv2/msteamsv2.go index f5ae9b8b04..3028807ad6 100644 --- a/notify/msteamsv2/msteamsv2.go +++ b/notify/msteamsv2/msteamsv2.go @@ -49,23 +49,53 @@ type Notifier struct { postJSONFunc func(ctx context.Context, client *http.Client, url string, body io.Reader) (*http.Response, error) } +type Action struct { + Type string `json:"type"` + Title string `json:"title"` + URL string `json:"url"` +} + // https://learn.microsoft.com/en-us/connectors/teams/?tabs=text1#adaptivecarditemschema type Content struct { - Schema string `json:"$schema"` - Type string `json:"type"` - Version string `json:"version"` - Body []Body `json:"body"` - Msteams Msteams `json:"msteams,omitempty"` + Schema string `json:"$schema"` + Type string `json:"type"` + Version string `json:"version"` + Body []Body `json:"body"` + Msteams Msteams `json:"msteams,omitempty"` + Actions []Action `json:"actions,omitempty"` } -type Body struct { +type Item struct { Type string `json:"type"` - Text string `json:"text"` Weight string `json:"weight,omitempty"` Size string `json:"size,omitempty"` Wrap bool `json:"wrap,omitempty"` Style string `json:"style,omitempty"` Color string `json:"color,omitempty"` + Text string `json:"text"` +} + +type Column struct { + Type string `json:"type"` + Width string `json:"width"` + Items []Item `json:"items"` +} + +type Fact struct { + Title string `json:"title"` + Value string `json:"value"` +} + +type Body struct { + Type string `json:"type"` + Text string `json:"text"` + Weight string `json:"weight,omitempty"` + Size string `json:"size,omitempty"` + Wrap bool `json:"wrap,omitempty"` + Style string `json:"style,omitempty"` + Color string `json:"color,omitempty"` + Columns []Column `json:"columns,omitempty"` + Facts []Fact `json:"facts,omitempty"` } type Msteams struct { @@ -131,12 +161,20 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) } alerts := types.Alerts(as...) + // summary := "" color := colorGrey + status := "unknown" + statusIcon := "⚠" + switch alerts.Status() { case model.AlertFiring: color = colorRed + status = "firing" + statusIcon = "🔥" case model.AlertResolved: color = colorGreen + status = "resolved" + statusIcon = "✅" } var url string @@ -163,24 +201,80 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) Content: Content{ Schema: "http://adaptivecards.io/schemas/adaptive-card.json", Type: "AdaptiveCard", - Version: "1.2", + Version: "1.4", + Msteams: Msteams{ + Width: "Full"}, Body: []Body{ { - Type: "TextBlock", - Text: title, - Weight: "Bolder", - Size: "Medium", - Wrap: true, - Style: "heading", - Color: color, + Type: "ColumnSet", + Style: color, + Columns: []Column{ + { + Type: "Column", + Width: "stretch", + Items: []Item{ + { + Type: "TextBlock", + Weight: "Bolder", + Size: "ExtraLarge", + Color: color, + Text: fmt.Sprintf("%s %s", statusIcon, title), + }, + { + Type: "TextBlock", + Weight: "Bolder", + Size: "ExtraLarge", + Text: text, + Wrap: true, + }, + }, + }, + }, }, { - Type: "TextBlock", - Text: text, + Type: "FactSet", + Facts: []Fact{ + { + Title: "Status", + Value: fmt.Sprintf("%s %s", status, statusIcon), + }, + { + Title: "Alert", + Value: data.CommonLabels["alertname"], + }, + { + Title: "Summary", + Value: data.CommonAnnotations["summary"], + }, + { + Title: "Severity", + Value: renderSeverity(data.CommonLabels["severity"]), + }, + { + Title: "In Host", + Value: data.CommonLabels["instance"], + }, + { + Title: "Description", + Value: data.CommonAnnotations["description"], + }, + { + Title: "Common Labels", + Value: renderCommonLabels(data.CommonLabels), + }, + { + Title: "Common Annotations", + Value: renderCommonAnnotations(data.CommonAnnotations), + }, + }, }, }, - Msteams: Msteams{ - Width: "full", + Actions: []Action{ + { + Type: "Action.OpenUrl", + Title: "View details", + URL: data.CommonAnnotations["runbook_url"], + }, }, }, }, @@ -214,3 +308,30 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) } return shouldRetry, err } + +func renderSeverity(severity string) string { + switch severity { + case "critical": + return fmt.Sprintf("%s %s", severity, "❌") + case "error": + return fmt.Sprintf("%s %s", severity, "❗️") + case "warning": + return fmt.Sprintf("%s %s", severity, "⚠️") + case "info": + return fmt.Sprintf("%s %s", severity, "ℹ️") + default: + return fmt.Sprintf("%s %s", severity, "ℹ❓") + } +} + +func renderCommonLabels(commonLabels template.KV) string { + removeList := []string{"alertname", "instance", "severity"} + + return commonLabels.Remove(removeList).String() +} + +func renderCommonAnnotations(commonLabels template.KV) string { + removeList := []string{"summary", "description"} + + return commonLabels.Remove(removeList).String() +} From 7c2485fc4982d2e2a9fb7001cee49c0437c88588 Mon Sep 17 00:00:00 2001 From: Tossaporn Jiw Date: Wed, 26 Feb 2025 22:47:13 +0700 Subject: [PATCH 7/9] fix: eof Signed-off-by: Tossaporn Jiw --- examples/msteamsv2/card.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/msteamsv2/card.tmpl b/examples/msteamsv2/card.tmpl index af086213a9..517a2dbf62 100644 --- a/examples/msteamsv2/card.tmpl +++ b/examples/msteamsv2/card.tmpl @@ -72,4 +72,4 @@ } ] } -{{ end }} \ No newline at end of file +{{ end }} From eaa1c8a3d56ef43cd56e3ef09f7e9c2d73f73cf5 Mon Sep 17 00:00:00 2001 From: Tossaporn Jiw Date: Wed, 26 Feb 2025 23:02:34 +0700 Subject: [PATCH 8/9] fix: handle key not found Signed-off-by: Tossaporn Jiw --- notify/msteamsv2/msteamsv2.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/notify/msteamsv2/msteamsv2.go b/notify/msteamsv2/msteamsv2.go index 3028807ad6..e659ebfdf9 100644 --- a/notify/msteamsv2/msteamsv2.go +++ b/notify/msteamsv2/msteamsv2.go @@ -240,11 +240,11 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) }, { Title: "Alert", - Value: data.CommonLabels["alertname"], + Value: extractKV(data.CommonLabels, "alertname"), }, { Title: "Summary", - Value: data.CommonAnnotations["summary"], + Value: extractKV(data.CommonAnnotations, "summary"), }, { Title: "Severity", @@ -252,11 +252,11 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) }, { Title: "In Host", - Value: data.CommonLabels["instance"], + Value: extractKV(data.CommonLabels, "instance"), }, { Title: "Description", - Value: data.CommonAnnotations["description"], + Value: extractKV(data.CommonAnnotations, "description"), }, { Title: "Common Labels", @@ -273,7 +273,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { Type: "Action.OpenUrl", Title: "View details", - URL: data.CommonAnnotations["runbook_url"], + URL: extractKV(data.CommonAnnotations, "runbook_url"), }, }, }, @@ -281,6 +281,8 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) }, } + // Check if summary exists in CommonLabels + if err = json.NewEncoder(&payload).Encode(t); err != nil { return false, err } @@ -335,3 +337,10 @@ func renderCommonAnnotations(commonLabels template.KV) string { return commonLabels.Remove(removeList).String() } + +func extractKV(kv template.KV, key string) string { + if v, ok := kv[key]; ok { + return v + } + return "" +} From f69c86aa74262f32c24df0058aff720cdcec0b84 Mon Sep 17 00:00:00 2001 From: Tossaporn Jiw Date: Wed, 26 Feb 2025 23:05:46 +0700 Subject: [PATCH 9/9] fix: handle key not found Signed-off-by: Tossaporn Jiw --- notify/msteamsv2/msteamsv2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notify/msteamsv2/msteamsv2.go b/notify/msteamsv2/msteamsv2.go index e659ebfdf9..f7d9c4e7d3 100644 --- a/notify/msteamsv2/msteamsv2.go +++ b/notify/msteamsv2/msteamsv2.go @@ -248,7 +248,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) }, { Title: "Severity", - Value: renderSeverity(data.CommonLabels["severity"]), + Value: renderSeverity(extractKV(data.CommonLabels, "severity")), }, { Title: "In Host", @@ -322,7 +322,7 @@ func renderSeverity(severity string) string { case "info": return fmt.Sprintf("%s %s", severity, "ℹ️") default: - return fmt.Sprintf("%s %s", severity, "ℹ❓") + return "unknown ❓" } }