fix merge conflicts, update import paths
This commit is contained in:
commit
3145a732f2
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -1,4 +1,10 @@
|
||||||
## v0.1.5 [unreleased]
|
## v0.1.6 [unreleased]
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
|
||||||
|
## v0.1.5 [2015-08-13]
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- [#54](https://github.com/influxdb/telegraf/pull/54): MongoDB plugin. Thanks @jipperinbham!
|
- [#54](https://github.com/influxdb/telegraf/pull/54): MongoDB plugin. Thanks @jipperinbham!
|
||||||
|
@ -15,6 +21,8 @@
|
||||||
- [#103](https://github.com/influxdb/telegraf/pull/103): Filter by metric tags. Thanks @srfraser!
|
- [#103](https://github.com/influxdb/telegraf/pull/103): Filter by metric tags. Thanks @srfraser!
|
||||||
- [#106](https://github.com/influxdb/telegraf/pull/106): Options to filter plugins on startup. Thanks @zepouet!
|
- [#106](https://github.com/influxdb/telegraf/pull/106): Options to filter plugins on startup. Thanks @zepouet!
|
||||||
- [#107](https://github.com/influxdb/telegraf/pull/107): Multiple outputs beyong influxdb. Thanks @jipperinbham!
|
- [#107](https://github.com/influxdb/telegraf/pull/107): Multiple outputs beyong influxdb. Thanks @jipperinbham!
|
||||||
|
- [#108](https://github.com/influxdb/telegraf/issues/108): Support setting per-CPU and total-CPU gathering.
|
||||||
|
- [#111](https://github.com/influxdb/telegraf/pull/111): Report CPU Usage in cpu plugin. Thanks @jpalay!
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- [#85](https://github.com/influxdb/telegraf/pull/85): Fix GetLocalHost testutil function for mac users
|
- [#85](https://github.com/influxdb/telegraf/pull/85): Fix GetLocalHost testutil function for mac users
|
||||||
|
|
128
README.md
128
README.md
|
@ -18,9 +18,14 @@ writing new plugins.
|
||||||
|
|
||||||
### Linux packages for Debian/Ubuntu and RHEL/CentOS:
|
### Linux packages for Debian/Ubuntu and RHEL/CentOS:
|
||||||
|
|
||||||
|
NOTE: version 0.1.5 has introduced some breaking changes! A 0.1.5 telegraf
|
||||||
|
agent is NOT backwards-compatible with a config file from 0.1.4 and below.
|
||||||
|
That being said, the difference is not huge, see below for an example on
|
||||||
|
how to setup the new config file.
|
||||||
|
|
||||||
```
|
```
|
||||||
http://get.influxdb.org/telegraf/telegraf_0.1.4_amd64.deb
|
http://get.influxdb.org/telegraf/telegraf_0.1.5_amd64.deb
|
||||||
http://get.influxdb.org/telegraf/telegraf-0.1.4-1.x86_64.rpm
|
http://get.influxdb.org/telegraf/telegraf-0.1.5-1.x86_64.rpm
|
||||||
```
|
```
|
||||||
|
|
||||||
### OSX via Homebrew:
|
### OSX via Homebrew:
|
||||||
|
@ -35,21 +40,9 @@ brew install telegraf
|
||||||
* Run `telegraf -sample-config > telegraf.toml` to create an initial configuration
|
* Run `telegraf -sample-config > telegraf.toml` to create an initial configuration
|
||||||
* Edit the configuration to match your needs
|
* Edit the configuration to match your needs
|
||||||
* Run `telegraf -config telegraf.toml -test` to output one full measurement sample to STDOUT
|
* Run `telegraf -config telegraf.toml -test` to output one full measurement sample to STDOUT
|
||||||
* Run `telegraf -config telegraf.toml` to gather and send metrics to InfluxDB
|
* Run `telegraf -config telegraf.toml` to gather and send metrics to configured outputs.
|
||||||
* Run `telegraf -config telegraf.toml -filter system:swap` to enable only two plugins described into config file
|
* Run `telegraf -config telegraf.toml -filter system:swap`
|
||||||
|
to enable only the system & swap plugins defined in the config.
|
||||||
### Telegraf Usage
|
|
||||||
|
|
||||||
```telegraf --help```
|
|
||||||
|
|
||||||
* -config="": configuration file to load
|
|
||||||
* -debug=false: show metrics as they're generated to stdout
|
|
||||||
* -filter="": filter the plugins to enable, separator is :
|
|
||||||
* -httptest.serve="": if non-empty, httptest.NewServer serves on this address and blocks
|
|
||||||
* -pidfile="": file to write our pid to
|
|
||||||
* -sample-config=false: print out full sample configuration
|
|
||||||
* -test=false: gather metrics, print them out, and exit
|
|
||||||
* -version=false: display the version
|
|
||||||
|
|
||||||
## Telegraf Options
|
## Telegraf Options
|
||||||
|
|
||||||
|
@ -66,6 +59,62 @@ unit parser, ie "10s" for 10 seconds or "5m" for 5 minutes.
|
||||||
* **debug**: Set to true to gather and send metrics to STDOUT as well as
|
* **debug**: Set to true to gather and send metrics to STDOUT as well as
|
||||||
InfluxDB.
|
InfluxDB.
|
||||||
|
|
||||||
|
## Plugin Options
|
||||||
|
|
||||||
|
There are 5 configuration options that are configurable per plugin:
|
||||||
|
|
||||||
|
* **pass**: An array of strings that is used to filter metrics generated by the
|
||||||
|
current plugin. Each string in the array is tested as a prefix against metric names
|
||||||
|
and if it matches, the metric is emitted.
|
||||||
|
* **drop**: The inverse of pass, if a metric name matches, it is not emitted.
|
||||||
|
* **tagpass**: tag names and arrays of strings that are used to filter metrics by
|
||||||
|
the current plugin. Each string in the array is tested as an exact match against
|
||||||
|
the tag name, and if it matches the metric is emitted.
|
||||||
|
* **tagdrop**: The inverse of tagpass. If a tag matches, the metric is not emitted.
|
||||||
|
This is tested on metrics that have passed the tagpass test.
|
||||||
|
* **interval**: How often to gather this metric. Normal plugins use a single
|
||||||
|
global interval, but if one particular plugin should be run less or more often,
|
||||||
|
you can configure that here.
|
||||||
|
|
||||||
|
### Plugin Configuration Examples
|
||||||
|
|
||||||
|
This is a full working config that will output CPU data to an InfluxDB instance
|
||||||
|
at 192.168.59.103:8086, tagging measurements with dc="Denver-1". It will output
|
||||||
|
measurements at a 10s interval and will collect totalcpu & percpu data.
|
||||||
|
```
|
||||||
|
[outputs]
|
||||||
|
[outputs.influxdb]
|
||||||
|
url = "http://192.168.59.103:8086" # required.
|
||||||
|
database = "telegraf" # required.
|
||||||
|
|
||||||
|
[tags]
|
||||||
|
dc = "denver-1"
|
||||||
|
|
||||||
|
[agent]
|
||||||
|
interval = "10s"
|
||||||
|
|
||||||
|
# PLUGINS
|
||||||
|
[cpu]
|
||||||
|
percpu = true
|
||||||
|
totalcpu = true
|
||||||
|
```
|
||||||
|
|
||||||
|
Below is how to configure `tagpass` parameters (added in 0.1.5)
|
||||||
|
|
||||||
|
```
|
||||||
|
# Don't collect CPU data for cpu6 & cpu7
|
||||||
|
[cpu.tagdrop]
|
||||||
|
cpu = [ "cpu6", "cpu7" ]
|
||||||
|
|
||||||
|
[disk]
|
||||||
|
[disk.tagpass]
|
||||||
|
# tagpass conditions are OR, not AND.
|
||||||
|
# If the (filesystem is ext4 or xfs) OR (the path is /opt or /home)
|
||||||
|
# then the metric passes
|
||||||
|
fstype = [ "ext4", "xfs" ]
|
||||||
|
path = [ "/opt", "/home" ]
|
||||||
|
```
|
||||||
|
|
||||||
## Supported Plugins
|
## Supported Plugins
|
||||||
|
|
||||||
Telegraf currently has support for collecting metrics from:
|
Telegraf currently has support for collecting metrics from:
|
||||||
|
@ -87,51 +136,6 @@ Telegraf currently has support for collecting metrics from:
|
||||||
We'll be adding support for many more over the coming months. Read on if you
|
We'll be adding support for many more over the coming months. Read on if you
|
||||||
want to add support for another service or third-party API.
|
want to add support for another service or third-party API.
|
||||||
|
|
||||||
## Plugin Options
|
|
||||||
|
|
||||||
There are 3 configuration options that are configurable per plugin:
|
|
||||||
|
|
||||||
* **pass**: An array of strings that is used to filter metrics generated by the
|
|
||||||
current plugin. Each string in the array is tested as a prefix against metric names
|
|
||||||
and if it matches, the metric is emitted.
|
|
||||||
* **drop**: The inverse of pass, if a metric name matches, it is not emitted.
|
|
||||||
* **tagpass**: tag names and arrays of strings that are used to filter metrics by
|
|
||||||
the current plugin. Each string in the array is tested as an exact match against
|
|
||||||
the tag name, and if it matches the metric is emitted.
|
|
||||||
* **tagdrop**: The inverse of tagpass. If a tag matches, the metric is not emitted.
|
|
||||||
This is tested on metrics that have passed the tagpass test.
|
|
||||||
* **interval**: How often to gather this metric. Normal plugins use a single
|
|
||||||
global interval, but if one particular plugin should be run less or more often,
|
|
||||||
you can configure that here.
|
|
||||||
|
|
||||||
### Plugin Configuration Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
# Read metrics about disk usage by mount point
|
|
||||||
[disk]
|
|
||||||
interval = "1m" # Run at a 1 minute interval instead of the default
|
|
||||||
|
|
||||||
[disk.tagpass]
|
|
||||||
# These tag conditions are OR, not AND.
|
|
||||||
# If the (filesystem is ext4 or xfs) or (the path is /opt or /home) then the metric passes
|
|
||||||
fstype = [ "ext4", "xfs" ]
|
|
||||||
path = [ "/opt", "/home" ]
|
|
||||||
|
|
||||||
[postgresql]
|
|
||||||
|
|
||||||
[postgresql.tagdrop]
|
|
||||||
# Don't report stats about the database name 'testdatabase'
|
|
||||||
db = [ "testdatabase" ]
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
[disk]
|
|
||||||
# Don't report stats about the following filesystem types
|
|
||||||
[disk.tagdrop]
|
|
||||||
fstype = [ "nfs", "tmpfs", "ecryptfs" ]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
|
||||||
This section is for developers that want to create new collection plugins.
|
This section is for developers that want to create new collection plugins.
|
||||||
|
|
|
@ -13,11 +13,11 @@ test:
|
||||||
# install binaries
|
# install binaries
|
||||||
- go install ./...
|
- go install ./...
|
||||||
# Go fmt should pass all files
|
# Go fmt should pass all files
|
||||||
- "[ `git ls-files | grep '.go$' | xargs gofmt -l 2>&1 | wc -l` -eq 0 ]"
|
- "[ `git ls-files | grep '.go$' | xargs gofmt -l | tee /tmp/foo | wc -l` -eq 0 ] || (cat /tmp/foo; exit 1)"
|
||||||
- go vet ./...
|
- go vet ./...
|
||||||
- golint .
|
- "[ `golint . | tee /tmp/foo | wc -l` == 0 ] || (cat /tmp/foo; exit 1)"
|
||||||
- golint testutil/...
|
- "[ `golint testutil/... | tee /tmp/foo | wc -l` == 0 ] || (cat /tmp/foo; exit 1)"
|
||||||
- golint cmd/...
|
- "[ `golint cmd/... | tee /tmp/foo | wc -l` == 0 ] || (cat /tmp/foo; exit 1)"
|
||||||
override:
|
override:
|
||||||
- make test-short
|
- make test-short
|
||||||
post:
|
post:
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/influxdb/telegraf"
|
||||||
|
_ "github.com/influxdb/telegraf/outputs/all"
|
||||||
_ "github.com/influxdb/telegraf/plugins/all"
|
_ "github.com/influxdb/telegraf/plugins/all"
|
||||||
"github.com/jipperinbham/telegraf"
|
|
||||||
_ "github.com/jipperinbham/telegraf/outputs/all"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var fDebug = flag.Bool("debug", false, "show metrics as they're generated to stdout")
|
var fDebug = flag.Bool("debug", false, "show metrics as they're generated to stdout")
|
||||||
|
@ -22,7 +22,7 @@ var fPidfile = flag.String("pidfile", "", "file to write our pid to")
|
||||||
var fPLuginsFilter = flag.String("filter", "", "filter the plugins to enable, separator is :")
|
var fPLuginsFilter = flag.String("filter", "", "filter the plugins to enable, separator is :")
|
||||||
|
|
||||||
// Telegraf version
|
// Telegraf version
|
||||||
var Version = "0.1.5-dev"
|
var Version = "0.1.6-dev"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
@ -48,7 +48,9 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
config = telegraf.DefaultConfig()
|
fmt.Println("Usage: Telegraf")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ag, err := telegraf.NewAgent(config)
|
ag, err := telegraf.NewAgent(config)
|
||||||
|
@ -65,7 +67,7 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
if len(outputs) == 0 {
|
if len(outputs) == 0 {
|
||||||
log.Printf("Error: no outputs found, did you provide a config file?")
|
log.Printf("Error: no outputs found, did you provide a valid config file?")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +76,7 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
if len(plugins) == 0 {
|
if len(plugins) == 0 {
|
||||||
log.Printf("Error: no plugins found, did you provide a config file?")
|
log.Printf("Error: no plugins found, did you provide a valid config file?")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +118,7 @@ func main() {
|
||||||
log.Printf("Agent Config: Interval:%s, Debug:%#v, Hostname:%#v\n",
|
log.Printf("Agent Config: Interval:%s, Debug:%#v, Hostname:%#v\n",
|
||||||
ag.Interval, ag.Debug, ag.Hostname)
|
ag.Interval, ag.Debug, ag.Hostname)
|
||||||
}
|
}
|
||||||
log.Printf("Tags enabled: %v", config.ListTags())
|
log.Printf("Tags enabled: %s", config.ListTags())
|
||||||
|
|
||||||
if *fPidfile != "" {
|
if *fPidfile != "" {
|
||||||
f, err := os.Create(*fPidfile)
|
f, err := os.Create(*fPidfile)
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (c *Config) Outputs() map[string]*ast.Table {
|
||||||
return c.outputs
|
return c.outputs
|
||||||
}
|
}
|
||||||
|
|
||||||
// The name of a tag, and the values on which to filter
|
// TagFilter is the name of a tag, and the values on which to filter
|
||||||
type TagFilter struct {
|
type TagFilter struct {
|
||||||
Name string
|
Name string
|
||||||
Filter []string
|
Filter []string
|
||||||
|
@ -253,11 +253,6 @@ func declared(endpoints map[string]*ast.Table) []string {
|
||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig returns an empty default configuration
|
|
||||||
func DefaultConfig() *Config {
|
|
||||||
return &Config{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errInvalidConfig = errors.New("invalid configuration")
|
var errInvalidConfig = errors.New("invalid configuration")
|
||||||
|
|
||||||
// LoadConfig loads the given config file and returns a *Config pointer
|
// LoadConfig loads the given config file and returns a *Config pointer
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package all
|
package all
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "github.com/influxdb/telegraf/outputs/datadog"
|
||||||
_ "github.com/influxdb/telegraf/outputs/influxdb"
|
_ "github.com/influxdb/telegraf/outputs/influxdb"
|
||||||
_ "github.com/jipperinbham/telegraf/outputs/datadog"
|
|
||||||
)
|
)
|
||||||
|
|
12
package.sh
12
package.sh
|
@ -224,7 +224,7 @@ EOF
|
||||||
|
|
||||||
if [ $# -ne 1 ]; then
|
if [ $# -ne 1 ]; then
|
||||||
usage 1
|
usage 1
|
||||||
elif [ $1 == "-h" ]; then
|
elif [ "$1" == "-h" ]; then
|
||||||
usage 0
|
usage 0
|
||||||
else
|
else
|
||||||
VERSION=$1
|
VERSION=$1
|
||||||
|
@ -232,11 +232,11 @@ fi
|
||||||
|
|
||||||
echo -e "\nStarting package process...\n"
|
echo -e "\nStarting package process...\n"
|
||||||
|
|
||||||
if [ $CIRCLE_BRANCH == "" ]; then
|
if [ "$CIRCLE_BRANCH" == "" ]; then
|
||||||
check_gvm
|
check_gvm
|
||||||
fi
|
fi
|
||||||
check_gopath
|
check_gopath
|
||||||
if [ $CIRCLE_BRANCH == "" ]; then
|
if [ "$CIRCLE_BRANCH" == "" ]; then
|
||||||
check_clean_tree
|
check_clean_tree
|
||||||
update_tree
|
update_tree
|
||||||
fi
|
fi
|
||||||
|
@ -282,7 +282,7 @@ generate_postinstall_script $VERSION
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Create the actual packages.
|
# Create the actual packages.
|
||||||
|
|
||||||
if [ $CIRCLE_BRANCH == "" ]; then
|
if [ "$CIRCLE_BRANCH" == "" ]; then
|
||||||
echo -n "Commence creation of $ARCH packages, version $VERSION? [Y/n] "
|
echo -n "Commence creation of $ARCH packages, version $VERSION? [Y/n] "
|
||||||
read response
|
read response
|
||||||
response=`echo $response | tr 'A-Z' 'a-z'`
|
response=`echo $response | tr 'A-Z' 'a-z'`
|
||||||
|
@ -323,7 +323,7 @@ echo "Debian package created successfully."
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Offer to tag the repo.
|
# Offer to tag the repo.
|
||||||
|
|
||||||
if [ $CIRCLE_BRANCH == "" ]; then
|
if [ "$CIRCLE_BRANCH" == "" ]; then
|
||||||
echo -n "Tag source tree with v$VERSION and push to repo? [y/N] "
|
echo -n "Tag source tree with v$VERSION and push to repo? [y/N] "
|
||||||
read response
|
read response
|
||||||
response=`echo $response | tr 'A-Z' 'a-z'`
|
response=`echo $response | tr 'A-Z' 'a-z'`
|
||||||
|
@ -347,7 +347,7 @@ fi
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Offer to publish the packages.
|
# Offer to publish the packages.
|
||||||
|
|
||||||
if [ $CIRCLE_BRANCH == "" ]; then
|
if [ "$CIRCLE_BRANCH" == "" ]; then
|
||||||
echo -n "Publish packages to S3? [y/N] "
|
echo -n "Publish packages to S3? [y/N] "
|
||||||
read response
|
read response
|
||||||
response=`echo $response | tr 'A-Z' 'a-z'`
|
response=`echo $response | tr 'A-Z' 'a-z'`
|
||||||
|
|
|
@ -4,29 +4,51 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/influxdb/telegraf/plugins"
|
"github.com/influxdb/telegraf/plugins"
|
||||||
|
"github.com/influxdb/telegraf/plugins/system/ps/cpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CPUStats struct {
|
type CPUStats struct {
|
||||||
ps PS
|
ps PS
|
||||||
|
lastStats []cpu.CPUTimesStat
|
||||||
|
|
||||||
|
PerCPU bool `toml:"percpu"`
|
||||||
|
TotalCPU bool `toml:"totalcpu"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCPUStats(ps PS) *CPUStats {
|
||||||
|
return &CPUStats{
|
||||||
|
ps: ps,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *CPUStats) Description() string {
|
func (_ *CPUStats) Description() string {
|
||||||
return "Read metrics about cpu usage"
|
return "Read metrics about cpu usage"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *CPUStats) SampleConfig() string { return "" }
|
var sampleConfig = `
|
||||||
|
# Whether to report per-cpu stats or not
|
||||||
|
percpu = true
|
||||||
|
# Whether to report total system cpu stats or not
|
||||||
|
totalcpu = true`
|
||||||
|
|
||||||
|
func (_ *CPUStats) SampleConfig() string {
|
||||||
|
return sampleConfig
|
||||||
|
}
|
||||||
|
|
||||||
func (s *CPUStats) Gather(acc plugins.Accumulator) error {
|
func (s *CPUStats) Gather(acc plugins.Accumulator) error {
|
||||||
times, err := s.ps.CPUTimes()
|
times, err := s.ps.CPUTimes(s.PerCPU, s.TotalCPU)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting CPU info: %s", err)
|
return fmt.Errorf("error getting CPU info: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cts := range times {
|
for i, cts := range times {
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"cpu": cts.CPU,
|
"cpu": cts.CPU,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
busy, total := busyAndTotalCpuTime(cts)
|
||||||
|
|
||||||
|
// Add total cpu numbers
|
||||||
add(acc, "user", cts.User, tags)
|
add(acc, "user", cts.User, tags)
|
||||||
add(acc, "system", cts.System, tags)
|
add(acc, "system", cts.System, tags)
|
||||||
add(acc, "idle", cts.Idle, tags)
|
add(acc, "idle", cts.Idle, tags)
|
||||||
|
@ -38,11 +60,54 @@ func (s *CPUStats) Gather(acc plugins.Accumulator) error {
|
||||||
add(acc, "guest", cts.Guest, tags)
|
add(acc, "guest", cts.Guest, tags)
|
||||||
add(acc, "guestNice", cts.GuestNice, tags)
|
add(acc, "guestNice", cts.GuestNice, tags)
|
||||||
add(acc, "stolen", cts.Stolen, tags)
|
add(acc, "stolen", cts.Stolen, tags)
|
||||||
|
add(acc, "busy", busy, tags)
|
||||||
|
|
||||||
|
// Add in percentage
|
||||||
|
if len(s.lastStats) == 0 {
|
||||||
|
// If it's the 1st gather, can't get CPU stats yet
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lastCts := s.lastStats[i]
|
||||||
|
lastBusy, lastTotal := busyAndTotalCpuTime(lastCts)
|
||||||
|
busyDelta := busy - lastBusy
|
||||||
|
totalDelta := total - lastTotal
|
||||||
|
|
||||||
|
if totalDelta < 0 {
|
||||||
|
return fmt.Errorf("Error: current total CPU time is less than previous total CPU time")
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalDelta == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
add(acc, "percentageUser", 100*(cts.User-lastCts.User)/totalDelta, tags)
|
||||||
|
add(acc, "percentageSystem", 100*(cts.System-lastCts.System)/totalDelta, tags)
|
||||||
|
add(acc, "percentageIdle", 100*(cts.Idle-lastCts.Idle)/totalDelta, tags)
|
||||||
|
add(acc, "percentageNice", 100*(cts.Nice-lastCts.Nice)/totalDelta, tags)
|
||||||
|
add(acc, "percentageIowait", 100*(cts.Iowait-lastCts.Iowait)/totalDelta, tags)
|
||||||
|
add(acc, "percentageIrq", 100*(cts.Irq-lastCts.Irq)/totalDelta, tags)
|
||||||
|
add(acc, "percentageSoftirq", 100*(cts.Softirq-lastCts.Softirq)/totalDelta, tags)
|
||||||
|
add(acc, "percentageSteal", 100*(cts.Steal-lastCts.Steal)/totalDelta, tags)
|
||||||
|
add(acc, "percentageGuest", 100*(cts.Guest-lastCts.Guest)/totalDelta, tags)
|
||||||
|
add(acc, "percentageGuestNice", 100*(cts.GuestNice-lastCts.GuestNice)/totalDelta, tags)
|
||||||
|
add(acc, "percentageStolen", 100*(cts.Stolen-lastCts.Stolen)/totalDelta, tags)
|
||||||
|
|
||||||
|
add(acc, "percentageBusy", 100*busyDelta/totalDelta, tags)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.lastStats = times
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func busyAndTotalCpuTime(t cpu.CPUTimesStat) (float64, float64) {
|
||||||
|
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq + t.Softirq + t.Steal +
|
||||||
|
t.Guest + t.GuestNice + t.Stolen
|
||||||
|
|
||||||
|
return busy, busy + t.Idle
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
plugins.Add("cpu", func() plugins.Plugin {
|
plugins.Add("cpu", func() plugins.Plugin {
|
||||||
return &CPUStats{ps: &systemPS{}}
|
return &CPUStats{ps: &systemPS{}}
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (m *MockPS) LoadAvg() (*load.LoadAvgStat, error) {
|
||||||
|
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
func (m *MockPS) CPUTimes() ([]cpu.CPUTimesStat, error) {
|
func (m *MockPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error) {
|
||||||
ret := m.Called()
|
ret := m.Called()
|
||||||
|
|
||||||
r0 := ret.Get(0).([]cpu.CPUTimesStat)
|
r0 := ret.Get(0).([]cpu.CPUTimesStat)
|
||||||
|
|
|
@ -25,7 +25,7 @@ type DockerContainerStat struct {
|
||||||
|
|
||||||
type PS interface {
|
type PS interface {
|
||||||
LoadAvg() (*load.LoadAvgStat, error)
|
LoadAvg() (*load.LoadAvgStat, error)
|
||||||
CPUTimes() ([]cpu.CPUTimesStat, error)
|
CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error)
|
||||||
DiskUsage() ([]*disk.DiskUsageStat, error)
|
DiskUsage() ([]*disk.DiskUsageStat, error)
|
||||||
NetIO() ([]net.NetIOCountersStat, error)
|
NetIO() ([]net.NetIOCountersStat, error)
|
||||||
DiskIO() (map[string]disk.DiskIOCountersStat, error)
|
DiskIO() (map[string]disk.DiskIOCountersStat, error)
|
||||||
|
@ -49,8 +49,23 @@ func (s *systemPS) LoadAvg() (*load.LoadAvgStat, error) {
|
||||||
return load.LoadAvg()
|
return load.LoadAvg()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemPS) CPUTimes() ([]cpu.CPUTimesStat, error) {
|
func (s *systemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error) {
|
||||||
return cpu.CPUTimes(true)
|
var cpuTimes []cpu.CPUTimesStat
|
||||||
|
if perCPU {
|
||||||
|
if perCPUTimes, err := cpu.CPUTimes(true); err == nil {
|
||||||
|
cpuTimes = append(cpuTimes, perCPUTimes...)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if totalCPU {
|
||||||
|
if totalCPUTimes, err := cpu.CPUTimes(false); err == nil {
|
||||||
|
cpuTimes = append(cpuTimes, totalCPUTimes...)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cpuTimes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemPS) DiskUsage() ([]*disk.DiskUsageStat, error) {
|
func (s *systemPS) DiskUsage() ([]*disk.DiskUsageStat, error) {
|
||||||
|
|
|
@ -85,18 +85,11 @@ func perCPUTimes() ([]CPUTimesStat, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c := CPUTimesStat{
|
c := CPUTimesStat{
|
||||||
CPU: fmt.Sprintf("cpu%d", i),
|
CPU: fmt.Sprintf("cpu%d", i),
|
||||||
User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
|
User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
|
||||||
System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
|
System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
|
||||||
Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
|
Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
|
||||||
Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
|
Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
|
||||||
Iowait: -1,
|
|
||||||
Irq: -1,
|
|
||||||
Softirq: -1,
|
|
||||||
Steal: -1,
|
|
||||||
Guest: -1,
|
|
||||||
GuestNice: -1,
|
|
||||||
Stolen: -1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, c)
|
ret = append(ret, c)
|
||||||
|
@ -119,18 +112,11 @@ func allCPUTimes() ([]CPUTimesStat, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c := CPUTimesStat{
|
c := CPUTimesStat{
|
||||||
CPU: "cpu-total",
|
CPU: "cpu-total",
|
||||||
User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
|
User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
|
||||||
System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
|
System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
|
||||||
Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
|
Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
|
||||||
Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
|
Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
|
||||||
Iowait: -1,
|
|
||||||
Irq: -1,
|
|
||||||
Softirq: -1,
|
|
||||||
Steal: -1,
|
|
||||||
Guest: -1,
|
|
||||||
GuestNice: -1,
|
|
||||||
Stolen: -1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []CPUTimesStat{c}, nil
|
return []CPUTimesStat{c}, nil
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/influxdb/telegraf/plugins/system/ps/cpu"
|
"github.com/influxdb/telegraf/plugins/system/ps/cpu"
|
||||||
|
@ -44,6 +46,21 @@ func TestSystemStats_GenerateStats(t *testing.T) {
|
||||||
Stolen: 0.051,
|
Stolen: 0.051,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cts2 := cpu.CPUTimesStat{
|
||||||
|
CPU: "cpu0",
|
||||||
|
User: 11.4, // increased by 8.3
|
||||||
|
System: 10.9, // increased by 2.7
|
||||||
|
Idle: 158.8699, // increased by 78.7699 (for total increase of 100)
|
||||||
|
Nice: 2.5, // increased by 1.2
|
||||||
|
Iowait: 0.7, // increased by 0.5
|
||||||
|
Irq: 1.2, // increased by 1.1
|
||||||
|
Softirq: 0.31, // increased by 0.2
|
||||||
|
Steal: 0.0002, // increased by 0.0001
|
||||||
|
Guest: 12.9, // increased by 4.8
|
||||||
|
GuestNice: 2.524, // increased by 2.2
|
||||||
|
Stolen: 0.281, // increased by 0.23
|
||||||
|
}
|
||||||
|
|
||||||
mps.On("CPUTimes").Return([]cpu.CPUTimesStat{cts}, nil)
|
mps.On("CPUTimes").Return([]cpu.CPUTimesStat{cts}, nil)
|
||||||
|
|
||||||
du := &disk.DiskUsageStat{
|
du := &disk.DiskUsageStat{
|
||||||
|
@ -171,26 +188,72 @@ func TestSystemStats_GenerateStats(t *testing.T) {
|
||||||
assert.True(t, acc.CheckValue("load5", 1.5))
|
assert.True(t, acc.CheckValue("load5", 1.5))
|
||||||
assert.True(t, acc.CheckValue("load15", 0.8))
|
assert.True(t, acc.CheckValue("load15", 0.8))
|
||||||
|
|
||||||
cs := &CPUStats{ps: &mps}
|
cs := NewCPUStats(&mps)
|
||||||
|
|
||||||
cputags := map[string]string{
|
cputags := map[string]string{
|
||||||
"cpu": "cpu0",
|
"cpu": "cpu0",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preCPUPoints := len(acc.Points)
|
||||||
|
err = cs.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
numCPUPoints := len(acc.Points) - preCPUPoints
|
||||||
|
|
||||||
|
expectedCPUPoints := 12
|
||||||
|
assert.Equal(t, numCPUPoints, expectedCPUPoints)
|
||||||
|
|
||||||
|
// Computed values are checked with delta > 0 becasue of floating point arithmatic
|
||||||
|
// imprecision
|
||||||
|
assertContainsTaggedFloat(t, acc, "user", 3.1, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "system", 8.2, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "idle", 80.1, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "nice", 1.3, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "iowait", 0.2, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "irq", 0.1, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "softirq", 0.11, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "steal", 0.0001, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "guest", 8.1, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "guestNice", 0.324, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "stolen", 0.051, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "busy", 21.4851, 0.0005, cputags)
|
||||||
|
|
||||||
|
mps2 := MockPS{}
|
||||||
|
mps2.On("CPUTimes").Return([]cpu.CPUTimesStat{cts2}, nil)
|
||||||
|
cs.ps = &mps2
|
||||||
|
|
||||||
|
// Should have added cpu percentages too
|
||||||
err = cs.Gather(&acc)
|
err = cs.Gather(&acc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, acc.CheckTaggedValue("user", 3.1, cputags))
|
numCPUPoints = len(acc.Points) - (preCPUPoints + numCPUPoints)
|
||||||
assert.True(t, acc.CheckTaggedValue("system", 8.2, cputags))
|
expectedCPUPoints = 24
|
||||||
assert.True(t, acc.CheckTaggedValue("idle", 80.1, cputags))
|
assert.Equal(t, numCPUPoints, expectedCPUPoints)
|
||||||
assert.True(t, acc.CheckTaggedValue("nice", 1.3, cputags))
|
|
||||||
assert.True(t, acc.CheckTaggedValue("iowait", 0.2, cputags))
|
assertContainsTaggedFloat(t, acc, "user", 11.4, 0, cputags)
|
||||||
assert.True(t, acc.CheckTaggedValue("irq", 0.1, cputags))
|
assertContainsTaggedFloat(t, acc, "system", 10.9, 0, cputags)
|
||||||
assert.True(t, acc.CheckTaggedValue("softirq", 0.11, cputags))
|
assertContainsTaggedFloat(t, acc, "idle", 158.8699, 0, cputags)
|
||||||
assert.True(t, acc.CheckTaggedValue("steal", 0.0001, cputags))
|
assertContainsTaggedFloat(t, acc, "nice", 2.5, 0, cputags)
|
||||||
assert.True(t, acc.CheckTaggedValue("guest", 8.1, cputags))
|
assertContainsTaggedFloat(t, acc, "iowait", 0.7, 0, cputags)
|
||||||
assert.True(t, acc.CheckTaggedValue("guestNice", 0.324, cputags))
|
assertContainsTaggedFloat(t, acc, "irq", 1.2, 0, cputags)
|
||||||
assert.True(t, acc.CheckTaggedValue("stolen", 0.051, cputags))
|
assertContainsTaggedFloat(t, acc, "softirq", 0.31, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "steal", 0.0002, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "guest", 12.9, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "guestNice", 2.524, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "stolen", 0.281, 0, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "busy", 42.7152, 0.0005, cputags)
|
||||||
|
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageUser", 8.3, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageSystem", 2.7, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageIdle", 78.7699, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageNice", 1.2, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageIowait", 0.5, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageIrq", 1.1, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageSoftirq", 0.2, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageSteal", 0.0001, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageGuest", 4.8, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageGuestNice", 2.2, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageStolen", 0.23, 0.0005, cputags)
|
||||||
|
assertContainsTaggedFloat(t, acc, "percentageBusy", 21.2301, 0.0005, cputags)
|
||||||
|
|
||||||
err = (&DiskStats{&mps}).Gather(&acc)
|
err = (&DiskStats{&mps}).Gather(&acc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -319,3 +382,44 @@ func TestSystemStats_GenerateStats(t *testing.T) {
|
||||||
assert.True(t, acc.CheckTaggedValue("total_active_file", uint64(26), dockertags))
|
assert.True(t, acc.CheckTaggedValue("total_active_file", uint64(26), dockertags))
|
||||||
assert.True(t, acc.CheckTaggedValue("total_unevictable", uint64(27), dockertags))
|
assert.True(t, acc.CheckTaggedValue("total_unevictable", uint64(27), dockertags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Asserts that a given accumulator contains a measurment of type float64 with
|
||||||
|
// specific tags within a certain distance of a given expected value. Asserts a failure
|
||||||
|
// if the measurement is of the wrong type, or if no matching measurements are found
|
||||||
|
//
|
||||||
|
// Paramaters:
|
||||||
|
// t *testing.T : Testing object to use
|
||||||
|
// acc testutil.Accumulator: Accumulator to examine
|
||||||
|
// measurement string : Name of the measurement to examine
|
||||||
|
// expectedValue float64 : Value to search for within the measurement
|
||||||
|
// delta float64 : Maximum acceptable distance of an accumulated value
|
||||||
|
// from the expectedValue parameter. Useful when
|
||||||
|
// floating-point arithmatic imprecision makes looking
|
||||||
|
// for an exact match impractical
|
||||||
|
// tags map[string]string : Tag set the found measurement must have. Set to nil to
|
||||||
|
// ignore the tag set.
|
||||||
|
func assertContainsTaggedFloat(
|
||||||
|
t *testing.T,
|
||||||
|
acc testutil.Accumulator,
|
||||||
|
measurement string,
|
||||||
|
expectedValue float64,
|
||||||
|
delta float64,
|
||||||
|
tags map[string]string,
|
||||||
|
) {
|
||||||
|
for _, pt := range acc.Points {
|
||||||
|
if pt.Measurement == measurement {
|
||||||
|
if (tags == nil) || reflect.DeepEqual(pt.Tags, tags) {
|
||||||
|
if value, ok := pt.Values["value"].(float64); ok {
|
||||||
|
if (value >= expectedValue-delta) && (value <= expectedValue+delta) {
|
||||||
|
// Found the point, return without failing
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert.Fail(t, fmt.Sprintf("Measurement \"%s\" does not have type float64", measurement))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Fail(t, fmt.Sprintf("Could not find measurement \"%s\" with requested tags within %f of %f", measurement, delta, expectedValue))
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ password = "root"
|
||||||
database = "telegraf"
|
database = "telegraf"
|
||||||
|
|
||||||
[tags]
|
[tags]
|
||||||
dc = "us-phx-1" }
|
dc = "us-phx-1"
|
||||||
|
|
||||||
[redis]
|
[redis]
|
||||||
address = ":6379"
|
address = ":6379"
|
||||||
|
|
|
@ -57,7 +57,8 @@ database = "telegraf" # required.
|
||||||
|
|
||||||
# Read metrics about cpu usage
|
# Read metrics about cpu usage
|
||||||
[cpu]
|
[cpu]
|
||||||
# no configuration
|
totalcpu = true
|
||||||
|
percpu = false
|
||||||
|
|
||||||
# Read metrics about disk usage by mount point
|
# Read metrics about disk usage by mount point
|
||||||
[disk]
|
[disk]
|
||||||
|
|
Loading…
Reference in New Issue