feat(alerting): custom alert support endpoint errors (#844)
* feat(alerting): add support for including endpoint errors in custom alerts - Updated `buildHTTPRequest` method in `AlertProvider` to accept a `result` parameter. - Added support for including `[ENDPOINT_ERRORS]` in both the request body and URL, which will be replaced by the errors from `Result.Errors[]`. - Adjusted `CreateExternalEndpointResult` to capture and store errors from query parameters. - This allows custom alerts to include detailed error information, enhancing the flexibility of alert notifications. * feat: add ENDPOINT_ERRORS example * feat: add tests * Refactor: code review feedback * delete unsed errors * Update README.md * Apply suggestions from code review --------- Co-authored-by: raojinlin <raojinlin302@gmail.com> Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
@ -50,7 +50,7 @@ func (provider *AlertProvider) GetAlertStatePlaceholderValue(resolved bool) stri
|
||||
return status
|
||||
}
|
||||
|
||||
func (provider *AlertProvider) buildHTTPRequest(ep *endpoint.Endpoint, alert *alert.Alert, resolved bool) *http.Request {
|
||||
func (provider *AlertProvider) buildHTTPRequest(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) *http.Request {
|
||||
body, url, method := provider.Body, provider.URL, provider.Method
|
||||
body = strings.ReplaceAll(body, "[ALERT_DESCRIPTION]", alert.GetDescription())
|
||||
url = strings.ReplaceAll(url, "[ALERT_DESCRIPTION]", alert.GetDescription())
|
||||
@ -60,6 +60,8 @@ func (provider *AlertProvider) buildHTTPRequest(ep *endpoint.Endpoint, alert *al
|
||||
url = strings.ReplaceAll(url, "[ENDPOINT_GROUP]", ep.Group)
|
||||
body = strings.ReplaceAll(body, "[ENDPOINT_URL]", ep.URL)
|
||||
url = strings.ReplaceAll(url, "[ENDPOINT_URL]", ep.URL)
|
||||
body = strings.ReplaceAll(body, "[RESULT_ERRORS]", strings.Join(result.Errors, ","))
|
||||
url = strings.ReplaceAll(url, "[RESULT_ERRORS]", strings.Join(result.Errors, ","))
|
||||
if resolved {
|
||||
body = strings.ReplaceAll(body, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetAlertStatePlaceholderValue(true))
|
||||
url = strings.ReplaceAll(url, "[ALERT_TRIGGERED_OR_RESOLVED]", provider.GetAlertStatePlaceholderValue(true))
|
||||
@ -79,7 +81,7 @@ func (provider *AlertProvider) buildHTTPRequest(ep *endpoint.Endpoint, alert *al
|
||||
}
|
||||
|
||||
func (provider *AlertProvider) Send(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) error {
|
||||
request := provider.buildHTTPRequest(ep, alert, resolved)
|
||||
request := provider.buildHTTPRequest(ep, alert, result, resolved)
|
||||
response, err := client.GetHTTPClient(provider.ClientConfig).Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -140,6 +140,53 @@ func TestAlertProvider_buildHTTPRequest(t *testing.T) {
|
||||
request := customAlertProvider.buildHTTPRequest(
|
||||
&endpoint.Endpoint{Name: "endpoint-name", Group: "endpoint-group", URL: "https://example.com"},
|
||||
&alert.Alert{Description: &alertDescription},
|
||||
&endpoint.Result{Errors: []string{}},
|
||||
scenario.Resolved,
|
||||
)
|
||||
if request.URL.String() != scenario.ExpectedURL {
|
||||
t.Error("expected URL to be", scenario.ExpectedURL, "got", request.URL.String())
|
||||
}
|
||||
body, _ := io.ReadAll(request.Body)
|
||||
if string(body) != scenario.ExpectedBody {
|
||||
t.Error("expected body to be", scenario.ExpectedBody, "got", string(body))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertProviderWithResultErrors_buildHTTPRequest(t *testing.T) {
|
||||
customAlertWithErrorsProvider := &AlertProvider{
|
||||
URL: "https://example.com/[ENDPOINT_GROUP]/[ENDPOINT_NAME]?event=[ALERT_TRIGGERED_OR_RESOLVED]&description=[ALERT_DESCRIPTION]&url=[ENDPOINT_URL]&error=[RESULT_ERRORS]",
|
||||
Body: "[ENDPOINT_NAME],[ENDPOINT_GROUP],[ALERT_DESCRIPTION],[ENDPOINT_URL],[ALERT_TRIGGERED_OR_RESOLVED],[RESULT_ERRORS]",
|
||||
}
|
||||
alertDescription := "alert-description"
|
||||
scenarios := []struct {
|
||||
AlertProvider *AlertProvider
|
||||
Resolved bool
|
||||
ExpectedURL string
|
||||
ExpectedBody string
|
||||
Errors []string
|
||||
}{
|
||||
{
|
||||
AlertProvider: customAlertWithErrorsProvider,
|
||||
Resolved: true,
|
||||
ExpectedURL: "https://example.com/endpoint-group/endpoint-name?event=RESOLVED&description=alert-description&url=https://example.com&error=",
|
||||
ExpectedBody: "endpoint-name,endpoint-group,alert-description,https://example.com,RESOLVED,",
|
||||
},
|
||||
{
|
||||
AlertProvider: customAlertWithErrorsProvider,
|
||||
Resolved: false,
|
||||
ExpectedURL: "https://example.com/endpoint-group/endpoint-name?event=TRIGGERED&description=alert-description&url=https://example.com&error=error1,error2",
|
||||
ExpectedBody: "endpoint-name,endpoint-group,alert-description,https://example.com,TRIGGERED,error1,error2",
|
||||
Errors: []string{"error1", "error2"},
|
||||
},
|
||||
}
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(fmt.Sprintf("resolved-%v-with-default-placeholders-and-result-errors", scenario.Resolved), func(t *testing.T) {
|
||||
request := customAlertWithErrorsProvider.buildHTTPRequest(
|
||||
&endpoint.Endpoint{Name: "endpoint-name", Group: "endpoint-group", URL: "https://example.com"},
|
||||
&alert.Alert{Description: &alertDescription},
|
||||
&endpoint.Result{Errors: scenario.Errors},
|
||||
scenario.Resolved,
|
||||
)
|
||||
if request.URL.String() != scenario.ExpectedURL {
|
||||
@ -190,6 +237,7 @@ func TestAlertProvider_buildHTTPRequestWithCustomPlaceholder(t *testing.T) {
|
||||
request := customAlertProvider.buildHTTPRequest(
|
||||
&endpoint.Endpoint{Name: "endpoint-name", Group: "endpoint-group"},
|
||||
&alert.Alert{Description: &alertDescription},
|
||||
&endpoint.Result{},
|
||||
scenario.Resolved,
|
||||
)
|
||||
if request.URL.String() != scenario.ExpectedURL {
|
||||
|
Reference in New Issue
Block a user