From 1e9d7cd6e972d1be46137f7bf6648dd8e8bd4df9 Mon Sep 17 00:00:00 2001
From: Daniel Nelson <daniel.nelson@influxdb.com>
Date: Wed, 16 Aug 2017 15:33:47 -0700
Subject: [PATCH] Add error status handle to tomcat input

---
 plugins/inputs/all/all.go       |   1 +
 plugins/inputs/tomcat/README.md | 106 +++++++++++++++---------------
 plugins/inputs/tomcat/tomcat.go | 111 ++++++++++++++++++++++----------
 3 files changed, 133 insertions(+), 85 deletions(-)

diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go
index 8b99b190..955c3a2c 100644
--- a/plugins/inputs/all/all.go
+++ b/plugins/inputs/all/all.go
@@ -83,6 +83,7 @@ import (
 	_ "github.com/influxdata/telegraf/plugins/inputs/system"
 	_ "github.com/influxdata/telegraf/plugins/inputs/tail"
 	_ "github.com/influxdata/telegraf/plugins/inputs/tcp_listener"
+	_ "github.com/influxdata/telegraf/plugins/inputs/tomcat"
 	_ "github.com/influxdata/telegraf/plugins/inputs/trig"
 	_ "github.com/influxdata/telegraf/plugins/inputs/twemproxy"
 	_ "github.com/influxdata/telegraf/plugins/inputs/udp_listener"
diff --git a/plugins/inputs/tomcat/README.md b/plugins/inputs/tomcat/README.md
index d2fa2e72..3baf6855 100644
--- a/plugins/inputs/tomcat/README.md
+++ b/plugins/inputs/tomcat/README.md
@@ -1,73 +1,77 @@
 # Tomcat Input Plugin
 
-The Tomcat plugin collects statistics available from the tomcat manager status page from the `http://<host>/manager/status/all?XML=true URL.`
-(`XML=true` will return only xml data). See the [Tomcat documentation](https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html#Server_Status) for details of these statistics.
+The Tomcat plugin collects statistics available from the tomcat manager status page from the `http://<host>/manager/status/all?XML=true URL.` (`XML=true` will return only xml data).
+
+See the [Tomcat documentation](https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html#Server_Status) for details of these statistics.
 
 ### Configuration:
 
 ```toml
-# A Telegraf plugin to collect tomcat metrics.
+# Gather metrics from the Tomcat server status page.
 [[inputs.tomcat]]
-  # A Tomcat status URI to gather stats.
-  # Default is "http://127.0.0.1:8080/manager/status/all?XML=true".
-  url = "http://127.0.0.1:8080/manager/status/all?XML=true"
-  # Credentials for status URI.
-  # Default is tomcat/s3cret.
-  username = "tomcat"
-  password = "s3cret"
+  ## URL of the Tomcat server status
+  # url = "http://127.0.0.1:8080/manager/status/all?XML=true"
+
+  ## HTTP Basic Auth Credentials
+  # username = "tomcat"
+  # password = "s3cret"
+
+  ## Request timeout
+  # timeout = "5s"
+
+  ## Optional SSL Config
+  # ssl_ca = "/etc/telegraf/ca.pem"
+  # ssl_cert = "/etc/telegraf/cert.pem"
+  # ssl_key = "/etc/telegraf/key.pem"
+  ## Use SSL but skip chain & host verification
+  # insecure_skip_verify = false
 ```
 
 ### Measurements & Fields:
 
-- tomcat\_jvm\_memory
-    - free
-    - total
-    - max
-- tomcat\_jvm\_memorypool
-  - max\_threads
-  - current\_thread\_count
-  - current\_threads\_busy
-  - max\_time
-  - processing\_time
-  - request\_count
-  - error\_count
-  - bytes\_received
-  - bytes\_sent
-- tomcat\_connector
-  - max\_threads
-  - current\_thread\_count
-  - current\_thread\_busy
-  - max\_time
-  - processing\_time
-  - request\_count
-  - error\_count
-  - bytes\_received
-  - bytes\_sent
+- tomcat_jvm_memory
+  - free
+  - total
+  - max
+- tomcat_jvm_memorypool
+  - max_threads
+  - current_thread_count
+  - current_threads_busy
+  - max_time
+  - processing_time
+  - request_count
+  - error_count
+  - bytes_received
+  - bytes_sent
+- tomcat_connector
+  - max_threads
+  - current_thread_count
+  - current_thread_busy
+  - max_time
+  - processing_time
+  - request_count
+  - error_count
+  - bytes_received
+  - bytes_sent
 
 ### Tags:
 
-- tomcat\_jvm\_memorypool has the following tags:
+- tomcat_jvm_memorypool has the following tags:
   - name
   - type
-- tomcat\_connector
+- tomcat_connector
   - name
 
-### Sample Queries:
-
-TODO
-
 ### Example Output:
 
 ```
-$ ./telegraf -config telegraf.conf -input-filter tomcat -test
-* Plugin: tomcat, Collection 1
-> tomcat_jvm_memory,host=N8-MBP free=20014352i,max=127729664i,total=41459712i 1474663361000000000
-> tomcat_jvm_memorypool,host=N8-MBP,name=Eden\ Space,type=Heap\ memory committed=11534336i,init=2228224i,max=35258368i,used=1941200i 1474663361000000000
-> tomcat_jvm_memorypool,host=N8-MBP,name=Survivor\ Space,type=Heap\ memory committed=1376256i,init=262144i,max=4390912i,used=1376248i 1474663361000000000
-> tomcat_jvm_memorypool,host=N8-MBP,name=Tenured\ Gen,type=Heap\ memory committed=28549120i,init=5636096i,max=88080384i,used=18127912i 1474663361000000000
-> tomcat_jvm_memorypool,host=N8-MBP,name=Code\ Cache,type=Non-heap\ memory committed=6946816i,init=2555904i,max=251658240i,used=6406528i 1474663361000000000
-> tomcat_jvm_memorypool,host=N8-MBP,name=Compressed\ Class\ Space,type=Non-heap\ memory committed=1966080i,init=0i,max=1073741824i,used=1816120i 1474663361000000000
-> tomcat_jvm_memorypool,host=N8-MBP,name=Metaspace,type=Non-heap\ memory committed=18219008i,init=0i,max=-1i,used=17559376i 1474663361000000000
-> tomcat_connector,host=N8-MBP,name=ajp-bio-8009 bytes_received=0i,bytes_sent=0i,current_thread_count=0i,current_threads_busy=0i,error_count=0i,max_threads=200i,max_time=0i,processing_time=0i,request_count=0i 1474663361000000000
-> tomcat_connector,host=N8-MBP,name=http-bio-8080 bytes_received=0i,bytes_sent=86435i,current_thread_count=10i,current_threads_busy=1i,error_count=2i,max_threads=200i,max_time=167i,processing_time=245i,request_count=15i 1474663361000000000
+tomcat_jvm_memory,host=N8-MBP free=20014352i,max=127729664i,total=41459712i 1474663361000000000
+tomcat_jvm_memorypool,host=N8-MBP,name=Eden\ Space,type=Heap\ memory committed=11534336i,init=2228224i,max=35258368i,used=1941200i 1474663361000000000
+tomcat_jvm_memorypool,host=N8-MBP,name=Survivor\ Space,type=Heap\ memory committed=1376256i,init=262144i,max=4390912i,used=1376248i 1474663361000000000
+tomcat_jvm_memorypool,host=N8-MBP,name=Tenured\ Gen,type=Heap\ memory committed=28549120i,init=5636096i,max=88080384i,used=18127912i 1474663361000000000
+tomcat_jvm_memorypool,host=N8-MBP,name=Code\ Cache,type=Non-heap\ memory committed=6946816i,init=2555904i,max=251658240i,used=6406528i 1474663361000000000
+tomcat_jvm_memorypool,host=N8-MBP,name=Compressed\ Class\ Space,type=Non-heap\ memory committed=1966080i,init=0i,max=1073741824i,used=1816120i 1474663361000000000
+tomcat_jvm_memorypool,host=N8-MBP,name=Metaspace,type=Non-heap\ memory committed=18219008i,init=0i,max=-1i,used=17559376i 1474663361000000000
+tomcat_connector,host=N8-MBP,name=ajp-bio-8009 bytes_received=0i,bytes_sent=0i,current_thread_count=0i,current_threads_busy=0i,error_count=0i,max_threads=200i,max_time=0i,processing_time=0i,request_count=0i 1474663361000000000
+tomcat_connector,host=N8-MBP,name=http-bio-8080 bytes_received=0i,bytes_sent=86435i,current_thread_count=10i,current_threads_busy=1i,error_count=2i,max_threads=200i,max_time=167i,processing_time=245i,request_count=15i 1474663361000000000
 ```
diff --git a/plugins/inputs/tomcat/tomcat.go b/plugins/inputs/tomcat/tomcat.go
index dfde52ca..b9dcc731 100644
--- a/plugins/inputs/tomcat/tomcat.go
+++ b/plugins/inputs/tomcat/tomcat.go
@@ -3,12 +3,13 @@ package tomcat
 import (
 	"encoding/xml"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"net/url"
 	"strconv"
+	"time"
 
 	"github.com/influxdata/telegraf"
+	"github.com/influxdata/telegraf/internal"
 	"github.com/influxdata/telegraf/plugins/inputs"
 )
 
@@ -61,20 +62,38 @@ type Tomcat struct {
 	URL      string
 	Username string
 	Password string
+	Timeout  internal.Duration
+
+	SSLCA              string `toml:"ssl_ca"`
+	SSLCert            string `toml:"ssl_cert"`
+	SSLKey             string `toml:"ssl_key"`
+	InsecureSkipVerify bool
+
+	client  *http.Client
+	request *http.Request
 }
 
 var sampleconfig = `
-  ## A Tomcat status URI to gather stats.
-  ## Default is "http://127.0.0.1:8080/manager/status/all?XML=true".
-  url = "http://127.0.0.1:8080/manager/status/all?XML=true"
-  ## Credentials for status URI.
-  ## Default is tomcat/s3cret.
-  username = "tomcat"
-  password = "s3cret"
+  ## URL of the Tomcat server status
+  # url = "http://127.0.0.1:8080/manager/status/all?XML=true"
+
+  ## HTTP Basic Auth Credentials
+  # username = "tomcat"
+  # password = "s3cret"
+
+  ## Request timeout
+  # timeout = "5s"
+
+  ## Optional SSL Config
+  # ssl_ca = "/etc/telegraf/ca.pem"
+  # ssl_cert = "/etc/telegraf/cert.pem"
+  # ssl_key = "/etc/telegraf/key.pem"
+  ## Use SSL but skip chain & host verification
+  # insecure_skip_verify = false
 `
 
 func (s *Tomcat) Description() string {
-	return "A Telegraf plugin to collect tomcat metrics."
+	return "Gather metrics from the Tomcat server status page."
 }
 
 func (s *Tomcat) SampleConfig() string {
@@ -82,36 +101,40 @@ func (s *Tomcat) SampleConfig() string {
 }
 
 func (s *Tomcat) Gather(acc telegraf.Accumulator) error {
-
-	if s.URL == "" {
-		s.URL = "http://127.0.0.1:8080/manager/status/all?XML=true"
-	}
-
-	if s.Username == "" {
-		s.Username = "tomcat"
+	if s.client == nil {
+		client, err := s.createHttpClient()
+		if err != nil {
+			return err
+		}
+		s.client = client
 	}
 
-	if s.Password == "" {
-		s.Password = "s3cret"
+	if s.request == nil {
+		_, err := url.Parse(s.URL)
+		if err != nil {
+			return err
+		}
+		request, err := http.NewRequest("GET", s.URL, nil)
+		if err != nil {
+			return err
+		}
+		request.SetBasicAuth(s.Username, s.Password)
+		s.request = request
 	}
 
-	_, err := url.Parse(s.URL)
+	resp, err := s.client.Do(s.request)
 	if err != nil {
-		return fmt.Errorf("Unable to parse address '%s': %s", s.URL, err)
+		return err
 	}
+	defer resp.Body.Close()
 
-	req, err := http.NewRequest("GET", s.URL, nil)
-	req.SetBasicAuth(s.Username, s.Password)
-	cli := &http.Client{}
-	resp, err := cli.Do(req)
-	if err != nil {
-		return fmt.Errorf("Unable to call URL '%s': %s", s.URL, err)
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("received HTTP status code %d from %q; expected 200",
+			resp.StatusCode, s.URL)
 	}
-	defer resp.Body.Close()
-	body, err := ioutil.ReadAll(resp.Body)
 
 	var status TomcatStatus
-	xml.Unmarshal(body, &status)
+	xml.NewDecoder(resp.Body).Decode(&status)
 
 	// add tomcat_jvm_memory measurements
 	tcm := map[string]interface{}{
@@ -123,7 +146,6 @@ func (s *Tomcat) Gather(acc telegraf.Accumulator) error {
 
 	// add tomcat_jvm_memorypool measurements
 	for _, mp := range status.TomcatJvm.JvmMemoryPools {
-
 		tcmpTags := map[string]string{
 			"name": mp.Name,
 			"type": mp.Type,
@@ -137,12 +159,10 @@ func (s *Tomcat) Gather(acc telegraf.Accumulator) error {
 		}
 
 		acc.AddFields("tomcat_jvm_memorypool", tcmpFields, tcmpTags)
-
 	}
 
 	// add tomcat_connector measurements
 	for _, c := range status.TomcatConnectors {
-
 		name, err := strconv.Unquote(c.Name)
 		if err != nil {
 			return fmt.Errorf("Unable to unquote name '%s': %s", c.Name, err)
@@ -165,12 +185,35 @@ func (s *Tomcat) Gather(acc telegraf.Accumulator) error {
 		}
 
 		acc.AddFields("tomcat_connector", tccFields, tccTags)
-
 	}
 
 	return nil
 }
 
+func (s *Tomcat) createHttpClient() (*http.Client, error) {
+	tlsConfig, err := internal.GetTLSConfig(
+		s.SSLCert, s.SSLKey, s.SSLCA, s.InsecureSkipVerify)
+	if err != nil {
+		return nil, err
+	}
+
+	client := &http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: tlsConfig,
+		},
+		Timeout: s.Timeout.Duration,
+	}
+
+	return client, nil
+}
+
 func init() {
-	inputs.Add("tomcat", func() telegraf.Input { return &Tomcat{} })
+	inputs.Add("tomcat", func() telegraf.Input {
+		return &Tomcat{
+			URL:      "http://127.0.0.1:8080/manager/status/all?XML=true",
+			Username: "tomcat",
+			Password: "s3cret",
+			Timeout:  internal.Duration{Duration: 5 * time.Second},
+		}
+	})
 }
-- 
GitLab