mirror of
https://github.com/TwiN/gatus.git
synced 2026-02-16 23:24:10 +00:00
feat(alerting): Add message-content parameter for Discord pings (#1335)
* feat(discord-alerts): add option for prefix-messages outside of embeds * chore(docs): add discord prefix-message to README * chore(discord-alerts): rename prefix-message to message-content --------- Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
@@ -920,6 +920,7 @@ endpoints:
|
|||||||
| `alerting.discord` | Configuration for alerts of type `discord` | `{}` |
|
| `alerting.discord` | Configuration for alerts of type `discord` | `{}` |
|
||||||
| `alerting.discord.webhook-url` | Discord Webhook URL | Required `""` |
|
| `alerting.discord.webhook-url` | Discord Webhook URL | Required `""` |
|
||||||
| `alerting.discord.title` | Title of the notification | `":helmet_with_white_cross: Gatus"` |
|
| `alerting.discord.title` | Title of the notification | `":helmet_with_white_cross: Gatus"` |
|
||||||
|
| `alerting.discord.message-content` | Message content to send before the embed (useful for pinging users/roles, e.g. `<@123>`) | `""` |
|
||||||
| `alerting.discord.default-alert` | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert) | N/A |
|
| `alerting.discord.default-alert` | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert) | N/A |
|
||||||
| `alerting.discord.overrides` | List of overrides that may be prioritized over the default configuration | `[]` |
|
| `alerting.discord.overrides` | List of overrides that may be prioritized over the default configuration | `[]` |
|
||||||
| `alerting.discord.overrides[].group` | Endpoint group for which the configuration will be overridden by this configuration | `""` |
|
| `alerting.discord.overrides[].group` | Endpoint group for which the configuration will be overridden by this configuration | `""` |
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
WebhookURL string `yaml:"webhook-url"`
|
WebhookURL string `yaml:"webhook-url"`
|
||||||
Title string `yaml:"title,omitempty"` // Title of the message that will be sent
|
Title string `yaml:"title,omitempty"` // Title of the message that will be sent
|
||||||
|
MessageContent string `yaml:"message-content,omitempty"` // Message content for pinging users or groups (e.g. "<@123456789>" or "<@&987654321>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) Validate() error {
|
func (cfg *Config) Validate() error {
|
||||||
@@ -38,6 +39,9 @@ func (cfg *Config) Merge(override *Config) {
|
|||||||
if len(override.Title) > 0 {
|
if len(override.Title) > 0 {
|
||||||
cfg.Title = override.Title
|
cfg.Title = override.Title
|
||||||
}
|
}
|
||||||
|
if len(override.MessageContent) > 0 {
|
||||||
|
cfg.MessageContent = override.MessageContent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlertProvider is the configuration necessary for sending an alert using Discord
|
// AlertProvider is the configuration necessary for sending an alert using Discord
|
||||||
@@ -142,7 +146,7 @@ func (provider *AlertProvider) buildRequestBody(cfg *Config, ep *endpoint.Endpoi
|
|||||||
title = cfg.Title
|
title = cfg.Title
|
||||||
}
|
}
|
||||||
body := Body{
|
body := Body{
|
||||||
Content: "",
|
Content: cfg.MessageContent,
|
||||||
Embeds: []Embed{
|
Embeds: []Embed{
|
||||||
{
|
{
|
||||||
Title: title,
|
Title: title,
|
||||||
|
|||||||
@@ -134,6 +134,16 @@ func TestAlertProvider_Send(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
ExpectedError: false,
|
ExpectedError: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "triggered-with-message-content",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{WebhookURL: "http://example.com", MessageContent: "<@123456789>"}},
|
||||||
|
Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: false,
|
||||||
|
MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
|
||||||
|
return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}
|
||||||
|
}),
|
||||||
|
ExpectedError: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
t.Run(scenario.Name, func(t *testing.T) {
|
t.Run(scenario.Name, func(t *testing.T) {
|
||||||
@@ -200,6 +210,27 @@ func TestAlertProvider_buildRequestBody(t *testing.T) {
|
|||||||
Resolved: false,
|
Resolved: false,
|
||||||
ExpectedBody: "{\"content\":\"\",\"embeds\":[{\"title\":\"provider-title\",\"description\":\"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row:\\n\\u003e description-1\",\"color\":15158332}]}",
|
ExpectedBody: "{\"content\":\"\",\"embeds\":[{\"title\":\"provider-title\",\"description\":\"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row:\\n\\u003e description-1\",\"color\":15158332}]}",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "triggered-with-message-content-user-mention",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{MessageContent: "<@123456789>"}},
|
||||||
|
Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: false,
|
||||||
|
ExpectedBody: "{\"content\":\"\\u003c@123456789\\u003e\",\"embeds\":[{\"title\":\":helmet_with_white_cross: Gatus\",\"description\":\"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row:\\n\\u003e description-1\",\"color\":15158332,\"fields\":[{\"name\":\"Condition results\",\"value\":\":x: - `[CONNECTED] == true`\\n:x: - `[STATUS] == 200`\\n:x: - `[BODY] != \\\"\\\"`\\n\",\"inline\":false}]}]}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "triggered-with-message-content-role-mention",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{MessageContent: "<@&987654321>"}},
|
||||||
|
Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: false,
|
||||||
|
ExpectedBody: "{\"content\":\"\\u003c@\\u0026987654321\\u003e\",\"embeds\":[{\"title\":\":helmet_with_white_cross: Gatus\",\"description\":\"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row:\\n\\u003e description-1\",\"color\":15158332,\"fields\":[{\"name\":\"Condition results\",\"value\":\":x: - `[CONNECTED] == true`\\n:x: - `[STATUS] == 200`\\n:x: - `[BODY] != \\\"\\\"`\\n\",\"inline\":false}]}]}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "resolved-with-message-content",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{MessageContent: "<@123456789>"}},
|
||||||
|
Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: true,
|
||||||
|
ExpectedBody: "{\"content\":\"\\u003c@123456789\\u003e\",\"embeds\":[{\"title\":\":helmet_with_white_cross: Gatus\",\"description\":\"An alert for **endpoint-name** has been resolved after passing successfully 5 time(s) in a row:\\n\\u003e description-2\",\"color\":3066993,\"fields\":[{\"name\":\"Condition results\",\"value\":\":white_check_mark: - `[CONNECTED] == true`\\n:white_check_mark: - `[STATUS] == 200`\\n:white_check_mark: - `[BODY] != \\\"\\\"`\\n\",\"inline\":false}]}]}",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
t.Run(scenario.Name, func(t *testing.T) {
|
t.Run(scenario.Name, func(t *testing.T) {
|
||||||
@@ -313,6 +344,39 @@ func TestAlertProvider_GetConfig(t *testing.T) {
|
|||||||
InputAlert: alert.Alert{ProviderOverride: map[string]any{"webhook-url": "http://alert-example.com"}},
|
InputAlert: alert.Alert{ProviderOverride: map[string]any{"webhook-url": "http://alert-example.com"}},
|
||||||
ExpectedOutput: Config{WebhookURL: "http://alert-example.com"},
|
ExpectedOutput: Config{WebhookURL: "http://alert-example.com"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "provider-with-message-content-default",
|
||||||
|
Provider: AlertProvider{
|
||||||
|
DefaultConfig: Config{WebhookURL: "http://example.com", MessageContent: "<@123456789>"},
|
||||||
|
},
|
||||||
|
InputGroup: "",
|
||||||
|
InputAlert: alert.Alert{},
|
||||||
|
ExpectedOutput: Config{WebhookURL: "http://example.com", MessageContent: "<@123456789>"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "provider-with-message-content-group-override",
|
||||||
|
Provider: AlertProvider{
|
||||||
|
DefaultConfig: Config{WebhookURL: "http://example.com", MessageContent: "<@123456789>"},
|
||||||
|
Overrides: []Override{
|
||||||
|
{
|
||||||
|
Group: "group",
|
||||||
|
Config: Config{WebhookURL: "http://group-example.com", MessageContent: "<@&987654321>"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InputGroup: "group",
|
||||||
|
InputAlert: alert.Alert{},
|
||||||
|
ExpectedOutput: Config{WebhookURL: "http://group-example.com", MessageContent: "<@&987654321>"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "provider-with-message-content-alert-override",
|
||||||
|
Provider: AlertProvider{
|
||||||
|
DefaultConfig: Config{WebhookURL: "http://example.com", MessageContent: "<@123456789>"},
|
||||||
|
},
|
||||||
|
InputGroup: "",
|
||||||
|
InputAlert: alert.Alert{ProviderOverride: map[string]any{"message-content": "<@999999999>"}},
|
||||||
|
ExpectedOutput: Config{WebhookURL: "http://example.com", MessageContent: "<@999999999>"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
t.Run(scenario.Name, func(t *testing.T) {
|
t.Run(scenario.Name, func(t *testing.T) {
|
||||||
@@ -323,6 +387,9 @@ func TestAlertProvider_GetConfig(t *testing.T) {
|
|||||||
if got.WebhookURL != scenario.ExpectedOutput.WebhookURL {
|
if got.WebhookURL != scenario.ExpectedOutput.WebhookURL {
|
||||||
t.Errorf("expected webhook URL to be %s, got %s", scenario.ExpectedOutput.WebhookURL, got.WebhookURL)
|
t.Errorf("expected webhook URL to be %s, got %s", scenario.ExpectedOutput.WebhookURL, got.WebhookURL)
|
||||||
}
|
}
|
||||||
|
if got.MessageContent != scenario.ExpectedOutput.MessageContent {
|
||||||
|
t.Errorf("expected message content to be %s, got %s", scenario.ExpectedOutput.MessageContent, got.MessageContent)
|
||||||
|
}
|
||||||
// Test ValidateOverrides as well, since it really just calls GetConfig
|
// Test ValidateOverrides as well, since it really just calls GetConfig
|
||||||
if err = scenario.Provider.ValidateOverrides(scenario.InputGroup, &scenario.InputAlert); err != nil {
|
if err = scenario.Provider.ValidateOverrides(scenario.InputGroup, &scenario.InputAlert); err != nil {
|
||||||
t.Errorf("unexpected error: %s", err)
|
t.Errorf("unexpected error: %s", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user