github.com/mackerelio/mackerel-agent-plugins@v0.89.3/mackerel-plugin-jmx-jolokia/lib/jmx-jolokia.go (about)

     1  package mpjmxjolokia
     2  
     3  import (
     4  	"encoding/json"
     5  	"flag"
     6  	"fmt"
     7  	"net/http"
     8  
     9  	mp "github.com/mackerelio/go-mackerel-plugin-helper"
    10  	"github.com/mackerelio/golib/logging"
    11  )
    12  
    13  var logger = logging.GetLogger("metrics.plugin.jmx-jolokia")
    14  
    15  // JmxJolokiaPlugin mackerel plugin for Jolokia
    16  type JmxJolokiaPlugin struct {
    17  	Target   string
    18  	Tempfile string
    19  }
    20  
    21  // JmxJolokiaResponse response for Jolokia
    22  type JmxJolokiaResponse struct {
    23  	Status    uint32
    24  	Timestamp uint32
    25  	Request   map[string]interface{}
    26  	Value     map[string]interface{}
    27  	Error     string
    28  }
    29  
    30  var graphdef = map[string]mp.Graphs{
    31  	"jmx.jolokia.memory.heap_memory_usage": {
    32  		Label: "Jmx HeapMemoryUsage",
    33  		Unit:  "bytes",
    34  		Metrics: []mp.Metrics{
    35  			{Name: "HeapMemoryInit", Label: "init", Diff: false, Type: "uint64"},
    36  			{Name: "HeapMemoryCommitted", Label: "committed", Diff: false, Type: "uint64"},
    37  			{Name: "HeapMemoryMax", Label: "max", Diff: false, Type: "uint64"},
    38  			{Name: "HeapMemoryUsed", Label: "used", Diff: false, Type: "uint64"},
    39  		},
    40  	},
    41  	"jmx.jolokia.memory.non_heap_memory_usage": {
    42  		Label: "Jmx NonHeapMemoryUsage",
    43  		Unit:  "bytes",
    44  		Metrics: []mp.Metrics{
    45  			{Name: "NonHeapMemoryInit", Label: "init", Diff: false, Type: "uint64"},
    46  			{Name: "NonHeapMemoryCommitted", Label: "committed", Diff: false, Type: "uint64"},
    47  			{Name: "NonHeapMemoryMax", Label: "max", Diff: false, Type: "uint64"},
    48  			{Name: "NonHeapMemoryUsed", Label: "used", Diff: false, Type: "uint64"},
    49  		},
    50  	},
    51  	"jmx.jolokia.class_load": {
    52  		Label: "Jmx ClassLoading",
    53  		Unit:  "integer",
    54  		Metrics: []mp.Metrics{
    55  			{Name: "LoadedClassCount", Label: "loaded", Diff: false, Type: "uint64"},
    56  			{Name: "UnloadedClassCount", Label: "unloaded", Diff: false, Type: "uint64"},
    57  			{Name: "TotalLoadedClassCount", Label: "total", Diff: false, Type: "uint64"},
    58  		},
    59  	},
    60  	"jmx.jolokia.thread": {
    61  		Label: "Jmx Threading",
    62  		Unit:  "integer",
    63  		Metrics: []mp.Metrics{
    64  			{Name: "ThreadCount", Label: "thread", Diff: false, Type: "uint64"},
    65  			{Name: "DaemonThreadCount", Label: "daemon", Diff: false, Type: "uint64"},
    66  			{Name: "PeakThreadCount", Label: "peak", Diff: false, Type: "uint64"},
    67  		},
    68  	},
    69  	"jmx.jolokia.ops.cpu_load": {
    70  		Label: "Jmx CpuLoad",
    71  		Unit:  "percentage",
    72  		Metrics: []mp.Metrics{
    73  			{Name: "ProcessCpuLoad", Label: "process", Diff: false, Type: "float64", Scale: 100},
    74  			{Name: "SystemCpuLoad", Label: "system", Diff: false, Type: "float64", Scale: 100},
    75  		},
    76  	},
    77  }
    78  
    79  // FetchMetrics interface for mackerelplugin
    80  func (j JmxJolokiaPlugin) FetchMetrics() (map[string]interface{}, error) {
    81  	stat := make(map[string]interface{})
    82  	if err := j.fetchMemory(stat); err != nil {
    83  		logger.Warningf(err.Error())
    84  	}
    85  
    86  	if err := j.fetchClassLoad(stat); err != nil {
    87  		logger.Warningf(err.Error())
    88  	}
    89  
    90  	if err := j.fetchThread(stat); err != nil {
    91  		logger.Warningf(err.Error())
    92  	}
    93  
    94  	if err := j.fetchOperatingSystem(stat); err != nil {
    95  		logger.Warningf(err.Error())
    96  	}
    97  
    98  	return stat, nil
    99  }
   100  
   101  func (j JmxJolokiaPlugin) fetchMemory(stat map[string]interface{}) error {
   102  	resp, err := j.executeGetRequest("java.lang:type=Memory")
   103  	if err != nil {
   104  		return err
   105  	}
   106  	heap := resp.Value["HeapMemoryUsage"].(map[string]interface{})
   107  	stat["HeapMemoryInit"] = heap["init"]
   108  	stat["HeapMemoryCommitted"] = heap["committed"]
   109  	stat["HeapMemoryMax"] = heap["max"]
   110  	stat["HeapMemoryUsed"] = heap["used"]
   111  
   112  	nonHeap := resp.Value["NonHeapMemoryUsage"].(map[string]interface{})
   113  	stat["NonHeapMemoryInit"] = nonHeap["init"]
   114  	stat["NonHeapMemoryCommitted"] = nonHeap["committed"]
   115  	stat["NonHeapMemoryMax"] = nonHeap["max"]
   116  	stat["NonHeapMemoryUsed"] = nonHeap["used"]
   117  
   118  	return nil
   119  }
   120  
   121  func (j JmxJolokiaPlugin) fetchClassLoad(stat map[string]interface{}) error {
   122  	resp, err := j.executeGetRequest("java.lang:type=ClassLoading")
   123  	if err != nil {
   124  		return err
   125  	}
   126  	stat["LoadedClassCount"] = resp.Value["LoadedClassCount"]
   127  	stat["UnloadedClassCount"] = resp.Value["UnloadedClassCount"]
   128  	stat["TotalLoadedClassCount"] = resp.Value["TotalLoadedClassCount"]
   129  
   130  	return nil
   131  }
   132  
   133  func (j JmxJolokiaPlugin) fetchThread(stat map[string]interface{}) error {
   134  	resp, err := j.executeGetRequest("java.lang:type=Threading")
   135  	if err != nil {
   136  		return err
   137  	}
   138  	stat["ThreadCount"] = resp.Value["ThreadCount"]
   139  	stat["DaemonThreadCount"] = resp.Value["DaemonThreadCount"]
   140  	stat["PeakThreadCount"] = resp.Value["PeakThreadCount"]
   141  
   142  	return nil
   143  }
   144  
   145  func (j JmxJolokiaPlugin) fetchOperatingSystem(stat map[string]interface{}) error {
   146  	resp, err := j.executeGetRequest("java.lang:type=OperatingSystem")
   147  	if err != nil {
   148  		return err
   149  	}
   150  	stat["ProcessCpuLoad"] = resp.Value["ProcessCpuLoad"]
   151  	stat["SystemCpuLoad"] = resp.Value["SystemCpuLoad"]
   152  
   153  	return nil
   154  }
   155  
   156  func (j JmxJolokiaPlugin) executeGetRequest(mbean string) (*JmxJolokiaResponse, error) {
   157  	req, err := http.NewRequest(http.MethodGet, j.Target+mbean, nil)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	req.Header.Set("User-Agent", "mackerel-plugin-jmx-jolokia")
   162  
   163  	resp, err := http.DefaultClient.Do(req)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	defer resp.Body.Close()
   168  	var respJ JmxJolokiaResponse
   169  	dec := json.NewDecoder(resp.Body)
   170  	if err := dec.Decode(&respJ); err != nil {
   171  		return nil, err
   172  	}
   173  	return &respJ, nil
   174  }
   175  
   176  // GraphDefinition interface for mackerelplugin
   177  func (j JmxJolokiaPlugin) GraphDefinition() map[string]mp.Graphs {
   178  	return graphdef
   179  }
   180  
   181  // Do the plugin
   182  func Do() {
   183  	optHost := flag.String("host", "localhost", "Hostname")
   184  	optPort := flag.String("port", "8778", "Port")
   185  	optTempfile := flag.String("tempfile", "", "Temp file name")
   186  	flag.Parse()
   187  
   188  	var jmxJolokia JmxJolokiaPlugin
   189  	jmxJolokia.Target = fmt.Sprintf("http://%s:%s/jolokia/read/", *optHost, *optPort)
   190  
   191  	helper := mp.NewMackerelPlugin(jmxJolokia)
   192  	if *optTempfile != "" {
   193  		helper.Tempfile = *optTempfile
   194  	} else {
   195  		helper.SetTempfileByBasename(fmt.Sprintf("mackerel-plugin-jmx-jolokia-%s-%s", *optHost, *optPort))
   196  	}
   197  	helper.Run()
   198  }