diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index bffc5397e87..918be2a4bbe 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -99,15 +99,15 @@ provided, which starts with "xoxb". Setting | Description ---------- | ----------- -Url | Slack incoming webhook URL. +Url | Slack incoming webhook URL, or eventually the [chat.postMessage](https://api.slack.com/methods/chat.postMessage) Slack API endpoint. Username | Set the username for the bot's message. -Recipient | Allows you to override the Slack recipient. You must either provide a channel Slack ID, a user Slack ID, a username reference (@<user>, all lowercase, no whitespace), or a channel reference (#<channel>, all lowercase, no whitespace). +Recipient | Allows you to override the Slack recipient. You must either provide a channel Slack ID, a user Slack ID, a username reference (@<user>, all lowercase, no whitespace), or a channel reference (#<channel>, all lowercase, no whitespace). If you use the `chat.postMessage` Slack API endpoint, this is required. Icon emoji | Provide an emoji to use as the icon for the bot's message. Ex :smile: Icon URL | Provide a URL to an image to use as the icon for the bot's message. Mention Users | Optionally mention one or more users in the Slack notification sent by Grafana. You have to refer to users, comma-separated, via their corresponding Slack IDs (which you can find by clicking the overflow button on each user's Slack profile). Mention Groups | Optionally mention one or more groups in the Slack notification sent by Grafana. You have to refer to groups, comma-separated, via their corresponding Slack IDs (which you can get from each group's Slack profile URL). Mention Channel | Optionally mention either all channel members or just active ones. -Token | If provided, Grafana will upload the generated image via Slack's file.upload API method, not the external image destination. +Token | If provided, Grafana will upload the generated image via Slack's file.upload API method, not the external image destination. If you use the `chat.postMessage` Slack API endpoint, this is required. If you are using the token for a slack bot, then you have to invite the bot to the channel you want to send notifications and add the channel to the recipient field. diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go index 5effa547e56..53a88093ef8 100644 --- a/pkg/services/alerting/notifiers/slack.go +++ b/pkg/services/alerting/notifiers/slack.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "mime/multipart" + "net/http" "os" "path/filepath" "regexp" @@ -291,13 +292,15 @@ func (sn *SlackNotifier) Notify(evalContext *alerting.EvalContext) error { attachment["image_url"] = imageURL } body := map[string]interface{}{ - "text": evalContext.GetNotificationTitle(), - "blocks": blocks, + "text": evalContext.GetNotificationTitle(), "attachments": []map[string]interface{}{ attachment, }, "parse": "full", // to linkify urls, users and channels in alert message. } + if len(blocks) > 0 { + body["blocks"] = blocks + } //recipient override if sn.Recipient != "" { @@ -317,7 +320,17 @@ func (sn *SlackNotifier) Notify(evalContext *alerting.EvalContext) error { return err } - cmd := &models.SendWebhookSync{Url: sn.URL, Body: string(data)} + cmd := &models.SendWebhookSync{ + Url: sn.URL, + Body: string(data), + HttpMethod: http.MethodPost, + } + if sn.Token != "" { + sn.log.Debug("Adding authorization header to HTTP request") + cmd.HttpHeader = map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", sn.Token), + } + } if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { sn.log.Error("Failed to send slack notification", "error", err, "webhook", sn.Name) return err diff --git a/pkg/services/notifications/webhook.go b/pkg/services/notifications/webhook.go index 7cc74409278..13679949c9f 100644 --- a/pkg/services/notifications/webhook.go +++ b/pkg/services/notifications/webhook.go @@ -76,6 +76,7 @@ func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook * defer resp.Body.Close() if resp.StatusCode/100 == 2 { + ns.log.Debug("Webhook succeeded", "url", webhook.Url, "statuscode", resp.Status) // flushing the body enables the transport to reuse the same connection if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { ns.log.Error("Failed to copy resp.Body to ioutil.Discard", "err", err) @@ -88,6 +89,6 @@ func (ns *NotificationService) sendWebRequestSync(ctx context.Context, webhook * return err } - ns.log.Debug("Webhook failed", "statuscode", resp.Status, "body", string(body)) + ns.log.Debug("Webhook failed", "url", webhook.Url, "statuscode", resp.Status, "body", string(body)) return fmt.Errorf("Webhook response status %v", resp.Status) }