2015-10-28 08:13:22 +00:00
|
|
|
|
package jolokia
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"net/http"
|
2015-10-29 12:25:16 +00:00
|
|
|
|
"net/url"
|
2015-10-28 08:13:22 +00:00
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/influxdb/telegraf/plugins"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Server struct {
|
2015-10-29 13:48:39 +00:00
|
|
|
|
Name string
|
|
|
|
|
Host string
|
|
|
|
|
Port string
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Metric struct {
|
2015-10-29 13:48:39 +00:00
|
|
|
|
Name string
|
|
|
|
|
Jmx string
|
|
|
|
|
Pass []string
|
|
|
|
|
Drop []string
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-29 16:00:26 +00:00
|
|
|
|
type JolokiaClient interface {
|
|
|
|
|
MakeRequest(req *http.Request) (*http.Response, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type JolokiaClientImpl struct {
|
|
|
|
|
client *http.Client
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c JolokiaClientImpl) MakeRequest(req *http.Request) (*http.Response, error) {
|
|
|
|
|
return c.client.Do(req)
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-28 08:13:22 +00:00
|
|
|
|
type Jolokia struct {
|
2015-10-29 16:00:26 +00:00
|
|
|
|
jClient JolokiaClient
|
2015-10-29 13:48:39 +00:00
|
|
|
|
Context string
|
|
|
|
|
Servers []Server
|
|
|
|
|
Metrics []Metric
|
|
|
|
|
Tags map[string]string
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (j *Jolokia) SampleConfig() string {
|
2015-10-29 13:51:15 +00:00
|
|
|
|
return `
|
2015-11-12 16:52:10 +00:00
|
|
|
|
# This is the context root used to compose the jolokia url
|
2015-10-28 08:13:22 +00:00
|
|
|
|
context = "/jolokia/read"
|
|
|
|
|
|
2015-11-12 16:52:10 +00:00
|
|
|
|
# Tags added to each measurements
|
|
|
|
|
[jolokia.tags]
|
|
|
|
|
group = "as"
|
2015-10-28 10:36:03 +00:00
|
|
|
|
|
2015-11-12 16:52:10 +00:00
|
|
|
|
# List of servers exposing jolokia read service
|
2015-11-24 21:22:11 +00:00
|
|
|
|
[[plugins.jolokia.servers]]
|
2015-11-03 21:00:23 +00:00
|
|
|
|
name = "stable"
|
|
|
|
|
host = "192.168.103.2"
|
|
|
|
|
port = "8180"
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-11-12 16:52:10 +00:00
|
|
|
|
# List of metrics collected on above servers
|
|
|
|
|
# Each metric consists in a name, a jmx path and either a pass or drop slice attributes
|
|
|
|
|
# This collect all heap memory usage metrics
|
2015-11-24 21:22:11 +00:00
|
|
|
|
[[plugins.jolokia.metrics]]
|
2015-11-03 21:00:23 +00:00
|
|
|
|
name = "heap_memory_usage"
|
|
|
|
|
jmx = "/java.lang:type=Memory/HeapMemoryUsage"
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-11-03 21:00:23 +00:00
|
|
|
|
|
|
|
|
|
# This drops the 'committed' value from Eden space measurement
|
2015-11-24 21:22:11 +00:00
|
|
|
|
[[plugins.jolokia.metrics]]
|
2015-11-03 21:00:23 +00:00
|
|
|
|
name = "memory_eden"
|
|
|
|
|
jmx = "/java.lang:type=MemoryPool,name=PS Eden Space/Usage"
|
|
|
|
|
drop = [ "committed" ]
|
|
|
|
|
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-11-12 16:52:10 +00:00
|
|
|
|
# This passes only DaemonThreadCount and ThreadCount
|
2015-11-24 21:22:11 +00:00
|
|
|
|
[[plugins.jolokia.metrics]]
|
2015-11-12 16:52:10 +00:00
|
|
|
|
name = "heap_threads"
|
2015-11-03 21:00:23 +00:00
|
|
|
|
jmx = "/java.lang:type=Threading"
|
|
|
|
|
pass = [
|
2015-11-12 16:52:10 +00:00
|
|
|
|
"DaemonThreadCount",
|
|
|
|
|
"ThreadCount"
|
|
|
|
|
]
|
2015-10-28 08:13:22 +00:00
|
|
|
|
`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (j *Jolokia) Description() string {
|
|
|
|
|
return "Read JMX metrics through Jolokia"
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-29 16:00:26 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := j.jClient.MakeRequest(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-28 08:13:22 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
// Process response
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
err = fmt.Errorf("Response from url \"%s\" has status code %d (%s), expected %d (%s)",
|
|
|
|
|
requestUrl,
|
|
|
|
|
resp.StatusCode,
|
|
|
|
|
http.StatusText(resp.StatusCode),
|
|
|
|
|
http.StatusOK,
|
|
|
|
|
http.StatusText(http.StatusOK))
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// read body
|
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
2015-10-28 08:13:22 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
// Unmarshal json
|
|
|
|
|
var jsonOut map[string]interface{}
|
|
|
|
|
if err = json.Unmarshal([]byte(body), &jsonOut); err != nil {
|
|
|
|
|
return nil, errors.New("Error decoding JSON response")
|
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
return jsonOut, nil
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *Metric) shouldPass(field string) bool {
|
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
if m.Pass != nil {
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
for _, pass := range m.Pass {
|
|
|
|
|
if strings.HasPrefix(field, pass) {
|
2015-10-28 08:13:22 +00:00
|
|
|
|
return true
|
|
|
|
|
}
|
2015-10-29 13:48:39 +00:00
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
return false
|
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
if m.Drop != nil {
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
for _, drop := range m.Drop {
|
|
|
|
|
if strings.HasPrefix(field, drop) {
|
2015-10-28 08:13:22 +00:00
|
|
|
|
return false
|
|
|
|
|
}
|
2015-10-29 13:48:39 +00:00
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
return true
|
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
return true
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *Metric) filterFields(fields map[string]interface{}) map[string]interface{} {
|
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
for field, _ := range fields {
|
|
|
|
|
if !m.shouldPass(field) {
|
2015-10-28 08:13:22 +00:00
|
|
|
|
delete(fields, field)
|
|
|
|
|
}
|
2015-10-29 13:48:39 +00:00
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
return fields
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (j *Jolokia) Gather(acc plugins.Accumulator) error {
|
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
context := j.Context //"/jolokia/read"
|
|
|
|
|
servers := j.Servers
|
|
|
|
|
metrics := j.Metrics
|
2015-10-28 10:36:03 +00:00
|
|
|
|
tags := j.Tags
|
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
if tags == nil {
|
|
|
|
|
tags = map[string]string{}
|
2015-10-28 10:36:03 +00:00
|
|
|
|
}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
for _, server := range servers {
|
|
|
|
|
for _, metric := range metrics {
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
measurement := metric.Name
|
|
|
|
|
jmxPath := metric.Jmx
|
2015-10-28 08:13:22 +00:00
|
|
|
|
|
2015-10-29 13:48:39 +00:00
|
|
|
|
tags["server"] = server.Name
|
2015-10-28 08:13:22 +00:00
|
|
|
|
tags["port"] = server.Port
|
|
|
|
|
tags["host"] = server.Host
|
|
|
|
|
|
2015-10-29 12:25:16 +00:00
|
|
|
|
// Prepare URL
|
|
|
|
|
requestUrl, err := url.Parse("http://" + server.Host + ":" + server.Port + context + jmxPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-29 16:00:26 +00:00
|
|
|
|
out, _ := j.getAttr(requestUrl)
|
2015-10-29 13:48:39 +00:00
|
|
|
|
|
|
|
|
|
if values, ok := out["value"]; ok {
|
|
|
|
|
switch values.(type) {
|
|
|
|
|
case map[string]interface{}:
|
|
|
|
|
acc.AddFields(measurement, metric.filterFields(values.(map[string]interface{})), tags)
|
|
|
|
|
case interface{}:
|
|
|
|
|
acc.Add(measurement, values.(interface{}), tags)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf("Missing key 'value' in '%s' output response\n", requestUrl.String())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
2015-10-28 08:13:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
plugins.Add("jolokia", func() plugins.Plugin {
|
2015-10-29 16:00:26 +00:00
|
|
|
|
return &Jolokia{jClient: &JolokiaClientImpl{client: &http.Client{}}}
|
2015-10-28 08:13:22 +00:00
|
|
|
|
})
|
|
|
|
|
}
|