diff --git a/controller/controller_test.go b/controller/controller_test.go
index f0a526f8..d6f3ea36 100644
--- a/controller/controller_test.go
+++ b/controller/controller_test.go
@@ -38,7 +38,6 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
Errors: nil,
Connected: true,
Success: true,
@@ -64,7 +63,6 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
Errors: []string{"error-1", "error-2"},
Connected: true,
Success: false,
diff --git a/core/condition.go b/core/condition.go
index c610c34e..7c957d32 100644
--- a/core/condition.go
+++ b/core/condition.go
@@ -23,7 +23,7 @@ const (
// DNSRCodePlaceholder is a place holder for DNS_RCODE
//
- // Values that could be NOERROR, FORMERR, SERVFAIL, NXDOMAIN, NOTIMP and REFUSED
+ // Values that could replace the placeholder: NOERROR, FORMERR, SERVFAIL, NXDOMAIN, NOTIMP, REFUSED
DNSRCodePlaceholder = "[DNS_RCODE]"
// ResponseTimePlaceholder is a placeholder for the request response time, in milliseconds.
@@ -123,6 +123,12 @@ func (c Condition) evaluate(result *Result) bool {
return success
}
+// hasBodyPlaceholder checks whether the condition has a BodyPlaceholder
+// Used for determining whether the response body should be read or not
+func (c Condition) hasBodyPlaceholder() bool {
+ return strings.Contains(string(c), BodyPlaceholder)
+}
+
// isEqual compares two strings.
//
// Supports the pattern and the any functions.
@@ -181,7 +187,7 @@ func isEqual(first, second string) bool {
func sanitizeAndResolve(elements []string, result *Result) ([]string, []string) {
parameters := make([]string, len(elements))
resolvedParameters := make([]string, len(elements))
- body := strings.TrimSpace(string(result.Body))
+ body := strings.TrimSpace(string(result.body))
for i, element := range elements {
element = strings.TrimSpace(element)
parameters[i] = element
@@ -208,7 +214,7 @@ func sanitizeAndResolve(elements []string, result *Result) ([]string, []string)
wantLength = true
element = strings.TrimSuffix(strings.TrimPrefix(element, LengthFunctionPrefix), FunctionSuffix)
}
- resolvedElement, resolvedElementLength, err := jsonpath.Eval(strings.TrimPrefix(element, BodyPlaceholder+"."), result.Body)
+ resolvedElement, resolvedElementLength, err := jsonpath.Eval(strings.TrimPrefix(element, BodyPlaceholder+"."), result.body)
if err != nil {
if err.Error() != "unexpected end of JSON input" {
result.Errors = append(result.Errors, err.Error())
diff --git a/core/condition_bench_test.go b/core/condition_bench_test.go
index ea846e54..dbc1e582 100644
--- a/core/condition_bench_test.go
+++ b/core/condition_bench_test.go
@@ -5,7 +5,7 @@ import "testing"
func BenchmarkCondition_evaluateWithBodyStringAny(b *testing.B) {
condition := Condition("[BODY].name == any(john.doe, jane.doe)")
for n := 0; n < b.N; n++ {
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
}
b.ReportAllocs()
@@ -14,7 +14,7 @@ func BenchmarkCondition_evaluateWithBodyStringAny(b *testing.B) {
func BenchmarkCondition_evaluateWithBodyStringAnyFailure(b *testing.B) {
condition := Condition("[BODY].name == any(john.doe, jane.doe)")
for n := 0; n < b.N; n++ {
- result := &Result{Body: []byte("{\"name\": \"bob.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"bob.doe\"}")}
condition.evaluate(result)
}
b.ReportAllocs()
@@ -23,7 +23,7 @@ func BenchmarkCondition_evaluateWithBodyStringAnyFailure(b *testing.B) {
func BenchmarkCondition_evaluateWithBodyString(b *testing.B) {
condition := Condition("[BODY].name == john.doe")
for n := 0; n < b.N; n++ {
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
}
b.ReportAllocs()
@@ -32,7 +32,7 @@ func BenchmarkCondition_evaluateWithBodyString(b *testing.B) {
func BenchmarkCondition_evaluateWithBodyStringFailure(b *testing.B) {
condition := Condition("[BODY].name == john.doe")
for n := 0; n < b.N; n++ {
- result := &Result{Body: []byte("{\"name\": \"bob.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"bob.doe\"}")}
condition.evaluate(result)
}
b.ReportAllocs()
@@ -41,7 +41,7 @@ func BenchmarkCondition_evaluateWithBodyStringFailure(b *testing.B) {
func BenchmarkCondition_evaluateWithBodyStringLen(b *testing.B) {
condition := Condition("len([BODY].name) == 8")
for n := 0; n < b.N; n++ {
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
}
b.ReportAllocs()
@@ -50,7 +50,7 @@ func BenchmarkCondition_evaluateWithBodyStringLen(b *testing.B) {
func BenchmarkCondition_evaluateWithBodyStringLenFailure(b *testing.B) {
condition := Condition("len([BODY].name) == 8")
for n := 0; n < b.N; n++ {
- result := &Result{Body: []byte("{\"name\": \"bob.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"bob.doe\"}")}
condition.evaluate(result)
}
b.ReportAllocs()
diff --git a/core/condition_test.go b/core/condition_test.go
index 3b18240b..2b4d5d99 100644
--- a/core/condition_test.go
+++ b/core/condition_test.go
@@ -162,7 +162,7 @@ func TestCondition_evaluateWithResponseTimeUsingLessThanOrEqualTo(t *testing.T)
func TestCondition_evaluateWithBody(t *testing.T) {
condition := Condition("[BODY] == test")
- result := &Result{Body: []byte("test")}
+ result := &Result{body: []byte("test")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -175,7 +175,7 @@ func TestCondition_evaluateWithBody(t *testing.T) {
func TestCondition_evaluateWithBodyJSONPath(t *testing.T) {
condition := Condition("[BODY].status == UP")
- result := &Result{Body: []byte("{\"status\":\"UP\"}")}
+ result := &Result{body: []byte("{\"status\":\"UP\"}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -188,7 +188,7 @@ func TestCondition_evaluateWithBodyJSONPath(t *testing.T) {
func TestCondition_evaluateWithBodyJSONPathComplex(t *testing.T) {
condition := Condition("[BODY].data.name == john")
- result := &Result{Body: []byte("{\"data\": {\"id\": 1, \"name\": \"john\"}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 1, \"name\": \"john\"}}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -201,7 +201,7 @@ func TestCondition_evaluateWithBodyJSONPathComplex(t *testing.T) {
func TestCondition_evaluateWithInvalidBodyJSONPathComplex(t *testing.T) {
condition := Condition("[BODY].data.name == john")
- result := &Result{Body: []byte("{\"data\": {\"id\": 1}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure, because the path was invalid", condition)
@@ -214,7 +214,7 @@ func TestCondition_evaluateWithInvalidBodyJSONPathComplex(t *testing.T) {
func TestCondition_evaluateWithInvalidBodyJSONPathComplexWithLengthFunction(t *testing.T) {
condition := Condition("len([BODY].data.name) == john")
- result := &Result{Body: []byte("{\"data\": {\"id\": 1}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure, because the path was invalid", condition)
@@ -227,7 +227,7 @@ func TestCondition_evaluateWithInvalidBodyJSONPathComplexWithLengthFunction(t *t
func TestCondition_evaluateWithBodyJSONPathDoublePlaceholders(t *testing.T) {
condition := Condition("[BODY].user.firstName != [BODY].user.lastName")
- result := &Result{Body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")}
+ result := &Result{body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -240,7 +240,7 @@ func TestCondition_evaluateWithBodyJSONPathDoublePlaceholders(t *testing.T) {
func TestCondition_evaluateWithBodyJSONPathDoublePlaceholdersFailure(t *testing.T) {
condition := Condition("[BODY].user.firstName == [BODY].user.lastName")
- result := &Result{Body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")}
+ result := &Result{body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure", condition)
@@ -253,7 +253,7 @@ func TestCondition_evaluateWithBodyJSONPathDoublePlaceholdersFailure(t *testing.
func TestCondition_evaluateWithBodyJSONPathLongInt(t *testing.T) {
condition := Condition("[BODY].data.id == 1")
- result := &Result{Body: []byte("{\"data\": {\"id\": 1}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -266,7 +266,7 @@ func TestCondition_evaluateWithBodyJSONPathLongInt(t *testing.T) {
func TestCondition_evaluateWithBodyJSONPathComplexInt(t *testing.T) {
condition := Condition("[BODY].data[1].id == 2")
- result := &Result{Body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")}
+ result := &Result{body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -279,7 +279,7 @@ func TestCondition_evaluateWithBodyJSONPathComplexInt(t *testing.T) {
func TestCondition_evaluateWithBodyJSONPathComplexIntUsingGreaterThan(t *testing.T) {
condition := Condition("[BODY].data.id > 0")
- result := &Result{Body: []byte("{\"data\": {\"id\": 1}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -292,7 +292,7 @@ func TestCondition_evaluateWithBodyJSONPathComplexIntUsingGreaterThan(t *testing
func TestCondition_evaluateWithBodyJSONPathComplexIntFailureUsingGreaterThan(t *testing.T) {
condition := Condition("[BODY].data.id > 5")
- result := &Result{Body: []byte("{\"data\": {\"id\": 1}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure", condition)
@@ -305,7 +305,7 @@ func TestCondition_evaluateWithBodyJSONPathComplexIntFailureUsingGreaterThan(t *
func TestCondition_evaluateWithBodyJSONPathComplexIntUsingLessThan(t *testing.T) {
condition := Condition("[BODY].data.id < 5")
- result := &Result{Body: []byte("{\"data\": {\"id\": 2}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 2}}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -318,7 +318,7 @@ func TestCondition_evaluateWithBodyJSONPathComplexIntUsingLessThan(t *testing.T)
func TestCondition_evaluateWithBodyJSONPathComplexIntFailureUsingLessThan(t *testing.T) {
condition := Condition("[BODY].data.id < 5")
- result := &Result{Body: []byte("{\"data\": {\"id\": 10}}")}
+ result := &Result{body: []byte("{\"data\": {\"id\": 10}}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure", condition)
@@ -331,7 +331,7 @@ func TestCondition_evaluateWithBodyJSONPathComplexIntFailureUsingLessThan(t *tes
func TestCondition_evaluateWithBodySliceLength(t *testing.T) {
condition := Condition("len([BODY].data) == 3")
- result := &Result{Body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")}
+ result := &Result{body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -344,7 +344,7 @@ func TestCondition_evaluateWithBodySliceLength(t *testing.T) {
func TestCondition_evaluateWithBodyStringLength(t *testing.T) {
condition := Condition("len([BODY].name) == 8")
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -357,7 +357,7 @@ func TestCondition_evaluateWithBodyStringLength(t *testing.T) {
func TestCondition_evaluateWithBodyPattern(t *testing.T) {
condition := Condition("[BODY] == pat(*john*)")
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -370,7 +370,7 @@ func TestCondition_evaluateWithBodyPattern(t *testing.T) {
func TestCondition_evaluateWithReverseBodyPattern(t *testing.T) {
condition := Condition("pat(*john*) == [BODY]")
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -383,7 +383,7 @@ func TestCondition_evaluateWithReverseBodyPattern(t *testing.T) {
func TestCondition_evaluateWithBodyStringPattern(t *testing.T) {
condition := Condition("[BODY].name == pat(*ohn*)")
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -397,7 +397,7 @@ func TestCondition_evaluateWithBodyStringPattern(t *testing.T) {
func TestCondition_evaluateWithBodyHTMLPattern(t *testing.T) {
var html = `
john.doe
`
condition := Condition("[BODY] == pat(*john.doe
*)")
- result := &Result{Body: []byte(html)}
+ result := &Result{body: []byte(html)}
condition.evaluate(result)
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
@@ -410,7 +410,7 @@ func TestCondition_evaluateWithBodyHTMLPattern(t *testing.T) {
func TestCondition_evaluateWithBodyStringPatternFailure(t *testing.T) {
condition := Condition("[BODY].name == pat(bob*)")
- result := &Result{Body: []byte("{\"name\": \"john.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure", condition)
@@ -477,8 +477,8 @@ func TestCondition_evaluateWithBodyStringAny(t *testing.T) {
condition := Condition("[BODY].name == any(john.doe, jane.doe)")
expectedConditionDisplayed := "[BODY].name == any(john.doe, jane.doe)"
results := []*Result{
- {Body: []byte("{\"name\": \"john.doe\"}")},
- {Body: []byte("{\"name\": \"jane.doe\"}")},
+ {body: []byte("{\"name\": \"john.doe\"}")},
+ {body: []byte("{\"name\": \"jane.doe\"}")},
}
for _, result := range results {
success := condition.evaluate(result)
@@ -493,7 +493,7 @@ func TestCondition_evaluateWithBodyStringAny(t *testing.T) {
func TestCondition_evaluateWithBodyStringAnyFailure(t *testing.T) {
condition := Condition("[BODY].name == any(john.doe, jane.doe)")
- result := &Result{Body: []byte("{\"name\": \"bob.doe\"}")}
+ result := &Result{body: []byte("{\"name\": \"bob.doe\"}")}
condition.evaluate(result)
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure", condition)
@@ -660,3 +660,27 @@ func TestCondition_evaluateWithCertificateExpirationGreaterThanDurationFailure(t
t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
}
}
+
+func TestCondition_evaluateWithInvalidOperator(t *testing.T) {
+ condition := Condition("[STATUS] ? 201")
+ result := &Result{HTTPStatus: 201}
+ condition.evaluate(result)
+ if result.Success {
+ t.Error("condition was invalid, result should've been a failure")
+ }
+ if len(result.Errors) != 1 {
+ t.Error("condition was invalid, result should've had an error")
+ }
+}
+
+func TestCondition_evaluateWithNoPlaceholder(t *testing.T) {
+ condition := Condition("1 == 2")
+ result := &Result{}
+ condition.evaluate(result)
+ if result.ConditionResults[0].Success {
+ t.Errorf("Condition '%s' should have been a failure", condition)
+ }
+ if result.ConditionResults[0].Condition != string(condition) {
+ t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, condition, result.ConditionResults[0].Condition)
+ }
+}
diff --git a/core/dns.go b/core/dns.go
index 6afcf5e6..8a77ba85 100644
--- a/core/dns.go
+++ b/core/dns.go
@@ -60,26 +60,26 @@ func (d *DNS) query(url string, result *Result) {
switch rr.Header().Rrtype {
case dns.TypeA:
if a, ok := rr.(*dns.A); ok {
- result.Body = []byte(a.A.String())
+ result.body = []byte(a.A.String())
}
case dns.TypeAAAA:
if aaaa, ok := rr.(*dns.AAAA); ok {
- result.Body = []byte(aaaa.AAAA.String())
+ result.body = []byte(aaaa.AAAA.String())
}
case dns.TypeCNAME:
if cname, ok := rr.(*dns.CNAME); ok {
- result.Body = []byte(cname.Target)
+ result.body = []byte(cname.Target)
}
case dns.TypeMX:
if mx, ok := rr.(*dns.MX); ok {
- result.Body = []byte(mx.Mx)
+ result.body = []byte(mx.Mx)
}
case dns.TypeNS:
if ns, ok := rr.(*dns.NS); ok {
- result.Body = []byte(ns.Ns)
+ result.body = []byte(ns.Ns)
}
default:
- result.Body = []byte("query type is not supported yet")
+ result.body = []byte("query type is not supported yet")
}
}
}
diff --git a/core/dns_test.go b/core/dns_test.go
index d5073463..c037d5b4 100644
--- a/core/dns_test.go
+++ b/core/dns_test.go
@@ -91,12 +91,12 @@ func TestIntegrationQuery(t *testing.T) {
if test.inputDNS.QueryType == "NS" {
// Because there are often multiple nameservers backing a single domain, we'll only look at the suffix
- if !pattern.Match(test.expectedBody, string(result.Body)) {
- t.Errorf("got %s, expected result %s,", string(result.Body), test.expectedBody)
+ if !pattern.Match(test.expectedBody, string(result.body)) {
+ t.Errorf("got %s, expected result %s,", string(result.body), test.expectedBody)
}
} else {
- if string(result.Body) != test.expectedBody {
- t.Errorf("got %s, expected result %s,", string(result.Body), test.expectedBody)
+ if string(result.body) != test.expectedBody {
+ t.Errorf("got %s, expected result %s,", string(result.body), test.expectedBody)
}
}
})
diff --git a/core/result.go b/core/result.go
index 032dcb81..ea08b899 100644
--- a/core/result.go
+++ b/core/result.go
@@ -12,10 +12,7 @@ type Result struct {
// DNSRCode is the response code of a DNS query in a human readable format
DNSRCode string `json:"-"`
- // Body is the response body
- Body []byte `json:"-"`
-
- // Hostname extracted from the Service URL
+ // Hostname extracted from Service.URL
Hostname string `json:"hostname"`
// IP resolved from the Service URL
@@ -41,4 +38,11 @@ type Result struct {
// CertificateExpiration is the duration before the certificate expires
CertificateExpiration time.Duration `json:"-"`
+
+ // body is the response body
+ //
+ // Note that this variable is only used during the evaluation of a service's health.
+ // This means that the call Service.EvaluateHealth both populates the body (if necessary)
+ // and sets it to nil after the evaluation has been completed.
+ body []byte
}
diff --git a/core/service-status_bench_test.go b/core/service-status_bench_test.go
index fb981296..4f5e7c41 100644
--- a/core/service-status_bench_test.go
+++ b/core/service-status_bench_test.go
@@ -29,7 +29,7 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
+ body: []byte("body"),
Errors: nil,
Connected: true,
Success: true,
@@ -55,7 +55,7 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
+ body: []byte("body"),
Errors: []string{"error-1", "error-2"},
Connected: true,
Success: false,
diff --git a/core/service.go b/core/service.go
index 12f47381..4c24df92 100644
--- a/core/service.go
+++ b/core/service.go
@@ -80,7 +80,7 @@ type Service struct {
// NumberOfFailuresInARow is the number of unsuccessful evaluations in a row
NumberOfFailuresInARow int
- // NumberOfFailuresInARow is the number of successful evaluations in a row
+ // NumberOfSuccessesInARow is the number of successful evaluations in a row
NumberOfSuccessesInARow int
}
@@ -149,6 +149,8 @@ func (service *Service) EvaluateHealth() *Result {
}
}
result.Timestamp = time.Now()
+ // No need to keep the body after the service has been evaluated
+ result.body = nil
return result
}
@@ -220,9 +222,12 @@ func (service *Service) call(result *Result) {
}
result.HTTPStatus = response.StatusCode
result.Connected = response.StatusCode > 0
- result.Body, err = ioutil.ReadAll(response.Body)
- if err != nil {
- result.Errors = append(result.Errors, err.Error())
+ // Only read the body if there's a condition that uses the BodyPlaceholder
+ if service.needsToReadBody() {
+ result.body, err = ioutil.ReadAll(response.Body)
+ if err != nil {
+ result.Errors = append(result.Errors, err.Error())
+ }
}
}
}
@@ -247,3 +252,13 @@ func (service *Service) buildHTTPRequest() *http.Request {
}
return request
}
+
+// needsToReadBody checks if there's any conditions that requires the response body to be read
+func (service *Service) needsToReadBody() bool {
+ for _, condition := range service.Conditions {
+ if condition.hasBodyPlaceholder() {
+ return true
+ }
+ }
+ return false
+}
diff --git a/core/service_test.go b/core/service_test.go
index 6e9a0fc9..8eb55557 100644
--- a/core/service_test.go
+++ b/core/service_test.go
@@ -10,7 +10,7 @@ import (
func TestService_ValidateAndSetDefaults(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
Alerts: []*Alert{{Type: PagerDutyAlert}},
@@ -94,7 +94,7 @@ func TestService_ValidateAndSetDefaultsWithDNS(t *testing.T) {
func TestService_GetAlertsTriggered(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
Alerts: []*Alert{{Type: PagerDutyAlert, Enabled: true}},
@@ -118,7 +118,7 @@ func TestService_GetAlertsTriggered(t *testing.T) {
func TestService_buildHTTPRequest(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
}
@@ -138,7 +138,7 @@ func TestService_buildHTTPRequest(t *testing.T) {
func TestService_buildHTTPRequestWithCustomUserAgent(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
Headers: map[string]string{
@@ -161,7 +161,7 @@ func TestService_buildHTTPRequestWithCustomUserAgent(t *testing.T) {
func TestService_buildHTTPRequestWithHostHeader(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
Method: "POST",
Conditions: []*Condition{&condition},
@@ -182,7 +182,7 @@ func TestService_buildHTTPRequestWithHostHeader(t *testing.T) {
func TestService_buildHTTPRequestWithGraphQLEnabled(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-graphql",
URL: "https://twinnation.org/graphql",
Method: "POST",
Conditions: []*Condition{&condition},
@@ -206,16 +206,17 @@ func TestService_buildHTTPRequestWithGraphQLEnabled(t *testing.T) {
}
body, _ := ioutil.ReadAll(request.Body)
if !strings.HasPrefix(string(body), "{\"query\":") {
- t.Error("request.Body should've started with '{\"query\":', but it didn't:", string(body))
+ t.Error("request.body should've started with '{\"query\":', but it didn't:", string(body))
}
}
func TestIntegrationEvaluateHealth(t *testing.T) {
condition := Condition("[STATUS] == 200")
+ bodyCondition := Condition("[BODY].status == UP")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
- Conditions: []*Condition{&condition},
+ Conditions: []*Condition{&condition, &bodyCondition},
}
result := service.EvaluateHealth()
if !result.ConditionResults[0].Success {
@@ -232,7 +233,7 @@ func TestIntegrationEvaluateHealth(t *testing.T) {
func TestIntegrationEvaluateHealthWithFailure(t *testing.T) {
condition := Condition("[STATUS] == 500")
service := Service{
- Name: "TwiNNatioN",
+ Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
}
@@ -252,7 +253,7 @@ func TestIntegrationEvaluateHealthForDNS(t *testing.T) {
conditionSuccess := Condition("[DNS_RCODE] == NOERROR")
conditionBody := Condition("[BODY] == 93.184.216.34")
service := Service{
- Name: "TwiNNatioN",
+ Name: "example",
URL: "8.8.8.8",
DNS: &DNS{
QueryType: "A",
@@ -275,7 +276,7 @@ func TestIntegrationEvaluateHealthForDNS(t *testing.T) {
func TestIntegrationEvaluateHealthForICMP(t *testing.T) {
conditionSuccess := Condition("[CONNECTED] == true")
service := Service{
- Name: "ICMP test",
+ Name: "icmp-test",
URL: "icmp://127.0.0.1",
Conditions: []*Condition{&conditionSuccess},
}
@@ -294,7 +295,7 @@ func TestIntegrationEvaluateHealthForICMP(t *testing.T) {
func TestService_getIP(t *testing.T) {
conditionSuccess := Condition("[CONNECTED] == true")
service := Service{
- Name: "Invalid URL test",
+ Name: "invalid-url-test",
URL: "",
Conditions: []*Condition{&conditionSuccess},
}
@@ -304,3 +305,27 @@ func TestService_getIP(t *testing.T) {
t.Error("service.getIP(result) should've thrown an error because the URL is invalid, thus cannot be parsed")
}
}
+
+func TestService_NeedsToReadBody(t *testing.T) {
+ statusCondition := Condition("[STATUS] == 200")
+ bodyCondition := Condition("[BODY].status == UP")
+ bodyConditionWithLength := Condition("len([BODY].tags) > 0")
+ if (&Service{Conditions: []*Condition{&statusCondition}}).needsToReadBody() {
+ t.Error("expected false, got true")
+ }
+ if !(&Service{Conditions: []*Condition{&bodyCondition}}).needsToReadBody() {
+ t.Error("expected true, got false")
+ }
+ if !(&Service{Conditions: []*Condition{&bodyConditionWithLength}}).needsToReadBody() {
+ t.Error("expected true, got false")
+ }
+ if !(&Service{Conditions: []*Condition{&statusCondition, &bodyCondition}}).needsToReadBody() {
+ t.Error("expected true, got false")
+ }
+ if !(&Service{Conditions: []*Condition{&bodyCondition, &statusCondition}}).needsToReadBody() {
+ t.Error("expected true, got false")
+ }
+ if !(&Service{Conditions: []*Condition{&bodyConditionWithLength, &statusCondition}}).needsToReadBody() {
+ t.Error("expected true, got false")
+ }
+}
diff --git a/storage/store/memory/memory_test.go b/storage/store/memory/memory_test.go
index d3162f9a..ecdb51e8 100644
--- a/storage/store/memory/memory_test.go
+++ b/storage/store/memory/memory_test.go
@@ -33,7 +33,6 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
Errors: nil,
Connected: true,
Success: true,
@@ -59,7 +58,6 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
Errors: []string{"error-1", "error-2"},
Connected: true,
Success: false,
@@ -107,9 +105,6 @@ func TestStore_Insert(t *testing.T) {
if r.DNSRCode != expectedResult.DNSRCode {
t.Errorf("Result at index %d should've had a DNSRCode of %s, but was actually %s", i, expectedResult.DNSRCode, r.DNSRCode)
}
- if len(r.Body) != len(expectedResult.Body) {
- t.Errorf("Result at index %d should've had a body of length %d, but was actually %d", i, len(expectedResult.Body), len(r.Body))
- }
if r.Hostname != expectedResult.Hostname {
t.Errorf("Result at index %d should've had a Hostname of %s, but was actually %s", i, expectedResult.Hostname, r.Hostname)
}
diff --git a/storage/store/store_bench_test.go b/storage/store/store_bench_test.go
index 1637d59d..a6488ed5 100644
--- a/storage/store/store_bench_test.go
+++ b/storage/store/store_bench_test.go
@@ -32,7 +32,6 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
Errors: nil,
Connected: true,
Success: true,
@@ -58,7 +57,6 @@ var (
Hostname: "example.org",
IP: "127.0.0.1",
HTTPStatus: 200,
- Body: []byte("body"),
Errors: []string{"error-1", "error-2"},
Connected: true,
Success: false,
diff --git a/watchdog/watchdog.go b/watchdog/watchdog.go
index 255615e6..5781756c 100644
--- a/watchdog/watchdog.go
+++ b/watchdog/watchdog.go
@@ -1,7 +1,6 @@
package watchdog
import (
- "fmt"
"log"
"sync"
"time"
@@ -37,26 +36,22 @@ func monitor(service *core.Service) {
monitoringMutex.Lock()
}
if cfg.Debug {
- log.Printf("[watchdog][monitor] Monitoring serviceName=%s", service.Name)
+ log.Printf("[watchdog][monitor] Monitoring group=%s; service=%s", service.Group, service.Name)
}
result := service.EvaluateHealth()
metric.PublishMetricsForService(service, result)
UpdateServiceStatuses(service, result)
- var extra string
- if !result.Success {
- extra = fmt.Sprintf("responseBody=%s", result.Body)
- }
log.Printf(
- "[watchdog][monitor] Monitored serviceName=%s; success=%v; errors=%d; requestDuration=%s; %s",
+ "[watchdog][monitor] Monitored group=%s; service=%s; success=%v; errors=%d; duration=%s",
+ service.Group,
service.Name,
result.Success,
len(result.Errors),
result.Duration.Round(time.Millisecond),
- extra,
)
HandleAlerting(service, result)
if cfg.Debug {
- log.Printf("[watchdog][monitor] Waiting for interval=%s before monitoring serviceName=%s again", service.Interval, service.Name)
+ log.Printf("[watchdog][monitor] Waiting for interval=%s before monitoring group=%s service=%s again", service.Interval, service.Group, service.Name)
}
if !cfg.DisableMonitoringLock {
monitoringMutex.Unlock()