Skip to content

Commit

Permalink
Add critical severity, add result severity to pagerduty
Browse files Browse the repository at this point in the history
  • Loading branch information
bestwebua committed Jun 27, 2023
1 parent 161bf83 commit ad00df2
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 52 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,14 @@ Here are some examples of conditions you can use:

#### Severity

For failure case you can specify index of severity for each condition. Example of usage: `Low :: [STATUS] == 200`. For case, when severity index is omitted, high severity will be used.
For failure case you can specify index of severity for each condition. Example of usage: `Low :: [STATUS] == 200`. For case, when severity index is omitted, critical severity will be used.

| Available Severity statuses |
|:----------------------------|
|`Low` |
|`Medium` |
|`High` |
|`Critical` |

#### Functions
| Function | Description | Example |
Expand Down
2 changes: 1 addition & 1 deletion alerting/provider/pagerduty/pagerduty.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (provider *AlertProvider) buildRequestBody(endpoint *core.Endpoint, alert *
Payload: Payload{
Summary: message,
Source: "Gatus",
Severity: "critical",
Severity: result.SeverityToString(),
},
})
return body
Expand Down
6 changes: 4 additions & 2 deletions core/condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ func (c Condition) evaluate(result *Result, dontResolveFailedConditions bool) bo
// Extracts severity status from condition.
// Returns separated SeverityStatus and condition
func (c Condition) sanitizeSeverityCondition() (SeverityStatus, string) {
severityStatus, complexCondition := High, string(c)
regex, _ := regexp.Compile(`(Low|Medium|High) :: (.+)`)
severityStatus, complexCondition := Critical, string(c)
regex, _ := regexp.Compile(`(Low|Medium|High|Critical) :: (.+)`)
matchedStringsSlice := regex.FindStringSubmatch(complexCondition)
if len(matchedStringsSlice) == 0 {
return severityStatus, complexCondition
Expand All @@ -176,6 +176,8 @@ func (c Condition) sanitizeSeverityCondition() (SeverityStatus, string) {
severityStatus = Medium
case foundSeverityStatus == "High":
severityStatus = High
case foundSeverityStatus == "Critical":
severityStatus = Critical
}

return severityStatus, matchedStringsSlice[2]
Expand Down
69 changes: 39 additions & 30 deletions core/condition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{HTTPStatus: 500},
ExpectedSuccess: false,
ExpectedOutput: "[STATUS] (500) == 200",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "status-failure",
Expand All @@ -112,6 +112,14 @@ func TestCondition_evaluate(t *testing.T) {
ExpectedOutput: "[STATUS] (500) == 200",
ExpectedSeverity: High,
},
{
Name: "status-failure",
Condition: Condition("Critical :: [STATUS] == 200"),
Result: &Result{HTTPStatus: 500},
ExpectedSuccess: false,
ExpectedOutput: "[STATUS] (500) == 200",
ExpectedSeverity: Critical,
},
{
Name: "status-using-less-than",
Condition: Condition("[STATUS] < 300"),
Expand All @@ -126,7 +134,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{HTTPStatus: 404},
ExpectedSuccess: false,
ExpectedOutput: "[STATUS] (404) < 300",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "response-time-using-less-than",
Expand All @@ -150,7 +158,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Duration: 50 * time.Millisecond},
ExpectedSuccess: false,
ExpectedOutput: "[RESPONSE_TIME] (50) < potato (0)", // Non-numerical values automatically resolve to 0
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "response-time-using-greater-than",
Expand Down Expand Up @@ -182,15 +190,15 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Duration: 499 * time.Millisecond},
ExpectedSuccess: false,
ExpectedOutput: "[RESPONSE_TIME] (499) >= 500",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "response-time-using-greater-than-or-equal-to-failure",
Condition: Condition("[RESPONSE_TIME] >= 500"),
Result: &Result{Duration: 499 * time.Millisecond},
ExpectedSuccess: false,
ExpectedOutput: "[RESPONSE_TIME] (499) >= 500",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "response-time-using-less-than-or-equal-to-equal",
Expand All @@ -214,7 +222,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Duration: 750 * time.Millisecond},
ExpectedSuccess: false,
ExpectedOutput: "[RESPONSE_TIME] (750) <= 500",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body",
Expand Down Expand Up @@ -254,7 +262,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("100")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY] (100) > 123",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body-jsonpath",
Expand All @@ -278,15 +286,15 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"data\": {\"id\": 1}}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY].data.name (INVALID) == john",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body-jsonpath-complex-len-invalid",
Condition: Condition("len([BODY].data.name) == john"),
Result: &Result{Body: []byte("{\"data\": {\"id\": 1}}")},
ExpectedSuccess: false,
ExpectedOutput: "len([BODY].data.name) (INVALID) == john",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body-jsonpath-double-placeholder",
Expand All @@ -302,7 +310,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY].user.firstName (john) == [BODY].user.lastName (doe)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body-jsonpath-when-body-is-array",
Expand All @@ -318,7 +326,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"statusCode\": 500, \"message\": \"Internal Server Error\"}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY][0].name (INVALID) == test",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body-jsonpath-complex-int",
Expand Down Expand Up @@ -350,7 +358,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"data\": {\"id\": 1}}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY].data.id (1) > 5",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "body-jsonpath-float-using-greater-than-issue433", // As of v5.3.1, Gatus will convert a float to an int. We're losing precision, but it's better than just returning 0
Expand All @@ -374,7 +382,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"data\": {\"id\": 10}}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY].data.id (10) < 5",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "connected",
Expand All @@ -390,7 +398,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Connected: false},
ExpectedSuccess: false,
ExpectedOutput: "[CONNECTED] (false) == true",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "certificate-expiration-not-set",
Expand All @@ -414,7 +422,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{CertificateExpiration: time.Hour * 24 * 14},
ExpectedSuccess: false,
ExpectedOutput: "[CERTIFICATE_EXPIRATION] (1209600000) > 2419200000",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "certificate-expiration-greater-than-duration",
Expand All @@ -430,15 +438,15 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{CertificateExpiration: 24 * time.Hour},
ExpectedSuccess: false,
ExpectedOutput: "[CERTIFICATE_EXPIRATION] (86400000) > 48h (172800000)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "no-placeholders",
Condition: Condition("1 == 2"),
Result: &Result{},
ExpectedSuccess: false,
ExpectedOutput: "1 == 2",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
///////////////
// Functions //
Expand Down Expand Up @@ -474,7 +482,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"name\": \"john.doe\"}")},
ExpectedSuccess: false,
ExpectedOutput: "len([BODY].data) (INVALID) == 8",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "len-body-string",
Expand Down Expand Up @@ -563,7 +571,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"name\": \"john.doe\"}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY].name (john.doe) == pat(bob*)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "pat-body-html",
Expand All @@ -579,15 +587,15 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte(`<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body><div id="user">jane.doe</div></body></html>`)},
ExpectedSuccess: false,
ExpectedOutput: "[BODY] (<!DOCTYPE html><html lang...(truncated)) == pat(*<div id=\"user\">john.doe</div>*)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "pat-body-html-failure-alt",
Condition: Condition("pat(*<div id=\"user\">john.doe</div>*) == [BODY]"),
Result: &Result{Body: []byte(`<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body><div id="user">jane.doe</div></body></html>`)},
ExpectedSuccess: false,
ExpectedOutput: "pat(*<div id=\"user\">john.doe</div>*) == [BODY] (<!DOCTYPE html><html lang...(truncated))",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "pat-body-in-array",
Expand All @@ -611,7 +619,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{IP: "255.255.255.255"},
ExpectedSuccess: false,
ExpectedOutput: "[IP] (255.255.255.255) == pat(10.*)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "pat-status",
Expand All @@ -627,7 +635,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{HTTPStatus: 200},
ExpectedSuccess: false,
ExpectedOutput: "[STATUS] (200) == pat(4*)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
// any
{
Expand All @@ -652,7 +660,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"name\": \"bob\"}")},
ExpectedSuccess: false,
ExpectedOutput: "[BODY].name (bob) == any(john.doe, jane.doe)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "any-status-1",
Expand Down Expand Up @@ -684,7 +692,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{HTTPStatus: 404},
ExpectedSuccess: false,
ExpectedOutput: "[STATUS] (404) == any(200, 429)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "any-status-failure-but-dont-resolve",
Expand All @@ -693,7 +701,7 @@ func TestCondition_evaluate(t *testing.T) {
DontResolveFailedConditions: true,
ExpectedSuccess: false,
ExpectedOutput: "[STATUS] == any(200, 429)",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
// has
{
Expand All @@ -719,7 +727,7 @@ func TestCondition_evaluate(t *testing.T) {
Result: &Result{Body: []byte("{\"errors\": [\"1\"]}")},
ExpectedSuccess: false,
ExpectedOutput: "has([BODY].errors) (true) == false",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
{
Name: "has-failure-but-dont-resolve",
Expand All @@ -728,7 +736,7 @@ func TestCondition_evaluate(t *testing.T) {
DontResolveFailedConditions: true,
ExpectedSuccess: false,
ExpectedOutput: "has([BODY].errors) == false",
ExpectedSeverity: High,
ExpectedSeverity: Critical,
},
}
for _, scenario := range scenarios {
Expand All @@ -753,11 +761,12 @@ func TestCondition_sanitizeSeverityCondition(t *testing.T) {
expectedSeverity SeverityStatus
expectedCondition string
}{
{condition: "[STATUS] == 200", expectedSeverity: High, expectedCondition: "[STATUS] == 200"},
{condition: "[STATUS] == 200", expectedSeverity: Critical, expectedCondition: "[STATUS] == 200"},
{condition: "Low :: [STATUS] == 201", expectedSeverity: Low, expectedCondition: "[STATUS] == 201"},
{condition: "Medium :: [STATUS] == 404", expectedSeverity: Medium, expectedCondition: "[STATUS] == 404"},
{condition: "High :: [STATUS] == 500", expectedSeverity: High, expectedCondition: "[STATUS] == 500"},
{condition: "NotValid :: [STATUS] == 42", expectedSeverity: High, expectedCondition: "NotValid :: [STATUS] == 42"},
{condition: "Critical :: [STATUS] == 500", expectedSeverity: Critical, expectedCondition: "[STATUS] == 500"},
{condition: "NotValid :: [STATUS] == 42", expectedSeverity: Critical, expectedCondition: "NotValid :: [STATUS] == 42"},
}

for _, scenario := range scenarios {
Expand Down
2 changes: 2 additions & 0 deletions core/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ func (endpoint *Endpoint) EvaluateHealth() *Result {
result.Severity.Medium = true
case severityStatus == High:
result.Severity.High = true
case severityStatus == Critical:
result.Severity.Critical = true
}

result.SeverityStatus = result.determineSeverityStatus()
Expand Down
20 changes: 10 additions & 10 deletions core/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ func TestEndpoint(t *testing.T) {
Success: false,
Connected: true,
Hostname: "twin.sh",
Severity: Severity{High: true},
SeverityStatus: High,
Severity: Severity{Critical: true},
SeverityStatus: Critical,
ConditionResults: []*ConditionResult{
{Condition: "[STATUS] == 200", Success: true},
{Condition: "[BODY].status (DOWN) == UP", Success: false},
Expand All @@ -84,8 +84,8 @@ func TestEndpoint(t *testing.T) {
Success: false,
Connected: true,
Hostname: "twin.sh",
Severity: Severity{High: true},
SeverityStatus: High,
Severity: Severity{Critical: true},
SeverityStatus: Critical,
ConditionResults: []*ConditionResult{
{Condition: "[STATUS] (502) == 200", Success: false},
},
Expand All @@ -107,8 +107,8 @@ func TestEndpoint(t *testing.T) {
Success: false,
Connected: true,
Hostname: "twin.sh",
Severity: Severity{High: true},
SeverityStatus: High,
Severity: Severity{Critical: true},
SeverityStatus: Critical,
ConditionResults: []*ConditionResult{
// Because UIConfig.DontResolveFailedConditions is true, the values in the condition should not be resolved
{Condition: "[CERTIFICATE_EXPIRATION] > 100h", Success: false},
Expand Down Expand Up @@ -155,8 +155,8 @@ func TestEndpoint(t *testing.T) {
ExpectedResult: &Result{
Success: false,
Connected: false,
Severity: Severity{High: true},
SeverityStatus: High,
Severity: Severity{Critical: true},
SeverityStatus: Critical,
Hostname: "", // Because Endpoint.UIConfig.HideHostname is true, this should be empty.
ConditionResults: []*ConditionResult{
{Condition: "[CONNECTED] (false) == true", Success: false},
Expand All @@ -180,8 +180,8 @@ func TestEndpoint(t *testing.T) {
ExpectedResult: &Result{
Success: false,
Connected: false,
Severity: Severity{High: true},
SeverityStatus: High,
Severity: Severity{Critical: true},
SeverityStatus: Critical,
Hostname: "twin.sh",
ConditionResults: []*ConditionResult{
{Condition: "[CONNECTED] (false) == true", Success: false},
Expand Down
Loading

0 comments on commit ad00df2

Please sign in to comment.