mirror of
https://github.com/TwiN/gatus.git
synced 2025-06-30 22:41:19 +02:00
Add endpoints.onErrorAdd
Add endpoints[].onErrorAdd to add response body or parts of it as error, when the conditions fail for easier debugging. Implements https://github.com/TwiN/gatus/issues/742
This commit is contained in:
@ -272,6 +272,7 @@ You can then configure alerts to be triggered when an endpoint is unhealthy once
|
||||
| `endpoints[].ui.hide-url` | Whether to ensure the URL is not displayed in the results. Useful if the URL contains a token. | `false` |
|
||||
| `endpoints[].ui.dont-resolve-failed-conditions` | Whether to resolve failed conditions for the UI. | `false` |
|
||||
| `endpoints[].ui.badge.reponse-time` | List of response time thresholds. Each time a threshold is reached, the badge has a different color. | `[50, 200, 300, 500, 750]` |
|
||||
| `endpoints[].onErrorAdd` | Add whole response Body ("[BODY]") or part of JSON ("[BODY].error") when an error occurs. | `""` |
|
||||
|
||||
|
||||
### External Endpoints
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TwiN/gatus/v5/jsonpath"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -120,6 +121,9 @@ type Endpoint struct {
|
||||
|
||||
// NumberOfSuccessesInARow is the number of successful evaluations in a row
|
||||
NumberOfSuccessesInARow int `yaml:"-"`
|
||||
|
||||
// OnErrorAdd is the message or [BODY] or part of [BODY].json to add to the result's errors if the endpoint fails
|
||||
OnErrorAdd string `yaml:"onErrorAdd,omitempty"`
|
||||
}
|
||||
|
||||
// IsEnabled returns whether the endpoint is enabled or not
|
||||
@ -302,6 +306,25 @@ func (endpoint *Endpoint) EvaluateHealth() *Result {
|
||||
if endpoint.UIConfig.HideConditions {
|
||||
result.ConditionResults = nil
|
||||
}
|
||||
|
||||
if endpoint.OnErrorAdd != "" && !result.Success {
|
||||
if endpoint.OnErrorAdd == BodyPlaceholder && len(result.Body) > 0 {
|
||||
result.Errors = append(result.Errors, string(result.Body))
|
||||
} else if strings.Contains(endpoint.OnErrorAdd, BodyPlaceholder) && len(result.Body) > 0 {
|
||||
resolvedElement, resolvedElementLength, err := jsonpath.Eval(strings.TrimPrefix(
|
||||
strings.TrimPrefix(endpoint.OnErrorAdd, BodyPlaceholder), "."), result.Body)
|
||||
if err != nil {
|
||||
result.Errors = append(result.Errors, "Decoding of endpoint.OnErrorAdd failed: "+err.Error())
|
||||
} else {
|
||||
if resolvedElementLength > 0 {
|
||||
result.Errors = append(result.Errors, resolvedElement)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.Errors = append(result.Errors, endpoint.OnErrorAdd)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@ -417,6 +440,9 @@ func (endpoint *Endpoint) buildHTTPRequest() *http.Request {
|
||||
|
||||
// needsToReadBody checks if there's any condition that requires the response Body to be read
|
||||
func (endpoint *Endpoint) needsToReadBody() bool {
|
||||
if strings.Contains(endpoint.OnErrorAdd, BodyPlaceholder) {
|
||||
return true
|
||||
}
|
||||
for _, condition := range endpoint.Conditions {
|
||||
if condition.hasBodyPlaceholder() {
|
||||
return true
|
||||
|
@ -204,6 +204,29 @@ func TestEndpoint(t *testing.T) {
|
||||
},
|
||||
MockRoundTripper: nil,
|
||||
},
|
||||
{
|
||||
Name: "failed-status-with-error-from-body",
|
||||
Endpoint: Endpoint{
|
||||
Name: "website-health",
|
||||
URL: "https://twin.sh/health",
|
||||
Conditions: []Condition{"[STATUS] == 200"},
|
||||
OnErrorAdd: "[BODY].error",
|
||||
},
|
||||
ExpectedResult: &Result{
|
||||
Success: false,
|
||||
Connected: true,
|
||||
Hostname: "twin.sh",
|
||||
ConditionResults: []*ConditionResult{
|
||||
{Condition: "[STATUS] (502) == 200", Success: false},
|
||||
},
|
||||
DomainExpiration: 0, // Because there's no [DOMAIN_EXPIRATION] condition, this is not resolved, so it should be 0.
|
||||
Errors: []string{"something went wrong"},
|
||||
},
|
||||
MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
|
||||
return &http.Response{StatusCode: http.StatusBadGateway, Body: io.NopCloser(strings.NewReader(
|
||||
"{\"error\":\"something went wrong\"}"))}
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(scenario.Name, func(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user