Skip to content

Commit 86fa446

Browse files
committed
add slack support
1 parent 847a651 commit 86fa446

File tree

11 files changed

+157
-1
lines changed

11 files changed

+157
-1
lines changed

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ You can use multiple notifiers at the same time. Just define them to the `config
4141

4242
- [x] Squadcast
4343
- [x] Telegram
44-
- [ ] Slack ( WIP )
44+
- [x] Slack
4545
- [ ] Webhook ( WIP )
4646

4747
### Squadcast
@@ -77,6 +77,21 @@ notifier:
7777
topic: "56789"
7878
```
7979

80+
### Slack
81+
82+
1. Create a new Application in Slack
83+
2. Use `Incoming Webhook` as type
84+
3. Define the webhook in `config.yml` file
85+
86+
```yaml
87+
notifier:
88+
slack:
89+
enable: true
90+
teams:
91+
team1: "<WEBHOOK-URL>"
92+
team2: "<WEBHOOK-URL>"
93+
```
94+
8095
## Monitoring
8196

8297
We have some metrics for monitoring our service in `/metrics` path.
@@ -88,6 +103,8 @@ We have some metrics for monitoring our service in `/metrics` path.
88103
| `UPTIME_webhook_telegram_failure` | Total number of failure Telegram notify |
89104
| `UPTIME_webhook_squadcast_success` | Total number of successful Squadcast notify |
90105
| `UPTIME_webhook_squadcast_failure` | Total number of failure Squadcast notify |
106+
| `UPTIME_webhook_slack_success` | Total number of successful Slack notify |
107+
| `UPTIME_webhook_slack_failure` | Total number of failure Slack notify |
91108

92109
---
93110

configs/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ type Config struct {
3737
Token string `yaml:"token"`
3838
Teams map[string][]TelegramTeam `yaml:"teams"`
3939
} `yaml:"telegram"`
40+
Slack struct {
41+
IsEnabled bool `yaml:"enable"`
42+
Teams map[string]string
43+
} `yaml:"slack"`
4044
}
4145

4246
Version string

configs/config.yml.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,8 @@ notifier:
3434
team2:
3535
- chat: "-124564"
3636
topic: "56789"
37+
slack:
38+
enable: true
39+
teams:
40+
team1: ""
41+
team2: ""

internal/models/slack.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package models
2+
3+
// TelegramMessage is a struct for Telegram message
4+
type SlackMessage struct {
5+
Text string `json:"text,omitempty"`
6+
}

internal/platform/monitoring/event.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const (
1414
IncSquadcastSendSuccess
1515
// IncSquadcastSendFailure will show the total failure squadcast sends
1616
IncSquadcastSendFailure
17+
// IncSlackSendSuccess will show the total success squadcast sends
18+
IncSlackSendSuccess
19+
// IncSlackSendFailure will show the total failure squadcast sends
20+
IncSlackSendFailure
1721
// SetActiveJobsInAlertPool will show the total active jobs in alert pool
1822
SetActiveJobsInAlertPool
1923
// SetAlertPoolCapacity will show the total capacity of alert pool

internal/platform/monitoring/mock.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ func (i MockMonitor) Record(events []Event) {
2727
log.Info("====IncSquadcastSendSuccess=====")
2828
case IncSquadcastSendFailure:
2929
log.Info("====IncSquadcastSendFailure=====")
30+
case IncSlackSendSuccess:
31+
log.Info("====IncSlackSendSuccess=====")
32+
case IncSlackSendFailure:
33+
log.Info("====IncSlackSendFailure=====")
3034
case SetActiveJobsInAlertPool:
3135
log.Info("====SetActiveJobsInAlertPool=====")
3236
case SetAlertPoolCapacity:

internal/platform/monitoring/prometheus.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ var (
1818
telegramFailure prometheus.Counter
1919
squadcastSuccess prometheus.Counter
2020
squadcastFailure prometheus.Counter
21+
slackSuccess prometheus.Counter
22+
slackFailure prometheus.Counter
2123
alertPoolCapacity prometheus.Gauge
2224
alertPoolRunningJobs prometheus.Gauge
2325
)
@@ -66,6 +68,20 @@ func NewPrometheusMonitor() Monitor {
6668
Help: "Total number of failure notify requests to Squadcast.",
6769
})
6870

71+
slackSuccess = promauto.NewCounter(prometheus.CounterOpts{
72+
Namespace: namespace,
73+
Subsystem: subsystem,
74+
Name: "slack_success",
75+
Help: "Total number of successful notify requests to Slack.",
76+
})
77+
78+
slackFailure = promauto.NewCounter(prometheus.CounterOpts{
79+
Namespace: namespace,
80+
Subsystem: subsystem,
81+
Name: "slack_failure",
82+
Help: "Total number of failure notify requests to Slack.",
83+
})
84+
6985
alertPoolCapacity = promauto.NewGauge(prometheus.GaugeOpts{
7086
Namespace: namespace,
7187
Subsystem: subsystem,
@@ -97,6 +113,10 @@ func (i PrometheusMonitor) Record(events []Event) {
97113
squadcastSuccess.Inc()
98114
case IncSquadcastSendFailure:
99115
squadcastFailure.Inc()
116+
case IncSlackSendSuccess:
117+
slackSuccess.Inc()
118+
case IncSlackSendFailure:
119+
slackFailure.Inc()
100120
case SetActiveJobsInAlertPool:
101121
alertPoolRunningJobs.Set(float64(event.GetParam(0).(int)))
102122
case SetAlertPoolCapacity:

internal/platform/repositories/alert/alert_repository.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,11 @@ func (r *Repository) CreateAlert(ctx context.Context, alert models.Alert) error
4646
}
4747
}
4848

49+
if r.config.Notifier.Slack.IsEnabled {
50+
if err := r.CreateSlackMessage(alert); err != nil {
51+
return err
52+
}
53+
}
54+
4955
return nil
5056
}

internal/platform/repositories/alert/helper.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,33 @@ func formatSquadcastMessage(alert models.Alert) models.SquadcastIncident {
8686
return payload
8787
}
8888

89+
func formatSlackMessage(alert models.Alert) models.SlackMessage {
90+
var text string
91+
92+
if alert.Event == "alert_raised" {
93+
text = "🔥 *Alert - " + alert.Data.Alert.State + "*\n\n"
94+
text += "📌 *Source:* Uptime\n\n"
95+
text += "🏷 *Title:* The \"" + alert.Data.Service.ShortName + "\" is down\n\n"
96+
text += "📄 *Description:* Your `" + alert.Data.Service.DisplayName +
97+
"` service is down" +
98+
" at *" + alert.Data.Alert.CreatedAt.Format("2006-01-02 15:04:05") + "*\n\n"
99+
text += "💻 *Address:* " + alert.Data.Device.Address + "\n\n"
100+
text += "🔍 *Result:* " + alert.Data.Alert.ShortOutput + "\n"
101+
} else {
102+
text = "✅ *Resolved*\n\n"
103+
text += "📌 *Source:* Uptime\n\n"
104+
text += "🏷 *Title:* The \"" + alert.Data.Service.ShortName + "\" is up\n\n"
105+
text += "💻 *Address:* " + alert.Data.Device.Address + "\n\n"
106+
text += "⏱️ *Time:* " + alert.Data.Date.Format("2006-01-02 15:04:05") + "\n\n"
107+
}
108+
109+
payload := models.SlackMessage{
110+
Text: text,
111+
}
112+
113+
return payload
114+
}
115+
89116
func getAlertColor(state string) models.SquadcastTag {
90117
var color string
91118

internal/platform/repositories/alert/pool.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,27 @@ func (r *Repository) CallTelegram(url string, body []byte) error {
8181
}
8282
})
8383
}
84+
85+
// CallSlack will send a Slack http request
86+
func (r *Repository) CallSlack(url string, body []byte) error {
87+
u, err := net_url.ParseRequestURI(url)
88+
89+
if err != nil {
90+
log.WithError(err).Errorf("[SLACK] Error parsing URL: %s", url)
91+
r.monitoring.Record([]monitoring.Event{monitoring.NewEvent(monitoring.IncSlackSendFailure)})
92+
return err
93+
}
94+
95+
return r.pool.Submit(func() {
96+
result, err := sendPOSTRequest(u.String(), body, r.version)
97+
98+
if err != nil {
99+
log.WithError(err).Error("[SLACK] Error sending request to " + u.String())
100+
r.monitoring.Record([]monitoring.Event{monitoring.NewEvent(monitoring.IncSlackSendFailure)})
101+
return
102+
}
103+
104+
log.Debugf("[SLACK] Result: %s", result)
105+
r.monitoring.Record([]monitoring.Event{monitoring.NewEvent(monitoring.IncSlackSendSuccess)})
106+
})
107+
}

0 commit comments

Comments
 (0)