From 3ef28e332fe8dba93fd873542c16effb6cb4e54c Mon Sep 17 00:00:00 2001
From: Daniel Nelson <daniel.nelson@influxdb.com>
Date: Tue, 8 May 2018 16:04:28 -0700
Subject: [PATCH] Use result and result_code in net_response

---
 plugins/inputs/net_response/README.md         | 70 +++++---------
 plugins/inputs/net_response/net_response.go   | 93 +++++++++++--------
 .../inputs/net_response/net_response_test.go  | 51 +++++-----
 3 files changed, 101 insertions(+), 113 deletions(-)

diff --git a/plugins/inputs/net_response/README.md b/plugins/inputs/net_response/README.md
index 50dbc9f8..1982ced0 100644
--- a/plugins/inputs/net_response/README.md
+++ b/plugins/inputs/net_response/README.md
@@ -1,11 +1,12 @@
 # Network Response Input Plugin
 
-The input plugin test UDP/TCP connections response time.
-It can also check response text.
+The input plugin test UDP/TCP connections response time and can optional
+verify text in the response.
 
 ### Configuration:
 
-```
+```toml
+# Collect response time of a TCP or UDP connection
 [[inputs.net_response]]
   ## Protocol, must be "tcp" or "udp"
   ## NOTE: because the "udp" protocol does not respond to requests, it requires
@@ -13,11 +14,12 @@ It can also check response text.
   protocol = "tcp"
   ## Server address (default localhost)
   address = "localhost:80"
+
   ## Set timeout
-  timeout = "1s"
+  # timeout = "1s"
 
   ## Set read timeout (only used if expecting a response)
-  read_timeout = "1s"
+  # read_timeout = "1s"
 
   ## The following options are required for UDP checks. For TCP, they are
   ## optional. The plugin will send the given string to the server and then
@@ -27,59 +29,29 @@ It can also check response text.
   ## expected string in answer
   # expect = "ssh"
 
-[[inputs.net_response]]
-  protocol = "tcp"
-  address = ":80"
-
-# TCP or UDP 'ping' given url and collect response time in seconds
-[[inputs.net_response]]
-  ## Protocol, must be "tcp" or "udp"
-  protocol = "tcp"
-  ## Server address (default localhost)
-  address = "github.com:80"
-  ## Set timeout
-  timeout = "1s"
-
-  ## Optional string sent to the server
-  send = "ssh"
-  ## Optional expected string in answer
-  expect = "ssh"
-  ## Set read timeout (only used if expecting a response)
-  read_timeout = "1s"
-
-[[inputs.net_response]]
-  protocol = "udp"
-  address = "localhost:161"
-  timeout = "2s"
-  send = "hello server"
-  expect = "hello client"
+  ## Uncomment to remove deprecated fields; recommended for new deploys
+  # fieldexclude = ["result_type", "string_found"]
 ```
 
-### Measurements & Fields:
+### Metrics:
 
 - net_response
-    - response_time (float, seconds)
-    - success (int) # success 0, failure 1
-    - result_code (int) # success = 0, Failure = 1
-    - [**DEPRECATED**] result_type (string) # success, timeout, connection_failed, read_failed, string_mismatch
-    - [**DEPRECATED**] string_found (boolean)
-
-### Tags:
-
-- All measurements have the following tags:
+  - tags:
     - server
     - port
     - protocol
-    - result_text (string) # This will contain the text from the now deprecated result_type
+    - result
+  - fields:
+    - response_time (float, seconds)
+    - success (int) # success 0, failure 1
+    - result_code (int, success = 0, timeout = 1, connection_failed = 2, read_failed = 3, string_mismatch = 4)
+    - result_type (string) **DEPRECATED in 1.7; use result tag**
+    - string_found (boolean) **DEPRECATED in 1.4; use result tag**
 
 ### Example Output:
 
 ```
-net_response,server=influxdata.com,port=8080,protocol=tcp,host=localhost,result_text="timeout" result_code=1i,result_type="timeout" 1499310361000000000
-net_response,server=influxdata.com,port=443,protocol=tcp,host=localhost,result_text="success" result_code=0i,result_type="success",response_time=0.088703864 1499310361000000000
-net_response,protocol=tcp,host=localhost,server=this.domain.does.not.exist,port=443,result_text="connection_failed" result_code=1i,result_type="connection_failed" 1499310361000000000
-net_response,protocol=udp,host=localhost,server=influxdata.com,port=8080,result_text="read_failed" result_code=1i,result_type="read_failed" 1499310362000000000
-net_response,port=31338,protocol=udp,host=localhost,server=localhost,result_text="string_mismatch" result_code=1i,result_type="string_mismatch",string_found=false,response_time=0.00242682 1499310362000000000
-net_response,protocol=udp,host=localhost,server=localhost,port=31338,result_text="success" response_time=0.001128598,result_code=0i,result_type="success",string_found=true 1499310362000000000
-net_response,server=this.domain.does.not.exist,port=443,protocol=udp,host=localhost,result_text="connection_failed" result_code=1i,result_type="connection_failed" 1499310362000000000
+net_response,port=8086,protocol=tcp,result=success,server=localhost response_time=0.000092948,result_code=0i,result_type="success" 1525820185000000000
+net_response,port=8080,protocol=tcp,result=connection_failed,server=localhost result_code=2i,result_type="connection_failed" 1525820088000000000
+net_response,port=8080,protocol=udp,result=read_failed,server=localhost result_code=3i,result_type="read_failed",string_found=false 1525820088000000000
 ```
diff --git a/plugins/inputs/net_response/net_response.go b/plugins/inputs/net_response/net_response.go
index 75986843..66511a31 100644
--- a/plugins/inputs/net_response/net_response.go
+++ b/plugins/inputs/net_response/net_response.go
@@ -13,6 +13,16 @@ import (
 	"github.com/influxdata/telegraf/plugins/inputs"
 )
 
+type ResultType uint64
+
+const (
+	Success          ResultType = 0
+	Timeout                     = 1
+	ConnectionFailed            = 2
+	ReadFailed                  = 3
+	StringMismatch              = 4
+)
+
 // NetResponse struct
 type NetResponse struct {
 	Address     string
@@ -23,7 +33,7 @@ type NetResponse struct {
 	Protocol    string
 }
 
-var description = "TCP or UDP 'ping' given url and collect response time in seconds"
+var description = "Collect response time of a TCP or UDP connection"
 
 // Description will return a short string to explain what the plugin does.
 func (*NetResponse) Description() string {
@@ -37,11 +47,12 @@ var sampleConfig = `
   protocol = "tcp"
   ## Server address (default localhost)
   address = "localhost:80"
+
   ## Set timeout
-  timeout = "1s"
+  # timeout = "1s"
 
   ## Set read timeout (only used if expecting a response)
-  read_timeout = "1s"
+  # read_timeout = "1s"
 
   ## The following options are required for UDP checks. For TCP, they are
   ## optional. The plugin will send the given string to the server and then
@@ -50,6 +61,9 @@ var sampleConfig = `
   # send = "ssh"
   ## expected string in answer
   # expect = "ssh"
+
+  ## Uncomment to remove deprecated fields
+  # fieldexclude = ["result_type", "string_found"]
 `
 
 // SampleConfig will return a complete configuration example with details about each field.
@@ -72,13 +86,9 @@ func (n *NetResponse) TCPGather() (tags map[string]string, fields map[string]int
 	// Handle error
 	if err != nil {
 		if e, ok := err.(net.Error); ok && e.Timeout() {
-			tags["result_text"] = "timeout"
-			fields["result_code"] = 1
-			fields["result_type"] = "timeout"
+			setResult(Timeout, fields, tags, n.Expect)
 		} else {
-			tags["result_text"] = "connection_failed"
-			fields["result_code"] = 1
-			fields["result_type"] = "connection_failed"
+			setResult(ConnectionFailed, fields, tags, n.Expect)
 		}
 		return tags, fields
 	}
@@ -103,31 +113,19 @@ func (n *NetResponse) TCPGather() (tags map[string]string, fields map[string]int
 		responseTime = time.Since(start).Seconds()
 		// Handle error
 		if err != nil {
-			tags["result_text"] = "read_failed"
-			fields["result_code"] = 1
-			fields["string_found"] = false
-			tags["result_type"] = "read_failed"
-			fields["success"] = 1
+			setResult(ReadFailed, fields, tags, n.Expect)
 		} else {
 			// Looking for string in answer
 			RegEx := regexp.MustCompile(`.*` + n.Expect + `.*`)
 			find := RegEx.FindString(string(data))
 			if find != "" {
-				tags["result_text"] = "success"
-				fields["result_code"] = 0
-				fields["result_type"] = "success"
-				fields["string_found"] = true
+				setResult(Success, fields, tags, n.Expect)
 			} else {
-				tags["result_text"] = "string_mismatch"
-				fields["result_code"] = 1
-				fields["result_type"] = "string_mismatch"
-				fields["string_found"] = false
+				setResult(StringMismatch, fields, tags, n.Expect)
 			}
 		}
 	} else {
-		tags["result_text"] = "success"
-		fields["result_code"] = 0
-		fields["result_type"] = "success"
+		setResult(Success, fields, tags, n.Expect)
 	}
 	fields["response_time"] = responseTime
 	return tags, fields
@@ -148,9 +146,7 @@ func (n *NetResponse) UDPGather() (tags map[string]string, fields map[string]int
 	conn, err := net.DialUDP("udp", LocalAddr, udpAddr)
 	// Handle error
 	if err != nil {
-		tags["result_text"] = "connection_failed"
-		fields["result_code"] = 1
-		fields["result_type"] = "connection_failed"
+		setResult(ConnectionFailed, fields, tags, n.Expect)
 		return tags, fields
 	}
 	defer conn.Close()
@@ -167,9 +163,7 @@ func (n *NetResponse) UDPGather() (tags map[string]string, fields map[string]int
 	responseTime := time.Since(start).Seconds()
 	// Handle error
 	if err != nil {
-		tags["result_text"] = "read_failed"
-		fields["result_code"] = 1
-		fields["result_type"] = "read_failed"
+		setResult(ReadFailed, fields, tags, n.Expect)
 		return tags, fields
 	}
 
@@ -177,15 +171,9 @@ func (n *NetResponse) UDPGather() (tags map[string]string, fields map[string]int
 	RegEx := regexp.MustCompile(`.*` + n.Expect + `.*`)
 	find := RegEx.FindString(string(buf))
 	if find != "" {
-		tags["result_text"] = "success"
-		fields["result_code"] = 0
-		fields["result_type"] = "success"
-		fields["string_found"] = true
+		setResult(Success, fields, tags, n.Expect)
 	} else {
-		tags["result_text"] = "string_mismatch"
-		fields["result_code"] = 1
-		fields["result_type"] = "string_mismatch"
-		fields["string_found"] = false
+		setResult(StringMismatch, fields, tags, n.Expect)
 	}
 
 	fields["response_time"] = responseTime
@@ -248,6 +236,33 @@ func (n *NetResponse) Gather(acc telegraf.Accumulator) error {
 	return nil
 }
 
+func setResult(result ResultType, fields map[string]interface{}, tags map[string]string, expect string) {
+	var tag string
+	switch result {
+	case Success:
+		tag = "success"
+	case Timeout:
+		tag = "timeout"
+	case ConnectionFailed:
+		tag = "connection_failed"
+	case ReadFailed:
+		tag = "read_failed"
+	case StringMismatch:
+		tag = "string_mismatch"
+	}
+
+	tags["result"] = tag
+	fields["result_code"] = uint64(result)
+
+	// deprecated in 1.7; use result tag
+	fields["result_type"] = tag
+
+	// deprecated in 1.4; use result tag
+	if expect != "" {
+		fields["string_found"] = result == Success
+	}
+}
+
 func init() {
 	inputs.Add("net_response", func() telegraf.Input {
 		return &NetResponse{}
diff --git a/plugins/inputs/net_response/net_response_test.go b/plugins/inputs/net_response/net_response_test.go
index 0f1ab2f7..ef4d0714 100644
--- a/plugins/inputs/net_response/net_response_test.go
+++ b/plugins/inputs/net_response/net_response_test.go
@@ -98,14 +98,14 @@ func TestTCPError(t *testing.T) {
 	acc.AssertContainsTaggedFields(t,
 		"net_response",
 		map[string]interface{}{
-			"result_code": 1,
+			"result_code": uint64(2),
 			"result_type": "connection_failed",
 		},
 		map[string]string{
-			"server":      "",
-			"port":        "9999",
-			"protocol":    "tcp",
-			"result_text": "connection_failed",
+			"server":   "",
+			"port":     "9999",
+			"protocol": "tcp",
+			"result":   "connection_failed",
 		},
 	)
 }
@@ -138,16 +138,16 @@ func TestTCPOK1(t *testing.T) {
 	acc.AssertContainsTaggedFields(t,
 		"net_response",
 		map[string]interface{}{
-			"result_code":   0,
+			"result_code":   uint64(0),
 			"result_type":   "success",
 			"string_found":  true,
 			"response_time": 1.0,
 		},
 		map[string]string{
-			"result_text": "success",
-			"server":      "127.0.0.1",
-			"port":        "2004",
-			"protocol":    "tcp",
+			"result":   "success",
+			"server":   "127.0.0.1",
+			"port":     "2004",
+			"protocol": "tcp",
 		},
 	)
 	// Waiting TCPserver
@@ -182,16 +182,16 @@ func TestTCPOK2(t *testing.T) {
 	acc.AssertContainsTaggedFields(t,
 		"net_response",
 		map[string]interface{}{
-			"result_code":   1,
+			"result_code":   uint64(4),
 			"result_type":   "string_mismatch",
 			"string_found":  false,
 			"response_time": 1.0,
 		},
 		map[string]string{
-			"result_text": "string_mismatch",
-			"server":      "127.0.0.1",
-			"port":        "2004",
-			"protocol":    "tcp",
+			"result":   "string_mismatch",
+			"server":   "127.0.0.1",
+			"port":     "2004",
+			"protocol": "tcp",
 		},
 	)
 	// Waiting TCPserver
@@ -218,15 +218,16 @@ func TestUDPError(t *testing.T) {
 	acc.AssertContainsTaggedFields(t,
 		"net_response",
 		map[string]interface{}{
-			"result_code":   1,
+			"result_code":   uint64(3),
 			"result_type":   "read_failed",
 			"response_time": 1.0,
+			"string_found":  false,
 		},
 		map[string]string{
-			"result_text": "read_failed",
-			"server":      "",
-			"port":        "9999",
-			"protocol":    "udp",
+			"result":   "read_failed",
+			"server":   "",
+			"port":     "9999",
+			"protocol": "udp",
 		},
 	)
 }
@@ -259,16 +260,16 @@ func TestUDPOK1(t *testing.T) {
 	acc.AssertContainsTaggedFields(t,
 		"net_response",
 		map[string]interface{}{
-			"result_code":   0,
+			"result_code":   uint64(0),
 			"result_type":   "success",
 			"string_found":  true,
 			"response_time": 1.0,
 		},
 		map[string]string{
-			"result_text": "success",
-			"server":      "127.0.0.1",
-			"port":        "2004",
-			"protocol":    "udp",
+			"result":   "success",
+			"server":   "127.0.0.1",
+			"port":     "2004",
+			"protocol": "udp",
 		},
 	)
 	// Waiting TCPserver
-- 
GitLab