jolokia: add proxy mode
This commit is contained in:
parent
a7b0861436
commit
cf5980ace2
|
@ -5,13 +5,22 @@
|
||||||
```toml
|
```toml
|
||||||
[[inputs.jolokia]]
|
[[inputs.jolokia]]
|
||||||
## This is the context root used to compose the jolokia url
|
## This is the context root used to compose the jolokia url
|
||||||
context = "/jolokia/read"
|
context = "/jolokia"
|
||||||
|
|
||||||
## List of servers exposing jolokia read service
|
# This specifies the mode used
|
||||||
|
# mode = "proxy"
|
||||||
|
#
|
||||||
|
# When in proxy mode this section is used to specify further proxy address configurations.
|
||||||
|
# Remember to change servers addresses
|
||||||
|
# [inputs.jolokia.proxy]
|
||||||
|
# host = "127.0.0.1"
|
||||||
|
# port = "8080"
|
||||||
|
|
||||||
|
# List of servers exposing jolokia read service
|
||||||
[[inputs.jolokia.servers]]
|
[[inputs.jolokia.servers]]
|
||||||
name = "stable"
|
name = "as-server-01"
|
||||||
host = "192.168.103.2"
|
host = "127.0.0.1"
|
||||||
port = "8180"
|
port = "8080"
|
||||||
# username = "myuser"
|
# username = "myuser"
|
||||||
# password = "mypassword"
|
# password = "mypassword"
|
||||||
|
|
||||||
|
@ -21,17 +30,20 @@
|
||||||
## This collect all heap memory usage metrics.
|
## This collect all heap memory usage metrics.
|
||||||
[[inputs.jolokia.metrics]]
|
[[inputs.jolokia.metrics]]
|
||||||
name = "heap_memory_usage"
|
name = "heap_memory_usage"
|
||||||
jmx = "/java.lang:type=Memory/HeapMemoryUsage"
|
mbean = "java.lang:type=Memory"
|
||||||
|
attribute = "HeapMemoryUsage"
|
||||||
|
|
||||||
## This collect thread counts metrics.
|
## This collect thread counts metrics.
|
||||||
[[inputs.jolokia.metrics]]
|
[[inputs.jolokia.metrics]]
|
||||||
name = "thread_count"
|
name = "thread_count"
|
||||||
jmx = "/java.lang:type=Threading/TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount"
|
mbean = "java.lang:type=Threading"
|
||||||
|
attribute = "TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount"
|
||||||
|
|
||||||
## This collect number of class loaded/unloaded counts metrics.
|
## This collect number of class loaded/unloaded counts metrics.
|
||||||
[[inputs.jolokia.metrics]]
|
[[inputs.jolokia.metrics]]
|
||||||
name = "class_count"
|
name = "class_count"
|
||||||
jmx = "/java.lang:type=ClassLoading/LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount"
|
mbean = "java.lang:type=ClassLoading"
|
||||||
|
attribute = "LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Description
|
#### Description
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
"bytes"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs"
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
|
@ -23,7 +24,9 @@ type Server struct {
|
||||||
|
|
||||||
type Metric struct {
|
type Metric struct {
|
||||||
Name string
|
Name string
|
||||||
Jmx string
|
Mbean string
|
||||||
|
Attribute string
|
||||||
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
type JolokiaClient interface {
|
type JolokiaClient interface {
|
||||||
|
@ -41,20 +44,32 @@ func (c JolokiaClientImpl) MakeRequest(req *http.Request) (*http.Response, error
|
||||||
type Jolokia struct {
|
type Jolokia struct {
|
||||||
jClient JolokiaClient
|
jClient JolokiaClient
|
||||||
Context string
|
Context string
|
||||||
|
Mode string
|
||||||
Servers []Server
|
Servers []Server
|
||||||
Metrics []Metric
|
Metrics []Metric
|
||||||
|
Proxy Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jolokia) SampleConfig() string {
|
func (j *Jolokia) SampleConfig() string {
|
||||||
return `
|
return `
|
||||||
## This is the context root used to compose the jolokia url
|
# This is the context root used to compose the jolokia url
|
||||||
context = "/jolokia/read"
|
context = "/jolokia"
|
||||||
|
|
||||||
## List of servers exposing jolokia read service
|
# This specifies the mode used
|
||||||
|
# mode = "proxy"
|
||||||
|
#
|
||||||
|
# When in proxy mode this section is used to specify further proxy address configurations.
|
||||||
|
# Remember to change servers addresses
|
||||||
|
# [inputs.jolokia.proxy]
|
||||||
|
# host = "127.0.0.1"
|
||||||
|
# port = "8080"
|
||||||
|
|
||||||
|
|
||||||
|
# List of servers exposing jolokia read service
|
||||||
[[inputs.jolokia.servers]]
|
[[inputs.jolokia.servers]]
|
||||||
name = "stable"
|
name = "as-server-01"
|
||||||
host = "192.168.103.2"
|
host = "127.0.0.1"
|
||||||
port = "8180"
|
port = "8080"
|
||||||
# username = "myuser"
|
# username = "myuser"
|
||||||
# password = "mypassword"
|
# password = "mypassword"
|
||||||
|
|
||||||
|
@ -64,17 +79,20 @@ func (j *Jolokia) SampleConfig() string {
|
||||||
## This collect all heap memory usage metrics.
|
## This collect all heap memory usage metrics.
|
||||||
[[inputs.jolokia.metrics]]
|
[[inputs.jolokia.metrics]]
|
||||||
name = "heap_memory_usage"
|
name = "heap_memory_usage"
|
||||||
jmx = "/java.lang:type=Memory/HeapMemoryUsage"
|
mbean = "java.lang:type=Memory"
|
||||||
|
attribute = "HeapMemoryUsage"
|
||||||
|
|
||||||
## This collect thread counts metrics.
|
## This collect thread counts metrics.
|
||||||
[[inputs.jolokia.metrics]]
|
[[inputs.jolokia.metrics]]
|
||||||
name = "thread_count"
|
name = "thread_count"
|
||||||
jmx = "/java.lang:type=Threading/TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount"
|
mbean = "java.lang:type=Threading"
|
||||||
|
attribute = "TotalStartedThreadCount,ThreadCount,DaemonThreadCount,PeakThreadCount"
|
||||||
|
|
||||||
## This collect number of class loaded/unloaded counts metrics.
|
## This collect number of class loaded/unloaded counts metrics.
|
||||||
[[inputs.jolokia.metrics]]
|
[[inputs.jolokia.metrics]]
|
||||||
name = "class_count"
|
name = "class_count"
|
||||||
jmx = "/java.lang:type=ClassLoading/LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount"
|
mbean = "java.lang:type=ClassLoading"
|
||||||
|
attribute = "LoadedClassCount,UnloadedClassCount,TotalLoadedClassCount"
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,12 +100,7 @@ func (j *Jolokia) Description() string {
|
||||||
return "Read JMX metrics through Jolokia"
|
return "Read JMX metrics through Jolokia"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jolokia) getAttr(requestUrl *url.URL) (map[string]interface{}, error) {
|
func (j *Jolokia) doRequest(req *http.Request) (map[string]interface{}, error) {
|
||||||
// Create + send request
|
|
||||||
req, err := http.NewRequest("GET", requestUrl.String(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := j.jClient.MakeRequest(req)
|
resp, err := j.jClient.MakeRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -98,7 +111,7 @@ func (j *Jolokia) getAttr(requestUrl *url.URL) (map[string]interface{}, error) {
|
||||||
// Process response
|
// Process response
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
err = fmt.Errorf("Response from url \"%s\" has status code %d (%s), expected %d (%s)",
|
err = fmt.Errorf("Response from url \"%s\" has status code %d (%s), expected %d (%s)",
|
||||||
requestUrl,
|
req.RequestURI,
|
||||||
resp.StatusCode,
|
resp.StatusCode,
|
||||||
http.StatusText(resp.StatusCode),
|
http.StatusText(resp.StatusCode),
|
||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
|
@ -118,52 +131,159 @@ func (j *Jolokia) getAttr(requestUrl *url.URL) (map[string]interface{}, error) {
|
||||||
return nil, errors.New("Error decoding JSON response")
|
return nil, errors.New("Error decoding JSON response")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if status, ok := jsonOut["status"]; ok {
|
||||||
|
if status != float64(200) {
|
||||||
|
return nil, fmt.Errorf("Not expected status value in response body: %3.f", status)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Missing status in response body")
|
||||||
|
}
|
||||||
|
|
||||||
return jsonOut, nil
|
return jsonOut, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *Jolokia) getAttr(requestUrl *url.URL) (map[string]interface{}, error) {
|
||||||
|
// Create + send request
|
||||||
|
req, err := http.NewRequest("GET", requestUrl.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return j.doRequest(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (j *Jolokia) collectMeasurement(measurement string, out map[string]interface{}, fields map[string]interface{}) {
|
||||||
|
|
||||||
|
if values, ok := out["value"]; ok {
|
||||||
|
switch t := values.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
for k, v := range t {
|
||||||
|
fields[measurement+"_"+k] = v
|
||||||
|
}
|
||||||
|
case interface{}:
|
||||||
|
fields[measurement] = t
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Missing key 'value' in output response\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (j *Jolokia) Gather(acc telegraf.Accumulator) error {
|
func (j *Jolokia) Gather(acc telegraf.Accumulator) error {
|
||||||
context := j.Context //"/jolokia/read"
|
context := j.Context // Usually "/jolokia"
|
||||||
servers := j.Servers
|
servers := j.Servers
|
||||||
metrics := j.Metrics
|
metrics := j.Metrics
|
||||||
tags := make(map[string]string)
|
tags := make(map[string]string)
|
||||||
|
mode := j.Mode
|
||||||
|
|
||||||
for _, server := range servers {
|
if( mode == "agent" || mode == ""){
|
||||||
tags["server"] = server.Name
|
|
||||||
tags["port"] = server.Port
|
|
||||||
tags["host"] = server.Host
|
|
||||||
fields := make(map[string]interface{})
|
|
||||||
for _, metric := range metrics {
|
|
||||||
|
|
||||||
measurement := metric.Name
|
for _, server := range servers {
|
||||||
jmxPath := metric.Jmx
|
tags["server"] = server.Name
|
||||||
|
tags["port"] = server.Port
|
||||||
|
tags["host"] = server.Host
|
||||||
|
fields := make(map[string]interface{})
|
||||||
|
for _, metric := range metrics {
|
||||||
|
|
||||||
|
measurement := metric.Name
|
||||||
|
jmxPath := "/" + metric.Mbean
|
||||||
|
if metric.Attribute != "" {
|
||||||
|
jmxPath = jmxPath + "/" + metric.Attribute
|
||||||
|
|
||||||
|
if metric.Path != "" {
|
||||||
|
jmxPath = jmxPath + "/" + metric.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare URL
|
// Prepare URL
|
||||||
requestUrl, err := url.Parse("http://" + server.Host + ":" +
|
requestUrl, err := url.Parse("http://" + server.Host + ":" +
|
||||||
server.Port + context + jmxPath)
|
server.Port + context + "/read" + jmxPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
if server.Username != "" || server.Password != "" {
|
|
||||||
requestUrl.User = url.UserPassword(server.Username, server.Password)
|
|
||||||
}
|
|
||||||
|
|
||||||
out, _ := j.getAttr(requestUrl)
|
|
||||||
|
|
||||||
if values, ok := out["value"]; ok {
|
|
||||||
switch t := values.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
for k, v := range t {
|
|
||||||
fields[measurement+"_"+k] = v
|
|
||||||
}
|
|
||||||
case interface{}:
|
|
||||||
fields[measurement] = t
|
|
||||||
}
|
}
|
||||||
} else {
|
if server.Username != "" || server.Password != "" {
|
||||||
fmt.Printf("Missing key 'value' in '%s' output response\n",
|
requestUrl.User = url.UserPassword(server.Username, server.Password)
|
||||||
requestUrl.String())
|
}
|
||||||
|
out, _ := j.getAttr(requestUrl)
|
||||||
|
j.collectMeasurement(measurement, out, fields)
|
||||||
}
|
}
|
||||||
|
acc.AddFields("jolokia", fields, tags)
|
||||||
}
|
}
|
||||||
acc.AddFields("jolokia", fields, tags)
|
|
||||||
|
} else if ( mode == "proxy") {
|
||||||
|
|
||||||
|
proxy := j.Proxy
|
||||||
|
|
||||||
|
// Prepare ProxyURL
|
||||||
|
proxyURL, err := url.Parse("http://" + proxy.Host + ":" +
|
||||||
|
proxy.Port + context)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if proxy.Username != "" || proxy.Password != "" {
|
||||||
|
proxyURL.User = url.UserPassword(proxy.Username, proxy.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, server := range servers {
|
||||||
|
tags["server"] = server.Name
|
||||||
|
tags["port"] = server.Port
|
||||||
|
tags["host"] = server.Host
|
||||||
|
fields := make(map[string]interface{})
|
||||||
|
for _, metric := range metrics {
|
||||||
|
|
||||||
|
measurement := metric.Name
|
||||||
|
// Prepare URL
|
||||||
|
serviceUrl := fmt.Sprintf("service:jmx:rmi:///jndi/rmi://%s:%s/jmxrmi", server.Host, server.Port)
|
||||||
|
|
||||||
|
target := map[string]string{
|
||||||
|
"url": serviceUrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.Username != "" {
|
||||||
|
target["user"] = server.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
if server.Password != "" {
|
||||||
|
target["password"] = server.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create + send request
|
||||||
|
bodyContent := map[string]interface{}{
|
||||||
|
"type": "read",
|
||||||
|
"mbean": metric.Mbean,
|
||||||
|
"target": target,
|
||||||
|
}
|
||||||
|
|
||||||
|
if metric.Attribute != "" {
|
||||||
|
bodyContent["attribute"] = metric.Attribute
|
||||||
|
if metric.Path != "" {
|
||||||
|
bodyContent["path"] = metric.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody, err := json.Marshal(bodyContent)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", proxyURL.String(), bytes.NewBuffer(requestBody))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Content-type", "application/json")
|
||||||
|
|
||||||
|
out, err := j.doRequest(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error handling response: %s\n", err)
|
||||||
|
}else {
|
||||||
|
j.collectMeasurement(measurement, out, fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc.AddFields("jolokia", fields, tags)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -47,8 +47,10 @@ const invalidJSON = "I don't think this is JSON"
|
||||||
const empty = ""
|
const empty = ""
|
||||||
|
|
||||||
var Servers = []Server{Server{Name: "as1", Host: "127.0.0.1", Port: "8080"}}
|
var Servers = []Server{Server{Name: "as1", Host: "127.0.0.1", Port: "8080"}}
|
||||||
var HeapMetric = Metric{Name: "heap_memory_usage", Jmx: "/java.lang:type=Memory/HeapMemoryUsage"}
|
var HeapMetric = Metric{Name: "heap_memory_usage",
|
||||||
var UsedHeapMetric = Metric{Name: "heap_memory_usage", Jmx: "/java.lang:type=Memory/HeapMemoryUsage"}
|
Mbean: "java.lang:type=Memory", Attribute: "HeapMemoryUsage" }
|
||||||
|
var UsedHeapMetric = Metric{Name: "heap_memory_usage",
|
||||||
|
Mbean: "java.lang:type=Memory", Attribute: "HeapMemoryUsage"}
|
||||||
|
|
||||||
type jolokiaClientStub struct {
|
type jolokiaClientStub struct {
|
||||||
responseBody string
|
responseBody string
|
||||||
|
@ -114,3 +116,18 @@ func TestHttpJsonOn404(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 0, len(acc.Metrics))
|
assert.Equal(t, 0, len(acc.Metrics))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Test that the proper values are ignored or collected
|
||||||
|
func TestHttpInvalidJson(t *testing.T) {
|
||||||
|
|
||||||
|
jolokia := genJolokiaClientStub(invalidJSON, 200, Servers,
|
||||||
|
[]Metric{UsedHeapMetric})
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
acc.SetDebug(true)
|
||||||
|
err := jolokia.Gather(&acc)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 0, len(acc.Metrics))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue