From 91f2764cd5214d1041d1d07b2c5cbd2da5e16df8 Mon Sep 17 00:00:00 2001
From: Frederick Roth <f-roth@megaera.de>
Date: Tue, 6 Jun 2017 22:39:07 +0200
Subject: [PATCH] Add result_type field for http_response input (#2814)

---
 plugins/inputs/http_response/README.md        |  1 +
 plugins/inputs/http_response/http_response.go | 19 +++++++++++---
 .../http_response/http_response_test.go       | 26 ++++++++++++++++---
 3 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/plugins/inputs/http_response/README.md b/plugins/inputs/http_response/README.md
index 3f4e62d9..866fcbb2 100644
--- a/plugins/inputs/http_response/README.md
+++ b/plugins/inputs/http_response/README.md
@@ -41,6 +41,7 @@ This input plugin will test HTTP/HTTPS connections.
 - http_response
     - response_time (float, seconds)
     - http_response_code (int) #The code received
+	- result_type (string) # success, timeout, response_string_mismatch, connection_failed
 
 ### Tags:
 
diff --git a/plugins/inputs/http_response/http_response.go b/plugins/inputs/http_response/http_response.go
index cd3d735d..f3deaf9e 100644
--- a/plugins/inputs/http_response/http_response.go
+++ b/plugins/inputs/http_response/http_response.go
@@ -5,6 +5,7 @@ import (
 	"io"
 	"io/ioutil"
 	"log"
+	"net"
 	"net/http"
 	"net/url"
 	"regexp"
@@ -130,15 +131,21 @@ func (h *HTTPResponse) httpGather() (map[string]interface{}, error) {
 	// Start Timer
 	start := time.Now()
 	resp, err := h.client.Do(request)
+
 	if err != nil {
+		if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
+			fields["result_type"] = "timeout"
+			return fields, nil
+		}
+		fields["result_type"] = "connection_failed"
 		if h.FollowRedirects {
-			return nil, err
+			return fields, nil
 		}
 		if urlError, ok := err.(*url.Error); ok &&
 			urlError.Err == ErrRedirectAttempted {
 			err = nil
 		} else {
-			return nil, err
+			return fields, nil
 		}
 	}
 	defer func() {
@@ -157,7 +164,7 @@ func (h *HTTPResponse) httpGather() (map[string]interface{}, error) {
 			h.compiledStringMatch = regexp.MustCompile(h.ResponseStringMatch)
 			if err != nil {
 				log.Printf("E! Failed to compile regular expression %s : %s", h.ResponseStringMatch, err)
-				fields["response_string_match"] = 0
+				fields["result_type"] = "response_string_mismatch"
 				return fields, nil
 			}
 		}
@@ -165,16 +172,20 @@ func (h *HTTPResponse) httpGather() (map[string]interface{}, error) {
 		bodyBytes, err := ioutil.ReadAll(resp.Body)
 		if err != nil {
 			log.Printf("E! Failed to read body of HTTP Response : %s", err)
+			fields["result_type"] = "response_string_mismatch"
 			fields["response_string_match"] = 0
 			return fields, nil
 		}
 
 		if h.compiledStringMatch.Match(bodyBytes) {
+			fields["result_type"] = "success"
 			fields["response_string_match"] = 1
 		} else {
+			fields["result_type"] = "response_string_mismatch"
 			fields["response_string_match"] = 0
 		}
-
+	} else {
+		fields["result_type"] = "success"
 	}
 
 	return fields, nil
diff --git a/plugins/inputs/http_response/http_response_test.go b/plugins/inputs/http_response/http_response_test.go
index ee2390d2..484a06f2 100644
--- a/plugins/inputs/http_response/http_response_test.go
+++ b/plugins/inputs/http_response/http_response_test.go
@@ -106,6 +106,9 @@ func TestFields(t *testing.T) {
 	value, ok := acc.IntField("http_response", "http_response_code")
 	require.True(t, ok)
 	require.Equal(t, http.StatusOK, value)
+	response_value, ok := acc.StringField("http_response", "result_type")
+	require.True(t, ok)
+	require.Equal(t, "success", response_value)
 }
 
 func TestRedirects(t *testing.T) {
@@ -143,10 +146,13 @@ func TestRedirects(t *testing.T) {
 	}
 	acc = testutil.Accumulator{}
 	err = h.Gather(&acc)
-	require.Error(t, err)
+	require.NoError(t, err)
 
 	value, ok = acc.IntField("http_response", "http_response_code")
 	require.False(t, ok)
+	response_value, ok := acc.StringField("http_response", "result_type")
+	require.True(t, ok)
+	require.Equal(t, "connection_failed", response_value)
 }
 
 func TestMethod(t *testing.T) {
@@ -277,6 +283,9 @@ func TestStringMatch(t *testing.T) {
 	value, ok = acc.IntField("http_response", "response_string_match")
 	require.True(t, ok)
 	require.Equal(t, 1, value)
+	response_value, ok := acc.StringField("http_response", "result_type")
+	require.True(t, ok)
+	require.Equal(t, "success", response_value)
 	_, ok = acc.FloatField("http_response", "response_time")
 	require.True(t, ok)
 }
@@ -307,6 +316,9 @@ func TestStringMatchJson(t *testing.T) {
 	value, ok = acc.IntField("http_response", "response_string_match")
 	require.True(t, ok)
 	require.Equal(t, 1, value)
+	response_value, ok := acc.StringField("http_response", "result_type")
+	require.True(t, ok)
+	require.Equal(t, "success", response_value)
 	_, ok = acc.FloatField("http_response", "response_time")
 	require.True(t, ok)
 }
@@ -338,6 +350,9 @@ func TestStringMatchFail(t *testing.T) {
 	value, ok = acc.IntField("http_response", "response_string_match")
 	require.True(t, ok)
 	require.Equal(t, 0, value)
+	response_value, ok := acc.StringField("http_response", "result_type")
+	require.True(t, ok)
+	require.Equal(t, "response_string_mismatch", response_value)
 	_, ok = acc.FloatField("http_response", "response_time")
 	require.True(t, ok)
 }
@@ -363,8 +378,13 @@ func TestTimeout(t *testing.T) {
 	}
 	var acc testutil.Accumulator
 	err := h.Gather(&acc)
-	require.Error(t, err)
+	require.NoError(t, err)
 
-	ok := acc.HasIntField("http_response", "http_response_code")
+	_, ok := acc.IntField("http_response", "http_response_code")
+	require.False(t, ok)
+	response_value, ok := acc.StringField("http_response", "result_type")
+	require.True(t, ok)
+	require.Equal(t, "timeout", response_value)
+	_, ok = acc.FloatField("http_response", "response_time")
 	require.False(t, ok)
 }
-- 
GitLab