-
Notifications
You must be signed in to change notification settings - Fork 9
/
slackVendor.go
137 lines (114 loc) · 3.93 KB
/
slackVendor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"context"
"fmt"
"net/http"
"strconv"
"strings"
"time"
gometrics "github.com/rcrowley/go-metrics"
"github.com/slack-go/slack"
)
type SlackVendor struct {
*Vendor
slackClient *slack.Client
}
// NewSlackVendor create new SlackVendor instance
func NewSlackVendor(dbClient *DbClient, config *Config, logger *Logger, metricsRegistry *gometrics.Registry) *SlackVendor {
vendor := NewVendor(dbClient, config, logger, "slack")
// initialize slack client
client := &http.Client{}
if config.OutboundProxyParsedURL != nil {
client.Transport = &http.Transport{
Proxy: http.ProxyURL(config.OutboundProxyParsedURL),
}
}
slackClient := slack.New(config.SlackAPIKey, slack.OptionDebug(config.Debug), slack.OptionHTTPClient(client))
slackVendor := SlackVendor{
Vendor: vendor,
slackClient: slackClient,
}
if appConfig.MetricsDryRun == false && metricsRegistry != nil {
slackVendor.Vendor.RegisterMetrics(*metricsRegistry)
}
return &slackVendor
}
func (s *SlackVendor) SendMessage(messageQueueItem MessageQueueItem) bool {
var attachment slack.Attachment
// if notification is from an incident add the required attachment
if messageQueueItem.incidentID != 0 {
attachment = s.constructIncidentAttachment(messageQueueItem)
}
// TODO: handle custom notification block rendering
if err := s.sendMessage(messageQueueItem, attachment); err != nil {
errorText := err.Error()
if errorText == "channel_not_found" || errorText == "not_in_channel" {
status := fmt.Sprintf("failed with error: %s", errorText)
s.Vendor.persistMsg(messageQueueItem, "", status)
// return true to avoid retries
return true
}
if messageQueueItem.retries >= s.Vendor.config.MaxMessageRetries {
status := fmt.Sprintf("failed with error: %s", errorText)
s.Vendor.persistMsg(messageQueueItem, "", status)
}
s.Vendor.logger.Errorf("Failed sending slack message with error %s. message: %+v", errorText, messageQueueItem)
s.Vendor.counterFailures.Inc(1)
return false
}
s.Vendor.counterSuccesses.Inc(1)
// store message and status in the db
s.Vendor.persistMsg(messageQueueItem, "", "sent to vendor")
return true
}
// post message to slack api
func (s *SlackVendor) sendMessage(messageQueueItem MessageQueueItem, attachment slack.Attachment) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Second*s.config.SlackTimeout))
defer cancel()
destination := messageQueueItem.message.Destination
// if destination does not have a # or @ prefix assume it is a user and add a @ prefix so slack can resolve it
if !(strings.HasPrefix(destination, "#") || strings.HasPrefix(destination, "@")) {
destination = "@" + destination
}
_, _, err := s.slackClient.PostMessageContext(
ctx,
destination,
slack.MsgOptionText(messageQueueItem.message.Body, false),
slack.MsgOptionAttachments(attachment),
slack.MsgOptionAsUser(true),
//slack.MsgOptionBlocks(), //TODO add support for blocks
)
return err
}
// build incident message attachment
func (s *SlackVendor) constructIncidentAttachment(messageQueueItem MessageQueueItem) slack.Attachment {
attachment := slack.Attachment{
Title: fmt.Sprintf("Iris incident %v", messageQueueItem.incidentID),
TitleLink: fmt.Sprintf("%s/%d", s.config.SlackTitleURL, messageQueueItem.incidentID),
CallbackID: strconv.FormatUint(messageQueueItem.incidentID, 10),
Color: "danger",
Fallback: "Iris Alert Fired!",
Actions: []slack.AttachmentAction{
slack.AttachmentAction{
Name: "claim",
Text: "Claim Incident",
Type: "button",
Value: "claimed",
},
slack.AttachmentAction{
Name: "claim all",
Text: "Claim All",
Style: "danger",
Type: "button",
Value: "claimed all",
Confirm: &slack.ConfirmationField{
Title: "Are you sure?",
Text: "This will claim all active incidents targeting you.",
OkText: "Yes",
DismissText: "No",
},
},
},
}
return attachment
}