Add hsperfdata Input Plugin
For gather data from the shared memory exposed by running processes.
This commit is contained in:
parent
536dbfb724
commit
68f132001f
1
Godeps
1
Godeps
|
@ -51,6 +51,7 @@ github.com/shirou/gopsutil 1516eb9ddc5e61ba58874047a98f8b44b5e585e8
|
|||
github.com/soniah/gosnmp 3fe3beb30fa9700988893c56a63b1df8e1b68c26
|
||||
github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744
|
||||
github.com/stretchr/testify 1f4a1643a57e798696635ea4c126e9127adb7d3c
|
||||
github.com/tokuhirom/go-hsperfdata 63efb7d3b4adbb23528abb6edcb7361a0c7ac22b
|
||||
github.com/vjeantet/grok 83bfdfdfd1a8146795b28e547a8e3c8b28a466c2
|
||||
github.com/wvanbergen/kafka 46f9a1cf3f670edec492029fadded9c2d9e18866
|
||||
github.com/wvanbergen/kazoo-go 0f768712ae6f76454f987c3356177e138df258f8
|
||||
|
|
|
@ -157,6 +157,7 @@ configuration options.
|
|||
* [filestat](./plugins/inputs/filestat)
|
||||
* [haproxy](./plugins/inputs/haproxy)
|
||||
* [hddtemp](./plugins/inputs/hddtemp)
|
||||
* [hsperfdata](./plugins/inputs/hsperfdata) (Hostpot JVMs)
|
||||
* [http_response](./plugins/inputs/http_response)
|
||||
* [httpjson](./plugins/inputs/httpjson) (generic JSON-emitting http service plugin)
|
||||
* [influxdb](./plugins/inputs/influxdb)
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
_ "github.com/influxdata/telegraf/plugins/inputs/jolokia"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/kafka_consumer"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/kubernetes"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/hsperfdata"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/leofs"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/logparser"
|
||||
_ "github.com/influxdata/telegraf/plugins/inputs/lustre2"
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# hsperfdata Plugin
|
||||
|
||||
The plugin gathers data from Hotspot JVMs via the hsperfdata files they expose. This plugin won't work if you've disabled their creation using `-XX:-UsePerfData` or `-XX:+PerfDisableSharedMem`!
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
[[inputs.hsperfdata]]
|
||||
# Optional: gather data from processes belonging to a different user. By
|
||||
# default, the username in the USER environment variable is used to generate
|
||||
# the hsperfdata directory name (usually "/tmp/hsperfdata_username")
|
||||
user: "root"
|
||||
|
||||
# use the named keys in the hsperfdata file as tags, not fields. By default,
|
||||
# every key is exposed as a field. This example shows how to tag by JVM major
|
||||
# version:
|
||||
tags: ["java.property.java.vm.specification.version"]
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
All metrics are gathered as the "java" measurement.
|
||||
|
||||
All keys in the hsperfdata file are exposed as fields; there's no comprehensive list as they vary by Hotspot version.
|
||||
|
||||
### Tags:
|
||||
|
||||
- All measurements have the following tags:
|
||||
- pid (the process id of the monitored process)
|
||||
- procname (the class name containing the `main` function being run)
|
||||
|
||||
### Example Output:
|
||||
|
||||
Most fields abbreviated; there's usually 200-300 of them:
|
||||
|
||||
```
|
||||
$ ./telegraf -config telegraf.conf -input-filter example -test
|
||||
java,host=nwhite91-mac,pid=17427,procname=com.sun.javaws.Main java.ci.totalTime="49874911809",...,sun.zip.zipFiles="28" 1479466710000000000
|
||||
```
|
|
@ -0,0 +1,89 @@
|
|||
package hsperfdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
"github.com/tokuhirom/go-hsperfdata/hsperfdata"
|
||||
)
|
||||
|
||||
type Hsperfdata struct {
|
||||
User string
|
||||
Tags []string
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
## Use the hsperfdata directory belonging to a different user.
|
||||
# user = "root"
|
||||
#
|
||||
## Use the value for these keys in the hsperfdata as tags, not fields. By
|
||||
## default everything is a field.
|
||||
# tags = ["sun.rt.jvmVersion"]
|
||||
`
|
||||
|
||||
func (n *Hsperfdata) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (n *Hsperfdata) Repo() (*hsperfdata.Repository, error) {
|
||||
if n.User == "" {
|
||||
return hsperfdata.New()
|
||||
} else {
|
||||
return hsperfdata.NewUser(n.User)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Hsperfdata) Gather(acc telegraf.Accumulator) error {
|
||||
repo, err := n.Repo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
files, err := repo.GetFiles()
|
||||
if err != nil {
|
||||
// the directory doesn't exist - so there aren't any Java processes running
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
result, err := file.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tags := map[string]string{"pid": file.GetPid()}
|
||||
fields := result.GetMap()
|
||||
|
||||
procname := result.GetProcName()
|
||||
if procname != "" {
|
||||
tags["procname"] = procname
|
||||
}
|
||||
|
||||
for _, tag := range n.Tags {
|
||||
// don't tag metrics with "nil", just skip the tag if it's not there
|
||||
if value, ok := fields[tag]; ok {
|
||||
if valuestr, ok := value.(string); ok {
|
||||
tags[tag] = valuestr
|
||||
} else {
|
||||
tags[tag] = fmt.Sprintf("%#v", fields[tag])
|
||||
}
|
||||
delete(fields, tag)
|
||||
}
|
||||
}
|
||||
|
||||
acc.AddFields("java", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Hsperfdata) Description() string {
|
||||
return "Read performance data from running hotspot JVMs from shared memory"
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("hsperfdata", func() telegraf.Input {
|
||||
return &Hsperfdata{}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package hsperfdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const datadir = "hsperfdata_tokuhirom"
|
||||
|
||||
func TestGatherNoTags(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
hs := &Hsperfdata{User: "tokuhirom"}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
require.NoError(t, hs.Gather(&acc))
|
||||
|
||||
assert.New(t).Equal(acc.NMetrics(), uint64(2))
|
||||
|
||||
acc.Lock()
|
||||
defer acc.Unlock()
|
||||
for _, p := range acc.Metrics {
|
||||
if reflect.DeepEqual(
|
||||
map[string]string{
|
||||
"pid": "13223",
|
||||
},
|
||||
p.Tags) {
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
212,
|
||||
len(p.Fields))
|
||||
|
||||
// verify some of the fields (there's quite a lot!)
|
||||
assert.Equal(
|
||||
t,
|
||||
"367001600",
|
||||
p.Fields["sun.gc.generation.2.space.0.capacity"])
|
||||
assert.Equal(
|
||||
t,
|
||||
"/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries",
|
||||
p.Fields["sun.property.sun.boot.library.path"])
|
||||
|
||||
} else if reflect.DeepEqual(map[string]string{
|
||||
"pid": "21916",
|
||||
"procname": "org.jetbrains.jps.cmdline.Launcher",
|
||||
}, p.Tags) {
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
253,
|
||||
len(p.Fields),
|
||||
fmt.Sprintf("wrong number of fields in %v", p))
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
"3313990237",
|
||||
p.Fields["java.ci.totalTime"])
|
||||
assert.Equal(
|
||||
t,
|
||||
"/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib",
|
||||
p.Fields["sun.property.sun.boot.library.path"])
|
||||
|
||||
} else {
|
||||
msg := fmt.Sprintf("unknown with tags %v", p.Tags)
|
||||
assert.Fail(t, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGatherWithTags(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
hs := &Hsperfdata{
|
||||
User: "tokuhirom",
|
||||
Tags: []string{"java.property.java.vm.specification.vendor", "sun.gc.policy.minorCollectionSlope"}}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
require.NoError(t, hs.Gather(&acc))
|
||||
|
||||
assert.New(t).Equal(acc.NMetrics(), uint64(2))
|
||||
|
||||
acc.Lock()
|
||||
defer acc.Unlock()
|
||||
for _, p := range acc.Metrics {
|
||||
if reflect.DeepEqual(
|
||||
map[string]string{
|
||||
"pid": "13223",
|
||||
"java.property.java.vm.specification.vendor": "Sun Microsystems Inc.",
|
||||
},
|
||||
p.Tags) {
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
211,
|
||||
len(p.Fields))
|
||||
|
||||
assert.NotContains(
|
||||
t,
|
||||
p.Fields,
|
||||
"java.property.java.vm.specification.vendor",
|
||||
"value promoted to tag")
|
||||
|
||||
// verify some of the fields (there's quite a lot!)
|
||||
assert.Equal(
|
||||
t,
|
||||
"367001600",
|
||||
p.Fields["sun.gc.generation.2.space.0.capacity"])
|
||||
assert.Equal(
|
||||
t,
|
||||
"/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries",
|
||||
p.Fields["sun.property.sun.boot.library.path"])
|
||||
|
||||
} else if reflect.DeepEqual(map[string]string{
|
||||
"pid": "21916",
|
||||
"procname": "org.jetbrains.jps.cmdline.Launcher",
|
||||
"java.property.java.vm.specification.vendor": "Oracle Corporation",
|
||||
"sun.gc.policy.minorCollectionSlope": "0",
|
||||
}, p.Tags) {
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
251,
|
||||
len(p.Fields))
|
||||
|
||||
assert.NotContains(
|
||||
t,
|
||||
p.Fields,
|
||||
"java.property.java.vm.specification.vendor",
|
||||
"value promoted to tag")
|
||||
|
||||
assert.Equal(
|
||||
t,
|
||||
"3313990237",
|
||||
p.Fields["java.ci.totalTime"])
|
||||
assert.Equal(
|
||||
t,
|
||||
"/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib",
|
||||
p.Fields["sun.property.sun.boot.library.path"])
|
||||
|
||||
} else {
|
||||
msg := fmt.Sprintf("unknown with tags %v", p.Tags)
|
||||
assert.Fail(t, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoDirectoryNoMeasurements(t *testing.T) {
|
||||
hs := &Hsperfdata{User: "tokuhirom"}
|
||||
|
||||
acc := testutil.Accumulator{}
|
||||
require.NoError(t, hs.Gather(&acc))
|
||||
assert.New(t).Equal(acc.NMetrics(), uint64(0))
|
||||
}
|
||||
|
||||
func setup() {
|
||||
_, filename, _, _ := runtime.Caller(1)
|
||||
src := filepath.Join(
|
||||
strings.Replace(filename, "hsperfdata_test.go", "testdata", 1),
|
||||
datadir)
|
||||
dest := filepath.Join(
|
||||
os.TempDir(),
|
||||
datadir)
|
||||
os.Symlink(src, dest)
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
os.Remove(filepath.Join(os.TempDir(), datadir))
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue