Compare commits

..

27 Commits

Author SHA1 Message Date
Cameron Sparr
8b54c73ae4 0.3.0 Removing internal parallelism: twemproxy and rabbitmq 2015-12-19 20:26:18 -07:00
Cameron Sparr
c9ef073fba 0.3.0 Removing internal parallelism: procstat 2015-12-19 16:06:21 -07:00
Cameron Sparr
15f66d7d1b 0.3.0 Removing internal parallelism: postgresql 2015-12-19 15:58:57 -07:00
Cameron Sparr
b0f79f43ec 0.3.0 Removing internal parallelism: httpjson and exec 2015-12-19 15:37:16 -07:00
Cameron Sparr
c584129758 0.3.0 outputs: riemann 2015-12-19 14:55:44 -07:00
Cameron Sparr
d1930c90b5 CHANGELOG update 2015-12-19 14:46:33 -07:00
Cameron Sparr
1e76e36df2 0.3.0 outputs: opentsdb 2015-12-19 14:30:37 -07:00
Cameron Sparr
a73b5257dc 0.3.0 output: librato 2015-12-19 14:19:43 -07:00
Cameron Sparr
c16be04ca7 0.3.0 output: datadog and amon 2015-12-19 14:08:31 -07:00
Cameron Sparr
5513275f2c 0.3.0: mongodb and jolokia 2015-12-19 13:31:22 -07:00
Cameron Sparr
3a7b1688a3 0.3.0: postgresql and phpfpm 2015-12-18 17:09:01 -07:00
Cameron Sparr
35d5c7bae3 0.3.0 HAProxy rebase 2015-12-18 16:39:45 -07:00
Cameron Sparr
60b6693ae3 0.3.0: rethinkdb 2015-12-18 16:39:45 -07:00
Cameron Sparr
c1e1f2ace4 0.3.0: zookeeper and zfs 2015-12-18 16:39:45 -07:00
Cameron Sparr
6698d195d8 backwards compatability for io->diskio change 2015-12-18 16:39:45 -07:00
Cameron Sparr
23b21ca86a 0.3.0: trig and twemproxy 2015-12-18 16:39:45 -07:00
Cameron Sparr
56e14e4731 0.3.0 redis & rabbitmq 2015-12-18 16:39:45 -07:00
Cameron Sparr
7deb339b76 0.3.0: prometheus & puppetagent 2015-12-18 16:39:45 -07:00
Cameron Sparr
0e55c371b7 0.3.0: procstat 2015-12-18 16:39:45 -07:00
Cameron Sparr
f284c8c154 0.3.0: ping, mysql, nginx 2015-12-18 16:39:45 -07:00
Cameron Sparr
e3b314cacb 0.3.0: mailchimp & memcached 2015-12-18 16:39:45 -07:00
Cameron Sparr
9fce094b36 0.3.0: leofs & lustre2 2015-12-18 16:39:45 -07:00
Cameron Sparr
319c363c8e 0.3.0 httpjson 2015-12-18 16:39:45 -07:00
Cameron Sparr
40d84accee 0.3.0: HAProxy 2015-12-18 16:39:45 -07:00
Cameron Sparr
3fc43df84e Breakout JSON flattening into internal package, exec & elasticsearch aggregation 2015-12-18 16:39:45 -07:00
Cameron Sparr
59f804d77a Updating aerospike & apache plugins for 0.3.0 2015-12-18 16:39:45 -07:00
Cameron Sparr
96d5f0d0de Updating system plugins for 0.3.0 2015-12-18 16:39:45 -07:00
191 changed files with 4221 additions and 4270 deletions

4
.gitignore vendored
View File

@@ -1,6 +1,4 @@
tivan tivan
.vagrant .vagrant
/telegraf telegraf
.idea .idea
*~
*#

View File

@@ -1,38 +1,22 @@
## v0.10.0 [unreleased] ## v0.3.0 [unreleased]
### Release Notes ### Release Notes
- Linux packages have been taken out of `opt`, the binary is now in `/usr/bin`
and configuration files are in `/etc/telegraf`
- **breaking change** `plugins` have been renamed to `inputs`. This was done because
`plugins` is too generic, as there are now also "output plugins", and will likely
be "aggregator plugins" and "filter plugins" in the future. Additionally,
`inputs/` and `outputs/` directories have been placed in the root-level `plugins/`
directory.
- **breaking change** the `io` plugin has been renamed `diskio` - **breaking change** the `io` plugin has been renamed `diskio`
- **breaking change** plugin measurements aggregated into a single measurement. - **breaking change** Plugin measurements aggregated into a single measurement.
- **breaking change** `jolokia` plugin: must use global tag/drop/pass parameters - **breaking change** `jolokia` plugin: must use global tag/drop/pass parameters
for configuration. for configuration.
- **breaking change** `twemproxy` plugin: `prefix` option removed. - `twemproxy` plugin: `prefix` option removed.
- **breaking change** `procstat` cpu measurements are now prepended with `cpu_time_` - `procstat` cpu measurements are now prepended with `cpu_time_` instead of
instead of only `cpu_` only `cpu_`
- **breaking change** some command-line flags have been renamed to separate words.
`-configdirectory` -> `-config-directory`, `-filter` -> `-input-filter`,
`-outputfilter` -> `-output-filter`
- The prometheus plugin schema has not been changed (measurements have not been - The prometheus plugin schema has not been changed (measurements have not been
aggregated). aggregated).
### Packaging change note:
RHEL/CentOS users upgrading from 0.2.x to 0.10.0 will probably have their
configurations overwritten by the upgrade. There is a backup stored at
/etc/telegraf/telegraf.conf.$(date +%s).backup.
### Features ### Features
- Plugin measurements aggregated into a single measurement. - Plugin measurements aggregated into a single measurement.
- Added ability to specify per-plugin tags - Added ability to specify per-plugin tags
- Added ability to specify per-plugin measurement suffix and prefix. - Added ability to specify per-plugin measurement suffix and prefix.
(`name_prefix` and `name_suffix`) (`name_prefix` and `name_suffix`)
- Added ability to override base plugin measurement name. (`name_override`) - Added ability to override base plugin name. (`name_override`)
### Bugfixes ### Bugfixes
@@ -76,11 +60,11 @@ functional.
same type can be specified, like this: same type can be specified, like this:
``` ```
[[inputs.cpu]] [[plugins.cpu]]
percpu = false percpu = false
totalcpu = true totalcpu = true
[[inputs.cpu]] [[plugins.cpu]]
percpu = true percpu = true
totalcpu = false totalcpu = false
drop = ["cpu_time"] drop = ["cpu_time"]
@@ -107,7 +91,7 @@ same type can be specified, like this:
lists of servers/URLs. 0.2.2 is being released solely to fix that bug lists of servers/URLs. 0.2.2 is being released solely to fix that bug
### Bugfixes ### Bugfixes
- [#377](https://github.com/influxdb/telegraf/pull/377): Fix for duplicate slices in inputs. - [#377](https://github.com/influxdb/telegraf/pull/377): Fix for duplicate slices in plugins.
## v0.2.1 [2015-11-16] ## v0.2.1 [2015-11-16]
@@ -168,7 +152,7 @@ be controlled via the `round_interval` and `flush_jitter` config options.
- [#241](https://github.com/influxdb/telegraf/pull/241): MQTT Output. Thanks @shirou! - [#241](https://github.com/influxdb/telegraf/pull/241): MQTT Output. Thanks @shirou!
- Memory plugin: cached and buffered measurements re-added - Memory plugin: cached and buffered measurements re-added
- Logging: additional logging for each collection interval, track the number - Logging: additional logging for each collection interval, track the number
of metrics collected and from how many inputs. of metrics collected and from how many plugins.
- [#240](https://github.com/influxdb/telegraf/pull/240): procstat plugin, thanks @ranjib! - [#240](https://github.com/influxdb/telegraf/pull/240): procstat plugin, thanks @ranjib!
- [#244](https://github.com/influxdb/telegraf/pull/244): netstat plugin, thanks @shirou! - [#244](https://github.com/influxdb/telegraf/pull/244): netstat plugin, thanks @shirou!
- [#262](https://github.com/influxdb/telegraf/pull/262): zookeeper plugin, thanks @jrxFive! - [#262](https://github.com/influxdb/telegraf/pull/262): zookeeper plugin, thanks @jrxFive!
@@ -201,7 +185,7 @@ will still be backwards compatible if only `url` is specified.
- The -test flag will now output two metric collections - The -test flag will now output two metric collections
- Support for filtering telegraf outputs on the CLI -- Telegraf will now - Support for filtering telegraf outputs on the CLI -- Telegraf will now
allow filtering of output sinks on the command-line using the `-outputfilter` allow filtering of output sinks on the command-line using the `-outputfilter`
flag, much like how the `-filter` flag works for inputs. flag, much like how the `-filter` flag works for plugins.
- Support for filtering on config-file creation -- Telegraf now supports - Support for filtering on config-file creation -- Telegraf now supports
filtering to -sample-config command. You can now run filtering to -sample-config command. You can now run
`telegraf -sample-config -filter cpu -outputfilter influxdb` to get a config `telegraf -sample-config -filter cpu -outputfilter influxdb` to get a config

View File

@@ -1,55 +1,33 @@
# Telegraf Configuration # Telegraf Configuration
## Generating a Configuration File ## Plugin Configuration
A default Telegraf config file can be generated using the `-sample-config` flag, There are some configuration options that are configurable per plugin:
like this: `telegraf -sample-config`
To generate a file with specific inputs and outputs, you can use the
`-input-filter` and `-output-filter` flags, like this:
`telegraf -sample-config -input-filter cpu:mem:net:swap -output-filter influxdb:kafka`
## Telegraf Agent Configuration
Telegraf has a few options you can configure under the `agent` section of the
config.
* **hostname**: The hostname is passed as a tag. By default this will be
the value returned by `hostname` on the machine running Telegraf.
You can override that value here.
* **interval**: How often to gather metrics. Uses a simple number +
unit parser, e.g. "10s" for 10 seconds or "5m" for 5 minutes.
* **debug**: Set to true to gather and send metrics to STDOUT as well as
InfluxDB.
## Input Configuration
There are some configuration options that are configurable per input:
* **name_override**: Override the base name of the measurement. * **name_override**: Override the base name of the measurement.
(Default is the name of the input). (Default is the name of the plugin).
* **name_prefix**: Specifies a prefix to attach to the measurement name. * **name_prefix**: Specifies a prefix to attach to the measurement name.
* **name_suffix**: Specifies a suffix to attach to the measurement name. * **name_suffix**: Specifies a suffix to attach to the measurement name.
* **tags**: A map of tags to apply to a specific input's measurements. * **tags**: A map of tags to apply to a specific plugin's measurements.
* **interval**: How often to gather this metric. Normal plugins use a single
global interval, but if one particular input should be run less or more often,
you can configure that here.
### Input Filters ### Plugin Filters
There are also filters that can be configured per input: There are also filters that can be configured per plugin:
* **pass**: An array of strings that is used to filter metrics generated by the * **pass**: An array of strings that is used to filter metrics generated by the
current input. Each string in the array is tested as a glob match against field names current plugin. Each string in the array is tested as a glob match against field names
and if it matches, the field is emitted. and if it matches, the field is emitted.
* **drop**: The inverse of pass, if a field name matches, it is not emitted. * **drop**: The inverse of pass, if a field name matches, it is not emitted.
* **tagpass**: tag names and arrays of strings that are used to filter * **tagpass**: tag names and arrays of strings that are used to filter
measurements by the current input. Each string in the array is tested as a glob measurements by the current plugin. Each string in the array is tested as a glob
match against the tag name, and if it matches the measurement is emitted. match against the tag name, and if it matches the measurement is emitted.
* **tagdrop**: The inverse of tagpass. If a tag matches, the measurement is not * **tagdrop**: The inverse of tagpass. If a tag matches, the measurement is not emitted.
emitted. This is tested on measurements that have passed the tagpass test. This is tested on measurements 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.
### Input Configuration Examples ### Plugin Configuration Examples
This is a full working config that will output CPU data to an InfluxDB instance 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 at 192.168.59.103:8086, tagging measurements with dc="denver-1". It will output
@@ -64,32 +42,35 @@ fields which begin with `time_`.
interval = "10s" interval = "10s"
# OUTPUTS # OUTPUTS
[outputs]
[[outputs.influxdb]] [[outputs.influxdb]]
url = "http://192.168.59.103:8086" # required. url = "http://192.168.59.103:8086" # required.
database = "telegraf" # required. database = "telegraf" # required.
precision = "s" precision = "s"
# INPUTS # PLUGINS
[[inputs.cpu]] [plugins]
[[plugins.cpu]]
percpu = true percpu = true
totalcpu = false totalcpu = false
# filter all fields beginning with 'time_' # filter all fields beginning with 'time_'
drop = ["time_*"] drop = ["time_*"]
``` ```
### Input Config: tagpass and tagdrop ### Plugin Config: tagpass and tagdrop
```toml ```toml
[[inputs.cpu]] [plugins]
[[plugins.cpu]]
percpu = true percpu = true
totalcpu = false totalcpu = false
drop = ["cpu_time"] drop = ["cpu_time"]
# Don't collect CPU data for cpu6 & cpu7 # Don't collect CPU data for cpu6 & cpu7
[inputs.cpu.tagdrop] [plugins.cpu.tagdrop]
cpu = [ "cpu6", "cpu7" ] cpu = [ "cpu6", "cpu7" ]
[[inputs.disk]] [[plugins.disk]]
[inputs.disk.tagpass] [plugins.disk.tagpass]
# tagpass conditions are OR, not AND. # tagpass conditions are OR, not AND.
# If the (filesystem is ext4 or xfs) OR (the path is /opt or /home) # If the (filesystem is ext4 or xfs) OR (the path is /opt or /home)
# then the metric passes # then the metric passes
@@ -98,26 +79,26 @@ fields which begin with `time_`.
path = [ "/opt", "/home*" ] path = [ "/opt", "/home*" ]
``` ```
### Input Config: pass and drop ### Plugin Config: pass and drop
```toml ```toml
# Drop all metrics for guest & steal CPU usage # Drop all metrics for guest & steal CPU usage
[[inputs.cpu]] [[plugins.cpu]]
percpu = false percpu = false
totalcpu = true totalcpu = true
drop = ["usage_guest", "usage_steal"] drop = ["usage_guest", "usage_steal"]
# Only store inode related metrics for disks # Only store inode related metrics for disks
[[inputs.disk]] [[plugins.disk]]
pass = ["inodes*"] pass = ["inodes*"]
``` ```
### Input config: prefix, suffix, and override ### Plugin config: prefix, suffix, and override
This plugin will emit measurements with the name `cpu_total` This plugin will emit measurements with the name `cpu_total`
```toml ```toml
[[inputs.cpu]] [[plugins.cpu]]
name_suffix = "_total" name_suffix = "_total"
percpu = false percpu = false
totalcpu = true totalcpu = true
@@ -126,42 +107,39 @@ This plugin will emit measurements with the name `cpu_total`
This will emit measurements with the name `foobar` This will emit measurements with the name `foobar`
```toml ```toml
[[inputs.cpu]] [[plugins.cpu]]
name_override = "foobar" name_override = "foobar"
percpu = false percpu = false
totalcpu = true totalcpu = true
``` ```
### Input config: tags ### Plugin config: tags
This plugin will emit measurements with two additional tags: `tag1=foo` and This plugin will emit measurements with two additional tags: `tag1=foo` and
`tag2=bar` `tag2=bar`
```toml ```toml
[[inputs.cpu]] [[plugins.cpu]]
percpu = false percpu = false
totalcpu = true totalcpu = true
[inputs.cpu.tags] [plugins.cpu.tags]
tag1 = "foo" tag1 = "foo"
tag2 = "bar" tag2 = "bar"
``` ```
### Multiple inputs of the same type ### Multiple plugins of the same type
Additional inputs (or outputs) of the same type can be specified, Additional plugins (or outputs) of the same type can be specified,
just define more instances in the config file. It is highly recommended that just define more instances in the config file:
you utilize `name_override`, `name_prefix`, or `name_suffix` config options
to avoid measurement collisions:
```toml ```toml
[[inputs.cpu]] [[plugins.cpu]]
percpu = false percpu = false
totalcpu = true totalcpu = true
[[inputs.cpu]] [[plugins.cpu]]
percpu = true percpu = true
totalcpu = false totalcpu = false
name_override = "percpu_usage"
drop = ["cpu_time*"] drop = ["cpu_time*"]
``` ```
@@ -171,8 +149,8 @@ Telegraf also supports specifying multiple output sinks to send data to,
configuring each output sink is different, but examples can be configuring each output sink is different, but examples can be
found by running `telegraf -sample-config`. found by running `telegraf -sample-config`.
Outputs also support the same configurable options as inputs Outputs also support the same configurable options as plugins
(pass, drop, tagpass, tagdrop) (pass, drop, tagpass, tagdrop), added in 0.2.4
```toml ```toml
[[outputs.influxdb]] [[outputs.influxdb]]

View File

@@ -3,31 +3,33 @@
Before we can merge a pull request, you will need to sign the CLA, Before we can merge a pull request, you will need to sign the CLA,
which can be found [on our website](http://influxdb.com/community/cla.html) which can be found [on our website](http://influxdb.com/community/cla.html)
## Input Plugins ## Plugins
This section is for developers who want to create new collection inputs. This section is for developers who want to create new collection plugins.
Telegraf is entirely plugin driven. This interface allows for operators to Telegraf is entirely plugin driven. This interface allows for operators to
pick and chose what is gathered as well as makes it easy for developers pick and chose what is gathered as well as makes it easy for developers
to create new ways of generating metrics. to create new ways of generating metrics.
Plugin authorship is kept as simple as possible to promote people to develop Plugin authorship is kept as simple as possible to promote people to develop
and submit new inputs. and submit new plugins.
### Input Plugin Guidelines ### Plugin Guidelines
* A plugin must conform to the `inputs.Input` interface. * A plugin must conform to the `plugins.Plugin` interface.
* Input Plugins should call `inputs.Add` in their `init` function to register themselves. * Each generated metric automatically has the name of the plugin that generated
it prepended. This is to keep plugins honest.
* Plugins should call `plugins.Add` in their `init` function to register themselves.
See below for a quick example. See below for a quick example.
* Input Plugins must be added to the * To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdb/telegraf/plugins/inputs/all/all.go` file. `github.com/influxdb/telegraf/plugins/all/all.go` file.
* The `SampleConfig` function should return valid toml that describes how the * The `SampleConfig` function should return valid toml that describes how the
plugin can be configured. This is include in `telegraf -sample-config`. plugin can be configured. This is include in `telegraf -sample-config`.
* The `Description` function should say in one line what this plugin does. * The `Description` function should say in one line what this plugin does.
### Input interface ### Plugin interface
```go ```go
type Input interface { type Plugin interface {
SampleConfig() string SampleConfig() string
Description() string Description() string
Gather(Accumulator) error Gather(Accumulator) error
@@ -50,32 +52,52 @@ type Accumulator interface {
The way that a plugin emits metrics is by interacting with the Accumulator. The way that a plugin emits metrics is by interacting with the Accumulator.
The `Add` function takes 3 arguments: The `Add` function takes 3 arguments:
* **measurement**: A string description of the metric. For instance `bytes_read` or ` * **measurement**: A string description of the metric. For instance `bytes_read` or `faults`.
faults`.
* **value**: A value for the metric. This accepts 5 different types of value: * **value**: A value for the metric. This accepts 5 different types of value:
* **int**: The most common type. All int types are accepted but favor using `int64` * **int**: The most common type. All int types are accepted but favor using `int64`
Useful for counters, etc. Useful for counters, etc.
* **float**: Favor `float64`, useful for gauges, percentages, etc. * **float**: Favor `float64`, useful for gauges, percentages, etc.
* **bool**: `true` or `false`, useful to indicate the presence of a state. `light_on`, * **bool**: `true` or `false`, useful to indicate the presence of a state. `light_on`, etc.
etc. * **string**: Typically used to indicate a message, or some kind of freeform information.
* **string**: Typically used to indicate a message, or some kind of freeform * **time.Time**: Useful for indicating when a state last occurred, for instance `light_on_since`.
information.
* **time.Time**: Useful for indicating when a state last occurred, for instance `
light_on_since`.
* **tags**: This is a map of strings to strings to describe the where or who * **tags**: This is a map of strings to strings to describe the where or who
about the metric. For instance, the `net` plugin adds a tag named `"interface"` about the metric. For instance, the `net` plugin adds a tag named `"interface"`
set to the name of the network interface, like `"eth0"`. set to the name of the network interface, like `"eth0"`.
The `AddFieldsWithTime` allows multiple values for a point to be passed. The values
used are the same type profile as **value** above. The **timestamp** argument
allows a point to be registered as having occurred at an arbitrary time.
Let's say you've written a plugin that emits metrics about processes on the current host. Let's say you've written a plugin that emits metrics about processes on the current host.
### Input Plugin Example ```go
type Process struct {
CPUTime float64
MemoryBytes int64
PID int
}
func Gather(acc plugins.Accumulator) error {
for _, process := range system.Processes() {
tags := map[string]string {
"pid": fmt.Sprintf("%d", process.Pid),
}
acc.Add("cpu", process.CPUTime, tags, time.Now())
acc.Add("memory", process.MemoryBytes, tags, time.Now())
}
}
```
### Plugin Example
```go ```go
package simple package simple
// simple.go // simple.go
import "github.com/influxdb/telegraf/plugins/inputs" import "github.com/influxdb/telegraf/plugins"
type Simple struct { type Simple struct {
Ok bool Ok bool
@@ -89,7 +111,7 @@ func (s *Simple) SampleConfig() string {
return "ok = true # indicate if everything is fine" return "ok = true # indicate if everything is fine"
} }
func (s *Simple) Gather(acc inputs.Accumulator) error { func (s *Simple) Gather(acc plugins.Accumulator) error {
if s.Ok { if s.Ok {
acc.Add("state", "pretty good", nil) acc.Add("state", "pretty good", nil)
} else { } else {
@@ -100,19 +122,19 @@ func (s *Simple) Gather(acc inputs.Accumulator) error {
} }
func init() { func init() {
inputs.Add("simple", func() inputs.Input { return &Simple{} }) plugins.Add("simple", func() plugins.Plugin { return &Simple{} })
} }
``` ```
## Service Input Plugins ## Service Plugins
This section is for developers who want to create new "service" collection This section is for developers who want to create new "service" collection
inputs. A service plugin differs from a regular plugin in that it operates plugins. A service plugin differs from a regular plugin in that it operates
a background service while Telegraf is running. One example would be the `statsd` a background service while Telegraf is running. One example would be the `statsd`
plugin, which operates a statsd server. plugin, which operates a statsd server.
Service Input Plugins are substantially more complicated than a regular plugin, as they Service Plugins are substantially more complicated than a regular plugin, as they
will require threads and locks to verify data integrity. Service Input Plugins should will require threads and locks to verify data integrity. Service Plugins should
be avoided unless there is no way to create their behavior with a regular plugin. be avoided unless there is no way to create their behavior with a regular plugin.
Their interface is quite similar to a regular plugin, with the addition of `Start()` Their interface is quite similar to a regular plugin, with the addition of `Start()`
@@ -121,7 +143,7 @@ and `Stop()` methods.
### Service Plugin Guidelines ### Service Plugin Guidelines
* Same as the `Plugin` guidelines, except that they must conform to the * Same as the `Plugin` guidelines, except that they must conform to the
`inputs.ServiceInput` interface. `plugins.ServicePlugin` interface.
### Service Plugin interface ### Service Plugin interface
@@ -135,19 +157,19 @@ type ServicePlugin interface {
} }
``` ```
## Output Plugins ## Outputs
This section is for developers who want to create a new output sink. Outputs This section is for developers who want to create a new output sink. Outputs
are created in a similar manner as collection plugins, and their interface has are created in a similar manner as collection plugins, and their interface has
similar constructs. similar constructs.
### Output Plugin Guidelines ### Output Guidelines
* An output must conform to the `outputs.Output` interface. * An output must conform to the `outputs.Output` interface.
* Outputs should call `outputs.Add` in their `init` function to register themselves. * Outputs should call `outputs.Add` in their `init` function to register themselves.
See below for a quick example. See below for a quick example.
* To be available within Telegraf itself, plugins must add themselves to the * To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdb/telegraf/plugins/outputs/all/all.go` file. `github.com/influxdb/telegraf/outputs/all/all.go` file.
* The `SampleConfig` function should return valid toml that describes how the * The `SampleConfig` function should return valid toml that describes how the
output can be configured. This is include in `telegraf -sample-config`. output can be configured. This is include in `telegraf -sample-config`.
* The `Description` function should say in one line what this output does. * The `Description` function should say in one line what this output does.
@@ -171,7 +193,7 @@ package simpleoutput
// simpleoutput.go // simpleoutput.go
import "github.com/influxdb/telegraf/plugins/outputs" import "github.com/influxdb/telegraf/outputs"
type Simple struct { type Simple struct {
Ok bool Ok bool
@@ -208,7 +230,7 @@ func init() {
``` ```
## Service Output Plugins ## Service Outputs
This section is for developers who want to create new "service" output. A This section is for developers who want to create new "service" output. A
service output differs from a regular output in that it operates a background service service output differs from a regular output in that it operates a background service
@@ -221,7 +243,7 @@ and `Stop()` methods.
### Service Output Guidelines ### Service Output Guidelines
* Same as the `Output` guidelines, except that they must conform to the * Same as the `Output` guidelines, except that they must conform to the
`output.ServiceOutput` interface. `plugins.ServiceOutput` interface.
### Service Output interface ### Service Output interface
@@ -252,7 +274,7 @@ which would take some time to replicate.
To overcome this situation we've decided to use docker containers to provide a To overcome this situation we've decided to use docker containers to provide a
fast and reproducible environment to test those services which require it. fast and reproducible environment to test those services which require it.
For other situations For other situations
(i.e: https://github.com/influxdb/telegraf/blob/master/plugins/redis/redis_test.go) (i.e: https://github.com/influxdb/telegraf/blob/master/plugins/redis/redis_test.go )
a simple mock will suffice. a simple mock will suffice.
To execute Telegraf tests follow these simple steps: To execute Telegraf tests follow these simple steps:

38
Godeps
View File

@@ -1,51 +1,51 @@
git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git dbd8d5c40a582eb9adacde36b47932b3a3ad0034 git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git dbd8d5c40a582eb9adacde36b47932b3a3ad0034
github.com/Shopify/sarama d37c73f2b2bce85f7fa16b6a550d26c5372892ef github.com/Shopify/sarama 159e9990b0796511607dd0d7aaa3eb37d1829d16
github.com/Sirupsen/logrus 446d1c146faa8ed3f4218f056fcd165f6bcfda81 github.com/Sirupsen/logrus 446d1c146faa8ed3f4218f056fcd165f6bcfda81
github.com/amir/raidman 6a8e089bbe32e6b907feae5ba688841974b3c339 github.com/amir/raidman 6a8e089bbe32e6b907feae5ba688841974b3c339
github.com/armon/go-metrics 345426c77237ece5dab0e1605c3e4b35c3f54757 github.com/armon/go-metrics 06b60999766278efd6d2b5d8418a58c3d5b99e87
github.com/aws/aws-sdk-go f09322ae1e6468fe828c862542389bc45baf3c00 github.com/aws/aws-sdk-go 999b1591218c36d5050d1ba7266eba956e65965f
github.com/beorn7/perks b965b613227fddccbfffe13eae360ed3fa822f8d github.com/beorn7/perks b965b613227fddccbfffe13eae360ed3fa822f8d
github.com/boltdb/bolt 34a0fa5307f7562980fb8e7ff4723f7987edf49b github.com/boltdb/bolt b34b35ea8d06bb9ae69d9a349119252e4c1d8ee0
github.com/cenkalti/backoff 4dc77674aceaabba2c7e3da25d4c823edfb73f99 github.com/cenkalti/backoff 4dc77674aceaabba2c7e3da25d4c823edfb73f99
github.com/dancannon/gorethink a124c9663325ed9f7fb669d17c69961b59151e6e github.com/dancannon/gorethink a124c9663325ed9f7fb669d17c69961b59151e6e
github.com/davecgh/go-spew 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d github.com/davecgh/go-spew 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
github.com/eapache/go-resiliency b86b1ec0dd4209a588dc1285cdd471e73525c0b3 github.com/eapache/go-resiliency f341fb4dca45128e4aa86389fa6a675d55fe25e1
github.com/eapache/queue ded5959c0d4e360646dc9e9908cff48666781367 github.com/eapache/queue ded5959c0d4e360646dc9e9908cff48666781367
github.com/fsouza/go-dockerclient 175e1df973274f04e9b459a62cffc49808f1a649 github.com/fsouza/go-dockerclient 7177a9e3543b0891a5d91dbf7051e0f71455c8ef
github.com/go-ini/ini afbd495e5aaea13597b5e14fe514ddeaa4d76fc3 github.com/go-ini/ini 9314fb0ef64171d6a3d0a4fa570dfa33441cba05
github.com/go-sql-driver/mysql 7a8740a6bd8feb6af5786ab9a9f1513970019d8c github.com/go-sql-driver/mysql d512f204a577a4ab037a1816604c48c9c13210be
github.com/gogo/protobuf 7b1331554dbe882cb3613ee8f1824a5583627963 github.com/gogo/protobuf e492fd34b12d0230755c45aa5fb1e1eea6a84aa9
github.com/golang/protobuf 2402d76f3d41f928c7902a765dfc872356dd3aad github.com/golang/protobuf 68415e7123da32b07eab49c96d2c4d6158360e9b
github.com/golang/snappy 723cc1e459b8eea2dea4583200fd60757d40097a github.com/golang/snappy 723cc1e459b8eea2dea4583200fd60757d40097a
github.com/gonuts/go-shellquote e842a11b24c6abfb3dd27af69a17f482e4b483c2 github.com/gonuts/go-shellquote e842a11b24c6abfb3dd27af69a17f482e4b483c2
github.com/hailocab/go-hostpool 50839ee41f32bfca8d03a183031aa634b2dc1c64 github.com/hailocab/go-hostpool 0637eae892be221164aff5fcbccc57171aea6406
github.com/hashicorp/go-msgpack fa3f63826f7c23912c15263591e65d54d080b458 github.com/hashicorp/go-msgpack fa3f63826f7c23912c15263591e65d54d080b458
github.com/hashicorp/raft d136cd15dfb7876fd7c89cad1995bc4f19ceb294 github.com/hashicorp/raft d136cd15dfb7876fd7c89cad1995bc4f19ceb294
github.com/hashicorp/raft-boltdb d1e82c1ec3f15ee991f7cc7ffd5b67ff6f5bbaee github.com/hashicorp/raft-boltdb d1e82c1ec3f15ee991f7cc7ffd5b67ff6f5bbaee
github.com/influxdb/influxdb bd63489ef0faae2465ae5b1f0a28bd7e71e02e38 github.com/influxdb/influxdb 69a7664f2d4b75aec300b7cbfc7e57c971721f04
github.com/jmespath/go-jmespath c01cf91b011868172fdcd9f41838e80c9d716264 github.com/jmespath/go-jmespath c01cf91b011868172fdcd9f41838e80c9d716264
github.com/klauspost/crc32 a3b15ae34567abb20a22992b989cd76f48d09c47 github.com/klauspost/crc32 0aff1ea9c20474c3901672b5b6ead0ac611156de
github.com/lib/pq 11fc39a580a008f1f39bb3d11d984fb34ed778d9 github.com/lib/pq 11fc39a580a008f1f39bb3d11d984fb34ed778d9
github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453 github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453
github.com/mreiferson/go-snappystream 028eae7ab5c4c9e2d1cb4c4ca1e53259bbe7e504 github.com/mreiferson/go-snappystream 028eae7ab5c4c9e2d1cb4c4ca1e53259bbe7e504
github.com/naoina/go-stringutil 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b github.com/naoina/go-stringutil 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b
github.com/naoina/toml 751171607256bb66e64c9f0220c00662420c38e9 github.com/naoina/toml 751171607256bb66e64c9f0220c00662420c38e9
github.com/nsqio/go-nsq 2118015c120962edc5d03325c680daf3163a8b5f github.com/nsqio/go-nsq 2118015c120962edc5d03325c680daf3163a8b5f
github.com/pborman/uuid dee7705ef7b324f27ceb85a121c61f2c2e8ce988 github.com/pborman/uuid cccd189d45f7ac3368a0d127efb7f4d08ae0b655
github.com/pmezard/go-difflib e8554b8641db39598be7f6342874b958f12ae1d4 github.com/pmezard/go-difflib e8554b8641db39598be7f6342874b958f12ae1d4
github.com/prometheus/client_golang 67994f177195311c3ea3d4407ed0175e34a4256f github.com/prometheus/client_golang 67994f177195311c3ea3d4407ed0175e34a4256f
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
github.com/prometheus/common 0a3005bb37bc411040083a55372e77c405f6464c github.com/prometheus/common 56b90312e937d43b930f06a59bf0d6a4ae1944bc
github.com/prometheus/procfs 406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8 github.com/prometheus/procfs 406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8
github.com/samuel/go-zookeeper 218e9c81c0dd8b3b18172b2bbfad92cc7d6db55f github.com/samuel/go-zookeeper 218e9c81c0dd8b3b18172b2bbfad92cc7d6db55f
github.com/shirou/gopsutil ef151b7ff7fe76308f89a389447b7b78dfa02e0f github.com/shirou/gopsutil fc932d9090f13a84fb4b3cb8baa124610cab184c
github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744 github.com/streadway/amqp b4f3ceab0337f013208d31348b578d83c0064744
github.com/stretchr/objx 1a9d0bb9f541897e62256577b352fdbc1fb4fd94 github.com/stretchr/objx 1a9d0bb9f541897e62256577b352fdbc1fb4fd94
github.com/stretchr/testify c92828f29518bc633893affbce12904ba41a7cfa github.com/stretchr/testify e3a8ff8ce36581f87a15341206f205b1da467059
github.com/wvanbergen/kafka 1a8639a45164fcc245d5c7b4bd3ccfbd1a0ffbf3 github.com/wvanbergen/kafka 1a8639a45164fcc245d5c7b4bd3ccfbd1a0ffbf3
github.com/wvanbergen/kazoo-go 0f768712ae6f76454f987c3356177e138df258f8 github.com/wvanbergen/kazoo-go 0f768712ae6f76454f987c3356177e138df258f8
golang.org/x/crypto f23ba3a5ee43012fcb4b92e1a2a405a92554f4f2 golang.org/x/crypto 7b85b097bf7527677d54d3220065e966a0e3b613
golang.org/x/net 520af5de654dc4dd4f0f65aa40e66dbbd9043df1 golang.org/x/net 1796f9b8b7178e3c7587dff118d3bb9d37f9b0b3
gopkg.in/dancannon/gorethink.v1 a124c9663325ed9f7fb669d17c69961b59151e6e gopkg.in/dancannon/gorethink.v1 a124c9663325ed9f7fb669d17c69961b59151e6e
gopkg.in/fatih/pool.v2 cba550ebf9bce999a02e963296d4bc7a486cb715 gopkg.in/fatih/pool.v2 cba550ebf9bce999a02e963296d4bc7a486cb715
gopkg.in/mgo.v2 e30de8ac9ae3b30df7065f766c71f88bba7d4e49 gopkg.in/mgo.v2 e30de8ac9ae3b30df7065f766c71f88bba7d4e49

111
README.md
View File

@@ -1,42 +1,30 @@
# Telegraf [![Circle CI](https://circleci.com/gh/influxdata/telegraf.svg?style=svg)](https://circleci.com/gh/influxdata/telegraf) # Telegraf - A native agent for InfluxDB [![Circle CI](https://circleci.com/gh/influxdb/telegraf.svg?style=svg)](https://circleci.com/gh/influxdb/telegraf)
Telegraf is an agent written in Go for collecting metrics from the system it's Telegraf is an agent written in Go for collecting metrics from the system it's
running on, or from other services, and writing them into InfluxDB or other running on, or from other services, and writing them into InfluxDB.
[outputs](https://github.com/influxdata/telegraf#supported-output-plugins).
Design goals are to have a minimal memory footprint with a plugin system so Design goals are to have a minimal memory footprint with a plugin system so
that developers in the community can easily add support for collecting metrics that developers in the community can easily add support for collecting metrics
from well known services (like Hadoop, Postgres, or Redis) and third party from well known services (like Hadoop, Postgres, or Redis) and third party
APIs (like Mailchimp, AWS CloudWatch, or Google Analytics). APIs (like Mailchimp, AWS CloudWatch, or Google Analytics).
New input and output plugins are designed to be easy to contribute, We'll eagerly accept pull requests for new plugins and will manage the set of
we'll eagerly accept pull plugins that Telegraf supports. See the
requests and will manage the set of plugins that Telegraf supports. [contributing guide](CONTRIBUTING.md) for instructions on
See the [contributing guide](CONTRIBUTING.md) for instructions on writing writing new plugins.
new plugins.
## Installation: ## Installation:
NOTE: Telegraf 0.10.x is **not** backwards-compatible with previous versions of
telegraf, both in the database layout and the configuration file. 0.2.x will
continue to be supported, see below for download links.
TODO: link to blog post about 0.10.x changes.
### Linux deb and rpm packages: ### Linux deb and rpm packages:
Latest: Latest:
* http://get.influxdb.org/telegraf/telegraf_0.10.0_amd64.deb
* http://get.influxdb.org/telegraf/telegraf-0.10.0-1.x86_64.rpm
0.2.x:
* http://get.influxdb.org/telegraf/telegraf_0.2.4_amd64.deb * http://get.influxdb.org/telegraf/telegraf_0.2.4_amd64.deb
* http://get.influxdb.org/telegraf/telegraf-0.2.4-1.x86_64.rpm * http://get.influxdb.org/telegraf/telegraf-0.2.4-1.x86_64.rpm
##### Package instructions: ##### Package instructions:
* Telegraf binary is installed in `/usr/bin/telegraf` * Telegraf binary is installed in `/opt/telegraf/telegraf`
* Telegraf daemon configuration file is in `/etc/telegraf/telegraf.conf` * Telegraf daemon configuration file is in `/etc/opt/telegraf/telegraf.conf`
* On sysv systems, the telegraf daemon can be controlled via * On sysv systems, the telegraf daemon can be controlled via
`service telegraf [action]` `service telegraf [action]`
* On systemd systems (such as Ubuntu 15+), the telegraf daemon can be * On systemd systems (such as Ubuntu 15+), the telegraf daemon can be
@@ -45,11 +33,6 @@ controlled via `systemctl [action] telegraf`
### Linux binaries: ### Linux binaries:
Latest: Latest:
* http://get.influxdb.org/telegraf/telegraf_linux_amd64_0.10.0.tar.gz
* http://get.influxdb.org/telegraf/telegraf_linux_386_0.10.0.tar.gz
* http://get.influxdb.org/telegraf/telegraf_linux_arm_0.10.0.tar.gz
0.2.x:
* http://get.influxdb.org/telegraf/telegraf_linux_amd64_0.2.4.tar.gz * http://get.influxdb.org/telegraf/telegraf_linux_amd64_0.2.4.tar.gz
* http://get.influxdb.org/telegraf/telegraf_linux_386_0.2.4.tar.gz * http://get.influxdb.org/telegraf/telegraf_linux_386_0.2.4.tar.gz
* http://get.influxdb.org/telegraf/telegraf_linux_arm_0.2.4.tar.gz * http://get.influxdb.org/telegraf/telegraf_linux_arm_0.2.4.tar.gz
@@ -82,49 +65,40 @@ if you don't have it already. You also must build with golang version 1.4+.
### How to use it: ### How to use it:
```console * Run `telegraf -sample-config > telegraf.conf` to create an initial configuration.
$ telegraf -help * Or run `telegraf -sample-config -filter cpu:mem -outputfilter influxdb > telegraf.conf`.
Telegraf, The plugin-driven server agent for reporting metrics into InfluxDB to create a config file with only CPU and memory plugins defined, and InfluxDB
output defined.
* Edit the configuration to match your needs.
* Run `telegraf -config telegraf.conf -test` to output one full measurement
sample to STDOUT. NOTE: you may want to run as the telegraf user if you are using
the linux packages `sudo -u telegraf telegraf -config telegraf.conf -test`
* Run `telegraf -config telegraf.conf` to gather and send metrics to configured outputs.
* Run `telegraf -config telegraf.conf -filter system:swap`.
to run telegraf with only the system & swap plugins defined in the config.
Usage: ## Telegraf Options
telegraf <flags> Telegraf has a few options you can configure under the `agent` section of the
config.
The flags are: * **hostname**: The hostname is passed as a tag. By default this will be
the value returned by `hostname` on the machine running Telegraf.
-config <file> configuration file to load You can override that value here.
-test gather metrics once, print them to stdout, and exit * **interval**: How often to gather metrics. Uses a simple number +
-sample-config print out full sample configuration to stdout unit parser, e.g. "10s" for 10 seconds or "5m" for 5 minutes.
-config-directory directory containing additional *.conf files * **debug**: Set to true to gather and send metrics to STDOUT as well as
-input-filter filter the input plugins to enable, separator is : InfluxDB.
-output-filter filter the output plugins to enable, separator is :
-usage print usage for a plugin, ie, 'telegraf -usage mysql'
-version print the version to stdout
Examples:
# generate a telegraf config file:
telegraf -sample-config > telegraf.conf
# generate config with only cpu input & influxdb output plugins defined
telegraf -sample-config -input-filter cpu -output-filter influxdb
# run a single telegraf collection, outputing metrics to stdout
telegraf -config telegraf.conf -test
# run telegraf with all plugins defined in config file
telegraf -config telegraf.conf
# run telegraf, enabling the cpu & memory input, and influxdb output plugins
telegraf -config telegraf.conf -input-filter cpu:mem -output-filter influxdb
```
## Configuration ## Configuration
See the [configuration guide](CONFIGURATION.md) for a rundown of the more advanced See the [configuration guide](CONFIGURATION.md) for a rundown of the more advanced
configuration options. configuration options.
## Supported Input Plugins ## Supported Plugins
**You can view usage instructions for each plugin by running**
`telegraf -usage <pluginname>`.
Telegraf currently has support for collecting metrics from: Telegraf currently has support for collecting metrics from:
@@ -166,7 +140,9 @@ Telegraf currently has support for collecting metrics from:
* diskio * diskio
* swap * swap
Telegraf can also collect metrics via the following service plugins: ## Supported Service Plugins
Telegraf can collect metrics via the following services:
* statsd * statsd
* kafka_consumer * kafka_consumer
@@ -174,19 +150,18 @@ Telegraf can also collect metrics via the following service plugins:
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.
## Supported Output Plugins ## Supported Outputs
* influxdb * influxdb
* amon
* amqp
* datadog
* kafka
* amazon kinesis
* librato
* mqtt
* nsq * nsq
* kafka
* datadog
* opentsdb * opentsdb
* amqp (rabbitmq)
* mqtt
* librato
* prometheus * prometheus
* amon
* riemann * riemann
## Contributing ## Contributing

View File

@@ -29,12 +29,12 @@ type Accumulator interface {
} }
func NewAccumulator( func NewAccumulator(
inputConfig *config.InputConfig, pluginConfig *config.PluginConfig,
points chan *client.Point, points chan *client.Point,
) Accumulator { ) Accumulator {
acc := accumulator{} acc := accumulator{}
acc.points = points acc.points = points
acc.inputConfig = inputConfig acc.pluginConfig = pluginConfig
return &acc return &acc
} }
@@ -47,7 +47,7 @@ type accumulator struct {
debug bool debug bool
inputConfig *config.InputConfig pluginConfig *config.PluginConfig
prefix string prefix string
} }
@@ -69,31 +69,27 @@ func (ac *accumulator) AddFields(
tags map[string]string, tags map[string]string,
t ...time.Time, t ...time.Time,
) { ) {
if len(fields) == 0 || len(measurement) == 0 { if !ac.pluginConfig.Filter.ShouldTagsPass(tags) {
return
}
if !ac.inputConfig.Filter.ShouldTagsPass(tags) {
return return
} }
// Override measurement name if set // Override measurement name if set
if len(ac.inputConfig.NameOverride) != 0 { if len(ac.pluginConfig.NameOverride) != 0 {
measurement = ac.inputConfig.NameOverride measurement = ac.pluginConfig.NameOverride
} }
// Apply measurement prefix and suffix if set // Apply measurement prefix and suffix if set
if len(ac.inputConfig.MeasurementPrefix) != 0 { if len(ac.pluginConfig.MeasurementPrefix) != 0 {
measurement = ac.inputConfig.MeasurementPrefix + measurement measurement = ac.pluginConfig.MeasurementPrefix + measurement
} }
if len(ac.inputConfig.MeasurementSuffix) != 0 { if len(ac.pluginConfig.MeasurementSuffix) != 0 {
measurement = measurement + ac.inputConfig.MeasurementSuffix measurement = measurement + ac.pluginConfig.MeasurementSuffix
} }
if tags == nil { if tags == nil {
tags = make(map[string]string) tags = make(map[string]string)
} }
// Apply plugin-wide tags if set // Apply plugin-wide tags if set
for k, v := range ac.inputConfig.Tags { for k, v := range ac.pluginConfig.Tags {
if _, ok := tags[k]; !ok { if _, ok := tags[k]; !ok {
tags[k] = v tags[k] = v
} }
@@ -108,8 +104,8 @@ func (ac *accumulator) AddFields(
result := make(map[string]interface{}) result := make(map[string]interface{})
for k, v := range fields { for k, v := range fields {
// Filter out any filtered fields // Filter out any filtered fields
if ac.inputConfig != nil { if ac.pluginConfig != nil {
if !ac.inputConfig.Filter.ShouldPass(k) { if !ac.pluginConfig.Filter.ShouldPass(k) {
continue continue
} }
} }

View File

@@ -10,8 +10,8 @@ import (
"time" "time"
"github.com/influxdb/telegraf/internal/config" "github.com/influxdb/telegraf/internal/config"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/outputs"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/plugins"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
) )
@@ -85,33 +85,33 @@ func (a *Agent) Close() error {
return err return err
} }
// gatherParallel runs the inputs that are using the same reporting interval // gatherParallel runs the plugins that are using the same reporting interval
// as the telegraf agent. // as the telegraf agent.
func (a *Agent) gatherParallel(pointChan chan *client.Point) error { func (a *Agent) gatherParallel(pointChan chan *client.Point) error {
var wg sync.WaitGroup var wg sync.WaitGroup
start := time.Now() start := time.Now()
counter := 0 counter := 0
for _, input := range a.Config.Inputs { for _, plugin := range a.Config.Plugins {
if input.Config.Interval != 0 { if plugin.Config.Interval != 0 {
continue continue
} }
wg.Add(1) wg.Add(1)
counter++ counter++
go func(input *config.RunningInput) { go func(plugin *config.RunningPlugin) {
defer wg.Done() defer wg.Done()
acc := NewAccumulator(input.Config, pointChan) acc := NewAccumulator(plugin.Config, pointChan)
acc.SetDebug(a.Config.Agent.Debug) acc.SetDebug(a.Config.Agent.Debug)
// acc.SetPrefix(input.Name + "_") // acc.SetPrefix(plugin.Name + "_")
acc.SetDefaultTags(a.Config.Tags) acc.SetDefaultTags(a.Config.Tags)
if err := input.Input.Gather(acc); err != nil { if err := plugin.Plugin.Gather(acc); err != nil {
log.Printf("Error in input [%s]: %s", input.Name, err) log.Printf("Error in plugin [%s]: %s", plugin.Name, err)
} }
}(input) }(plugin)
} }
if counter == 0 { if counter == 0 {
@@ -121,36 +121,36 @@ func (a *Agent) gatherParallel(pointChan chan *client.Point) error {
wg.Wait() wg.Wait()
elapsed := time.Since(start) elapsed := time.Since(start)
log.Printf("Gathered metrics, (%s interval), from %d inputs in %s\n", log.Printf("Gathered metrics, (%s interval), from %d plugins in %s\n",
a.Config.Agent.Interval.Duration, counter, elapsed) a.Config.Agent.Interval, counter, elapsed)
return nil return nil
} }
// gatherSeparate runs the inputs that have been configured with their own // gatherSeparate runs the plugins that have been configured with their own
// reporting interval. // reporting interval.
func (a *Agent) gatherSeparate( func (a *Agent) gatherSeparate(
shutdown chan struct{}, shutdown chan struct{},
input *config.RunningInput, plugin *config.RunningPlugin,
pointChan chan *client.Point, pointChan chan *client.Point,
) error { ) error {
ticker := time.NewTicker(input.Config.Interval) ticker := time.NewTicker(plugin.Config.Interval)
for { for {
var outerr error var outerr error
start := time.Now() start := time.Now()
acc := NewAccumulator(input.Config, pointChan) acc := NewAccumulator(plugin.Config, pointChan)
acc.SetDebug(a.Config.Agent.Debug) acc.SetDebug(a.Config.Agent.Debug)
// acc.SetPrefix(input.Name + "_") // acc.SetPrefix(plugin.Name + "_")
acc.SetDefaultTags(a.Config.Tags) acc.SetDefaultTags(a.Config.Tags)
if err := input.Input.Gather(acc); err != nil { if err := plugin.Plugin.Gather(acc); err != nil {
log.Printf("Error in input [%s]: %s", input.Name, err) log.Printf("Error in plugin [%s]: %s", plugin.Name, err)
} }
elapsed := time.Since(start) elapsed := time.Since(start)
log.Printf("Gathered metrics, (separate %s interval), from %s in %s\n", log.Printf("Gathered metrics, (separate %s interval), from %s in %s\n",
input.Config.Interval, input.Name, elapsed) plugin.Config.Interval, plugin.Name, elapsed)
if outerr != nil { if outerr != nil {
return outerr return outerr
@@ -165,7 +165,7 @@ func (a *Agent) gatherSeparate(
} }
} }
// Test verifies that we can 'Gather' from all inputs with their configured // Test verifies that we can 'Gather' from all plugins with their configured
// Config struct // Config struct
func (a *Agent) Test() error { func (a *Agent) Test() error {
shutdown := make(chan struct{}) shutdown := make(chan struct{})
@@ -184,27 +184,27 @@ func (a *Agent) Test() error {
} }
}() }()
for _, input := range a.Config.Inputs { for _, plugin := range a.Config.Plugins {
acc := NewAccumulator(input.Config, pointChan) acc := NewAccumulator(plugin.Config, pointChan)
acc.SetDebug(true) acc.SetDebug(true)
// acc.SetPrefix(input.Name + "_") // acc.SetPrefix(plugin.Name + "_")
fmt.Printf("* Plugin: %s, Collection 1\n", input.Name) fmt.Printf("* Plugin: %s, Collection 1\n", plugin.Name)
if input.Config.Interval != 0 { if plugin.Config.Interval != 0 {
fmt.Printf("* Internal: %s\n", input.Config.Interval) fmt.Printf("* Internal: %s\n", plugin.Config.Interval)
} }
if err := input.Input.Gather(acc); err != nil { if err := plugin.Plugin.Gather(acc); err != nil {
return err return err
} }
// Special instructions for some inputs. cpu, for example, needs to be // Special instructions for some plugins. cpu, for example, needs to be
// run twice in order to return cpu usage percentages. // run twice in order to return cpu usage percentages.
switch input.Name { switch plugin.Name {
case "cpu", "mongodb": case "cpu", "mongodb":
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
fmt.Printf("* Plugin: %s, Collection 2\n", input.Name) fmt.Printf("* Plugin: %s, Collection 2\n", plugin.Name)
if err := input.Input.Gather(acc); err != nil { if err := plugin.Plugin.Gather(acc); err != nil {
return err return err
} }
} }
@@ -332,10 +332,10 @@ func (a *Agent) Run(shutdown chan struct{}) error {
log.Printf("Agent Config: Interval:%s, Debug:%#v, Hostname:%#v, "+ log.Printf("Agent Config: Interval:%s, Debug:%#v, Hostname:%#v, "+
"Flush Interval:%s\n", "Flush Interval:%s\n",
a.Config.Agent.Interval.Duration, a.Config.Agent.Debug, a.Config.Agent.Interval, a.Config.Agent.Debug,
a.Config.Agent.Hostname, a.Config.Agent.FlushInterval.Duration) a.Config.Agent.Hostname, a.Config.Agent.FlushInterval)
// channel shared between all input threads for accumulating points // channel shared between all plugin threads for accumulating points
pointChan := make(chan *client.Point, 1000) pointChan := make(chan *client.Point, 1000)
// Round collection to nearest interval by sleeping // Round collection to nearest interval by sleeping
@@ -354,29 +354,29 @@ func (a *Agent) Run(shutdown chan struct{}) error {
} }
}() }()
for _, input := range a.Config.Inputs { for _, plugin := range a.Config.Plugins {
// Start service of any ServicePlugins // Start service of any ServicePlugins
switch p := input.Input.(type) { switch p := plugin.Plugin.(type) {
case inputs.ServiceInput: case plugins.ServicePlugin:
if err := p.Start(); err != nil { if err := p.Start(); err != nil {
log.Printf("Service for input %s failed to start, exiting\n%s\n", log.Printf("Service for plugin %s failed to start, exiting\n%s\n",
input.Name, err.Error()) plugin.Name, err.Error())
return err return err
} }
defer p.Stop() defer p.Stop()
} }
// Special handling for inputs that have their own collection interval // Special handling for plugins that have their own collection interval
// configured. Default intervals are handled below with gatherParallel // configured. Default intervals are handled below with gatherParallel
if input.Config.Interval != 0 { if plugin.Config.Interval != 0 {
wg.Add(1) wg.Add(1)
go func(input *config.RunningInput) { go func(plugin *config.RunningPlugin) {
defer wg.Done() defer wg.Done()
if err := a.gatherSeparate(shutdown, input, pointChan); err != nil { if err := a.gatherSeparate(shutdown, plugin, pointChan); err != nil {
log.Printf(err.Error()) log.Printf(err.Error())
} }
}(input) }(plugin)
} }
} }

View File

@@ -8,96 +8,77 @@ import (
"github.com/influxdb/telegraf/internal/config" "github.com/influxdb/telegraf/internal/config"
// needing to load the plugins // needing to load the plugins
_ "github.com/influxdb/telegraf/plugins/inputs/all" _ "github.com/influxdb/telegraf/plugins/all"
// needing to load the outputs // needing to load the outputs
_ "github.com/influxdb/telegraf/plugins/outputs/all" _ "github.com/influxdb/telegraf/outputs/all"
) )
func TestAgent_LoadPlugin(t *testing.T) { func TestAgent_LoadPlugin(t *testing.T) {
c := config.NewConfig() c := config.NewConfig()
c.InputFilters = []string{"mysql"} c.PluginFilters = []string{"mysql"}
err := c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ := NewAgent(c) a, _ := NewAgent(c)
assert.Equal(t, 1, len(a.Config.Inputs)) assert.Equal(t, 1, len(a.Config.Plugins))
c = config.NewConfig() c = config.NewConfig()
c.InputFilters = []string{"foo"} c.PluginFilters = []string{"foo"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 0, len(a.Config.Inputs)) assert.Equal(t, 0, len(a.Config.Plugins))
c = config.NewConfig() c = config.NewConfig()
c.InputFilters = []string{"mysql", "foo"} c.PluginFilters = []string{"mysql", "foo"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 1, len(a.Config.Inputs)) assert.Equal(t, 1, len(a.Config.Plugins))
c = config.NewConfig() c = config.NewConfig()
c.InputFilters = []string{"mysql", "redis"} c.PluginFilters = []string{"mysql", "redis"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 2, len(a.Config.Inputs)) assert.Equal(t, 2, len(a.Config.Plugins))
c = config.NewConfig() c = config.NewConfig()
c.InputFilters = []string{"mysql", "foo", "redis", "bar"} c.PluginFilters = []string{"mysql", "foo", "redis", "bar"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 2, len(a.Config.Inputs)) assert.Equal(t, 2, len(a.Config.Plugins))
} }
func TestAgent_LoadOutput(t *testing.T) { func TestAgent_LoadOutput(t *testing.T) {
c := config.NewConfig() c := config.NewConfig()
c.OutputFilters = []string{"influxdb"} c.OutputFilters = []string{"influxdb"}
err := c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ := NewAgent(c) a, _ := NewAgent(c)
assert.Equal(t, 2, len(a.Config.Outputs)) assert.Equal(t, 2, len(a.Config.Outputs))
c = config.NewConfig()
c.OutputFilters = []string{"kafka"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c)
assert.Equal(t, 1, len(a.Config.Outputs))
c = config.NewConfig() c = config.NewConfig()
c.OutputFilters = []string{} c.OutputFilters = []string{}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 3, len(a.Config.Outputs)) assert.Equal(t, 3, len(a.Config.Outputs))
c = config.NewConfig() c = config.NewConfig()
c.OutputFilters = []string{"foo"} c.OutputFilters = []string{"foo"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 0, len(a.Config.Outputs)) assert.Equal(t, 0, len(a.Config.Outputs))
c = config.NewConfig() c = config.NewConfig()
c.OutputFilters = []string{"influxdb", "foo"} c.OutputFilters = []string{"influxdb", "foo"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 2, len(a.Config.Outputs)) assert.Equal(t, 2, len(a.Config.Outputs))
c = config.NewConfig() c = config.NewConfig()
c.OutputFilters = []string{"influxdb", "kafka"} c.OutputFilters = []string{"influxdb", "kafka"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
assert.Equal(t, 3, len(c.Outputs))
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 3, len(a.Config.Outputs)) assert.Equal(t, 3, len(a.Config.Outputs))
c = config.NewConfig() c = config.NewConfig()
c.OutputFilters = []string{"influxdb", "foo", "kafka", "bar"} c.OutputFilters = []string{"influxdb", "foo", "kafka", "bar"}
err = c.LoadConfig("./internal/config/testdata/telegraf-agent.toml") c.LoadConfig("./internal/config/testdata/telegraf-agent.toml")
assert.NoError(t, err)
a, _ = NewAgent(c) a, _ = NewAgent(c)
assert.Equal(t, 3, len(a.Config.Outputs)) assert.Equal(t, 3, len(a.Config.Outputs))
} }

670
build.py
View File

@@ -1,670 +0,0 @@
#!/usr/bin/env python2.7
#
# This is the Telegraf build script.
#
# Current caveats:
# - Does not checkout the correct commit/branch (for now, you will need to do so manually)
# - Has external dependencies for packaging (fpm) and uploading (boto)
#
import sys
import os
import subprocess
import time
import datetime
import shutil
import tempfile
import hashlib
import re
try:
import boto
from boto.s3.key import Key
except ImportError:
pass
# PACKAGING VARIABLES
INSTALL_ROOT_DIR = "/usr/bin"
LOG_DIR = "/var/log/telegraf"
SCRIPT_DIR = "/usr/lib/telegraf/scripts"
CONFIG_DIR = "/etc/telegraf"
LOGROTATE_DIR = "/etc/logrotate.d"
INIT_SCRIPT = "scripts/init.sh"
SYSTEMD_SCRIPT = "scripts/telegraf.service"
LOGROTATE_SCRIPT = "etc/logrotate.d/telegraf"
DEFAULT_CONFIG = "etc/telegraf.conf"
POSTINST_SCRIPT = "scripts/post-install.sh"
PREINST_SCRIPT = "scripts/pre-install.sh"
# META-PACKAGE VARIABLES
PACKAGE_LICENSE = "MIT"
PACKAGE_URL = "https://github.com/influxdata/telegraf"
MAINTAINER = "support@influxdb.com"
VENDOR = "InfluxData"
DESCRIPTION = "Plugin-driven server agent for reporting metrics into InfluxDB."
# SCRIPT START
prereqs = [ 'git', 'go' ]
optional_prereqs = [ 'gvm', 'fpm', 'rpmbuild' ]
fpm_common_args = "-f -s dir --log error \
--vendor {} \
--url {} \
--license {} \
--maintainer {} \
--config-files {} \
--config-files {} \
--after-install {} \
--before-install {} \
--description \"{}\"".format(
VENDOR,
PACKAGE_URL,
PACKAGE_LICENSE,
MAINTAINER,
CONFIG_DIR + '/telegraf.conf',
LOGROTATE_DIR + '/telegraf',
POSTINST_SCRIPT,
PREINST_SCRIPT,
DESCRIPTION)
targets = {
'telegraf' : './cmd/telegraf/telegraf.go',
}
supported_builds = {
# TODO(rossmcdonald): Add support for multiple GOARM values
'darwin': [ "amd64", "386" ],
# 'windows': [ "amd64", "386", "arm", "arm64" ],
'linux': [ "amd64", "386", "arm" ]
}
supported_go = [ '1.5.1' ]
supported_packages = {
"darwin": [ "tar", "zip" ],
"linux": [ "deb", "rpm", "tar", "zip" ],
"windows": [ "tar", "zip" ],
}
def run(command, allow_failure=False, shell=False):
out = None
try:
if shell:
out = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell)
else:
out = subprocess.check_output(command.split(), stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print ""
print ""
print "Executed command failed!"
print "-- Command run was: {}".format(command)
print "-- Failure was: {}".format(e.output)
if allow_failure:
print "Continuing..."
return None
else:
print ""
print "Stopping."
sys.exit(1)
except OSError as e:
print ""
print ""
print "Invalid command!"
print "-- Command run was: {}".format(command)
print "-- Failure was: {}".format(e)
if allow_failure:
print "Continuing..."
return out
else:
print ""
print "Stopping."
sys.exit(1)
else:
return out
def create_temp_dir():
return tempfile.mkdtemp(prefix="telegraf-build.")
def get_current_version():
command = "git describe --always --tags --abbrev=0"
out = run(command)
return out.strip()
def get_current_commit(short=False):
command = None
if short:
command = "git log --pretty=format:'%h' -n 1"
else:
command = "git rev-parse HEAD"
out = run(command)
return out.strip('\'\n\r ')
def get_current_branch():
command = "git rev-parse --abbrev-ref HEAD"
out = run(command)
return out.strip()
def get_system_arch():
arch = os.uname()[4]
if arch == "x86_64":
arch = "amd64"
return arch
def get_system_platform():
if sys.platform.startswith("linux"):
return "linux"
else:
return sys.platform
def get_go_version():
out = run("go version")
matches = re.search('go version go(\S+)', out)
if matches is not None:
return matches.groups()[0].strip()
return None
def check_path_for(b):
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
full_path = os.path.join(path, b)
if os.path.isfile(full_path) and os.access(full_path, os.X_OK):
return full_path
def check_environ(build_dir = None):
print "\nChecking environment:"
for v in [ "GOPATH", "GOBIN", "GOROOT" ]:
print "\t- {} -> {}".format(v, os.environ.get(v))
cwd = os.getcwd()
if build_dir == None and os.environ.get("GOPATH") and os.environ.get("GOPATH") not in cwd:
print "\n!! WARNING: Your current directory is not under your GOPATH. This may lead to build failures."
def check_prereqs():
print "\nChecking for dependencies:"
for req in prereqs:
print "\t- {} ->".format(req),
path = check_path_for(req)
if path:
print "{}".format(path)
else:
print "?"
for req in optional_prereqs:
print "\t- {} (optional) ->".format(req),
path = check_path_for(req)
if path:
print "{}".format(path)
else:
print "?"
print ""
def upload_packages(packages, nightly=False):
print "Uploading packages to S3..."
print ""
c = boto.connect_s3()
# TODO(rossmcdonald) - Set to different S3 bucket for release vs nightly
bucket = c.get_bucket('telegraf-nightly')
for p in packages:
name = os.path.basename(p)
if bucket.get_key(name) is None or nightly:
print "\t - Uploading {}...".format(name),
k = Key(bucket)
k.key = name
if nightly:
n = k.set_contents_from_filename(p, replace=True)
else:
n = k.set_contents_from_filename(p, replace=False)
k.make_public()
print "[ DONE ]"
else:
print "\t - Not uploading {}, already exists.".format(p)
print ""
def run_tests(race, parallel, timeout, no_vet):
get_command = "go get -d -t ./..."
print "Retrieving Go dependencies...",
sys.stdout.flush()
run(get_command)
print "done."
print "Running tests:"
print "\tRace: ", race
if parallel is not None:
print "\tParallel:", parallel
if timeout is not None:
print "\tTimeout:", timeout
sys.stdout.flush()
p = subprocess.Popen(["go", "fmt", "./..."], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if len(out) > 0 or len(err) > 0:
print "Code not formatted. Please use 'go fmt ./...' to fix formatting errors."
print out
print err
return False
if not no_vet:
p = subprocess.Popen(["go", "tool", "vet", "-composites=false", "./"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if len(out) > 0 or len(err) > 0:
print "Go vet failed. Please run 'go vet ./...' and fix any errors."
print out
print err
return False
else:
print "Skipping go vet ..."
sys.stdout.flush()
test_command = "go test -v"
if race:
test_command += " -race"
if parallel is not None:
test_command += " -parallel {}".format(parallel)
if timeout is not None:
test_command += " -timeout {}".format(timeout)
test_command += " ./..."
code = os.system(test_command)
if code != 0:
print "Tests Failed"
return False
else:
print "Tests Passed"
return True
def build(version=None,
branch=None,
commit=None,
platform=None,
arch=None,
nightly=False,
rc=None,
race=False,
clean=False,
outdir=".",
goarm_version="6"):
print "-------------------------"
print ""
print "Build plan:"
print "\t- version: {}".format(version)
if rc:
print "\t- release candidate: {}".format(rc)
print "\t- commit: {}".format(commit)
print "\t- branch: {}".format(branch)
print "\t- platform: {}".format(platform)
print "\t- arch: {}".format(arch)
if arch == 'arm' and goarm_version:
print "\t- ARM version: {}".format(goarm_version)
print "\t- nightly? {}".format(str(nightly).lower())
print "\t- race enabled? {}".format(str(race).lower())
print ""
if not os.path.exists(outdir):
os.makedirs(outdir)
elif clean and outdir != '/':
print "Cleaning build directory..."
shutil.rmtree(outdir)
os.makedirs(outdir)
if rc:
# If a release candidate, update the version information accordingly
version = "{}rc{}".format(version, rc)
print "Starting build..."
for b, c in targets.iteritems():
print "\t- Building '{}'...".format(os.path.join(outdir, b)),
build_command = ""
build_command += "GOOS={} GOARCH={} ".format(platform, arch)
if arch == "arm" and goarm_version:
if goarm_version not in ["5", "6", "7", "arm64"]:
print "!! Invalid ARM build version: {}".format(goarm_version)
build_command += "GOARM={} ".format(goarm_version)
build_command += "go build -o {} ".format(os.path.join(outdir, b))
if race:
build_command += "-race "
go_version = get_go_version()
if "1.4" in go_version:
build_command += "-ldflags=\"-X main.buildTime '{}' ".format(datetime.datetime.utcnow().isoformat())
build_command += "-X main.Version {} ".format(version)
build_command += "-X main.Branch {} ".format(branch)
build_command += "-X main.Commit {}\" ".format(get_current_commit())
else:
build_command += "-ldflags=\"-X main.buildTime='{}' ".format(datetime.datetime.utcnow().isoformat())
build_command += "-X main.Version={} ".format(version)
build_command += "-X main.Branch={} ".format(branch)
build_command += "-X main.Commit={}\" ".format(get_current_commit())
build_command += c
run(build_command, shell=True)
print "[ DONE ]"
print ""
def create_dir(path):
try:
os.makedirs(path)
except OSError as e:
print e
def rename_file(fr, to):
try:
os.rename(fr, to)
except OSError as e:
print e
# Return the original filename
return fr
else:
# Return the new filename
return to
def copy_file(fr, to):
try:
shutil.copy(fr, to)
except OSError as e:
print e
def create_package_fs(build_root):
print "\t- Creating a filesystem hierarchy from directory: {}".format(build_root)
# Using [1:] for the path names due to them being absolute
# (will overwrite previous paths, per 'os.path.join' documentation)
dirs = [ INSTALL_ROOT_DIR[1:], LOG_DIR[1:], SCRIPT_DIR[1:], CONFIG_DIR[1:], LOGROTATE_DIR[1:] ]
for d in dirs:
create_dir(os.path.join(build_root, d))
os.chmod(os.path.join(build_root, d), 0755)
def package_scripts(build_root):
print "\t- Copying scripts and sample configuration to build directory"
shutil.copyfile(INIT_SCRIPT, os.path.join(build_root, SCRIPT_DIR[1:], INIT_SCRIPT.split('/')[1]))
os.chmod(os.path.join(build_root, SCRIPT_DIR[1:], INIT_SCRIPT.split('/')[1]), 0644)
shutil.copyfile(SYSTEMD_SCRIPT, os.path.join(build_root, SCRIPT_DIR[1:], SYSTEMD_SCRIPT.split('/')[1]))
os.chmod(os.path.join(build_root, SCRIPT_DIR[1:], SYSTEMD_SCRIPT.split('/')[1]), 0644)
shutil.copyfile(LOGROTATE_SCRIPT, os.path.join(build_root, LOGROTATE_DIR[1:], "telegraf"))
os.chmod(os.path.join(build_root, LOGROTATE_DIR[1:], "telegraf"), 0644)
shutil.copyfile(DEFAULT_CONFIG, os.path.join(build_root, CONFIG_DIR[1:], "telegraf.conf"))
os.chmod(os.path.join(build_root, CONFIG_DIR[1:], "telegraf.conf"), 0644)
def go_get(update=False):
get_command = None
if update:
get_command = "go get -u -f -d ./..."
else:
get_command = "go get -d ./..."
print "Retrieving Go dependencies...",
run(get_command)
print "done.\n"
def generate_md5_from_file(path):
m = hashlib.md5()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
m.update(chunk)
return m.hexdigest()
def build_packages(build_output, version, nightly=False, rc=None, iteration=1):
outfiles = []
tmp_build_dir = create_temp_dir()
try:
print "-------------------------"
print ""
print "Packaging..."
for p in build_output:
# Create top-level folder displaying which platform (linux, etc)
create_dir(os.path.join(tmp_build_dir, p))
for a in build_output[p]:
current_location = build_output[p][a]
# Create second-level directory displaying the architecture (amd64, etc)p
build_root = os.path.join(tmp_build_dir, p, a)
# Create directory tree to mimic file system of package
create_dir(build_root)
create_package_fs(build_root)
# Copy in packaging and miscellaneous scripts
package_scripts(build_root)
# Copy newly-built binaries to packaging directory
for b in targets:
if p == 'windows':
b = b + '.exe'
fr = os.path.join(current_location, b)
to = os.path.join(build_root, INSTALL_ROOT_DIR[1:], b)
print "\t- [{}][{}] - Moving from '{}' to '{}'".format(p, a, fr, to)
copy_file(fr, to)
# Package the directory structure
for package_type in supported_packages[p]:
print "\t- Packaging directory '{}' as '{}'...".format(build_root, package_type),
name = "telegraf"
package_version = version
package_iteration = iteration
if package_type in ['zip', 'tar']:
if nightly:
name = '{}-nightly_{}_{}'.format(name, p, a)
else:
name = '{}-{}_{}_{}'.format(name, version, p, a)
if package_type == 'tar':
# Add `tar.gz` to path to reduce package size
current_location = os.path.join(current_location, name + '.tar.gz')
if rc is not None:
package_iteration = "0.rc{}".format(rc)
fpm_command = "fpm {} --name {} -a {} -t {} --version {} --iteration {} -C {} -p {} ".format(
fpm_common_args,
name,
a,
package_type,
package_version,
package_iteration,
build_root,
current_location)
if package_type == "rpm":
fpm_command += "--depends coreutils "
out = run(fpm_command, shell=True)
matches = re.search(':path=>"(.*)"', out)
outfile = None
if matches is not None:
outfile = matches.groups()[0]
if outfile is None:
print "[ COULD NOT DETERMINE OUTPUT ]"
else:
# Strip nightly version (the unix epoch) from filename
if nightly and package_type in ['deb', 'rpm']:
outfile = rename_file(outfile, outfile.replace("{}-{}".format(version, iteration), "nightly"))
outfiles.append(os.path.join(os.getcwd(), outfile))
print "[ DONE ]"
# Display MD5 hash for generated package
print "\t\tMD5 = {}".format(generate_md5_from_file(outfile))
print ""
return outfiles
finally:
# Cleanup
shutil.rmtree(tmp_build_dir)
def print_usage():
print "Usage: ./build.py [options]"
print ""
print "Options:"
print "\t --outdir=<path> \n\t\t- Send build output to a specified path. Defaults to ./build."
print "\t --arch=<arch> \n\t\t- Build for specified architecture. Acceptable values: x86_64|amd64, 386, arm, or all"
print "\t --goarm=<arm version> \n\t\t- Build for specified ARM version (when building for ARM). Default value is: 6"
print "\t --platform=<platform> \n\t\t- Build for specified platform. Acceptable values: linux, windows, darwin, or all"
print "\t --version=<version> \n\t\t- Version information to apply to build metadata. If not specified, will be pulled from repo tag."
print "\t --commit=<commit> \n\t\t- Use specific commit for build (currently a NOOP)."
print "\t --branch=<branch> \n\t\t- Build from a specific branch (currently a NOOP)."
print "\t --rc=<rc number> \n\t\t- Whether or not the build is a release candidate (affects version information)."
print "\t --iteration=<iteration number> \n\t\t- The iteration to display on the package output (defaults to 0 for RC's, and 1 otherwise)."
print "\t --race \n\t\t- Whether the produced build should have race detection enabled."
print "\t --package \n\t\t- Whether the produced builds should be packaged for the target platform(s)."
print "\t --nightly \n\t\t- Whether the produced build is a nightly (affects version information)."
print "\t --update \n\t\t- Whether dependencies should be updated prior to building."
print "\t --test \n\t\t- Run Go tests. Will not produce a build."
print "\t --parallel \n\t\t- Run Go tests in parallel up to the count specified."
print "\t --timeout \n\t\t- Timeout for Go tests. Defaults to 480s."
print "\t --clean \n\t\t- Clean the build output directory prior to creating build."
print ""
def print_package_summary(packages):
print packages
def main():
# Command-line arguments
outdir = "build"
commit = None
target_platform = None
target_arch = None
nightly = False
race = False
branch = None
version = get_current_version()
rc = None
package = False
update = False
clean = False
upload = False
test = False
parallel = None
timeout = None
iteration = 1
no_vet = False
goarm_version = "6"
for arg in sys.argv[1:]:
if '--outdir' in arg:
# Output directory. If none is specified, then builds will be placed in the same directory.
output_dir = arg.split("=")[1]
if '--commit' in arg:
# Commit to build from. If none is specified, then it will build from the most recent commit.
commit = arg.split("=")[1]
if '--branch' in arg:
# Branch to build from. If none is specified, then it will build from the current branch.
branch = arg.split("=")[1]
elif '--arch' in arg:
# Target architecture. If none is specified, then it will build for the current arch.
target_arch = arg.split("=")[1]
elif '--platform' in arg:
# Target platform. If none is specified, then it will build for the current platform.
target_platform = arg.split("=")[1]
elif '--version' in arg:
# Version to assign to this build (0.9.5, etc)
version = arg.split("=")[1]
elif '--rc' in arg:
# Signifies that this is a release candidate build.
rc = arg.split("=")[1]
elif '--race' in arg:
# Signifies that race detection should be enabled.
race = True
elif '--package' in arg:
# Signifies that packages should be built.
package = True
elif '--nightly' in arg:
# Signifies that this is a nightly build.
nightly = True
elif '--update' in arg:
# Signifies that dependencies should be updated.
update = True
elif '--upload' in arg:
# Signifies that the resulting packages should be uploaded to S3
upload = True
elif '--test' in arg:
# Run tests and exit
test = True
elif '--parallel' in arg:
# Set parallel for tests.
parallel = int(arg.split("=")[1])
elif '--timeout' in arg:
# Set timeout for tests.
timeout = arg.split("=")[1]
elif '--clean' in arg:
# Signifies that the outdir should be deleted before building
clean = True
elif '--iteration' in arg:
iteration = arg.split("=")[1]
elif '--no-vet' in arg:
no_vet = True
elif '--goarm' in arg:
# Signifies GOARM flag to pass to build command when compiling for ARM
goarm_version = arg.split("=")[1]
elif '--help' in arg:
print_usage()
return 0
else:
print "!! Unknown argument: {}".format(arg)
print_usage()
return 1
if nightly:
if rc:
print "!! Cannot be both nightly and a release candidate! Stopping."
return 1
# In order to support nightly builds on the repository, we are adding the epoch timestamp
# to the version so that version numbers are always greater than the previous nightly.
version = "{}.n{}".format(version, int(time.time()))
# Pre-build checks
check_environ()
check_prereqs()
if not commit:
commit = get_current_commit(short=True)
if not branch:
branch = get_current_branch()
if not target_arch:
if 'arm' in get_system_arch():
# Prevent uname from reporting ARM arch (eg 'armv7l')
target_arch = "arm"
else:
target_arch = get_system_arch()
if not target_platform:
target_platform = get_system_platform()
if rc or nightly:
# If a release candidate or nightly, set iteration to 0 (instead of 1)
iteration = 0
build_output = {}
# TODO(rossmcdonald): Prepare git repo for build (checking out correct branch/commit, etc.)
# prepare(branch=branch, commit=commit)
if test:
if not run_tests(race, parallel, timeout, no_vet):
return 1
return 0
go_get(update=update)
platforms = []
single_build = True
if target_platform == 'all':
platforms = supported_builds.keys()
single_build = False
else:
platforms = [target_platform]
for platform in platforms:
build_output.update( { platform : {} } )
archs = []
if target_arch == "all":
single_build = False
archs = supported_builds.get(platform)
else:
archs = [target_arch]
for arch in archs:
od = outdir
if not single_build:
od = os.path.join(outdir, platform, arch)
build(version=version,
branch=branch,
commit=commit,
platform=platform,
arch=arch,
nightly=nightly,
rc=rc,
race=race,
clean=clean,
outdir=od,
goarm_version=goarm_version)
build_output.get(platform).update( { arch : od } )
# Build packages
if package:
if not check_path_for("fpm"):
print "!! Cannot package without command 'fpm'. Stopping."
return 1
packages = build_packages(build_output, version, nightly=nightly, rc=rc, iteration=iteration)
# TODO(rossmcdonald): Add nice output for print_package_summary()
# print_package_summary(packages)
# Optionally upload to S3
if upload:
upload_packages(packages, nightly=nightly)
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -4,12 +4,14 @@ machine:
post: post:
- sudo service zookeeper stop - sudo service zookeeper stop
- go version - go version
- go version | grep 1.5.2 || sudo rm -rf /usr/local/go - go version | grep 1.5.1 || sudo rm -rf /usr/local/go
- wget https://storage.googleapis.com/golang/go1.5.2.linux-amd64.tar.gz - wget https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz
- sudo tar -C /usr/local -xzf go1.5.2.linux-amd64.tar.gz - sudo tar -C /usr/local -xzf go1.5.1.linux-amd64.tar.gz
- go version - go version
dependencies: dependencies:
cache_directories:
- "~/telegraf-build/src"
override: override:
- docker info - docker info

View File

@@ -10,96 +10,41 @@ import (
"github.com/influxdb/telegraf" "github.com/influxdb/telegraf"
"github.com/influxdb/telegraf/internal/config" "github.com/influxdb/telegraf/internal/config"
_ "github.com/influxdb/telegraf/plugins/inputs/all" _ "github.com/influxdb/telegraf/outputs/all"
_ "github.com/influxdb/telegraf/plugins/outputs/all" _ "github.com/influxdb/telegraf/plugins/all"
) )
var fDebug = flag.Bool("debug", false, var fDebug = flag.Bool("debug", false,
"show metrics as they're generated to stdout") "show metrics as they're generated to stdout")
var fTest = flag.Bool("test", false, "gather metrics, print them out, and exit") var fTest = flag.Bool("test", false, "gather metrics, print them out, and exit")
var fConfig = flag.String("config", "", "configuration file to load") var fConfig = flag.String("config", "", "configuration file to load")
var fConfigDirectory = flag.String("config-directory", "", var fConfigDirectory = flag.String("configdirectory", "",
"directory containing additional *.conf files") "directory containing additional *.conf files")
var fVersion = flag.Bool("version", false, "display the version") var fVersion = flag.Bool("version", false, "display the version")
var fSampleConfig = flag.Bool("sample-config", false, var fSampleConfig = flag.Bool("sample-config", false,
"print out full sample configuration") "print out full sample configuration")
var fPidfile = flag.String("pidfile", "", "file to write our pid to") var fPidfile = flag.String("pidfile", "", "file to write our pid to")
var fInputFilters = flag.String("input-filter", "", var fPLuginFilters = flag.String("filter", "",
"filter the plugins to enable, separator is :") "filter the plugins to enable, separator is :")
var fOutputFilters = flag.String("output-filter", "", var fOutputFilters = flag.String("outputfilter", "",
"filter the outputs to enable, separator is :") "filter the outputs to enable, separator is :")
var fUsage = flag.String("usage", "", var fUsage = flag.String("usage", "",
"print usage for a plugin, ie, 'telegraf -usage mysql'") "print usage for a plugin, ie, 'telegraf -usage mysql'")
var fInputFiltersLegacy = flag.String("filter", "",
"filter the plugins to enable, separator is :")
var fOutputFiltersLegacy = flag.String("outputfilter", "",
"filter the outputs to enable, separator is :")
var fConfigDirectoryLegacy = flag.String("configdirectory", "",
"directory containing additional *.conf files")
// Telegraf version // Telegraf version
// -ldflags "-X main.Version=`git describe --always --tags`" // -ldflags "-X main.Version=`git describe --always --tags`"
var Version string var Version string
const usage = `Telegraf, The plugin-driven server agent for collecting and reporting metrics.
Usage:
telegraf <flags>
The flags are:
-config <file> configuration file to load
-test gather metrics once, print them to stdout, and exit
-sample-config print out full sample configuration to stdout
-config-directory directory containing additional *.conf files
-input-filter filter the input plugins to enable, separator is :
-output-filter filter the output plugins to enable, separator is :
-usage print usage for a plugin, ie, 'telegraf -usage mysql'
-version print the version to stdout
Examples:
# generate a telegraf config file:
telegraf -sample-config > telegraf.conf
# generate config with only cpu input & influxdb output plugins defined
telegraf -sample-config -input-filter cpu -output-filter influxdb
# run a single telegraf collection, outputing metrics to stdout
telegraf -config telegraf.conf -test
# run telegraf with all plugins defined in config file
telegraf -config telegraf.conf
# run telegraf, enabling the cpu & memory input, and influxdb output plugins
telegraf -config telegraf.conf -input-filter cpu:mem -output-filter influxdb
`
func main() { func main() {
flag.Usage = usageExit
flag.Parse() flag.Parse()
if flag.NFlag() == 0 { var pluginFilters []string
usageExit() if *fPLuginFilters != "" {
} pluginsFilter := strings.TrimSpace(*fPLuginFilters)
pluginFilters = strings.Split(":"+pluginsFilter+":", ":")
var inputFilters []string
if *fInputFiltersLegacy != "" {
inputFilter := strings.TrimSpace(*fInputFiltersLegacy)
inputFilters = strings.Split(":"+inputFilter+":", ":")
}
if *fInputFilters != "" {
inputFilter := strings.TrimSpace(*fInputFilters)
inputFilters = strings.Split(":"+inputFilter+":", ":")
} }
var outputFilters []string var outputFilters []string
if *fOutputFiltersLegacy != "" {
outputFilter := strings.TrimSpace(*fOutputFiltersLegacy)
outputFilters = strings.Split(":"+outputFilter+":", ":")
}
if *fOutputFilters != "" { if *fOutputFilters != "" {
outputFilter := strings.TrimSpace(*fOutputFilters) outputFilter := strings.TrimSpace(*fOutputFilters)
outputFilters = strings.Split(":"+outputFilter+":", ":") outputFilters = strings.Split(":"+outputFilter+":", ":")
@@ -112,12 +57,12 @@ func main() {
} }
if *fSampleConfig { if *fSampleConfig {
config.PrintSampleConfig(inputFilters, outputFilters) config.PrintSampleConfig(pluginFilters, outputFilters)
return return
} }
if *fUsage != "" { if *fUsage != "" {
if err := config.PrintInputConfig(*fUsage); err != nil { if err := config.PrintPluginConfig(*fUsage); err != nil {
if err2 := config.PrintOutputConfig(*fUsage); err2 != nil { if err2 := config.PrintOutputConfig(*fUsage); err2 != nil {
log.Fatalf("%s and %s", err, err2) log.Fatalf("%s and %s", err, err2)
} }
@@ -133,7 +78,7 @@ func main() {
if *fConfig != "" { if *fConfig != "" {
c = config.NewConfig() c = config.NewConfig()
c.OutputFilters = outputFilters c.OutputFilters = outputFilters
c.InputFilters = inputFilters c.PluginFilters = pluginFilters
err = c.LoadConfig(*fConfig) err = c.LoadConfig(*fConfig)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -144,13 +89,6 @@ func main() {
return return
} }
if *fConfigDirectoryLegacy != "" {
err = c.LoadDirectory(*fConfigDirectoryLegacy)
if err != nil {
log.Fatal(err)
}
}
if *fConfigDirectory != "" { if *fConfigDirectory != "" {
err = c.LoadDirectory(*fConfigDirectory) err = c.LoadDirectory(*fConfigDirectory)
if err != nil { if err != nil {
@@ -160,7 +98,7 @@ func main() {
if len(c.Outputs) == 0 { if len(c.Outputs) == 0 {
log.Fatalf("Error: no outputs found, did you provide a valid config file?") log.Fatalf("Error: no outputs found, did you provide a valid config file?")
} }
if len(c.Inputs) == 0 { if len(c.Plugins) == 0 {
log.Fatalf("Error: no plugins found, did you provide a valid config file?") log.Fatalf("Error: no plugins found, did you provide a valid config file?")
} }
@@ -196,7 +134,7 @@ func main() {
log.Printf("Starting Telegraf (version %s)\n", Version) log.Printf("Starting Telegraf (version %s)\n", Version)
log.Printf("Loaded outputs: %s", strings.Join(c.OutputNames(), " ")) log.Printf("Loaded outputs: %s", strings.Join(c.OutputNames(), " "))
log.Printf("Loaded plugins: %s", strings.Join(c.InputNames(), " ")) log.Printf("Loaded plugins: %s", strings.Join(c.PluginNames(), " "))
log.Printf("Tags enabled: %s", c.ListTags()) log.Printf("Tags enabled: %s", c.ListTags())
if *fPidfile != "" { if *fPidfile != "" {
@@ -212,8 +150,3 @@ func main() {
ag.Run(shutdown) ag.Run(shutdown)
} }
func usageExit() {
fmt.Println(usage)
os.Exit(0)
}

View File

@@ -1,7 +1,7 @@
# Telegraf configuration # Telegraf configuration
# Telegraf is entirely plugin driven. All metrics are gathered from the # Telegraf is entirely plugin driven. All metrics are gathered from the
# declared inputs. # declared plugins.
# Even if a plugin has no configuration, it must be declared in here # Even if a plugin has no configuration, it must be declared in here
# to be active. Declaring a plugin means just specifying the name # to be active. Declaring a plugin means just specifying the name
@@ -49,6 +49,8 @@
# OUTPUTS # # OUTPUTS #
############################################################################### ###############################################################################
[outputs]
# Configuration for influxdb server to send metrics to # Configuration for influxdb server to send metrics to
[[outputs.influxdb]] [[outputs.influxdb]]
# The full HTTP or UDP endpoint URL for your InfluxDB instance. # The full HTTP or UDP endpoint URL for your InfluxDB instance.
@@ -74,11 +76,13 @@
############################################################################### ###############################################################################
# INPUTS # # PLUGINS #
############################################################################### ###############################################################################
[plugins]
# Read metrics about cpu usage # Read metrics about cpu usage
[[inputs.cpu]] [[plugins.cpu]]
# Whether to report per-cpu stats or not # Whether to report per-cpu stats or not
percpu = true percpu = true
# Whether to report total system cpu stats or not # Whether to report total system cpu stats or not
@@ -87,33 +91,33 @@
drop = ["cpu_time"] drop = ["cpu_time"]
# Read metrics about disk usage by mount point # Read metrics about disk usage by mount point
[[inputs.disk]] [[plugins.disk]]
# By default, telegraf gather stats for all mountpoints. # By default, telegraf gather stats for all mountpoints.
# Setting mountpoints will restrict the stats to the specified mountpoints. # Setting mountpoints will restrict the stats to the specified mountpoints.
# Mountpoints=["/"] # Mountpoints=["/"]
# Read metrics about disk IO by device # Read metrics about disk IO by device
[[inputs.diskio]] [[plugins.diskio]]
# By default, telegraf will gather stats for all devices including # By default, telegraf will gather stats for all devices including
# disk partitions. # disk partitions.
# Setting devices will restrict the stats to the specified devices. # Setting devices will restrict the stats to the specified devcies.
# Devices=["sda","sdb"] # Devices=["sda","sdb"]
# Uncomment the following line if you do not need disk serial numbers. # Uncomment the following line if you do not need disk serial numbers.
# SkipSerialNumber = true # SkipSerialNumber = true
# Read metrics about memory usage # Read metrics about memory usage
[[inputs.mem]] [[plugins.mem]]
# no configuration # no configuration
# Read metrics about swap memory usage # Read metrics about swap memory usage
[[inputs.swap]] [[plugins.swap]]
# no configuration # no configuration
# Read metrics about system load & uptime # Read metrics about system load & uptime
[[inputs.system]] [[plugins.system]]
# no configuration # no configuration
############################################################################### ###############################################################################
# SERVICE INPUTS # # SERVICE PLUGINS #
############################################################################### ###############################################################################

View File

@@ -11,8 +11,8 @@ import (
"time" "time"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/outputs"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/plugins"
"github.com/naoina/toml" "github.com/naoina/toml"
"github.com/naoina/toml/ast" "github.com/naoina/toml/ast"
@@ -25,11 +25,11 @@ import (
// specified // specified
type Config struct { type Config struct {
Tags map[string]string Tags map[string]string
InputFilters []string PluginFilters []string
OutputFilters []string OutputFilters []string
Agent *AgentConfig Agent *AgentConfig
Inputs []*RunningInput Plugins []*RunningPlugin
Outputs []*RunningOutput Outputs []*RunningOutput
} }
@@ -45,9 +45,9 @@ func NewConfig() *Config {
}, },
Tags: make(map[string]string), Tags: make(map[string]string),
Inputs: make([]*RunningInput, 0), Plugins: make([]*RunningPlugin, 0),
Outputs: make([]*RunningOutput, 0), Outputs: make([]*RunningOutput, 0),
InputFilters: make([]string, 0), PluginFilters: make([]string, 0),
OutputFilters: make([]string, 0), OutputFilters: make([]string, 0),
} }
return c return c
@@ -93,10 +93,10 @@ type RunningOutput struct {
Config *OutputConfig Config *OutputConfig
} }
type RunningInput struct { type RunningPlugin struct {
Name string Name string
Input inputs.Input Plugin plugins.Plugin
Config *InputConfig Config *PluginConfig
} }
// Filter containing drop/pass and tagdrop/tagpass rules // Filter containing drop/pass and tagdrop/tagpass rules
@@ -110,8 +110,8 @@ type Filter struct {
IsActive bool IsActive bool
} }
// InputConfig containing a name, interval, and filter // PluginConfig containing a name, interval, and filter
type InputConfig struct { type PluginConfig struct {
Name string Name string
NameOverride string NameOverride string
MeasurementPrefix string MeasurementPrefix string
@@ -204,16 +204,16 @@ func (f Filter) ShouldTagsPass(tags map[string]string) bool {
return true return true
} }
// Inputs returns a list of strings of the configured inputs. // Plugins returns a list of strings of the configured plugins.
func (c *Config) InputNames() []string { func (c *Config) PluginNames() []string {
var name []string var name []string
for _, input := range c.Inputs { for _, plugin := range c.Plugins {
name = append(name, input.Name) name = append(name, plugin.Name)
} }
return name return name
} }
// Outputs returns a list of strings of the configured inputs. // Outputs returns a list of strings of the configured plugins.
func (c *Config) OutputNames() []string { func (c *Config) OutputNames() []string {
var name []string var name []string
for _, output := range c.Outputs { for _, output := range c.Outputs {
@@ -239,7 +239,7 @@ func (c *Config) ListTags() string {
var header = `# Telegraf configuration var header = `# Telegraf configuration
# Telegraf is entirely plugin driven. All metrics are gathered from the # Telegraf is entirely plugin driven. All metrics are gathered from the
# declared inputs. # declared plugins.
# Even if a plugin has no configuration, it must be declared in here # Even if a plugin has no configuration, it must be declared in here
# to be active. Declaring a plugin means just specifying the name # to be active. Declaring a plugin means just specifying the name
@@ -263,7 +263,7 @@ var header = `# Telegraf configuration
# Configuration for telegraf agent # Configuration for telegraf agent
[agent] [agent]
# Default data collection interval for all inputs # Default data collection interval for all plugins
interval = "10s" interval = "10s"
# Rounds collection interval to 'interval' # Rounds collection interval to 'interval'
# ie, if interval="10s" then always collect on :00, :10, :20, etc. # ie, if interval="10s" then always collect on :00, :10, :20, etc.
@@ -287,20 +287,22 @@ var header = `# Telegraf configuration
# OUTPUTS # # OUTPUTS #
############################################################################### ###############################################################################
[outputs]
` `
var pluginHeader = ` var pluginHeader = `
############################################################################### ###############################################################################
# INPUTS # # PLUGINS #
############################################################################### ###############################################################################
[plugins]
` `
var serviceInputHeader = ` var servicePluginHeader = `
############################################################################### ###############################################################################
# SERVICE INPUTS # # SERVICE PLUGINS #
############################################################################### ###############################################################################
` `
@@ -324,35 +326,35 @@ func PrintSampleConfig(pluginFilters []string, outputFilters []string) {
printConfig(oname, output, "outputs") printConfig(oname, output, "outputs")
} }
// Filter inputs // Filter plugins
var pnames []string var pnames []string
for pname := range inputs.Inputs { for pname := range plugins.Plugins {
if len(pluginFilters) == 0 || sliceContains(pname, pluginFilters) { if len(pluginFilters) == 0 || sliceContains(pname, pluginFilters) {
pnames = append(pnames, pname) pnames = append(pnames, pname)
} }
} }
sort.Strings(pnames) sort.Strings(pnames)
// Print Inputs // Print Plugins
fmt.Printf(pluginHeader) fmt.Printf(pluginHeader)
servInputs := make(map[string]inputs.ServiceInput) servPlugins := make(map[string]plugins.ServicePlugin)
for _, pname := range pnames { for _, pname := range pnames {
creator := inputs.Inputs[pname] creator := plugins.Plugins[pname]
input := creator() plugin := creator()
switch p := input.(type) { switch p := plugin.(type) {
case inputs.ServiceInput: case plugins.ServicePlugin:
servInputs[pname] = p servPlugins[pname] = p
continue continue
} }
printConfig(pname, input, "inputs") printConfig(pname, plugin, "plugins")
} }
// Print Service Inputs // Print Service Plugins
fmt.Printf(serviceInputHeader) fmt.Printf(servicePluginHeader)
for name, input := range servInputs { for name, plugin := range servPlugins {
printConfig(name, input, "inputs") printConfig(name, plugin, "plugins")
} }
} }
@@ -380,12 +382,12 @@ func sliceContains(name string, list []string) bool {
return false return false
} }
// PrintInputConfig prints the config usage of a single input. // PrintPluginConfig prints the config usage of a single plugin.
func PrintInputConfig(name string) error { func PrintPluginConfig(name string) error {
if creator, ok := inputs.Inputs[name]; ok { if creator, ok := plugins.Plugins[name]; ok {
printConfig(name, creator(), "inputs") printConfig(name, creator(), "plugins")
} else { } else {
return errors.New(fmt.Sprintf("Input %s not found", name)) return errors.New(fmt.Sprintf("Plugin %s not found", name))
} }
return nil return nil
} }
@@ -451,15 +453,33 @@ func (c *Config) LoadConfig(path string) error {
return err return err
} }
case "outputs": case "outputs":
for outputName, outputVal := range subTable.Fields {
switch outputSubTable := outputVal.(type) {
case *ast.Table:
if err = c.addOutput(outputName, outputSubTable); err != nil {
return err
}
case []*ast.Table:
for _, t := range outputSubTable {
if err = c.addOutput(outputName, t); err != nil {
return err
}
}
default:
return fmt.Errorf("Unsupported config format: %s",
outputName)
}
}
case "plugins":
for pluginName, pluginVal := range subTable.Fields { for pluginName, pluginVal := range subTable.Fields {
switch pluginSubTable := pluginVal.(type) { switch pluginSubTable := pluginVal.(type) {
case *ast.Table: case *ast.Table:
if err = c.addOutput(pluginName, pluginSubTable); err != nil { if err = c.addPlugin(pluginName, pluginSubTable); err != nil {
return err return err
} }
case []*ast.Table: case []*ast.Table:
for _, t := range pluginSubTable { for _, t := range pluginSubTable {
if err = c.addOutput(pluginName, t); err != nil { if err = c.addPlugin(pluginName, t); err != nil {
return err return err
} }
} }
@@ -468,28 +488,10 @@ func (c *Config) LoadConfig(path string) error {
pluginName) pluginName)
} }
} }
case "inputs", "plugins": // Assume it's a plugin for legacy config file support if no other
for pluginName, pluginVal := range subTable.Fields {
switch pluginSubTable := pluginVal.(type) {
case *ast.Table:
if err = c.addInput(pluginName, pluginSubTable); err != nil {
return err
}
case []*ast.Table:
for _, t := range pluginSubTable {
if err = c.addInput(pluginName, t); err != nil {
return err
}
}
default:
return fmt.Errorf("Unsupported config format: %s",
pluginName)
}
}
// Assume it's an input input for legacy config file support if no other
// identifiers are present // identifiers are present
default: default:
if err = c.addInput(name, subTable); err != nil { if err = c.addPlugin(name, subTable); err != nil {
return err return err
} }
} }
@@ -525,41 +527,41 @@ func (c *Config) addOutput(name string, table *ast.Table) error {
return nil return nil
} }
func (c *Config) addInput(name string, table *ast.Table) error { func (c *Config) addPlugin(name string, table *ast.Table) error {
if len(c.InputFilters) > 0 && !sliceContains(name, c.InputFilters) { if len(c.PluginFilters) > 0 && !sliceContains(name, c.PluginFilters) {
return nil return nil
} }
// Legacy support renaming io input to diskio // Legacy support renaming io plugin to diskio
if name == "io" { if name == "io" {
name = "diskio" name = "diskio"
} }
creator, ok := inputs.Inputs[name] creator, ok := plugins.Plugins[name]
if !ok { if !ok {
return fmt.Errorf("Undefined but requested input: %s", name) return fmt.Errorf("Undefined but requested plugin: %s", name)
} }
input := creator() plugin := creator()
pluginConfig, err := buildInput(name, table) pluginConfig, err := buildPlugin(name, table)
if err != nil { if err != nil {
return err return err
} }
if err := toml.UnmarshalTable(table, input); err != nil { if err := toml.UnmarshalTable(table, plugin); err != nil {
return err return err
} }
rp := &RunningInput{ rp := &RunningPlugin{
Name: name, Name: name,
Input: input, Plugin: plugin,
Config: pluginConfig, Config: pluginConfig,
} }
c.Inputs = append(c.Inputs, rp) c.Plugins = append(c.Plugins, rp)
return nil return nil
} }
// buildFilter builds a Filter (tagpass/tagdrop/pass/drop) to // buildFilter builds a Filter (tagpass/tagdrop/pass/drop) to
// be inserted into the OutputConfig/InputConfig to be used for prefix // be inserted into the OutputConfig/PluginConfig to be used for prefix
// filtering on tags and measurements // filtering on tags and measurements
func buildFilter(tbl *ast.Table) Filter { func buildFilter(tbl *ast.Table) Filter {
f := Filter{} f := Filter{}
@@ -635,11 +637,11 @@ func buildFilter(tbl *ast.Table) Filter {
return f return f
} }
// buildInput parses input specific items from the ast.Table, // buildPlugin parses plugin specific items from the ast.Table,
// builds the filter and returns a // builds the filter and returns a
// InputConfig to be inserted into RunningInput // PluginConfig to be inserted into RunningPlugin
func buildInput(name string, tbl *ast.Table) (*InputConfig, error) { func buildPlugin(name string, tbl *ast.Table) (*PluginConfig, error) {
cp := &InputConfig{Name: name} cp := &PluginConfig{Name: name}
if node, ok := tbl.Fields["interval"]; ok { if node, ok := tbl.Fields["interval"]; ok {
if kv, ok := node.(*ast.KeyValue); ok { if kv, ok := node.(*ast.KeyValue); ok {
if str, ok := kv.Value.(*ast.String); ok { if str, ok := kv.Value.(*ast.String); ok {
@@ -681,7 +683,7 @@ func buildInput(name string, tbl *ast.Table) (*InputConfig, error) {
if node, ok := tbl.Fields["tags"]; ok { if node, ok := tbl.Fields["tags"]; ok {
if subtbl, ok := node.(*ast.Table); ok { if subtbl, ok := node.(*ast.Table); ok {
if err := toml.UnmarshalTable(subtbl, cp.Tags); err != nil { if err := toml.UnmarshalTable(subtbl, cp.Tags); err != nil {
log.Printf("Could not parse tags for input %s\n", name) log.Printf("Could not parse tags for plugin %s\n", name)
} }
} }
} }
@@ -696,7 +698,7 @@ func buildInput(name string, tbl *ast.Table) (*InputConfig, error) {
} }
// buildOutput parses output specific items from the ast.Table, builds the filter and returns an // buildOutput parses output specific items from the ast.Table, builds the filter and returns an
// OutputConfig to be inserted into RunningInput // OutputConfig to be inserted into RunningPlugin
// Note: error exists in the return for future calls that might require error // Note: error exists in the return for future calls that might require error
func buildOutput(name string, tbl *ast.Table) (*OutputConfig, error) { func buildOutput(name string, tbl *ast.Table) (*OutputConfig, error) {
oc := &OutputConfig{ oc := &OutputConfig{

View File

@@ -4,21 +4,21 @@ import (
"testing" "testing"
"time" "time"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
"github.com/influxdb/telegraf/plugins/inputs/exec" "github.com/influxdb/telegraf/plugins/exec"
"github.com/influxdb/telegraf/plugins/inputs/memcached" "github.com/influxdb/telegraf/plugins/memcached"
"github.com/influxdb/telegraf/plugins/inputs/procstat" "github.com/influxdb/telegraf/plugins/procstat"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestConfig_LoadSingleInput(t *testing.T) { func TestConfig_LoadSinglePlugin(t *testing.T) {
c := NewConfig() c := NewConfig()
c.LoadConfig("./testdata/single_plugin.toml") c.LoadConfig("./testdata/single_plugin.toml")
memcached := inputs.Inputs["memcached"]().(*memcached.Memcached) memcached := plugins.Plugins["memcached"]().(*memcached.Memcached)
memcached.Servers = []string{"localhost"} memcached.Servers = []string{"localhost"}
mConfig := &InputConfig{ mConfig := &PluginConfig{
Name: "memcached", Name: "memcached",
Filter: Filter{ Filter: Filter{
Drop: []string{"other", "stuff"}, Drop: []string{"other", "stuff"},
@@ -39,11 +39,10 @@ func TestConfig_LoadSingleInput(t *testing.T) {
}, },
Interval: 5 * time.Second, Interval: 5 * time.Second,
} }
mConfig.Tags = make(map[string]string)
assert.Equal(t, memcached, c.Inputs[0].Input, assert.Equal(t, memcached, c.Plugins[0].Plugin,
"Testdata did not produce a correct memcached struct.") "Testdata did not produce a correct memcached struct.")
assert.Equal(t, mConfig, c.Inputs[0].Config, assert.Equal(t, mConfig, c.Plugins[0].Config,
"Testdata did not produce correct memcached metadata.") "Testdata did not produce correct memcached metadata.")
} }
@@ -58,10 +57,10 @@ func TestConfig_LoadDirectory(t *testing.T) {
t.Error(err) t.Error(err)
} }
memcached := inputs.Inputs["memcached"]().(*memcached.Memcached) memcached := plugins.Plugins["memcached"]().(*memcached.Memcached)
memcached.Servers = []string{"localhost"} memcached.Servers = []string{"localhost"}
mConfig := &InputConfig{ mConfig := &PluginConfig{
Name: "memcached", Name: "memcached",
Filter: Filter{ Filter: Filter{
Drop: []string{"other", "stuff"}, Drop: []string{"other", "stuff"},
@@ -82,40 +81,45 @@ func TestConfig_LoadDirectory(t *testing.T) {
}, },
Interval: 5 * time.Second, Interval: 5 * time.Second,
} }
mConfig.Tags = make(map[string]string) assert.Equal(t, memcached, c.Plugins[0].Plugin,
assert.Equal(t, memcached, c.Inputs[0].Input,
"Testdata did not produce a correct memcached struct.") "Testdata did not produce a correct memcached struct.")
assert.Equal(t, mConfig, c.Inputs[0].Config, assert.Equal(t, mConfig, c.Plugins[0].Config,
"Testdata did not produce correct memcached metadata.") "Testdata did not produce correct memcached metadata.")
ex := inputs.Inputs["exec"]().(*exec.Exec) ex := plugins.Plugins["exec"]().(*exec.Exec)
ex.Command = "/usr/bin/myothercollector --foo=bar" ex.Commands = []*exec.Command{
eConfig := &InputConfig{ &exec.Command{
Name: "exec", Command: "/usr/bin/myothercollector --foo=bar",
MeasurementSuffix: "_myothercollector", Name: "myothercollector",
},
} }
eConfig.Tags = make(map[string]string) eConfig := &PluginConfig{Name: "exec"}
assert.Equal(t, ex, c.Inputs[1].Input, assert.Equal(t, ex, c.Plugins[1].Plugin,
"Merged Testdata did not produce a correct exec struct.") "Merged Testdata did not produce a correct exec struct.")
assert.Equal(t, eConfig, c.Inputs[1].Config, assert.Equal(t, eConfig, c.Plugins[1].Config,
"Merged Testdata did not produce correct exec metadata.") "Merged Testdata did not produce correct exec metadata.")
memcached.Servers = []string{"192.168.1.1"} memcached.Servers = []string{"192.168.1.1"}
assert.Equal(t, memcached, c.Inputs[2].Input, assert.Equal(t, memcached, c.Plugins[2].Plugin,
"Testdata did not produce a correct memcached struct.") "Testdata did not produce a correct memcached struct.")
assert.Equal(t, mConfig, c.Inputs[2].Config, assert.Equal(t, mConfig, c.Plugins[2].Config,
"Testdata did not produce correct memcached metadata.") "Testdata did not produce correct memcached metadata.")
pstat := inputs.Inputs["procstat"]().(*procstat.Procstat) pstat := plugins.Plugins["procstat"]().(*procstat.Procstat)
pstat.PidFile = "/var/run/grafana-server.pid" pstat.Specifications = []*procstat.Specification{
&procstat.Specification{
PidFile: "/var/run/grafana-server.pid",
},
&procstat.Specification{
PidFile: "/var/run/influxdb/influxd.pid",
},
}
pConfig := &InputConfig{Name: "procstat"} pConfig := &PluginConfig{Name: "procstat"}
pConfig.Tags = make(map[string]string)
assert.Equal(t, pstat, c.Inputs[3].Input, assert.Equal(t, pstat, c.Plugins[3].Plugin,
"Merged Testdata did not produce a correct procstat struct.") "Merged Testdata did not produce a correct procstat struct.")
assert.Equal(t, pConfig, c.Inputs[3].Config, assert.Equal(t, pConfig, c.Plugins[3].Config,
"Merged Testdata did not produce correct procstat metadata.") "Merged Testdata did not produce correct procstat metadata.")
} }

View File

@@ -1,9 +1,9 @@
[[inputs.memcached]] [[plugins.memcached]]
servers = ["localhost"] servers = ["localhost"]
pass = ["some", "strings"] pass = ["some", "strings"]
drop = ["other", "stuff"] drop = ["other", "stuff"]
interval = "5s" interval = "5s"
[inputs.memcached.tagpass] [plugins.memcached.tagpass]
goodtag = ["mytag"] goodtag = ["mytag"]
[inputs.memcached.tagdrop] [plugins.memcached.tagdrop]
badtag = ["othertag"] badtag = ["othertag"]

View File

@@ -1,4 +1,8 @@
[[inputs.exec]] [[plugins.exec]]
# specify commands via an array of tables
[[plugins.exec.commands]]
# the command to run # the command to run
command = "/usr/bin/myothercollector --foo=bar" command = "/usr/bin/myothercollector --foo=bar"
name_suffix = "_myothercollector"
# name of the command (used as a prefix for measurements)
name = "myothercollector"

View File

@@ -1,9 +1,9 @@
[[inputs.memcached]] [[plugins.memcached]]
servers = ["192.168.1.1"] servers = ["192.168.1.1"]
pass = ["some", "strings"] pass = ["some", "strings"]
drop = ["other", "stuff"] drop = ["other", "stuff"]
interval = "5s" interval = "5s"
[inputs.memcached.tagpass] [plugins.memcached.tagpass]
goodtag = ["mytag"] goodtag = ["mytag"]
[inputs.memcached.tagdrop] [plugins.memcached.tagdrop]
badtag = ["othertag"] badtag = ["othertag"]

View File

@@ -1,2 +1,5 @@
[[inputs.procstat]] [[plugins.procstat]]
[[plugins.procstat.specifications]]
pid_file = "/var/run/grafana-server.pid" pid_file = "/var/run/grafana-server.pid"
[[plugins.procstat.specifications]]
pid_file = "/var/run/influxdb/influxd.pid"

View File

@@ -1,7 +1,7 @@
# Telegraf configuration # Telegraf configuration
# Telegraf is entirely plugin driven. All metrics are gathered from the # Telegraf is entirely plugin driven. All metrics are gathered from the
# declared inputs. # declared plugins.
# Even if a plugin has no configuration, it must be declared in here # Even if a plugin has no configuration, it must be declared in here
# to be active. Declaring a plugin means just specifying the name # to be active. Declaring a plugin means just specifying the name
@@ -21,13 +21,20 @@
# Tags can also be specified via a normal map, but only one form at a time: # Tags can also be specified via a normal map, but only one form at a time:
[tags] [tags]
dc = "us-east-1" # dc = "us-east-1"
# Configuration for telegraf agent # Configuration for telegraf agent
[agent] [agent]
# Default data collection interval for all plugins # Default data collection interval for all plugins
interval = "10s" interval = "10s"
# If utc = false, uses local time (utc is highly recommended)
utc = true
# Precision of writes, valid values are n, u, ms, s, m, and h
# note: using second precision greatly helps InfluxDB compression
precision = "s"
# run telegraf in debug mode # run telegraf in debug mode
debug = false debug = false
@@ -39,6 +46,8 @@
# OUTPUTS # # OUTPUTS #
############################################################################### ###############################################################################
[outputs]
# Configuration for influxdb server to send metrics to # Configuration for influxdb server to send metrics to
[[outputs.influxdb]] [[outputs.influxdb]]
# The full HTTP endpoint URL for your InfluxDB instance # The full HTTP endpoint URL for your InfluxDB instance
@@ -49,6 +58,17 @@
# The target database for metrics. This database must already exist # The target database for metrics. This database must already exist
database = "telegraf" # required. database = "telegraf" # required.
# Connection timeout (for the connection with InfluxDB), formatted as a string.
# Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
# If not provided, will default to 0 (no timeout)
# timeout = "5s"
# username = "telegraf"
# password = "metricsmetricsmetricsmetrics"
# Set the user agent for the POSTs (can be useful for log differentiation)
# user_agent = "telegraf"
[[outputs.influxdb]] [[outputs.influxdb]]
urls = ["udp://localhost:8089"] urls = ["udp://localhost:8089"]
database = "udp-telegraf" database = "udp-telegraf"
@@ -68,13 +88,15 @@
# PLUGINS # # PLUGINS #
############################################################################### ###############################################################################
[plugins]
# Read Apache status information (mod_status) # Read Apache status information (mod_status)
[[inputs.apache]] [[plugins.apache]]
# An array of Apache status URI to gather stats. # An array of Apache status URI to gather stats.
urls = ["http://localhost/server-status?auto"] urls = ["http://localhost/server-status?auto"]
# Read metrics about cpu usage # Read metrics about cpu usage
[[inputs.cpu]] [[plugins.cpu]]
# Whether to report per-cpu stats or not # Whether to report per-cpu stats or not
percpu = true percpu = true
# Whether to report total system cpu stats or not # Whether to report total system cpu stats or not
@@ -83,11 +105,11 @@
drop = ["cpu_time"] drop = ["cpu_time"]
# Read metrics about disk usage by mount point # Read metrics about disk usage by mount point
[[inputs.diskio]] [[plugins.diskio]]
# no configuration # no configuration
# Read metrics from one or many disque servers # Read metrics from one or many disque servers
[[inputs.disque]] [[plugins.disque]]
# An array of URI to gather stats about. Specify an ip or hostname # An array of URI to gather stats about. Specify an ip or hostname
# with optional port and password. ie disque://localhost, disque://10.10.3.33:18832, # with optional port and password. ie disque://localhost, disque://10.10.3.33:18832,
# 10.0.0.1:10000, etc. # 10.0.0.1:10000, etc.
@@ -96,7 +118,7 @@
servers = ["localhost"] servers = ["localhost"]
# Read stats from one or more Elasticsearch servers or clusters # Read stats from one or more Elasticsearch servers or clusters
[[inputs.elasticsearch]] [[plugins.elasticsearch]]
# specify a list of one or more Elasticsearch servers # specify a list of one or more Elasticsearch servers
servers = ["http://localhost:9200"] servers = ["http://localhost:9200"]
@@ -105,13 +127,17 @@
local = true local = true
# Read flattened metrics from one or more commands that output JSON to stdout # Read flattened metrics from one or more commands that output JSON to stdout
[[inputs.exec]] [[plugins.exec]]
# specify commands via an array of tables
[[exec.commands]]
# the command to run # the command to run
command = "/usr/bin/mycollector --foo=bar" command = "/usr/bin/mycollector --foo=bar"
name_suffix = "_mycollector"
# name of the command (used as a prefix for measurements)
name = "mycollector"
# Read metrics of haproxy, via socket or csv stats page # Read metrics of haproxy, via socket or csv stats page
[[inputs.haproxy]] [[plugins.haproxy]]
# An array of address to gather stats about. Specify an ip on hostname # An array of address to gather stats about. Specify an ip on hostname
# with optional port. ie localhost, 10.10.3.33:1936, etc. # with optional port. ie localhost, 10.10.3.33:1936, etc.
# #
@@ -121,30 +147,33 @@
# servers = ["socket:/run/haproxy/admin.sock"] # servers = ["socket:/run/haproxy/admin.sock"]
# Read flattened metrics from one or more JSON HTTP endpoints # Read flattened metrics from one or more JSON HTTP endpoints
[[inputs.httpjson]] [[plugins.httpjson]]
# a name for the service being polled # Specify services via an array of tables
name = "webserver_stats" [[httpjson.services]]
# URL of each server in the service's cluster # a name for the service being polled
servers = [ name = "webserver_stats"
"http://localhost:9999/stats/",
"http://localhost:9998/stats/",
]
# HTTP method to use (case-sensitive) # URL of each server in the service's cluster
method = "GET" servers = [
"http://localhost:9999/stats/",
"http://localhost:9998/stats/",
]
# HTTP parameters (all values must be strings) # HTTP method to use (case-sensitive)
[httpjson.parameters] method = "GET"
event_type = "cpu_spike"
threshold = "0.75" # HTTP parameters (all values must be strings)
[httpjson.services.parameters]
event_type = "cpu_spike"
threshold = "0.75"
# Read metrics about disk IO by device # Read metrics about disk IO by device
[[inputs.diskio]] [[plugins.io]]
# no configuration # no configuration
# read metrics from a Kafka topic # read metrics from a Kafka topic
[[inputs.kafka_consumer]] [[plugins.kafka_consumer]]
# topic(s) to consume # topic(s) to consume
topics = ["telegraf"] topics = ["telegraf"]
# an array of Zookeeper connection strings # an array of Zookeeper connection strings
@@ -157,7 +186,7 @@
offset = "oldest" offset = "oldest"
# Read metrics from a LeoFS Server via SNMP # Read metrics from a LeoFS Server via SNMP
[[inputs.leofs]] [[plugins.leofs]]
# An array of URI to gather stats about LeoFS. # An array of URI to gather stats about LeoFS.
# Specify an ip or hostname with port. ie 127.0.0.1:4020 # Specify an ip or hostname with port. ie 127.0.0.1:4020
# #
@@ -165,7 +194,7 @@
servers = ["127.0.0.1:4021"] servers = ["127.0.0.1:4021"]
# Read metrics from local Lustre service on OST, MDS # Read metrics from local Lustre service on OST, MDS
[[inputs.lustre2]] [[plugins.lustre2]]
# An array of /proc globs to search for Lustre stats # An array of /proc globs to search for Lustre stats
# If not specified, the default will work on Lustre 2.5.x # If not specified, the default will work on Lustre 2.5.x
# #
@@ -173,11 +202,11 @@
# mds_procfiles = ["/proc/fs/lustre/mdt/*/md_stats"] # mds_procfiles = ["/proc/fs/lustre/mdt/*/md_stats"]
# Read metrics about memory usage # Read metrics about memory usage
[[inputs.mem]] [[plugins.mem]]
# no configuration # no configuration
# Read metrics from one or many memcached servers # Read metrics from one or many memcached servers
[[inputs.memcached]] [[plugins.memcached]]
# An array of address to gather stats about. Specify an ip on hostname # An array of address to gather stats about. Specify an ip on hostname
# with optional port. ie localhost, 10.0.0.1:11211, etc. # with optional port. ie localhost, 10.0.0.1:11211, etc.
# #
@@ -185,7 +214,7 @@
servers = ["localhost"] servers = ["localhost"]
# Read metrics from one or many MongoDB servers # Read metrics from one or many MongoDB servers
[[inputs.mongodb]] [[plugins.mongodb]]
# An array of URI to gather stats about. Specify an ip or hostname # An array of URI to gather stats about. Specify an ip or hostname
# with optional port add password. ie mongodb://user:auth_key@10.10.3.30:27017, # with optional port add password. ie mongodb://user:auth_key@10.10.3.30:27017,
# mongodb://10.10.3.33:18832, 10.0.0.1:10000, etc. # mongodb://10.10.3.33:18832, 10.0.0.1:10000, etc.
@@ -194,7 +223,7 @@
servers = ["127.0.0.1:27017"] servers = ["127.0.0.1:27017"]
# Read metrics from one or many mysql servers # Read metrics from one or many mysql servers
[[inputs.mysql]] [[plugins.mysql]]
# specify servers via a url matching: # specify servers via a url matching:
# [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]] # [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify]]
# e.g. # e.g.
@@ -205,7 +234,7 @@
servers = ["localhost"] servers = ["localhost"]
# Read metrics about network interface usage # Read metrics about network interface usage
[[inputs.net]] [[plugins.net]]
# By default, telegraf gathers stats from any up interface (excluding loopback) # By default, telegraf gathers stats from any up interface (excluding loopback)
# Setting interfaces will tell it to gather these explicit interfaces, # Setting interfaces will tell it to gather these explicit interfaces,
# regardless of status. # regardless of status.
@@ -213,12 +242,12 @@
# interfaces = ["eth0", ... ] # interfaces = ["eth0", ... ]
# Read Nginx's basic status information (ngx_http_stub_status_module) # Read Nginx's basic status information (ngx_http_stub_status_module)
[[inputs.nginx]] [[plugins.nginx]]
# An array of Nginx stub_status URI to gather stats. # An array of Nginx stub_status URI to gather stats.
urls = ["http://localhost/status"] urls = ["http://localhost/status"]
# Ping given url(s) and return statistics # Ping given url(s) and return statistics
[[inputs.ping]] [[plugins.ping]]
# urls to ping # urls to ping
urls = ["www.google.com"] # required urls = ["www.google.com"] # required
# number of pings to send (ping -c <COUNT>) # number of pings to send (ping -c <COUNT>)
@@ -231,7 +260,10 @@
interface = "" interface = ""
# Read metrics from one or many postgresql servers # Read metrics from one or many postgresql servers
[[inputs.postgresql]] [[plugins.postgresql]]
# specify servers via an array of tables
[[postgresql.servers]]
# specify address via a url matching: # specify address via a url matching:
# postgres://[pqgotest[:password]]@localhost[/dbname]?sslmode=[disable|verify-ca|verify-full] # postgres://[pqgotest[:password]]@localhost[/dbname]?sslmode=[disable|verify-ca|verify-full]
# or a simple string: # or a simple string:
@@ -258,13 +290,14 @@
# address = "influx@remoteserver" # address = "influx@remoteserver"
# Read metrics from one or many prometheus clients # Read metrics from one or many prometheus clients
[[inputs.prometheus]] [[plugins.prometheus]]
# An array of urls to scrape metrics from. # An array of urls to scrape metrics from.
urls = ["http://localhost:9100/metrics"] urls = ["http://localhost:9100/metrics"]
# Read metrics from one or many RabbitMQ servers via the management API # Read metrics from one or many RabbitMQ servers via the management API
[[inputs.rabbitmq]] [[plugins.rabbitmq]]
# Specify servers via an array of tables # Specify servers via an array of tables
[[rabbitmq.servers]]
# name = "rmq-server-1" # optional tag # name = "rmq-server-1" # optional tag
# url = "http://localhost:15672" # url = "http://localhost:15672"
# username = "guest" # username = "guest"
@@ -275,7 +308,7 @@
# nodes = ["rabbit@node1", "rabbit@node2"] # nodes = ["rabbit@node1", "rabbit@node2"]
# Read metrics from one or many redis servers # Read metrics from one or many redis servers
[[inputs.redis]] [[plugins.redis]]
# An array of URI to gather stats about. Specify an ip or hostname # An array of URI to gather stats about. Specify an ip or hostname
# with optional port add password. ie redis://localhost, redis://10.10.3.33:18832, # with optional port add password. ie redis://localhost, redis://10.10.3.33:18832,
# 10.0.0.1:10000, etc. # 10.0.0.1:10000, etc.
@@ -284,7 +317,7 @@
servers = ["localhost"] servers = ["localhost"]
# Read metrics from one or many RethinkDB servers # Read metrics from one or many RethinkDB servers
[[inputs.rethinkdb]] [[plugins.rethinkdb]]
# An array of URI to gather stats about. Specify an ip or hostname # An array of URI to gather stats about. Specify an ip or hostname
# with optional port add password. ie rethinkdb://user:auth_key@10.10.3.30:28105, # with optional port add password. ie rethinkdb://user:auth_key@10.10.3.30:28105,
# rethinkdb://10.10.3.33:18832, 10.0.0.1:10000, etc. # rethinkdb://10.10.3.33:18832, 10.0.0.1:10000, etc.
@@ -293,9 +326,9 @@
servers = ["127.0.0.1:28015"] servers = ["127.0.0.1:28015"]
# Read metrics about swap memory usage # Read metrics about swap memory usage
[[inputs.swap]] [[plugins.swap]]
# no configuration # no configuration
# Read metrics about system load & uptime # Read metrics about system load & uptime
[[inputs.system]] [[plugins.system]]
# no configuration # no configuration

View File

@@ -51,7 +51,7 @@ func (f *JSONFlattener) FlattenJSON(
} }
case float64: case float64:
f.Fields[fieldname] = t f.Fields[fieldname] = t
case bool, string, []interface{}, nil: case bool, string, []interface{}:
// ignored types // ignored types
return nil return nil
default: default:

16
outputs/all/all.go Normal file
View File

@@ -0,0 +1,16 @@
package all
import (
_ "github.com/influxdb/telegraf/outputs/amon"
_ "github.com/influxdb/telegraf/outputs/amqp"
_ "github.com/influxdb/telegraf/outputs/datadog"
_ "github.com/influxdb/telegraf/outputs/influxdb"
_ "github.com/influxdb/telegraf/outputs/kafka"
_ "github.com/influxdb/telegraf/outputs/kinesis"
_ "github.com/influxdb/telegraf/outputs/librato"
_ "github.com/influxdb/telegraf/outputs/mqtt"
_ "github.com/influxdb/telegraf/outputs/nsq"
_ "github.com/influxdb/telegraf/outputs/opentsdb"
_ "github.com/influxdb/telegraf/outputs/prometheus_client"
_ "github.com/influxdb/telegraf/outputs/riemann"
)

View File

@@ -10,7 +10,7 @@ import (
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type Amon struct { type Amon struct {

View File

@@ -18,7 +18,7 @@ func TestBuildPoint(t *testing.T) {
err error err error
}{ }{
{ {
testutil.TestPoint(float64(0.0), "testpt"), testutil.TestPoint(float64(0.0)),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
0.0, 0.0,
@@ -26,7 +26,7 @@ func TestBuildPoint(t *testing.T) {
nil, nil,
}, },
{ {
testutil.TestPoint(float64(1.0), "testpt"), testutil.TestPoint(float64(1.0)),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
1.0, 1.0,
@@ -34,7 +34,7 @@ func TestBuildPoint(t *testing.T) {
nil, nil,
}, },
{ {
testutil.TestPoint(int(10), "testpt"), testutil.TestPoint(int(10)),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
10.0, 10.0,
@@ -42,7 +42,7 @@ func TestBuildPoint(t *testing.T) {
nil, nil,
}, },
{ {
testutil.TestPoint(int32(112345), "testpt"), testutil.TestPoint(int32(112345)),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
112345.0, 112345.0,
@@ -50,7 +50,7 @@ func TestBuildPoint(t *testing.T) {
nil, nil,
}, },
{ {
testutil.TestPoint(int64(112345), "testpt"), testutil.TestPoint(int64(112345)),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
112345.0, 112345.0,
@@ -58,7 +58,7 @@ func TestBuildPoint(t *testing.T) {
nil, nil,
}, },
{ {
testutil.TestPoint(float32(11234.5), "testpt"), testutil.TestPoint(float32(11234.5)),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
11234.5, 11234.5,
@@ -66,7 +66,7 @@ func TestBuildPoint(t *testing.T) {
nil, nil,
}, },
{ {
testutil.TestPoint("11234.5", "testpt"), testutil.TestPoint("11234.5"),
Point{ Point{
float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()), float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()),
11234.5, 11234.5,
@@ -75,16 +75,15 @@ func TestBuildPoint(t *testing.T) {
}, },
} }
for _, tt := range tagtests { for _, tt := range tagtests {
pt, err := buildPoints(tt.ptIn) pt, err := buildPoint(tt.ptIn)
if err != nil && tt.err == nil { if err != nil && tt.err == nil {
t.Errorf("%s: unexpected error, %+v\n", tt.ptIn.Name(), err) t.Errorf("%s: unexpected error, %+v\n", tt.ptIn.Name(), err)
} }
if tt.err != nil && err == nil { if tt.err != nil && err == nil {
t.Errorf("%s: expected an error (%s) but none returned", tt.ptIn.Name(), tt.err.Error()) t.Errorf("%s: expected an error (%s) but none returned", tt.ptIn.Name(), tt.err.Error())
} }
if !reflect.DeepEqual(pt["value"], tt.outPt) && tt.err == nil { if !reflect.DeepEqual(pt, tt.outPt) && tt.err == nil {
t.Errorf("%s: \nexpected %+v\ngot %+v\n", t.Errorf("%s: \nexpected %+v\ngot %+v\n", tt.ptIn.Name(), tt.outPt, pt)
tt.ptIn.Name(), tt.outPt, pt["value"])
} }
} }
} }

View File

@@ -8,7 +8,7 @@ import (
"time" "time"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
"github.com/streadway/amqp" "github.com/streadway/amqp"
) )

View File

@@ -12,7 +12,7 @@ import (
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type Datadog struct { type Datadog struct {

View File

@@ -162,16 +162,15 @@ func TestBuildPoint(t *testing.T) {
}, },
} }
for _, tt := range tagtests { for _, tt := range tagtests {
pt, err := buildPoints(tt.ptIn) pt, err := buildPoint(tt.ptIn)
if err != nil && tt.err == nil { if err != nil && tt.err == nil {
t.Errorf("%s: unexpected error, %+v\n", tt.ptIn.Name(), err) t.Errorf("%s: unexpected error, %+v\n", tt.ptIn.Name(), err)
} }
if tt.err != nil && err == nil { if tt.err != nil && err == nil {
t.Errorf("%s: expected an error (%s) but none returned", tt.ptIn.Name(), tt.err.Error()) t.Errorf("%s: expected an error (%s) but none returned", tt.ptIn.Name(), tt.err.Error())
} }
if !reflect.DeepEqual(pt["value"], tt.outPt) && tt.err == nil { if !reflect.DeepEqual(pt, tt.outPt) && tt.err == nil {
t.Errorf("%s: \nexpected %+v\ngot %+v\n", t.Errorf("%s: \nexpected %+v\ngot %+v\n", tt.ptIn.Name(), tt.outPt, pt)
tt.ptIn.Name(), tt.outPt, pt["value"])
} }
} }
} }

View File

@@ -11,7 +11,7 @@ import (
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type InfluxDB struct { type InfluxDB struct {

View File

@@ -6,7 +6,7 @@ import (
"github.com/Shopify/sarama" "github.com/Shopify/sarama"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type Kafka struct { type Kafka struct {

View File

@@ -16,7 +16,7 @@ import (
"github.com/aws/aws-sdk-go/service/kinesis" "github.com/aws/aws-sdk-go/service/kinesis"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type KinesisOutput struct { type KinesisOutput struct {

View File

@@ -9,7 +9,7 @@ import (
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type Librato struct { type Librato struct {

View File

@@ -142,20 +142,15 @@ func TestBuildGauge(t *testing.T) {
l := NewLibrato(fakeUrl) l := NewLibrato(fakeUrl)
for _, gt := range gaugeTests { for _, gt := range gaugeTests {
gauges, err := l.buildGauges(gt.ptIn) gauge, err := l.buildGauge(gt.ptIn)
if err != nil && gt.err == nil { if err != nil && gt.err == nil {
t.Errorf("%s: unexpected error, %+v\n", gt.ptIn.Name(), err) t.Errorf("%s: unexpected error, %+v\n", gt.ptIn.Name(), err)
} }
if gt.err != nil && err == nil { if gt.err != nil && err == nil {
t.Errorf("%s: expected an error (%s) but none returned", t.Errorf("%s: expected an error (%s) but none returned", gt.ptIn.Name(), gt.err.Error())
gt.ptIn.Name(), gt.err.Error())
} }
if len(gauges) == 0 { if !reflect.DeepEqual(gauge, gt.outGauge) && gt.err == nil {
continue t.Errorf("%s: \nexpected %+v\ngot %+v\n", gt.ptIn.Name(), gt.outGauge, gauge)
}
if gt.err == nil && !reflect.DeepEqual(gauges[0], gt.outGauge) {
t.Errorf("%s: \nexpected %+v\ngot %+v\n",
gt.ptIn.Name(), gt.outGauge, gauges[0])
} }
} }
} }
@@ -203,18 +198,15 @@ func TestBuildGaugeWithSource(t *testing.T) {
l := NewLibrato(fakeUrl) l := NewLibrato(fakeUrl)
l.SourceTag = "hostname" l.SourceTag = "hostname"
for _, gt := range gaugeTests { for _, gt := range gaugeTests {
gauges, err := l.buildGauges(gt.ptIn) gauge, err := l.buildGauge(gt.ptIn)
if err != nil && gt.err == nil { if err != nil && gt.err == nil {
t.Errorf("%s: unexpected error, %+v\n", gt.ptIn.Name(), err) t.Errorf("%s: unexpected error, %+v\n", gt.ptIn.Name(), err)
} }
if gt.err != nil && err == nil { if gt.err != nil && err == nil {
t.Errorf("%s: expected an error (%s) but none returned", gt.ptIn.Name(), gt.err.Error()) t.Errorf("%s: expected an error (%s) but none returned", gt.ptIn.Name(), gt.err.Error())
} }
if len(gauges) == 0 { if !reflect.DeepEqual(gauge, gt.outGauge) && gt.err == nil {
continue t.Errorf("%s: \nexpected %+v\ngot %+v\n", gt.ptIn.Name(), gt.outGauge, gauge)
}
if gt.err == nil && !reflect.DeepEqual(gauges[0], gt.outGauge) {
t.Errorf("%s: \nexpected %+v\ngot %+v\n", gt.ptIn.Name(), gt.outGauge, gauges[0])
} }
} }
} }

View File

@@ -12,7 +12,7 @@ import (
paho "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git" paho "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
const MaxClientIdLen = 8 const MaxClientIdLen = 8

View File

@@ -3,7 +3,7 @@ package nsq
import ( import (
"fmt" "fmt"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
"github.com/nsqio/go-nsq" "github.com/nsqio/go-nsq"
) )

View File

@@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type OpenTSDB struct { type OpenTSDB struct {

View File

@@ -6,7 +6,7 @@ import (
"net/http" "net/http"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )

View File

@@ -3,11 +3,11 @@ package prometheus_client
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/inputs/prometheus" "github.com/influxdb/telegraf/plugins/prometheus"
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var pTesting *PrometheusClient var pTesting *PrometheusClient
@@ -48,8 +48,7 @@ func TestPrometheusWritePointEmptyTag(t *testing.T) {
require.NoError(t, p.Gather(&acc)) require.NoError(t, p.Gather(&acc))
for _, e := range expected { for _, e := range expected {
acc.AssertContainsFields(t, "prometheus_"+e.name, assert.NoError(t, acc.ValidateValue(e.name, e.value))
map[string]interface{}{"value": e.value})
} }
} }
@@ -89,8 +88,7 @@ func TestPrometheusWritePointTag(t *testing.T) {
require.NoError(t, p.Gather(&acc)) require.NoError(t, p.Gather(&acc))
for _, e := range expected { for _, e := range expected {
acc.AssertContainsFields(t, "prometheus_"+e.name, assert.True(t, acc.CheckTaggedValue(e.name, e.value, tags))
map[string]interface{}{"value": e.value})
} }
} }

View File

@@ -7,7 +7,7 @@ import (
"github.com/amir/raidman" "github.com/amir/raidman"
"github.com/influxdb/influxdb/client/v2" "github.com/influxdb/influxdb/client/v2"
"github.com/influxdb/telegraf/plugins/outputs" "github.com/influxdb/telegraf/outputs"
) )
type Riemann struct { type Riemann struct {

View File

@@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
"net" "net"
"strconv" "strconv"
"strings" "strings"
@@ -119,7 +119,7 @@ func (a *Aerospike) Description() string {
return "Read stats from an aerospike server" return "Read stats from an aerospike server"
} }
func (a *Aerospike) Gather(acc inputs.Accumulator) error { func (a *Aerospike) Gather(acc plugins.Accumulator) error {
if len(a.Servers) == 0 { if len(a.Servers) == 0 {
return a.gatherServer("127.0.0.1:3000", acc) return a.gatherServer("127.0.0.1:3000", acc)
} }
@@ -140,7 +140,7 @@ func (a *Aerospike) Gather(acc inputs.Accumulator) error {
return outerr return outerr
} }
func (a *Aerospike) gatherServer(host string, acc inputs.Accumulator) error { func (a *Aerospike) gatherServer(host string, acc plugins.Accumulator) error {
aerospikeInfo, err := getMap(STATISTICS_COMMAND, host) aerospikeInfo, err := getMap(STATISTICS_COMMAND, host)
if err != nil { if err != nil {
return fmt.Errorf("Aerospike info failed: %s", err) return fmt.Errorf("Aerospike info failed: %s", err)
@@ -249,7 +249,7 @@ func get(key []byte, host string) (map[string]string, error) {
func readAerospikeStats( func readAerospikeStats(
stats map[string]string, stats map[string]string,
acc inputs.Accumulator, acc plugins.Accumulator,
host string, host string,
namespace string, namespace string,
) { ) {
@@ -336,7 +336,7 @@ func msgLenFromBytes(buf [6]byte) int64 {
} }
func init() { func init() {
inputs.Add("aerospike", func() inputs.Input { plugins.Add("aerospike", func() plugins.Plugin {
return &Aerospike{} return &Aerospike{}
}) })
} }

View File

@@ -1,12 +1,11 @@
package aerospike package aerospike
import ( import (
"reflect"
"testing"
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"reflect"
"testing"
) )
func TestAerospikeStatistics(t *testing.T) { func TestAerospikeStatistics(t *testing.T) {
@@ -32,7 +31,7 @@ func TestAerospikeStatistics(t *testing.T) {
} }
for _, metric := range asMetrics { for _, metric := range asMetrics {
assert.True(t, acc.HasIntField("aerospike", metric), metric) assert.True(t, acc.HasIntValue(metric), metric)
} }
} }
@@ -50,16 +49,13 @@ func TestReadAerospikeStatsNoNamespace(t *testing.T) {
"stat_read_reqs": "12345", "stat_read_reqs": "12345",
} }
readAerospikeStats(stats, &acc, "host1", "") readAerospikeStats(stats, &acc, "host1", "")
for k := range stats {
fields := map[string]interface{}{ if k == "stat-write-errs" {
"stat_write_errs": int64(12345), k = "stat_write_errs"
"stat_read_reqs": int64(12345), }
assert.True(t, acc.HasMeasurement(k))
assert.True(t, acc.CheckValue(k, int64(12345)))
} }
tags := map[string]string{
"aerospike_host": "host1",
"namespace": "_service",
}
acc.AssertContainsTaggedFields(t, "aerospike", fields, tags)
} }
func TestReadAerospikeStatsNamespace(t *testing.T) { func TestReadAerospikeStatsNamespace(t *testing.T) {
@@ -70,15 +66,13 @@ func TestReadAerospikeStatsNamespace(t *testing.T) {
} }
readAerospikeStats(stats, &acc, "host1", "test") readAerospikeStats(stats, &acc, "host1", "test")
fields := map[string]interface{}{
"stat_write_errs": int64(12345),
"stat_read_reqs": int64(12345),
}
tags := map[string]string{ tags := map[string]string{
"aerospike_host": "host1", "aerospike_host": "host1",
"namespace": "test", "namespace": "test",
} }
acc.AssertContainsTaggedFields(t, "aerospike", fields, tags) for k := range stats {
assert.True(t, acc.ValidateTaggedValue(k, int64(12345), tags) == nil)
}
} }
func TestAerospikeUnmarshalList(t *testing.T) { func TestAerospikeUnmarshalList(t *testing.T) {

37
plugins/all/all.go Normal file
View File

@@ -0,0 +1,37 @@
package all
import (
_ "github.com/influxdb/telegraf/plugins/aerospike"
_ "github.com/influxdb/telegraf/plugins/apache"
_ "github.com/influxdb/telegraf/plugins/bcache"
_ "github.com/influxdb/telegraf/plugins/disque"
_ "github.com/influxdb/telegraf/plugins/elasticsearch"
_ "github.com/influxdb/telegraf/plugins/exec"
_ "github.com/influxdb/telegraf/plugins/haproxy"
_ "github.com/influxdb/telegraf/plugins/httpjson"
_ "github.com/influxdb/telegraf/plugins/influxdb"
_ "github.com/influxdb/telegraf/plugins/jolokia"
_ "github.com/influxdb/telegraf/plugins/kafka_consumer"
_ "github.com/influxdb/telegraf/plugins/leofs"
_ "github.com/influxdb/telegraf/plugins/lustre2"
_ "github.com/influxdb/telegraf/plugins/mailchimp"
_ "github.com/influxdb/telegraf/plugins/memcached"
_ "github.com/influxdb/telegraf/plugins/mongodb"
_ "github.com/influxdb/telegraf/plugins/mysql"
_ "github.com/influxdb/telegraf/plugins/nginx"
_ "github.com/influxdb/telegraf/plugins/phpfpm"
_ "github.com/influxdb/telegraf/plugins/ping"
_ "github.com/influxdb/telegraf/plugins/postgresql"
_ "github.com/influxdb/telegraf/plugins/procstat"
_ "github.com/influxdb/telegraf/plugins/prometheus"
_ "github.com/influxdb/telegraf/plugins/puppetagent"
_ "github.com/influxdb/telegraf/plugins/rabbitmq"
_ "github.com/influxdb/telegraf/plugins/redis"
_ "github.com/influxdb/telegraf/plugins/rethinkdb"
_ "github.com/influxdb/telegraf/plugins/statsd"
_ "github.com/influxdb/telegraf/plugins/system"
_ "github.com/influxdb/telegraf/plugins/trig"
_ "github.com/influxdb/telegraf/plugins/twemproxy"
_ "github.com/influxdb/telegraf/plugins/zfs"
_ "github.com/influxdb/telegraf/plugins/zookeeper"
)

View File

@@ -11,7 +11,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
type Apache struct { type Apache struct {
@@ -31,7 +31,7 @@ func (n *Apache) Description() string {
return "Read Apache status information (mod_status)" return "Read Apache status information (mod_status)"
} }
func (n *Apache) Gather(acc inputs.Accumulator) error { func (n *Apache) Gather(acc plugins.Accumulator) error {
var wg sync.WaitGroup var wg sync.WaitGroup
var outerr error var outerr error
@@ -59,7 +59,7 @@ var tr = &http.Transport{
var client = &http.Client{Transport: tr} var client = &http.Client{Transport: tr}
func (n *Apache) gatherUrl(addr *url.URL, acc inputs.Accumulator) error { func (n *Apache) gatherUrl(addr *url.URL, acc plugins.Accumulator) error {
resp, err := client.Get(addr.String()) resp, err := client.Get(addr.String())
if err != nil { if err != nil {
return fmt.Errorf("error making HTTP request to %s: %s", addr.String(), err) return fmt.Errorf("error making HTTP request to %s: %s", addr.String(), err)
@@ -164,7 +164,7 @@ func getTags(addr *url.URL) map[string]string {
} }
func init() { func init() {
inputs.Add("apache", func() inputs.Input { plugins.Add("apache", func() plugins.Plugin {
return &Apache{} return &Apache{}
}) })
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -43,31 +44,37 @@ func TestHTTPApache(t *testing.T) {
err := a.Gather(&acc) err := a.Gather(&acc)
require.NoError(t, err) require.NoError(t, err)
fields := map[string]interface{}{ testInt := []struct {
"TotalAccesses": float64(1.29811861e+08), measurement string
"TotalkBytes": float64(5.213701865e+09), value float64
"CPULoad": float64(6.51929), }{
"Uptime": float64(941553), {"TotalAccesses", 1.29811861e+08},
"ReqPerSec": float64(137.87), {"TotalkBytes", 5.213701865e+09},
"BytesPerSec": float64(5.67024e+06), {"CPULoad", 6.51929},
"BytesPerReq": float64(41127.4), {"Uptime", 941553},
"BusyWorkers": float64(270), {"ReqPerSec", 137.87},
"IdleWorkers": float64(630), {"BytesPerSec", 5.67024e+06},
"ConnsTotal": float64(1451), {"BytesPerReq", 41127.4},
"ConnsAsyncWriting": float64(32), {"BusyWorkers", 270},
"ConnsAsyncKeepAlive": float64(945), {"IdleWorkers", 630},
"ConnsAsyncClosing": float64(205), {"ConnsTotal", 1451},
"scboard_waiting": float64(630), {"ConnsAsyncWriting", 32},
"scboard_starting": float64(0), {"ConnsAsyncKeepAlive", 945},
"scboard_reading": float64(157), {"ConnsAsyncClosing", 205},
"scboard_sending": float64(113), {"scboard_waiting", 630},
"scboard_keepalive": float64(0), {"scboard_starting", 0},
"scboard_dnslookup": float64(0), {"scboard_reading", 157},
"scboard_closing": float64(0), {"scboard_sending", 113},
"scboard_logging": float64(0), {"scboard_keepalive", 0},
"scboard_finishing": float64(0), {"scboard_dnslookup", 0},
"scboard_idle_cleanup": float64(0), {"scboard_closing", 0},
"scboard_open": float64(2850), {"scboard_logging", 0},
{"scboard_finishing", 0},
{"scboard_idle_cleanup", 0},
{"scboard_open", 2850},
}
for _, test := range testInt {
assert.True(t, acc.CheckValue(test.measurement, test.value))
} }
acc.AssertContainsFields(t, "apache", fields)
} }

View File

@@ -26,27 +26,27 @@ Measurement names:
dirty_data dirty_data
Amount of dirty data for this backing device in the cache. Continuously Amount of dirty data for this backing device in the cache. Continuously
updated unlike the cache set's version, but may be slightly off. updated unlike the cache set's version, but may be slightly off.
bypassed bypassed
Amount of IO (both reads and writes) that has bypassed the cache Amount of IO (both reads and writes) that has bypassed the cache
cache_bypass_hits cache_bypass_hits
cache_bypass_misses cache_bypass_misses
Hits and misses for IO that is intended to skip the cache are still counted, Hits and misses for IO that is intended to skip the cache are still counted,
but broken out here. but broken out here.
cache_hits cache_hits
cache_misses cache_misses
cache_hit_ratio cache_hit_ratio
Hits and misses are counted per individual IO as bcache sees them; a Hits and misses are counted per individual IO as bcache sees them; a
partial hit is counted as a miss. partial hit is counted as a miss.
cache_miss_collisions cache_miss_collisions
Counts instances where data was going to be inserted into the cache from a Counts instances where data was going to be inserted into the cache from a
cache miss, but raced with a write and data was already present (usually 0 cache miss, but raced with a write and data was already present (usually 0
since the synchronization for cache misses was rewritten) since the synchronization for cache misses was rewritten)
cache_readaheads cache_readaheads
Count of times readahead occurred. Count of times readahead occurred.
``` ```
@@ -70,7 +70,7 @@ Using this configuration:
When run with: When run with:
``` ```
./telegraf -config telegraf.conf -input-filter bcache -test ./telegraf -config telegraf.conf -filter bcache -test
``` ```
It produces: It produces:

View File

@@ -8,7 +8,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
type Bcache struct { type Bcache struct {
@@ -69,7 +69,7 @@ func prettyToBytes(v string) uint64 {
return uint64(result) return uint64(result)
} }
func (b *Bcache) gatherBcache(bdev string, acc inputs.Accumulator) error { func (b *Bcache) gatherBcache(bdev string, acc plugins.Accumulator) error {
tags := getTags(bdev) tags := getTags(bdev)
metrics, err := filepath.Glob(bdev + "/stats_total/*") metrics, err := filepath.Glob(bdev + "/stats_total/*")
if len(metrics) < 0 { if len(metrics) < 0 {
@@ -104,7 +104,7 @@ func (b *Bcache) gatherBcache(bdev string, acc inputs.Accumulator) error {
return nil return nil
} }
func (b *Bcache) Gather(acc inputs.Accumulator) error { func (b *Bcache) Gather(acc plugins.Accumulator) error {
bcacheDevsChecked := make(map[string]bool) bcacheDevsChecked := make(map[string]bool)
var restrictDevs bool var restrictDevs bool
if len(b.BcacheDevs) != 0 { if len(b.BcacheDevs) != 0 {
@@ -135,7 +135,7 @@ func (b *Bcache) Gather(acc inputs.Accumulator) error {
} }
func init() { func init() {
inputs.Add("bcache", func() inputs.Input { plugins.Add("bcache", func() plugins.Plugin {
return &Bcache{} return &Bcache{}
}) })
} }

View File

@@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -28,6 +29,11 @@ var (
testBcacheBackingDevPath = os.TempDir() + "/telegraf/sys/devices/virtual/block/md10" testBcacheBackingDevPath = os.TempDir() + "/telegraf/sys/devices/virtual/block/md10"
) )
type metrics struct {
name string
value uint64
}
func TestBcacheGeneratesMetrics(t *testing.T) { func TestBcacheGeneratesMetrics(t *testing.T) {
err := os.MkdirAll(testBcacheUuidPath, 0755) err := os.MkdirAll(testBcacheUuidPath, 0755)
require.NoError(t, err) require.NoError(t, err)
@@ -47,52 +53,70 @@ func TestBcacheGeneratesMetrics(t *testing.T) {
err = os.MkdirAll(testBcacheUuidPath+"/bdev0/stats_total", 0755) err = os.MkdirAll(testBcacheUuidPath+"/bdev0/stats_total", 0755)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/dirty_data", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/dirty_data", []byte(dirty_data), 0644)
[]byte(dirty_data), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/bypassed", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/bypassed", []byte(bypassed), 0644)
[]byte(bypassed), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_bypass_hits", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_bypass_hits", []byte(cache_bypass_hits), 0644)
[]byte(cache_bypass_hits), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_bypass_misses", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_bypass_misses", []byte(cache_bypass_misses), 0644)
[]byte(cache_bypass_misses), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_hit_ratio", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_hit_ratio", []byte(cache_hit_ratio), 0644)
[]byte(cache_hit_ratio), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_hits", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_hits", []byte(cache_hits), 0644)
[]byte(cache_hits), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_miss_collisions", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_miss_collisions", []byte(cache_miss_collisions), 0644)
[]byte(cache_miss_collisions), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_misses", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_misses", []byte(cache_misses), 0644)
[]byte(cache_misses), 0644)
require.NoError(t, err) require.NoError(t, err)
err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_readaheads", err = ioutil.WriteFile(testBcacheUuidPath+"/bdev0/stats_total/cache_readaheads", []byte(cache_readaheads), 0644)
[]byte(cache_readaheads), 0644)
require.NoError(t, err) require.NoError(t, err)
fields := map[string]interface{}{ intMetrics := []*metrics{
"dirty_data": uint64(1610612736), {
"bypassed": uint64(5167704440832), name: "dirty_data",
"cache_bypass_hits": uint64(146155333), value: 1610612736,
"cache_bypass_misses": uint64(0), },
"cache_hit_ratio": uint64(90), {
"cache_hits": uint64(511469583), name: "bypassed",
"cache_miss_collisions": uint64(157567), value: 5167704440832,
"cache_misses": uint64(50616331), },
"cache_readaheads": uint64(2), {
name: "cache_bypass_hits",
value: 146155333,
},
{
name: "cache_bypass_misses",
value: 0,
},
{
name: "cache_hit_ratio",
value: 90,
},
{
name: "cache_hits",
value: 511469583,
},
{
name: "cache_miss_collisions",
value: 157567,
},
{
name: "cache_misses",
value: 50616331,
},
{
name: "cache_readaheads",
value: 2,
},
} }
tags := map[string]string{ tags := map[string]string{
@@ -102,19 +126,27 @@ func TestBcacheGeneratesMetrics(t *testing.T) {
var acc testutil.Accumulator var acc testutil.Accumulator
// all devs //all devs
b := &Bcache{BcachePath: testBcachePath} b := &Bcache{BcachePath: testBcachePath}
err = b.Gather(&acc) err = b.Gather(&acc)
require.NoError(t, err) require.NoError(t, err)
acc.AssertContainsTaggedFields(t, "bcache", fields, tags)
// one exist dev for _, metric := range intMetrics {
assert.True(t, acc.HasUIntValue(metric.name), metric.name)
assert.True(t, acc.CheckTaggedValue(metric.name, metric.value, tags))
}
//one exist dev
b = &Bcache{BcachePath: testBcachePath, BcacheDevs: []string{"bcache0"}} b = &Bcache{BcachePath: testBcachePath, BcacheDevs: []string{"bcache0"}}
err = b.Gather(&acc) err = b.Gather(&acc)
require.NoError(t, err) require.NoError(t, err)
acc.AssertContainsTaggedFields(t, "bcache", fields, tags)
for _, metric := range intMetrics {
assert.True(t, acc.HasUIntValue(metric.name), metric.name)
assert.True(t, acc.CheckTaggedValue(metric.name, metric.value, tags))
}
err = os.RemoveAll(os.TempDir() + "/telegraf") err = os.RemoveAll(os.TempDir() + "/telegraf")
require.NoError(t, err) require.NoError(t, err)

View File

@@ -10,7 +10,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
type Disque struct { type Disque struct {
@@ -61,7 +61,7 @@ var ErrProtocolError = errors.New("disque protocol error")
// Reads stats from all configured servers accumulates stats. // Reads stats from all configured servers accumulates stats.
// Returns one of the errors encountered while gather stats (if any). // Returns one of the errors encountered while gather stats (if any).
func (g *Disque) Gather(acc inputs.Accumulator) error { func (g *Disque) Gather(acc plugins.Accumulator) error {
if len(g.Servers) == 0 { if len(g.Servers) == 0 {
url := &url.URL{ url := &url.URL{
Host: ":7711", Host: ":7711",
@@ -98,7 +98,7 @@ func (g *Disque) Gather(acc inputs.Accumulator) error {
const defaultPort = "7711" const defaultPort = "7711"
func (g *Disque) gatherServer(addr *url.URL, acc inputs.Accumulator) error { func (g *Disque) gatherServer(addr *url.URL, acc plugins.Accumulator) error {
if g.c == nil { if g.c == nil {
_, _, err := net.SplitHostPort(addr.Host) _, _, err := net.SplitHostPort(addr.Host)
@@ -198,7 +198,7 @@ func (g *Disque) gatherServer(addr *url.URL, acc inputs.Accumulator) error {
} }
func init() { func init() {
inputs.Add("disque", func() inputs.Input { plugins.Add("disque", func() plugins.Plugin {
return &Disque{} return &Disque{}
}) })
} }

View File

@@ -7,6 +7,7 @@ import (
"testing" "testing"
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -54,26 +55,42 @@ func TestDisqueGeneratesMetrics(t *testing.T) {
err = r.Gather(&acc) err = r.Gather(&acc)
require.NoError(t, err) require.NoError(t, err)
fields := map[string]interface{}{ checkInt := []struct {
"uptime": uint64(1452705), name string
"clients": uint64(31), value uint64
"blocked_clients": uint64(13), }{
"used_memory": uint64(1840104), {"uptime", 1452705},
"used_memory_rss": uint64(3227648), {"clients", 31},
"used_memory_peak": uint64(89603656), {"blocked_clients", 13},
"total_connections_received": uint64(5062777), {"used_memory", 1840104},
"total_commands_processed": uint64(12308396), {"used_memory_rss", 3227648},
"instantaneous_ops_per_sec": uint64(18), {"used_memory_peak", 89603656},
"latest_fork_usec": uint64(1644), {"total_connections_received", 5062777},
"registered_jobs": uint64(360), {"total_commands_processed", 12308396},
"registered_queues": uint64(12), {"instantaneous_ops_per_sec", 18},
"mem_fragmentation_ratio": float64(1.75), {"latest_fork_usec", 1644},
"used_cpu_sys": float64(19585.73), {"registered_jobs", 360},
"used_cpu_user": float64(11255.96), {"registered_queues", 12},
"used_cpu_sys_children": float64(1.75), }
"used_cpu_user_children": float64(1.91),
for _, c := range checkInt {
assert.True(t, acc.CheckValue(c.name, c.value))
}
checkFloat := []struct {
name string
value float64
}{
{"mem_fragmentation_ratio", 1.75},
{"used_cpu_sys", 19585.73},
{"used_cpu_user", 11255.96},
{"used_cpu_sys_children", 1.75},
{"used_cpu_user_children", 1.91},
}
for _, c := range checkFloat {
assert.True(t, acc.CheckValue(c.name, c.value))
} }
acc.AssertContainsFields(t, "disque", fields)
} }
func TestDisqueCanPullStatsFromMultipleServers(t *testing.T) { func TestDisqueCanPullStatsFromMultipleServers(t *testing.T) {
@@ -120,26 +137,42 @@ func TestDisqueCanPullStatsFromMultipleServers(t *testing.T) {
err = r.Gather(&acc) err = r.Gather(&acc)
require.NoError(t, err) require.NoError(t, err)
fields := map[string]interface{}{ checkInt := []struct {
"uptime": uint64(1452705), name string
"clients": uint64(31), value uint64
"blocked_clients": uint64(13), }{
"used_memory": uint64(1840104), {"uptime", 1452705},
"used_memory_rss": uint64(3227648), {"clients", 31},
"used_memory_peak": uint64(89603656), {"blocked_clients", 13},
"total_connections_received": uint64(5062777), {"used_memory", 1840104},
"total_commands_processed": uint64(12308396), {"used_memory_rss", 3227648},
"instantaneous_ops_per_sec": uint64(18), {"used_memory_peak", 89603656},
"latest_fork_usec": uint64(1644), {"total_connections_received", 5062777},
"registered_jobs": uint64(360), {"total_commands_processed", 12308396},
"registered_queues": uint64(12), {"instantaneous_ops_per_sec", 18},
"mem_fragmentation_ratio": float64(1.75), {"latest_fork_usec", 1644},
"used_cpu_sys": float64(19585.73), {"registered_jobs", 360},
"used_cpu_user": float64(11255.96), {"registered_queues", 12},
"used_cpu_sys_children": float64(1.75), }
"used_cpu_user_children": float64(1.91),
for _, c := range checkInt {
assert.True(t, acc.CheckValue(c.name, c.value))
}
checkFloat := []struct {
name string
value float64
}{
{"mem_fragmentation_ratio", 1.75},
{"used_cpu_sys", 19585.73},
{"used_cpu_user", 11255.96},
{"used_cpu_sys_children", 1.75},
{"used_cpu_user_children", 1.91},
}
for _, c := range checkFloat {
assert.True(t, acc.CheckValue(c.name, c.value))
} }
acc.AssertContainsFields(t, "disque", fields)
} }
const testOutput = `# Server const testOutput = `# Server

View File

@@ -7,7 +7,7 @@ import (
"time" "time"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
const statsPath = "/_nodes/stats" const statsPath = "/_nodes/stats"
@@ -92,7 +92,7 @@ func (e *Elasticsearch) Description() string {
// Gather reads the stats from Elasticsearch and writes it to the // Gather reads the stats from Elasticsearch and writes it to the
// Accumulator. // Accumulator.
func (e *Elasticsearch) Gather(acc inputs.Accumulator) error { func (e *Elasticsearch) Gather(acc plugins.Accumulator) error {
for _, serv := range e.Servers { for _, serv := range e.Servers {
var url string var url string
if e.Local { if e.Local {
@@ -110,7 +110,7 @@ func (e *Elasticsearch) Gather(acc inputs.Accumulator) error {
return nil return nil
} }
func (e *Elasticsearch) gatherNodeStats(url string, acc inputs.Accumulator) error { func (e *Elasticsearch) gatherNodeStats(url string, acc plugins.Accumulator) error {
nodeStats := &struct { nodeStats := &struct {
ClusterName string `json:"cluster_name"` ClusterName string `json:"cluster_name"`
Nodes map[string]*node `json:"nodes"` Nodes map[string]*node `json:"nodes"`
@@ -155,7 +155,7 @@ func (e *Elasticsearch) gatherNodeStats(url string, acc inputs.Accumulator) erro
return nil return nil
} }
func (e *Elasticsearch) gatherClusterStats(url string, acc inputs.Accumulator) error { func (e *Elasticsearch) gatherClusterStats(url string, acc plugins.Accumulator) error {
clusterStats := &clusterHealth{} clusterStats := &clusterHealth{}
if err := e.gatherData(url, clusterStats); err != nil { if err := e.gatherData(url, clusterStats); err != nil {
return err return err
@@ -220,7 +220,7 @@ func (e *Elasticsearch) gatherData(url string, v interface{}) error {
} }
func init() { func init() {
inputs.Add("elasticsearch", func() inputs.Input { plugins.Add("elasticsearch", func() plugins.Plugin {
return NewElasticsearch() return NewElasticsearch()
}) })
} }

View File

@@ -7,7 +7,7 @@ import (
"testing" "testing"
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -52,15 +52,23 @@ func TestElasticsearch(t *testing.T) {
"node_host": "test", "node_host": "test",
} }
acc.AssertContainsTaggedFields(t, "elasticsearch_indices", indicesExpected, tags) testTables := []map[string]float64{
acc.AssertContainsTaggedFields(t, "elasticsearch_os", osExpected, tags) indicesExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_process", processExpected, tags) osExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_jvm", jvmExpected, tags) processExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_thread_pool", threadPoolExpected, tags) jvmExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_fs", fsExpected, tags) threadPoolExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_transport", transportExpected, tags) fsExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_http", httpExpected, tags) transportExpected,
acc.AssertContainsTaggedFields(t, "elasticsearch_breakers", breakersExpected, tags) httpExpected,
breakersExpected,
}
for _, testTable := range testTables {
for k, v := range testTable {
assert.NoError(t, acc.ValidateTaggedValue(k, v, tags))
}
}
} }
func TestGatherClusterStats(t *testing.T) { func TestGatherClusterStats(t *testing.T) {
@@ -72,15 +80,29 @@ func TestGatherClusterStats(t *testing.T) {
var acc testutil.Accumulator var acc testutil.Accumulator
require.NoError(t, es.Gather(&acc)) require.NoError(t, es.Gather(&acc))
acc.AssertContainsTaggedFields(t, "elasticsearch_cluster_health", var clusterHealthTests = []struct {
clusterHealthExpected, measurement string
map[string]string{"name": "elasticsearch_telegraf"}) fields map[string]interface{}
tags map[string]string
}{
{
"cluster_health",
clusterHealthExpected,
map[string]string{"name": "elasticsearch_telegraf"},
},
{
"indices",
v1IndexExpected,
map[string]string{"index": "v1"},
},
{
"indices",
v2IndexExpected,
map[string]string{"index": "v2"},
},
}
acc.AssertContainsTaggedFields(t, "elasticsearch_indices", for _, exp := range clusterHealthTests {
v1IndexExpected, assert.NoError(t, acc.ValidateTaggedFields(exp.measurement, exp.fields, exp.tags))
map[string]string{"index": "v1"}) }
acc.AssertContainsTaggedFields(t, "elasticsearch_indices",
v2IndexExpected,
map[string]string{"index": "v2"})
} }

View File

@@ -0,0 +1,759 @@
package elasticsearch
const clusterResponse = `
{
"cluster_name": "elasticsearch_telegraf",
"status": "green",
"timed_out": false,
"number_of_nodes": 3,
"number_of_data_nodes": 3,
"active_primary_shards": 5,
"active_shards": 15,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"indices": {
"v1": {
"status": "green",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 10,
"active_shards": 20,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
},
"v2": {
"status": "red",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20
}
}
}
`
var clusterHealthExpected = map[string]interface{}{
"status": "green",
"timed_out": false,
"number_of_nodes": 3,
"number_of_data_nodes": 3,
"active_primary_shards": 5,
"active_shards": 15,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
}
var v1IndexExpected = map[string]interface{}{
"status": "green",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 10,
"active_shards": 20,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
}
var v2IndexExpected = map[string]interface{}{
"status": "red",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20,
}
const statsResponse = `
{
"cluster_name": "es-testcluster",
"nodes": {
"SDFsfSDFsdfFSDSDfSFDSDF": {
"timestamp": 1436365550135,
"name": "test.host.com",
"transport_address": "inet[/127.0.0.1:9300]",
"host": "test",
"ip": [
"inet[/127.0.0.1:9300]",
"NONE"
],
"attributes": {
"master": "true"
},
"indices": {
"docs": {
"count": 29652,
"deleted": 5229
},
"store": {
"size_in_bytes": 37715234,
"throttle_time_in_millis": 215
},
"indexing": {
"index_total": 84790,
"index_time_in_millis": 29680,
"index_current": 0,
"delete_total": 13879,
"delete_time_in_millis": 1139,
"delete_current": 0,
"noop_update_total": 0,
"is_throttled": false,
"throttle_time_in_millis": 0
},
"get": {
"total": 1,
"time_in_millis": 2,
"exists_total": 0,
"exists_time_in_millis": 0,
"missing_total": 1,
"missing_time_in_millis": 2,
"current": 0
},
"search": {
"open_contexts": 0,
"query_total": 1452,
"query_time_in_millis": 5695,
"query_current": 0,
"fetch_total": 414,
"fetch_time_in_millis": 146,
"fetch_current": 0
},
"merges": {
"current": 0,
"current_docs": 0,
"current_size_in_bytes": 0,
"total": 133,
"total_time_in_millis": 21060,
"total_docs": 203672,
"total_size_in_bytes": 142900226
},
"refresh": {
"total": 1076,
"total_time_in_millis": 20078
},
"flush": {
"total": 115,
"total_time_in_millis": 2401
},
"warmer": {
"current": 0,
"total": 2319,
"total_time_in_millis": 448
},
"filter_cache": {
"memory_size_in_bytes": 7384,
"evictions": 0
},
"id_cache": {
"memory_size_in_bytes": 0
},
"fielddata": {
"memory_size_in_bytes": 12996,
"evictions": 0
},
"percolate": {
"total": 0,
"time_in_millis": 0,
"current": 0,
"memory_size_in_bytes": -1,
"memory_size": "-1b",
"queries": 0
},
"completion": {
"size_in_bytes": 0
},
"segments": {
"count": 134,
"memory_in_bytes": 1285212,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 172368955,
"version_map_memory_in_bytes": 611844,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 17702,
"size_in_bytes": 17
},
"suggest": {
"total": 0,
"time_in_millis": 0,
"current": 0
},
"query_cache": {
"memory_size_in_bytes": 0,
"evictions": 0,
"hit_count": 0,
"miss_count": 0
},
"recovery": {
"current_as_source": 0,
"current_as_target": 0,
"throttle_time_in_millis": 0
}
},
"os": {
"timestamp": 1436460392944,
"load_average": [
0.01,
0.04,
0.05
],
"mem": {
"free_in_bytes": 477761536,
"used_in_bytes": 1621868544,
"free_percent": 74,
"used_percent": 25,
"actual_free_in_bytes": 1565470720,
"actual_used_in_bytes": 534159360
},
"swap": {
"used_in_bytes": 0,
"free_in_bytes": 487997440
}
},
"process": {
"timestamp": 1436460392945,
"open_file_descriptors": 160,
"cpu": {
"percent": 2,
"sys_in_millis": 1870,
"user_in_millis": 13610,
"total_in_millis": 15480
},
"mem": {
"total_virtual_in_bytes": 4747890688
}
},
"jvm": {
"timestamp": 1436460392945,
"uptime_in_millis": 202245,
"mem": {
"heap_used_in_bytes": 52709568,
"heap_used_percent": 5,
"heap_committed_in_bytes": 259522560,
"heap_max_in_bytes": 1038876672,
"non_heap_used_in_bytes": 39634576,
"non_heap_committed_in_bytes": 40841216,
"pools": {
"young": {
"used_in_bytes": 32685760,
"max_in_bytes": 279183360,
"peak_used_in_bytes": 71630848,
"peak_max_in_bytes": 279183360
},
"survivor": {
"used_in_bytes": 8912880,
"max_in_bytes": 34865152,
"peak_used_in_bytes": 8912888,
"peak_max_in_bytes": 34865152
},
"old": {
"used_in_bytes": 11110928,
"max_in_bytes": 724828160,
"peak_used_in_bytes": 14354608,
"peak_max_in_bytes": 724828160
}
}
},
"threads": {
"count": 44,
"peak_count": 45
},
"gc": {
"collectors": {
"young": {
"collection_count": 2,
"collection_time_in_millis": 98
},
"old": {
"collection_count": 1,
"collection_time_in_millis": 24
}
}
},
"buffer_pools": {
"direct": {
"count": 40,
"used_in_bytes": 6304239,
"total_capacity_in_bytes": 6304239
},
"mapped": {
"count": 0,
"used_in_bytes": 0,
"total_capacity_in_bytes": 0
}
}
},
"thread_pool": {
"percolate": {
"threads": 123,
"queue": 23,
"active": 13,
"rejected": 235,
"largest": 23,
"completed": 33
},
"fetch_shard_started": {
"threads": 3,
"queue": 1,
"active": 5,
"rejected": 6,
"largest": 4,
"completed": 54
},
"listener": {
"threads": 1,
"queue": 2,
"active": 4,
"rejected": 8,
"largest": 1,
"completed": 1
},
"index": {
"threads": 6,
"queue": 8,
"active": 4,
"rejected": 2,
"largest": 3,
"completed": 6
},
"refresh": {
"threads": 23,
"queue": 7,
"active": 3,
"rejected": 4,
"largest": 8,
"completed": 3
},
"suggest": {
"threads": 2,
"queue": 7,
"active": 2,
"rejected": 1,
"largest": 8,
"completed": 3
},
"generic": {
"threads": 1,
"queue": 4,
"active": 6,
"rejected": 3,
"largest": 2,
"completed": 27
},
"warmer": {
"threads": 2,
"queue": 7,
"active": 3,
"rejected": 2,
"largest": 3,
"completed": 1
},
"search": {
"threads": 5,
"queue": 7,
"active": 2,
"rejected": 7,
"largest": 2,
"completed": 4
},
"flush": {
"threads": 3,
"queue": 8,
"active": 0,
"rejected": 1,
"largest": 5,
"completed": 3
},
"optimize": {
"threads": 3,
"queue": 4,
"active": 1,
"rejected": 2,
"largest": 7,
"completed": 3
},
"fetch_shard_store": {
"threads": 1,
"queue": 7,
"active": 4,
"rejected": 2,
"largest": 4,
"completed": 1
},
"management": {
"threads": 2,
"queue": 3,
"active": 1,
"rejected": 6,
"largest": 2,
"completed": 22
},
"get": {
"threads": 1,
"queue": 8,
"active": 4,
"rejected": 3,
"largest": 2,
"completed": 1
},
"merge": {
"threads": 6,
"queue": 4,
"active": 5,
"rejected": 2,
"largest": 5,
"completed": 1
},
"bulk": {
"threads": 4,
"queue": 5,
"active": 7,
"rejected": 3,
"largest": 1,
"completed": 4
},
"snapshot": {
"threads": 8,
"queue": 5,
"active": 6,
"rejected": 2,
"largest": 1,
"completed": 0
}
},
"fs": {
"timestamp": 1436460392946,
"total": {
"total_in_bytes": 19507089408,
"free_in_bytes": 16909316096,
"available_in_bytes": 15894814720
},
"data": [
{
"path": "/usr/share/elasticsearch/data/elasticsearch/nodes/0",
"mount": "/usr/share/elasticsearch/data",
"type": "ext4",
"total_in_bytes": 19507089408,
"free_in_bytes": 16909316096,
"available_in_bytes": 15894814720
}
]
},
"transport": {
"server_open": 13,
"rx_count": 6,
"rx_size_in_bytes": 1380,
"tx_count": 6,
"tx_size_in_bytes": 1380
},
"http": {
"current_open": 3,
"total_opened": 3
},
"breakers": {
"fielddata": {
"limit_size_in_bytes": 623326003,
"limit_size": "594.4mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.03,
"tripped": 0
},
"request": {
"limit_size_in_bytes": 415550668,
"limit_size": "396.2mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.0,
"tripped": 0
},
"parent": {
"limit_size_in_bytes": 727213670,
"limit_size": "693.5mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.0,
"tripped": 0
}
}
}
}
}
`
var indicesExpected = map[string]float64{
"indices_id_cache_memory_size_in_bytes": 0,
"indices_completion_size_in_bytes": 0,
"indices_suggest_total": 0,
"indices_suggest_time_in_millis": 0,
"indices_suggest_current": 0,
"indices_query_cache_memory_size_in_bytes": 0,
"indices_query_cache_evictions": 0,
"indices_query_cache_hit_count": 0,
"indices_query_cache_miss_count": 0,
"indices_store_size_in_bytes": 37715234,
"indices_store_throttle_time_in_millis": 215,
"indices_merges_current_docs": 0,
"indices_merges_current_size_in_bytes": 0,
"indices_merges_total": 133,
"indices_merges_total_time_in_millis": 21060,
"indices_merges_total_docs": 203672,
"indices_merges_total_size_in_bytes": 142900226,
"indices_merges_current": 0,
"indices_filter_cache_memory_size_in_bytes": 7384,
"indices_filter_cache_evictions": 0,
"indices_indexing_index_total": 84790,
"indices_indexing_index_time_in_millis": 29680,
"indices_indexing_index_current": 0,
"indices_indexing_noop_update_total": 0,
"indices_indexing_throttle_time_in_millis": 0,
"indices_indexing_delete_total": 13879,
"indices_indexing_delete_time_in_millis": 1139,
"indices_indexing_delete_current": 0,
"indices_get_exists_time_in_millis": 0,
"indices_get_missing_total": 1,
"indices_get_missing_time_in_millis": 2,
"indices_get_current": 0,
"indices_get_total": 1,
"indices_get_time_in_millis": 2,
"indices_get_exists_total": 0,
"indices_refresh_total": 1076,
"indices_refresh_total_time_in_millis": 20078,
"indices_percolate_current": 0,
"indices_percolate_memory_size_in_bytes": -1,
"indices_percolate_queries": 0,
"indices_percolate_total": 0,
"indices_percolate_time_in_millis": 0,
"indices_translog_operations": 17702,
"indices_translog_size_in_bytes": 17,
"indices_recovery_current_as_source": 0,
"indices_recovery_current_as_target": 0,
"indices_recovery_throttle_time_in_millis": 0,
"indices_docs_count": 29652,
"indices_docs_deleted": 5229,
"indices_flush_total_time_in_millis": 2401,
"indices_flush_total": 115,
"indices_fielddata_memory_size_in_bytes": 12996,
"indices_fielddata_evictions": 0,
"indices_search_fetch_current": 0,
"indices_search_open_contexts": 0,
"indices_search_query_total": 1452,
"indices_search_query_time_in_millis": 5695,
"indices_search_query_current": 0,
"indices_search_fetch_total": 414,
"indices_search_fetch_time_in_millis": 146,
"indices_warmer_current": 0,
"indices_warmer_total": 2319,
"indices_warmer_total_time_in_millis": 448,
"indices_segments_count": 134,
"indices_segments_memory_in_bytes": 1285212,
"indices_segments_index_writer_memory_in_bytes": 0,
"indices_segments_index_writer_max_memory_in_bytes": 172368955,
"indices_segments_version_map_memory_in_bytes": 611844,
"indices_segments_fixed_bit_set_memory_in_bytes": 0,
}
var osExpected = map[string]float64{
"os_swap_used_in_bytes": 0,
"os_swap_free_in_bytes": 487997440,
"os_timestamp": 1436460392944,
"os_mem_free_percent": 74,
"os_mem_used_percent": 25,
"os_mem_actual_free_in_bytes": 1565470720,
"os_mem_actual_used_in_bytes": 534159360,
"os_mem_free_in_bytes": 477761536,
"os_mem_used_in_bytes": 1621868544,
}
var processExpected = map[string]float64{
"process_mem_total_virtual_in_bytes": 4747890688,
"process_timestamp": 1436460392945,
"process_open_file_descriptors": 160,
"process_cpu_total_in_millis": 15480,
"process_cpu_percent": 2,
"process_cpu_sys_in_millis": 1870,
"process_cpu_user_in_millis": 13610,
}
var jvmExpected = map[string]float64{
"jvm_timestamp": 1436460392945,
"jvm_uptime_in_millis": 202245,
"jvm_mem_non_heap_used_in_bytes": 39634576,
"jvm_mem_non_heap_committed_in_bytes": 40841216,
"jvm_mem_pools_young_max_in_bytes": 279183360,
"jvm_mem_pools_young_peak_used_in_bytes": 71630848,
"jvm_mem_pools_young_peak_max_in_bytes": 279183360,
"jvm_mem_pools_young_used_in_bytes": 32685760,
"jvm_mem_pools_survivor_peak_used_in_bytes": 8912888,
"jvm_mem_pools_survivor_peak_max_in_bytes": 34865152,
"jvm_mem_pools_survivor_used_in_bytes": 8912880,
"jvm_mem_pools_survivor_max_in_bytes": 34865152,
"jvm_mem_pools_old_peak_max_in_bytes": 724828160,
"jvm_mem_pools_old_used_in_bytes": 11110928,
"jvm_mem_pools_old_max_in_bytes": 724828160,
"jvm_mem_pools_old_peak_used_in_bytes": 14354608,
"jvm_mem_heap_used_in_bytes": 52709568,
"jvm_mem_heap_used_percent": 5,
"jvm_mem_heap_committed_in_bytes": 259522560,
"jvm_mem_heap_max_in_bytes": 1038876672,
"jvm_threads_peak_count": 45,
"jvm_threads_count": 44,
"jvm_gc_collectors_young_collection_count": 2,
"jvm_gc_collectors_young_collection_time_in_millis": 98,
"jvm_gc_collectors_old_collection_count": 1,
"jvm_gc_collectors_old_collection_time_in_millis": 24,
"jvm_buffer_pools_direct_count": 40,
"jvm_buffer_pools_direct_used_in_bytes": 6304239,
"jvm_buffer_pools_direct_total_capacity_in_bytes": 6304239,
"jvm_buffer_pools_mapped_count": 0,
"jvm_buffer_pools_mapped_used_in_bytes": 0,
"jvm_buffer_pools_mapped_total_capacity_in_bytes": 0,
}
var threadPoolExpected = map[string]float64{
"thread_pool_merge_threads": 6,
"thread_pool_merge_queue": 4,
"thread_pool_merge_active": 5,
"thread_pool_merge_rejected": 2,
"thread_pool_merge_largest": 5,
"thread_pool_merge_completed": 1,
"thread_pool_bulk_threads": 4,
"thread_pool_bulk_queue": 5,
"thread_pool_bulk_active": 7,
"thread_pool_bulk_rejected": 3,
"thread_pool_bulk_largest": 1,
"thread_pool_bulk_completed": 4,
"thread_pool_warmer_threads": 2,
"thread_pool_warmer_queue": 7,
"thread_pool_warmer_active": 3,
"thread_pool_warmer_rejected": 2,
"thread_pool_warmer_largest": 3,
"thread_pool_warmer_completed": 1,
"thread_pool_get_largest": 2,
"thread_pool_get_completed": 1,
"thread_pool_get_threads": 1,
"thread_pool_get_queue": 8,
"thread_pool_get_active": 4,
"thread_pool_get_rejected": 3,
"thread_pool_index_threads": 6,
"thread_pool_index_queue": 8,
"thread_pool_index_active": 4,
"thread_pool_index_rejected": 2,
"thread_pool_index_largest": 3,
"thread_pool_index_completed": 6,
"thread_pool_suggest_threads": 2,
"thread_pool_suggest_queue": 7,
"thread_pool_suggest_active": 2,
"thread_pool_suggest_rejected": 1,
"thread_pool_suggest_largest": 8,
"thread_pool_suggest_completed": 3,
"thread_pool_fetch_shard_store_queue": 7,
"thread_pool_fetch_shard_store_active": 4,
"thread_pool_fetch_shard_store_rejected": 2,
"thread_pool_fetch_shard_store_largest": 4,
"thread_pool_fetch_shard_store_completed": 1,
"thread_pool_fetch_shard_store_threads": 1,
"thread_pool_management_threads": 2,
"thread_pool_management_queue": 3,
"thread_pool_management_active": 1,
"thread_pool_management_rejected": 6,
"thread_pool_management_largest": 2,
"thread_pool_management_completed": 22,
"thread_pool_percolate_queue": 23,
"thread_pool_percolate_active": 13,
"thread_pool_percolate_rejected": 235,
"thread_pool_percolate_largest": 23,
"thread_pool_percolate_completed": 33,
"thread_pool_percolate_threads": 123,
"thread_pool_listener_active": 4,
"thread_pool_listener_rejected": 8,
"thread_pool_listener_largest": 1,
"thread_pool_listener_completed": 1,
"thread_pool_listener_threads": 1,
"thread_pool_listener_queue": 2,
"thread_pool_search_rejected": 7,
"thread_pool_search_largest": 2,
"thread_pool_search_completed": 4,
"thread_pool_search_threads": 5,
"thread_pool_search_queue": 7,
"thread_pool_search_active": 2,
"thread_pool_fetch_shard_started_threads": 3,
"thread_pool_fetch_shard_started_queue": 1,
"thread_pool_fetch_shard_started_active": 5,
"thread_pool_fetch_shard_started_rejected": 6,
"thread_pool_fetch_shard_started_largest": 4,
"thread_pool_fetch_shard_started_completed": 54,
"thread_pool_refresh_rejected": 4,
"thread_pool_refresh_largest": 8,
"thread_pool_refresh_completed": 3,
"thread_pool_refresh_threads": 23,
"thread_pool_refresh_queue": 7,
"thread_pool_refresh_active": 3,
"thread_pool_optimize_threads": 3,
"thread_pool_optimize_queue": 4,
"thread_pool_optimize_active": 1,
"thread_pool_optimize_rejected": 2,
"thread_pool_optimize_largest": 7,
"thread_pool_optimize_completed": 3,
"thread_pool_snapshot_largest": 1,
"thread_pool_snapshot_completed": 0,
"thread_pool_snapshot_threads": 8,
"thread_pool_snapshot_queue": 5,
"thread_pool_snapshot_active": 6,
"thread_pool_snapshot_rejected": 2,
"thread_pool_generic_threads": 1,
"thread_pool_generic_queue": 4,
"thread_pool_generic_active": 6,
"thread_pool_generic_rejected": 3,
"thread_pool_generic_largest": 2,
"thread_pool_generic_completed": 27,
"thread_pool_flush_threads": 3,
"thread_pool_flush_queue": 8,
"thread_pool_flush_active": 0,
"thread_pool_flush_rejected": 1,
"thread_pool_flush_largest": 5,
"thread_pool_flush_completed": 3,
}
var fsExpected = map[string]float64{
"fs_timestamp": 1436460392946,
"fs_total_free_in_bytes": 16909316096,
"fs_total_available_in_bytes": 15894814720,
"fs_total_total_in_bytes": 19507089408,
}
var transportExpected = map[string]float64{
"transport_server_open": 13,
"transport_rx_count": 6,
"transport_rx_size_in_bytes": 1380,
"transport_tx_count": 6,
"transport_tx_size_in_bytes": 1380,
}
var httpExpected = map[string]float64{
"http_current_open": 3,
"http_total_opened": 3,
}
var breakersExpected = map[string]float64{
"breakers_fielddata_estimated_size_in_bytes": 0,
"breakers_fielddata_overhead": 1.03,
"breakers_fielddata_tripped": 0,
"breakers_fielddata_limit_size_in_bytes": 623326003,
"breakers_request_estimated_size_in_bytes": 0,
"breakers_request_overhead": 1.0,
"breakers_request_tripped": 0,
"breakers_request_limit_size_in_bytes": 415550668,
"breakers_parent_overhead": 1.0,
"breakers_parent_tripped": 0,
"breakers_parent_limit_size_in_bytes": 727213670,
"breakers_parent_estimated_size_in_bytes": 0,
}

View File

@@ -9,19 +9,20 @@ import (
"github.com/gonuts/go-shellquote" "github.com/gonuts/go-shellquote"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
const sampleConfig = ` const sampleConfig = `
# the command to run # the command to run
command = "/usr/bin/mycollector --foo=bar" command = "/usr/bin/mycollector --foo=bar"
# measurement name suffix (for separating different commands) # name of the command (used as a prefix for measurements)
name_suffix = "_mycollector" name = "mycollector"
` `
type Exec struct { type Exec struct {
Command string Command string
Name string
runner Runner runner Runner
} }
@@ -61,7 +62,7 @@ func (e *Exec) Description() string {
return "Read flattened metrics from one or more commands that output JSON to stdout" return "Read flattened metrics from one or more commands that output JSON to stdout"
} }
func (e *Exec) Gather(acc inputs.Accumulator) error { func (e *Exec) Gather(acc plugins.Accumulator) error {
out, err := e.runner.Run(e) out, err := e.runner.Run(e)
if err != nil { if err != nil {
return err return err
@@ -80,12 +81,18 @@ func (e *Exec) Gather(acc inputs.Accumulator) error {
return err return err
} }
acc.AddFields("exec", f.Fields, nil) var msrmnt_name string
if e.Name == "" {
msrmnt_name = "exec"
} else {
msrmnt_name = "exec_" + e.Name
}
acc.AddFields(msrmnt_name, f.Fields, nil)
return nil return nil
} }
func init() { func init() {
inputs.Add("exec", func() inputs.Input { plugins.Add("exec", func() plugins.Plugin {
return NewExec() return NewExec()
}) })
} }

262
plugins/exec/exec_test.go Normal file
View File

@@ -0,0 +1,262 @@
package exec
import (
"fmt"
"github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"math"
"testing"
"time"
)
// Midnight 9/22/2015
const baseTimeSeconds = 1442905200
const validJson = `
{
"status": "green",
"num_processes": 82,
"cpu": {
"status": "red",
"nil_status": null,
"used": 8234,
"free": 32
},
"percent": 0.81,
"users": [0, 1, 2, 3]
}`
const malformedJson = `
{
"status": "green",
`
type runnerMock struct {
out []byte
err error
}
type clockMock struct {
now time.Time
}
func newRunnerMock(out []byte, err error) Runner {
return &runnerMock{
out: out,
err: err,
}
}
func (r runnerMock) Run(command *Command) ([]byte, error) {
if r.err != nil {
return nil, r.err
}
return r.out, nil
}
func newClockMock(now time.Time) Clock {
return &clockMock{now: now}
}
func (c clockMock) Now() time.Time {
return c.now
}
func TestExec(t *testing.T) {
runner := newRunnerMock([]byte(validJson), nil)
clock := newClockMock(time.Unix(baseTimeSeconds+20, 0))
command := Command{
Command: "testcommand arg1",
Name: "mycollector",
Interval: 10,
lastRunAt: time.Unix(baseTimeSeconds, 0),
}
e := &Exec{
runner: runner,
clock: clock,
Commands: []*Command{&command},
}
var acc testutil.Accumulator
initialPoints := len(acc.Points)
err := e.Gather(&acc)
deltaPoints := len(acc.Points) - initialPoints
require.NoError(t, err)
checkFloat := []struct {
name string
value float64
}{
{"mycollector_num_processes", 82},
{"mycollector_cpu_used", 8234},
{"mycollector_cpu_free", 32},
{"mycollector_percent", 0.81},
}
for _, c := range checkFloat {
assert.True(t, acc.CheckValue(c.name, c.value))
}
assert.Equal(t, deltaPoints, 4, "non-numeric measurements should be ignored")
}
func TestExecMalformed(t *testing.T) {
runner := newRunnerMock([]byte(malformedJson), nil)
clock := newClockMock(time.Unix(baseTimeSeconds+20, 0))
command := Command{
Command: "badcommand arg1",
Name: "mycollector",
Interval: 10,
lastRunAt: time.Unix(baseTimeSeconds, 0),
}
e := &Exec{
runner: runner,
clock: clock,
Commands: []*Command{&command},
}
var acc testutil.Accumulator
initialPoints := len(acc.Points)
err := e.Gather(&acc)
deltaPoints := len(acc.Points) - initialPoints
require.Error(t, err)
assert.Equal(t, deltaPoints, 0, "No new points should have been added")
}
func TestCommandError(t *testing.T) {
runner := newRunnerMock(nil, fmt.Errorf("exit status code 1"))
clock := newClockMock(time.Unix(baseTimeSeconds+20, 0))
command := Command{
Command: "badcommand",
Name: "mycollector",
Interval: 10,
lastRunAt: time.Unix(baseTimeSeconds, 0),
}
e := &Exec{
runner: runner,
clock: clock,
Commands: []*Command{&command},
}
var acc testutil.Accumulator
initialPoints := len(acc.Points)
err := e.Gather(&acc)
deltaPoints := len(acc.Points) - initialPoints
require.Error(t, err)
assert.Equal(t, deltaPoints, 0, "No new points should have been added")
}
func TestExecNotEnoughTime(t *testing.T) {
runner := newRunnerMock([]byte(validJson), nil)
clock := newClockMock(time.Unix(baseTimeSeconds+5, 0))
command := Command{
Command: "testcommand arg1",
Name: "mycollector",
Interval: 10,
lastRunAt: time.Unix(baseTimeSeconds, 0),
}
e := &Exec{
runner: runner,
clock: clock,
Commands: []*Command{&command},
}
var acc testutil.Accumulator
initialPoints := len(acc.Points)
err := e.Gather(&acc)
deltaPoints := len(acc.Points) - initialPoints
require.NoError(t, err)
assert.Equal(t, deltaPoints, 0, "No new points should have been added")
}
func TestExecUninitializedLastRunAt(t *testing.T) {
runner := newRunnerMock([]byte(validJson), nil)
clock := newClockMock(time.Unix(baseTimeSeconds, 0))
command := Command{
Command: "testcommand arg1",
Name: "mycollector",
Interval: math.MaxInt32,
// Uninitialized lastRunAt should default to time.Unix(0, 0), so this should
// run no matter what the interval is
}
e := &Exec{
runner: runner,
clock: clock,
Commands: []*Command{&command},
}
var acc testutil.Accumulator
initialPoints := len(acc.Points)
err := e.Gather(&acc)
deltaPoints := len(acc.Points) - initialPoints
require.NoError(t, err)
checkFloat := []struct {
name string
value float64
}{
{"mycollector_num_processes", 82},
{"mycollector_cpu_used", 8234},
{"mycollector_cpu_free", 32},
{"mycollector_percent", 0.81},
}
for _, c := range checkFloat {
assert.True(t, acc.CheckValue(c.name, c.value))
}
assert.Equal(t, deltaPoints, 4, "non-numeric measurements should be ignored")
}
func TestExecOneNotEnoughTimeAndOneEnoughTime(t *testing.T) {
runner := newRunnerMock([]byte(validJson), nil)
clock := newClockMock(time.Unix(baseTimeSeconds+5, 0))
notEnoughTimeCommand := Command{
Command: "testcommand arg1",
Name: "mycollector",
Interval: 10,
lastRunAt: time.Unix(baseTimeSeconds, 0),
}
enoughTimeCommand := Command{
Command: "testcommand arg1",
Name: "mycollector",
Interval: 3,
lastRunAt: time.Unix(baseTimeSeconds, 0),
}
e := &Exec{
runner: runner,
clock: clock,
Commands: []*Command{&notEnoughTimeCommand, &enoughTimeCommand},
}
var acc testutil.Accumulator
initialPoints := len(acc.Points)
err := e.Gather(&acc)
deltaPoints := len(acc.Points) - initialPoints
require.NoError(t, err)
checkFloat := []struct {
name string
value float64
}{
{"mycollector_num_processes", 82},
{"mycollector_cpu_used", 8234},
{"mycollector_cpu_free", 32},
{"mycollector_percent", 0.81},
}
for _, c := range checkFloat {
assert.True(t, acc.CheckValue(c.name, c.value))
}
assert.Equal(t, deltaPoints, 4, "Only one command should have been run")
}

View File

@@ -3,7 +3,7 @@ package haproxy
import ( import (
"encoding/csv" "encoding/csv"
"fmt" "fmt"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@@ -91,7 +91,7 @@ var sampleConfig = `
# If no servers are specified, then default to 127.0.0.1:1936 # If no servers are specified, then default to 127.0.0.1:1936
servers = ["http://myhaproxy.com:1936", "http://anotherhaproxy.com:1936"] servers = ["http://myhaproxy.com:1936", "http://anotherhaproxy.com:1936"]
# Or you can also use local socket(not work yet) # Or you can also use local socket(not work yet)
# servers = ["socket://run/haproxy/admin.sock"] # servers = ["socket:/run/haproxy/admin.sock"]
` `
func (r *haproxy) SampleConfig() string { func (r *haproxy) SampleConfig() string {
@@ -104,7 +104,7 @@ func (r *haproxy) Description() string {
// Reads stats from all configured servers accumulates stats. // Reads stats from all configured servers accumulates stats.
// Returns one of the errors encountered while gather stats (if any). // Returns one of the errors encountered while gather stats (if any).
func (g *haproxy) Gather(acc inputs.Accumulator) error { func (g *haproxy) Gather(acc plugins.Accumulator) error {
if len(g.Servers) == 0 { if len(g.Servers) == 0 {
return g.gatherServer("http://127.0.0.1:1936", acc) return g.gatherServer("http://127.0.0.1:1936", acc)
} }
@@ -126,7 +126,7 @@ func (g *haproxy) Gather(acc inputs.Accumulator) error {
return outerr return outerr
} }
func (g *haproxy) gatherServer(addr string, acc inputs.Accumulator) error { func (g *haproxy) gatherServer(addr string, acc plugins.Accumulator) error {
if g.client == nil { if g.client == nil {
client := &http.Client{} client := &http.Client{}
@@ -156,7 +156,7 @@ func (g *haproxy) gatherServer(addr string, acc inputs.Accumulator) error {
return importCsvResult(res.Body, acc, u.Host) return importCsvResult(res.Body, acc, u.Host)
} }
func importCsvResult(r io.Reader, acc inputs.Accumulator, host string) error { func importCsvResult(r io.Reader, acc plugins.Accumulator, host string) error {
csv := csv.NewReader(r) csv := csv.NewReader(r)
result, err := csv.ReadAll() result, err := csv.ReadAll()
now := time.Now() now := time.Now()
@@ -358,7 +358,7 @@ func importCsvResult(r io.Reader, acc inputs.Accumulator, host string) error {
} }
func init() { func init() {
inputs.Add("haproxy", func() inputs.Input { plugins.Add("haproxy", func() plugins.Plugin {
return &haproxy{} return &haproxy{}
}) })
} }

View File

@@ -47,39 +47,52 @@ func TestHaproxyGeneratesMetricsWithAuthentication(t *testing.T) {
"sv": "host0", "sv": "host0",
} }
fields := map[string]interface{}{ assert.NoError(t, acc.ValidateTaggedValue("stot", uint64(171014), tags))
"active_servers": uint64(1),
"backup_servers": uint64(0), checkInt := []struct {
"bin": uint64(510913516), name string
"bout": uint64(2193856571), value uint64
"check_duration": uint64(10), }{
"cli_abort": uint64(73),
"ctime": uint64(2), {"qmax", 81},
"downtime": uint64(0), {"scur", 288},
"dresp": uint64(0), {"smax", 713},
"econ": uint64(0), {"bin", 5557055817},
"eresp": uint64(1), {"bout", 24096715169},
"http_response.1xx": uint64(0), {"dreq", 1102},
"http_response.2xx": uint64(119534), {"dresp", 80},
"http_response.3xx": uint64(48051), {"ereq", 95740},
"http_response.4xx": uint64(2345), {"econ", 0},
"http_response.5xx": uint64(1056), {"eresp", 0},
"lbtot": uint64(171013), {"wretr", 17},
"qcur": uint64(0), {"wredis", 19},
"qmax": uint64(0), {"active_servers", 1},
"qtime": uint64(0), {"backup_servers", 0},
"rate": uint64(3), {"downtime", 0},
"rate_max": uint64(12), {"throttle", 13},
"rtime": uint64(312), {"lbtot", 114},
"scur": uint64(1), {"rate", 18},
"smax": uint64(32), {"rate_max", 102},
"srv_abort": uint64(1), {"check_duration", 1},
"stot": uint64(171014), {"http_response.1xx", 0},
"ttime": uint64(2341), {"http_response.2xx", 1314093},
"wredis": uint64(0), {"http_response.3xx", 537036},
"wretr": uint64(1), {"http_response.4xx", 123452},
{"http_response.5xx", 11966},
{"req_rate", 35},
{"req_rate_max", 140},
{"req_tot", 1987928},
{"cli_abort", 0},
{"srv_abort", 0},
{"qtime", 0},
{"ctime", 2},
{"rtime", 23},
{"ttime", 545},
}
for _, c := range checkInt {
assert.Equal(t, true, acc.CheckValue(c.name, c.value))
} }
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
//Here, we should get error because we don't pass authentication data //Here, we should get error because we don't pass authentication data
r = &haproxy{ r = &haproxy{
@@ -111,39 +124,10 @@ func TestHaproxyGeneratesMetricsWithoutAuthentication(t *testing.T) {
"sv": "host0", "sv": "host0",
} }
fields := map[string]interface{}{ assert.NoError(t, acc.ValidateTaggedValue("stot", uint64(171014), tags))
"active_servers": uint64(1), assert.NoError(t, acc.ValidateTaggedValue("scur", uint64(1), tags))
"backup_servers": uint64(0), assert.NoError(t, acc.ValidateTaggedValue("rate", uint64(3), tags))
"bin": uint64(510913516), assert.Equal(t, true, acc.CheckValue("bin", uint64(5557055817)))
"bout": uint64(2193856571),
"check_duration": uint64(10),
"cli_abort": uint64(73),
"ctime": uint64(2),
"downtime": uint64(0),
"dresp": uint64(0),
"econ": uint64(0),
"eresp": uint64(1),
"http_response.1xx": uint64(0),
"http_response.2xx": uint64(119534),
"http_response.3xx": uint64(48051),
"http_response.4xx": uint64(2345),
"http_response.5xx": uint64(1056),
"lbtot": uint64(171013),
"qcur": uint64(0),
"qmax": uint64(0),
"qtime": uint64(0),
"rate": uint64(3),
"rate_max": uint64(12),
"rtime": uint64(312),
"scur": uint64(1),
"smax": uint64(32),
"srv_abort": uint64(1),
"stot": uint64(171014),
"ttime": uint64(2341),
"wredis": uint64(0),
"wretr": uint64(1),
}
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
} }
//When not passing server config, we default to localhost //When not passing server config, we default to localhost

View File

@@ -11,7 +11,7 @@ import (
"sync" "sync"
"github.com/influxdb/telegraf/internal" "github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
type HttpJson struct { type HttpJson struct {
@@ -63,7 +63,7 @@ var sampleConfig = `
# ] # ]
# HTTP parameters (all values must be strings) # HTTP parameters (all values must be strings)
[inputs.httpjson.parameters] [plugins.httpjson.parameters]
event_type = "cpu_spike" event_type = "cpu_spike"
threshold = "0.75" threshold = "0.75"
` `
@@ -77,7 +77,7 @@ func (h *HttpJson) Description() string {
} }
// Gathers data for all servers. // Gathers data for all servers.
func (h *HttpJson) Gather(acc inputs.Accumulator) error { func (h *HttpJson) Gather(acc plugins.Accumulator) error {
var wg sync.WaitGroup var wg sync.WaitGroup
errorChannel := make(chan error, len(h.Servers)) errorChannel := make(chan error, len(h.Servers))
@@ -116,7 +116,7 @@ func (h *HttpJson) Gather(acc inputs.Accumulator) error {
// Returns: // Returns:
// error: Any error that may have occurred // error: Any error that may have occurred
func (h *HttpJson) gatherServer( func (h *HttpJson) gatherServer(
acc inputs.Accumulator, acc plugins.Accumulator,
serverURL string, serverURL string,
) error { ) error {
resp, err := h.sendRequest(serverURL) resp, err := h.sendRequest(serverURL)
@@ -153,7 +153,7 @@ func (h *HttpJson) gatherServer(
} else { } else {
msrmnt_name = "httpjson_" + h.Name msrmnt_name = "httpjson_" + h.Name
} }
acc.AddFields(msrmnt_name, f.Fields, tags) acc.AddFields(msrmnt_name, f.Fields, nil)
return nil return nil
} }
@@ -182,6 +182,7 @@ func (h *HttpJson) sendRequest(serverURL string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
defer req.Body.Close()
resp, err := h.client.MakeRequest(req) resp, err := h.client.MakeRequest(req)
if err != nil { if err != nil {
@@ -210,7 +211,7 @@ func (h *HttpJson) sendRequest(serverURL string) (string, error) {
} }
func init() { func init() {
inputs.Add("httpjson", func() inputs.Input { plugins.Add("httpjson", func() plugins.Plugin {
return &HttpJson{client: RealHTTPClient{client: &http.Client{}}} return &HttpJson{client: RealHTTPClient{client: &http.Client{}}}
}) })
} }

View File

@@ -1,6 +1,7 @@
package httpjson package httpjson
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
@@ -34,11 +35,6 @@ const validJSONTags = `
"build": "123" "build": "123"
}` }`
var expectedFields = map[string]interface{}{
"parent_child": float64(3),
"integer": float64(4),
}
const invalidJSON = "I don't think this is JSON" const invalidJSON = "I don't think this is JSON"
const empty = "" const empty = ""
@@ -80,36 +76,37 @@ func (c mockHTTPClient) MakeRequest(req *http.Request) (*http.Response, error) {
// //
// Returns: // Returns:
// *HttpJson: Pointer to an HttpJson object that uses the generated mock HTTP client // *HttpJson: Pointer to an HttpJson object that uses the generated mock HTTP client
func genMockHttpJson(response string, statusCode int) []*HttpJson { func genMockHttpJson(response string, statusCode int) *HttpJson {
return []*HttpJson{ return &HttpJson{
&HttpJson{ client: mockHTTPClient{responseBody: response, statusCode: statusCode},
client: mockHTTPClient{responseBody: response, statusCode: statusCode}, Services: []Service{
Servers: []string{ Service{
"http://server1.example.com/metrics/", Servers: []string{
"http://server2.example.com/metrics/", "http://server1.example.com/metrics/",
"http://server2.example.com/metrics/",
},
Name: "my_webapp",
Method: "GET",
Parameters: map[string]string{
"httpParam1": "12",
"httpParam2": "the second parameter",
},
}, },
Name: "my_webapp", Service{
Method: "GET", Servers: []string{
Parameters: map[string]string{ "http://server3.example.com/metrics/",
"httpParam1": "12", "http://server4.example.com/metrics/",
"httpParam2": "the second parameter", },
}, Name: "other_webapp",
}, Method: "POST",
&HttpJson{ Parameters: map[string]string{
client: mockHTTPClient{responseBody: response, statusCode: statusCode}, "httpParam1": "12",
Servers: []string{ "httpParam2": "the second parameter",
"http://server3.example.com/metrics/", },
"http://server4.example.com/metrics/", TagKeys: []string{
}, "role",
Name: "other_webapp", "build",
Method: "POST", },
Parameters: map[string]string{
"httpParam1": "12",
"httpParam2": "the second parameter",
},
TagKeys: []string{
"role",
"build",
}, },
}, },
} }
@@ -119,15 +116,28 @@ func genMockHttpJson(response string, statusCode int) []*HttpJson {
func TestHttpJson200(t *testing.T) { func TestHttpJson200(t *testing.T) {
httpjson := genMockHttpJson(validJSON, 200) httpjson := genMockHttpJson(validJSON, 200)
for _, service := range httpjson { var acc testutil.Accumulator
var acc testutil.Accumulator err := httpjson.Gather(&acc)
err := service.Gather(&acc) require.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 4, acc.NFields()) assert.Equal(t, 8, len(acc.Points))
for _, service := range httpjson.Services {
for _, srv := range service.Servers { for _, srv := range service.Servers {
tags := map[string]string{"server": srv} require.NoError(t,
mname := "httpjson_" + service.Name acc.ValidateTaggedValue(
acc.AssertContainsTaggedFields(t, mname, expectedFields, tags) fmt.Sprintf("%s_parent_child", service.Name),
3.0,
map[string]string{"server": srv},
),
)
require.NoError(t,
acc.ValidateTaggedValue(
fmt.Sprintf("%s_integer", service.Name),
4.0,
map[string]string{"server": srv},
),
)
} }
} }
} }
@@ -137,22 +147,28 @@ func TestHttpJson500(t *testing.T) {
httpjson := genMockHttpJson(validJSON, 500) httpjson := genMockHttpJson(validJSON, 500)
var acc testutil.Accumulator var acc testutil.Accumulator
err := httpjson[0].Gather(&acc) err := httpjson.Gather(&acc)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, 0, acc.NFields()) // 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
assert.Equal(t, 0, len(acc.Points))
} }
// Test response to HTTP 405 // Test response to HTTP 405
func TestHttpJsonBadMethod(t *testing.T) { func TestHttpJsonBadMethod(t *testing.T) {
httpjson := genMockHttpJson(validJSON, 200) httpjson := genMockHttpJson(validJSON, 200)
httpjson[0].Method = "NOT_A_REAL_METHOD" httpjson.Services[0].Method = "NOT_A_REAL_METHOD"
var acc testutil.Accumulator var acc testutil.Accumulator
err := httpjson[0].Gather(&acc) err := httpjson.Gather(&acc)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, 0, acc.NFields()) // 2 error lines for (2 urls) * (1 falied service)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
// (2 measurements) * (2 servers) * (1 successful service)
assert.Equal(t, 4, len(acc.Points))
} }
// Test response to malformed JSON // Test response to malformed JSON
@@ -160,10 +176,12 @@ func TestHttpJsonBadJson(t *testing.T) {
httpjson := genMockHttpJson(invalidJSON, 200) httpjson := genMockHttpJson(invalidJSON, 200)
var acc testutil.Accumulator var acc testutil.Accumulator
err := httpjson[0].Gather(&acc) err := httpjson.Gather(&acc)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, 0, acc.NFields()) // 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
assert.Equal(t, 0, len(acc.Points))
} }
// Test response to empty string as response objectgT // Test response to empty string as response objectgT
@@ -171,27 +189,34 @@ func TestHttpJsonEmptyResponse(t *testing.T) {
httpjson := genMockHttpJson(empty, 200) httpjson := genMockHttpJson(empty, 200)
var acc testutil.Accumulator var acc testutil.Accumulator
err := httpjson[0].Gather(&acc) err := httpjson.Gather(&acc)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, 0, acc.NFields()) // 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
assert.Equal(t, 0, len(acc.Points))
} }
// Test that the proper values are ignored or collected // Test that the proper values are ignored or collected
func TestHttpJson200Tags(t *testing.T) { func TestHttpJson200Tags(t *testing.T) {
httpjson := genMockHttpJson(validJSONTags, 200) httpjson := genMockHttpJson(validJSONTags, 200)
for _, service := range httpjson { var acc testutil.Accumulator
err := httpjson.Gather(&acc)
require.NoError(t, err)
assert.Equal(t, 4, len(acc.Points))
for _, service := range httpjson.Services {
if service.Name == "other_webapp" { if service.Name == "other_webapp" {
var acc testutil.Accumulator
err := service.Gather(&acc)
require.NoError(t, err)
assert.Equal(t, 2, acc.NFields())
for _, srv := range service.Servers { for _, srv := range service.Servers {
tags := map[string]string{"server": srv, "role": "master", "build": "123"} require.NoError(t,
fields := map[string]interface{}{"value": float64(15)} acc.ValidateTaggedValue(
mname := "httpjson_" + service.Name fmt.Sprintf("%s_value", service.Name),
acc.AssertContainsTaggedFields(t, mname, fields, tags) 15.0,
map[string]string{"server": srv, "role": "master", "build": "123"},
),
)
} }
} }
} }

View File

@@ -5,7 +5,7 @@ The influxdb plugin collects InfluxDB-formatted data from JSON endpoints.
With a configuration of: With a configuration of:
```toml ```toml
[[inputs.influxdb]] [[plugins.influxdb]]
urls = [ urls = [
"http://127.0.0.1:8086/debug/vars", "http://127.0.0.1:8086/debug/vars",
"http://192.168.2.1:8086/debug/vars" "http://192.168.2.1:8086/debug/vars"

View File

@@ -8,7 +8,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
type InfluxDB struct { type InfluxDB struct {
@@ -32,7 +32,7 @@ func (*InfluxDB) SampleConfig() string {
` `
} }
func (i *InfluxDB) Gather(acc inputs.Accumulator) error { func (i *InfluxDB) Gather(acc plugins.Accumulator) error {
errorChannel := make(chan error, len(i.URLs)) errorChannel := make(chan error, len(i.URLs))
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -77,7 +77,7 @@ type point struct {
// Returns: // Returns:
// error: Any error that may have occurred // error: Any error that may have occurred
func (i *InfluxDB) gatherURL( func (i *InfluxDB) gatherURL(
acc inputs.Accumulator, acc plugins.Accumulator,
url string, url string,
) error { ) error {
resp, err := http.Get(url) resp, err := http.Get(url)
@@ -140,7 +140,7 @@ func (i *InfluxDB) gatherURL(
} }
func init() { func init() {
inputs.Add("influxdb", func() inputs.Input { plugins.Add("influxdb", func() plugins.Plugin {
return &InfluxDB{} return &InfluxDB{}
}) })
} }

View File

@@ -5,7 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/influxdb/telegraf/plugins/inputs/influxdb" "github.com/influxdb/telegraf/plugins/influxdb"
"github.com/influxdb/telegraf/testutil" "github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -72,26 +72,29 @@ func TestBasic(t *testing.T) {
require.NoError(t, plugin.Gather(&acc)) require.NoError(t, plugin.Gather(&acc))
require.Len(t, acc.Points, 2) require.Len(t, acc.Points, 2)
fields := map[string]interface{}{ require.NoError(t, acc.ValidateTaggedFieldsValue(
// JSON will truncate floats to integer representations. "foo",
// Since there's no distinction in JSON, we can't assume it's an int. map[string]interface{}{
"i": -1.0, // JSON will truncate floats to integer representations.
"f": 0.5, // Since there's no distinction in JSON, we can't assume it's an int.
"b": true, "i": -1.0,
"s": "string", "f": 0.5,
} "b": true,
tags := map[string]string{ "s": "string",
"id": "ex1", },
"url": fakeServer.URL + "/endpoint", map[string]string{
} "id": "ex1",
acc.AssertContainsTaggedFields(t, "foo", fields, tags) "url": fakeServer.URL + "/endpoint",
},
fields = map[string]interface{}{ ))
"x": "x", require.NoError(t, acc.ValidateTaggedFieldsValue(
} "bar",
tags = map[string]string{ map[string]interface{}{
"id": "ex2", "x": "x",
"url": fakeServer.URL + "/endpoint", },
} map[string]string{
acc.AssertContainsTaggedFields(t, "bar", fields, tags) "id": "ex2",
"url": fakeServer.URL + "/endpoint",
},
))
} }

View File

@@ -1,37 +0,0 @@
package all
import (
_ "github.com/influxdb/telegraf/plugins/inputs/aerospike"
_ "github.com/influxdb/telegraf/plugins/inputs/apache"
_ "github.com/influxdb/telegraf/plugins/inputs/bcache"
_ "github.com/influxdb/telegraf/plugins/inputs/disque"
_ "github.com/influxdb/telegraf/plugins/inputs/elasticsearch"
_ "github.com/influxdb/telegraf/plugins/inputs/exec"
_ "github.com/influxdb/telegraf/plugins/inputs/haproxy"
_ "github.com/influxdb/telegraf/plugins/inputs/httpjson"
_ "github.com/influxdb/telegraf/plugins/inputs/influxdb"
_ "github.com/influxdb/telegraf/plugins/inputs/jolokia"
_ "github.com/influxdb/telegraf/plugins/inputs/kafka_consumer"
_ "github.com/influxdb/telegraf/plugins/inputs/leofs"
_ "github.com/influxdb/telegraf/plugins/inputs/lustre2"
_ "github.com/influxdb/telegraf/plugins/inputs/mailchimp"
_ "github.com/influxdb/telegraf/plugins/inputs/memcached"
_ "github.com/influxdb/telegraf/plugins/inputs/mongodb"
_ "github.com/influxdb/telegraf/plugins/inputs/mysql"
_ "github.com/influxdb/telegraf/plugins/inputs/nginx"
_ "github.com/influxdb/telegraf/plugins/inputs/phpfpm"
_ "github.com/influxdb/telegraf/plugins/inputs/ping"
_ "github.com/influxdb/telegraf/plugins/inputs/postgresql"
_ "github.com/influxdb/telegraf/plugins/inputs/procstat"
_ "github.com/influxdb/telegraf/plugins/inputs/prometheus"
_ "github.com/influxdb/telegraf/plugins/inputs/puppetagent"
_ "github.com/influxdb/telegraf/plugins/inputs/rabbitmq"
_ "github.com/influxdb/telegraf/plugins/inputs/redis"
_ "github.com/influxdb/telegraf/plugins/inputs/rethinkdb"
_ "github.com/influxdb/telegraf/plugins/inputs/statsd"
_ "github.com/influxdb/telegraf/plugins/inputs/system"
_ "github.com/influxdb/telegraf/plugins/inputs/trig"
_ "github.com/influxdb/telegraf/plugins/inputs/twemproxy"
_ "github.com/influxdb/telegraf/plugins/inputs/zfs"
_ "github.com/influxdb/telegraf/plugins/inputs/zookeeper"
)

View File

@@ -1,759 +0,0 @@
package elasticsearch
const clusterResponse = `
{
"cluster_name": "elasticsearch_telegraf",
"status": "green",
"timed_out": false,
"number_of_nodes": 3,
"number_of_data_nodes": 3,
"active_primary_shards": 5,
"active_shards": 15,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"indices": {
"v1": {
"status": "green",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 10,
"active_shards": 20,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
},
"v2": {
"status": "red",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20
}
}
}
`
var clusterHealthExpected = map[string]interface{}{
"status": "green",
"timed_out": false,
"number_of_nodes": 3,
"number_of_data_nodes": 3,
"active_primary_shards": 5,
"active_shards": 15,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
}
var v1IndexExpected = map[string]interface{}{
"status": "green",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 10,
"active_shards": 20,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
}
var v2IndexExpected = map[string]interface{}{
"status": "red",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20,
}
const statsResponse = `
{
"cluster_name": "es-testcluster",
"nodes": {
"SDFsfSDFsdfFSDSDfSFDSDF": {
"timestamp": 1436365550135,
"name": "test.host.com",
"transport_address": "inet[/127.0.0.1:9300]",
"host": "test",
"ip": [
"inet[/127.0.0.1:9300]",
"NONE"
],
"attributes": {
"master": "true"
},
"indices": {
"docs": {
"count": 29652,
"deleted": 5229
},
"store": {
"size_in_bytes": 37715234,
"throttle_time_in_millis": 215
},
"indexing": {
"index_total": 84790,
"index_time_in_millis": 29680,
"index_current": 0,
"delete_total": 13879,
"delete_time_in_millis": 1139,
"delete_current": 0,
"noop_update_total": 0,
"is_throttled": false,
"throttle_time_in_millis": 0
},
"get": {
"total": 1,
"time_in_millis": 2,
"exists_total": 0,
"exists_time_in_millis": 0,
"missing_total": 1,
"missing_time_in_millis": 2,
"current": 0
},
"search": {
"open_contexts": 0,
"query_total": 1452,
"query_time_in_millis": 5695,
"query_current": 0,
"fetch_total": 414,
"fetch_time_in_millis": 146,
"fetch_current": 0
},
"merges": {
"current": 0,
"current_docs": 0,
"current_size_in_bytes": 0,
"total": 133,
"total_time_in_millis": 21060,
"total_docs": 203672,
"total_size_in_bytes": 142900226
},
"refresh": {
"total": 1076,
"total_time_in_millis": 20078
},
"flush": {
"total": 115,
"total_time_in_millis": 2401
},
"warmer": {
"current": 0,
"total": 2319,
"total_time_in_millis": 448
},
"filter_cache": {
"memory_size_in_bytes": 7384,
"evictions": 0
},
"id_cache": {
"memory_size_in_bytes": 0
},
"fielddata": {
"memory_size_in_bytes": 12996,
"evictions": 0
},
"percolate": {
"total": 0,
"time_in_millis": 0,
"current": 0,
"memory_size_in_bytes": -1,
"memory_size": "-1b",
"queries": 0
},
"completion": {
"size_in_bytes": 0
},
"segments": {
"count": 134,
"memory_in_bytes": 1285212,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 172368955,
"version_map_memory_in_bytes": 611844,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 17702,
"size_in_bytes": 17
},
"suggest": {
"total": 0,
"time_in_millis": 0,
"current": 0
},
"query_cache": {
"memory_size_in_bytes": 0,
"evictions": 0,
"hit_count": 0,
"miss_count": 0
},
"recovery": {
"current_as_source": 0,
"current_as_target": 0,
"throttle_time_in_millis": 0
}
},
"os": {
"timestamp": 1436460392944,
"load_average": [
0.01,
0.04,
0.05
],
"mem": {
"free_in_bytes": 477761536,
"used_in_bytes": 1621868544,
"free_percent": 74,
"used_percent": 25,
"actual_free_in_bytes": 1565470720,
"actual_used_in_bytes": 534159360
},
"swap": {
"used_in_bytes": 0,
"free_in_bytes": 487997440
}
},
"process": {
"timestamp": 1436460392945,
"open_file_descriptors": 160,
"cpu": {
"percent": 2,
"sys_in_millis": 1870,
"user_in_millis": 13610,
"total_in_millis": 15480
},
"mem": {
"total_virtual_in_bytes": 4747890688
}
},
"jvm": {
"timestamp": 1436460392945,
"uptime_in_millis": 202245,
"mem": {
"heap_used_in_bytes": 52709568,
"heap_used_percent": 5,
"heap_committed_in_bytes": 259522560,
"heap_max_in_bytes": 1038876672,
"non_heap_used_in_bytes": 39634576,
"non_heap_committed_in_bytes": 40841216,
"pools": {
"young": {
"used_in_bytes": 32685760,
"max_in_bytes": 279183360,
"peak_used_in_bytes": 71630848,
"peak_max_in_bytes": 279183360
},
"survivor": {
"used_in_bytes": 8912880,
"max_in_bytes": 34865152,
"peak_used_in_bytes": 8912888,
"peak_max_in_bytes": 34865152
},
"old": {
"used_in_bytes": 11110928,
"max_in_bytes": 724828160,
"peak_used_in_bytes": 14354608,
"peak_max_in_bytes": 724828160
}
}
},
"threads": {
"count": 44,
"peak_count": 45
},
"gc": {
"collectors": {
"young": {
"collection_count": 2,
"collection_time_in_millis": 98
},
"old": {
"collection_count": 1,
"collection_time_in_millis": 24
}
}
},
"buffer_pools": {
"direct": {
"count": 40,
"used_in_bytes": 6304239,
"total_capacity_in_bytes": 6304239
},
"mapped": {
"count": 0,
"used_in_bytes": 0,
"total_capacity_in_bytes": 0
}
}
},
"thread_pool": {
"percolate": {
"threads": 123,
"queue": 23,
"active": 13,
"rejected": 235,
"largest": 23,
"completed": 33
},
"fetch_shard_started": {
"threads": 3,
"queue": 1,
"active": 5,
"rejected": 6,
"largest": 4,
"completed": 54
},
"listener": {
"threads": 1,
"queue": 2,
"active": 4,
"rejected": 8,
"largest": 1,
"completed": 1
},
"index": {
"threads": 6,
"queue": 8,
"active": 4,
"rejected": 2,
"largest": 3,
"completed": 6
},
"refresh": {
"threads": 23,
"queue": 7,
"active": 3,
"rejected": 4,
"largest": 8,
"completed": 3
},
"suggest": {
"threads": 2,
"queue": 7,
"active": 2,
"rejected": 1,
"largest": 8,
"completed": 3
},
"generic": {
"threads": 1,
"queue": 4,
"active": 6,
"rejected": 3,
"largest": 2,
"completed": 27
},
"warmer": {
"threads": 2,
"queue": 7,
"active": 3,
"rejected": 2,
"largest": 3,
"completed": 1
},
"search": {
"threads": 5,
"queue": 7,
"active": 2,
"rejected": 7,
"largest": 2,
"completed": 4
},
"flush": {
"threads": 3,
"queue": 8,
"active": 0,
"rejected": 1,
"largest": 5,
"completed": 3
},
"optimize": {
"threads": 3,
"queue": 4,
"active": 1,
"rejected": 2,
"largest": 7,
"completed": 3
},
"fetch_shard_store": {
"threads": 1,
"queue": 7,
"active": 4,
"rejected": 2,
"largest": 4,
"completed": 1
},
"management": {
"threads": 2,
"queue": 3,
"active": 1,
"rejected": 6,
"largest": 2,
"completed": 22
},
"get": {
"threads": 1,
"queue": 8,
"active": 4,
"rejected": 3,
"largest": 2,
"completed": 1
},
"merge": {
"threads": 6,
"queue": 4,
"active": 5,
"rejected": 2,
"largest": 5,
"completed": 1
},
"bulk": {
"threads": 4,
"queue": 5,
"active": 7,
"rejected": 3,
"largest": 1,
"completed": 4
},
"snapshot": {
"threads": 8,
"queue": 5,
"active": 6,
"rejected": 2,
"largest": 1,
"completed": 0
}
},
"fs": {
"timestamp": 1436460392946,
"total": {
"total_in_bytes": 19507089408,
"free_in_bytes": 16909316096,
"available_in_bytes": 15894814720
},
"data": [
{
"path": "/usr/share/elasticsearch/data/elasticsearch/nodes/0",
"mount": "/usr/share/elasticsearch/data",
"type": "ext4",
"total_in_bytes": 19507089408,
"free_in_bytes": 16909316096,
"available_in_bytes": 15894814720
}
]
},
"transport": {
"server_open": 13,
"rx_count": 6,
"rx_size_in_bytes": 1380,
"tx_count": 6,
"tx_size_in_bytes": 1380
},
"http": {
"current_open": 3,
"total_opened": 3
},
"breakers": {
"fielddata": {
"limit_size_in_bytes": 623326003,
"limit_size": "594.4mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.03,
"tripped": 0
},
"request": {
"limit_size_in_bytes": 415550668,
"limit_size": "396.2mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.0,
"tripped": 0
},
"parent": {
"limit_size_in_bytes": 727213670,
"limit_size": "693.5mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.0,
"tripped": 0
}
}
}
}
}
`
var indicesExpected = map[string]interface{}{
"id_cache_memory_size_in_bytes": float64(0),
"completion_size_in_bytes": float64(0),
"suggest_total": float64(0),
"suggest_time_in_millis": float64(0),
"suggest_current": float64(0),
"query_cache_memory_size_in_bytes": float64(0),
"query_cache_evictions": float64(0),
"query_cache_hit_count": float64(0),
"query_cache_miss_count": float64(0),
"store_size_in_bytes": float64(37715234),
"store_throttle_time_in_millis": float64(215),
"merges_current_docs": float64(0),
"merges_current_size_in_bytes": float64(0),
"merges_total": float64(133),
"merges_total_time_in_millis": float64(21060),
"merges_total_docs": float64(203672),
"merges_total_size_in_bytes": float64(142900226),
"merges_current": float64(0),
"filter_cache_memory_size_in_bytes": float64(7384),
"filter_cache_evictions": float64(0),
"indexing_index_total": float64(84790),
"indexing_index_time_in_millis": float64(29680),
"indexing_index_current": float64(0),
"indexing_noop_update_total": float64(0),
"indexing_throttle_time_in_millis": float64(0),
"indexing_delete_total": float64(13879),
"indexing_delete_time_in_millis": float64(1139),
"indexing_delete_current": float64(0),
"get_exists_time_in_millis": float64(0),
"get_missing_total": float64(1),
"get_missing_time_in_millis": float64(2),
"get_current": float64(0),
"get_total": float64(1),
"get_time_in_millis": float64(2),
"get_exists_total": float64(0),
"refresh_total": float64(1076),
"refresh_total_time_in_millis": float64(20078),
"percolate_current": float64(0),
"percolate_memory_size_in_bytes": float64(-1),
"percolate_queries": float64(0),
"percolate_total": float64(0),
"percolate_time_in_millis": float64(0),
"translog_operations": float64(17702),
"translog_size_in_bytes": float64(17),
"recovery_current_as_source": float64(0),
"recovery_current_as_target": float64(0),
"recovery_throttle_time_in_millis": float64(0),
"docs_count": float64(29652),
"docs_deleted": float64(5229),
"flush_total_time_in_millis": float64(2401),
"flush_total": float64(115),
"fielddata_memory_size_in_bytes": float64(12996),
"fielddata_evictions": float64(0),
"search_fetch_current": float64(0),
"search_open_contexts": float64(0),
"search_query_total": float64(1452),
"search_query_time_in_millis": float64(5695),
"search_query_current": float64(0),
"search_fetch_total": float64(414),
"search_fetch_time_in_millis": float64(146),
"warmer_current": float64(0),
"warmer_total": float64(2319),
"warmer_total_time_in_millis": float64(448),
"segments_count": float64(134),
"segments_memory_in_bytes": float64(1285212),
"segments_index_writer_memory_in_bytes": float64(0),
"segments_index_writer_max_memory_in_bytes": float64(172368955),
"segments_version_map_memory_in_bytes": float64(611844),
"segments_fixed_bit_set_memory_in_bytes": float64(0),
}
var osExpected = map[string]interface{}{
"swap_used_in_bytes": float64(0),
"swap_free_in_bytes": float64(487997440),
"timestamp": float64(1436460392944),
"mem_free_percent": float64(74),
"mem_used_percent": float64(25),
"mem_actual_free_in_bytes": float64(1565470720),
"mem_actual_used_in_bytes": float64(534159360),
"mem_free_in_bytes": float64(477761536),
"mem_used_in_bytes": float64(1621868544),
}
var processExpected = map[string]interface{}{
"mem_total_virtual_in_bytes": float64(4747890688),
"timestamp": float64(1436460392945),
"open_file_descriptors": float64(160),
"cpu_total_in_millis": float64(15480),
"cpu_percent": float64(2),
"cpu_sys_in_millis": float64(1870),
"cpu_user_in_millis": float64(13610),
}
var jvmExpected = map[string]interface{}{
"timestamp": float64(1436460392945),
"uptime_in_millis": float64(202245),
"mem_non_heap_used_in_bytes": float64(39634576),
"mem_non_heap_committed_in_bytes": float64(40841216),
"mem_pools_young_max_in_bytes": float64(279183360),
"mem_pools_young_peak_used_in_bytes": float64(71630848),
"mem_pools_young_peak_max_in_bytes": float64(279183360),
"mem_pools_young_used_in_bytes": float64(32685760),
"mem_pools_survivor_peak_used_in_bytes": float64(8912888),
"mem_pools_survivor_peak_max_in_bytes": float64(34865152),
"mem_pools_survivor_used_in_bytes": float64(8912880),
"mem_pools_survivor_max_in_bytes": float64(34865152),
"mem_pools_old_peak_max_in_bytes": float64(724828160),
"mem_pools_old_used_in_bytes": float64(11110928),
"mem_pools_old_max_in_bytes": float64(724828160),
"mem_pools_old_peak_used_in_bytes": float64(14354608),
"mem_heap_used_in_bytes": float64(52709568),
"mem_heap_used_percent": float64(5),
"mem_heap_committed_in_bytes": float64(259522560),
"mem_heap_max_in_bytes": float64(1038876672),
"threads_peak_count": float64(45),
"threads_count": float64(44),
"gc_collectors_young_collection_count": float64(2),
"gc_collectors_young_collection_time_in_millis": float64(98),
"gc_collectors_old_collection_count": float64(1),
"gc_collectors_old_collection_time_in_millis": float64(24),
"buffer_pools_direct_count": float64(40),
"buffer_pools_direct_used_in_bytes": float64(6304239),
"buffer_pools_direct_total_capacity_in_bytes": float64(6304239),
"buffer_pools_mapped_count": float64(0),
"buffer_pools_mapped_used_in_bytes": float64(0),
"buffer_pools_mapped_total_capacity_in_bytes": float64(0),
}
var threadPoolExpected = map[string]interface{}{
"merge_threads": float64(6),
"merge_queue": float64(4),
"merge_active": float64(5),
"merge_rejected": float64(2),
"merge_largest": float64(5),
"merge_completed": float64(1),
"bulk_threads": float64(4),
"bulk_queue": float64(5),
"bulk_active": float64(7),
"bulk_rejected": float64(3),
"bulk_largest": float64(1),
"bulk_completed": float64(4),
"warmer_threads": float64(2),
"warmer_queue": float64(7),
"warmer_active": float64(3),
"warmer_rejected": float64(2),
"warmer_largest": float64(3),
"warmer_completed": float64(1),
"get_largest": float64(2),
"get_completed": float64(1),
"get_threads": float64(1),
"get_queue": float64(8),
"get_active": float64(4),
"get_rejected": float64(3),
"index_threads": float64(6),
"index_queue": float64(8),
"index_active": float64(4),
"index_rejected": float64(2),
"index_largest": float64(3),
"index_completed": float64(6),
"suggest_threads": float64(2),
"suggest_queue": float64(7),
"suggest_active": float64(2),
"suggest_rejected": float64(1),
"suggest_largest": float64(8),
"suggest_completed": float64(3),
"fetch_shard_store_queue": float64(7),
"fetch_shard_store_active": float64(4),
"fetch_shard_store_rejected": float64(2),
"fetch_shard_store_largest": float64(4),
"fetch_shard_store_completed": float64(1),
"fetch_shard_store_threads": float64(1),
"management_threads": float64(2),
"management_queue": float64(3),
"management_active": float64(1),
"management_rejected": float64(6),
"management_largest": float64(2),
"management_completed": float64(22),
"percolate_queue": float64(23),
"percolate_active": float64(13),
"percolate_rejected": float64(235),
"percolate_largest": float64(23),
"percolate_completed": float64(33),
"percolate_threads": float64(123),
"listener_active": float64(4),
"listener_rejected": float64(8),
"listener_largest": float64(1),
"listener_completed": float64(1),
"listener_threads": float64(1),
"listener_queue": float64(2),
"search_rejected": float64(7),
"search_largest": float64(2),
"search_completed": float64(4),
"search_threads": float64(5),
"search_queue": float64(7),
"search_active": float64(2),
"fetch_shard_started_threads": float64(3),
"fetch_shard_started_queue": float64(1),
"fetch_shard_started_active": float64(5),
"fetch_shard_started_rejected": float64(6),
"fetch_shard_started_largest": float64(4),
"fetch_shard_started_completed": float64(54),
"refresh_rejected": float64(4),
"refresh_largest": float64(8),
"refresh_completed": float64(3),
"refresh_threads": float64(23),
"refresh_queue": float64(7),
"refresh_active": float64(3),
"optimize_threads": float64(3),
"optimize_queue": float64(4),
"optimize_active": float64(1),
"optimize_rejected": float64(2),
"optimize_largest": float64(7),
"optimize_completed": float64(3),
"snapshot_largest": float64(1),
"snapshot_completed": float64(0),
"snapshot_threads": float64(8),
"snapshot_queue": float64(5),
"snapshot_active": float64(6),
"snapshot_rejected": float64(2),
"generic_threads": float64(1),
"generic_queue": float64(4),
"generic_active": float64(6),
"generic_rejected": float64(3),
"generic_largest": float64(2),
"generic_completed": float64(27),
"flush_threads": float64(3),
"flush_queue": float64(8),
"flush_active": float64(0),
"flush_rejected": float64(1),
"flush_largest": float64(5),
"flush_completed": float64(3),
}
var fsExpected = map[string]interface{}{
"timestamp": float64(1436460392946),
"total_free_in_bytes": float64(16909316096),
"total_available_in_bytes": float64(15894814720),
"total_total_in_bytes": float64(19507089408),
}
var transportExpected = map[string]interface{}{
"server_open": float64(13),
"rx_count": float64(6),
"rx_size_in_bytes": float64(1380),
"tx_count": float64(6),
"tx_size_in_bytes": float64(1380),
}
var httpExpected = map[string]interface{}{
"current_open": float64(3),
"total_opened": float64(3),
}
var breakersExpected = map[string]interface{}{
"fielddata_estimated_size_in_bytes": float64(0),
"fielddata_overhead": float64(1.03),
"fielddata_tripped": float64(0),
"fielddata_limit_size_in_bytes": float64(623326003),
"request_estimated_size_in_bytes": float64(0),
"request_overhead": float64(1.0),
"request_tripped": float64(0),
"request_limit_size_in_bytes": float64(415550668),
"parent_overhead": float64(1.0),
"parent_tripped": float64(0),
"parent_limit_size_in_bytes": float64(727213670),
"parent_estimated_size_in_bytes": float64(0),
}

View File

@@ -1,95 +0,0 @@
package exec
import (
"fmt"
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Midnight 9/22/2015
const baseTimeSeconds = 1442905200
const validJson = `
{
"status": "green",
"num_processes": 82,
"cpu": {
"status": "red",
"nil_status": null,
"used": 8234,
"free": 32
},
"percent": 0.81,
"users": [0, 1, 2, 3]
}`
const malformedJson = `
{
"status": "green",
`
type runnerMock struct {
out []byte
err error
}
func newRunnerMock(out []byte, err error) Runner {
return &runnerMock{
out: out,
err: err,
}
}
func (r runnerMock) Run(e *Exec) ([]byte, error) {
if r.err != nil {
return nil, r.err
}
return r.out, nil
}
func TestExec(t *testing.T) {
e := &Exec{
runner: newRunnerMock([]byte(validJson), nil),
Command: "testcommand arg1",
}
var acc testutil.Accumulator
err := e.Gather(&acc)
require.NoError(t, err)
assert.Equal(t, acc.NFields(), 4, "non-numeric measurements should be ignored")
fields := map[string]interface{}{
"num_processes": float64(82),
"cpu_used": float64(8234),
"cpu_free": float64(32),
"percent": float64(0.81),
}
acc.AssertContainsFields(t, "exec", fields)
}
func TestExecMalformed(t *testing.T) {
e := &Exec{
runner: newRunnerMock([]byte(malformedJson), nil),
Command: "badcommand arg1",
}
var acc testutil.Accumulator
err := e.Gather(&acc)
require.Error(t, err)
assert.Equal(t, acc.NFields(), 0, "No new points should have been added")
}
func TestCommandError(t *testing.T) {
e := &Exec{
runner: newRunnerMock(nil, fmt.Errorf("exit status code 1")),
Command: "badcommand",
}
var acc testutil.Accumulator
err := e.Gather(&acc)
require.Error(t, err)
assert.Equal(t, acc.NFields(), 0, "No new points should have been added")
}

View File

@@ -1,48 +0,0 @@
package puppetagent
import (
"github.com/influxdb/telegraf/testutil"
"testing"
)
func TestGather(t *testing.T) {
var acc testutil.Accumulator
pa := PuppetAgent{
Location: "last_run_summary.yaml",
}
pa.Gather(&acc)
tags := map[string]string{"location": "last_run_summary.yaml"}
fields := map[string]interface{}{
"events_failure": int64(0),
"events_total": int64(0),
"events_success": int64(0),
"resources_failed": int64(0),
"resources_scheduled": int64(0),
"resources_changed": int64(0),
"resources_skipped": int64(0),
"resources_total": int64(109),
"resources_failedtorestart": int64(0),
"resources_restarted": int64(0),
"resources_outofsync": int64(0),
"changes_total": int64(0),
"time_lastrun": int64(1444936531),
"version_config": int64(1444936521),
"time_user": float64(0.004331),
"time_schedule": float64(0.001123),
"time_filebucket": float64(0.000353),
"time_file": float64(0.441472),
"time_exec": float64(0.508123),
"time_anchor": float64(0.000555),
"time_sshauthorizedkey": float64(0.000764),
"time_service": float64(1.807795),
"time_package": float64(1.325788),
"time_total": float64(8.85354707064819),
"time_configretrieval": float64(4.75567007064819),
"time_cron": float64(0.000584),
"version_puppet": "3.7.5",
}
acc.AssertContainsTaggedFields(t, "puppetagent", fields, tags)
}

View File

@@ -1,148 +0,0 @@
package system
import (
"fmt"
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/shirou/gopsutil/cpu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCPUStats(t *testing.T) {
var mps MockPS
defer mps.AssertExpectations(t)
var acc testutil.Accumulator
cts := cpu.CPUTimesStat{
CPU: "cpu0",
User: 3.1,
System: 8.2,
Idle: 80.1,
Nice: 1.3,
Iowait: 0.2,
Irq: 0.1,
Softirq: 0.11,
Steal: 0.0511,
Guest: 8.1,
GuestNice: 0.324,
}
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.2812, // increased by 0.0001
Guest: 12.9, // increased by 4.8
GuestNice: 2.524, // increased by 2.2
}
mps.On("CPUTimes").Return([]cpu.CPUTimesStat{cts}, nil)
cs := NewCPUStats(&mps)
cputags := map[string]string{
"cpu": "cpu0",
}
err := cs.Gather(&acc)
require.NoError(t, err)
// Computed values are checked with delta > 0 becasue of floating point arithmatic
// imprecision
assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 3.1, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_system", 8.2, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 80.1, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_nice", 1.3, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 0.2, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_irq", 0.1, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_softirq", 0.11, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_steal", 0.0511, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest", 8.1, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest_nice", 0.324, 0, cputags)
mps2 := MockPS{}
mps2.On("CPUTimes").Return([]cpu.CPUTimesStat{cts2}, nil)
cs.ps = &mps2
// Should have added cpu percentages too
err = cs.Gather(&acc)
require.NoError(t, err)
assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 11.4, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_system", 10.9, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 158.8699, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_nice", 2.5, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 0.7, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_irq", 1.2, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_softirq", 0.31, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_steal", 0.2812, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest", 12.9, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "time_guest_nice", 2.524, 0, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_user", 8.3, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_system", 2.7, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_idle", 78.7699, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_nice", 1.2, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_iowait", 0.5, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_irq", 1.1, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_softirq", 0.2, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_steal", 0.2301, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_guest", 4.8, 0.0005, cputags)
assertContainsTaggedFloat(t, &acc, "cpu", "usage_guest_nice", 2.2, 0.0005, cputags)
}
// 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,
field string,
expectedValue float64,
delta float64,
tags map[string]string,
) {
var actualValue float64
for _, pt := range acc.Points {
if pt.Measurement == measurement {
for fieldname, value := range pt.Fields {
if fieldname == field {
if value, ok := value.(float64); ok {
actualValue = value
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))
}
}
}
}
}
msg := fmt.Sprintf(
"Could not find measurement \"%s\" with requested tags within %f of %f, Actual: %f",
measurement, delta, expectedValue, actualValue)
assert.Fail(t, msg)
}

View File

@@ -1,165 +0,0 @@
package system
import (
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/shirou/gopsutil/disk"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDiskStats(t *testing.T) {
var mps MockPS
defer mps.AssertExpectations(t)
var acc testutil.Accumulator
var err error
du := []*disk.DiskUsageStat{
{
Path: "/",
Fstype: "ext4",
Total: 128,
Free: 23,
InodesTotal: 1234,
InodesFree: 234,
},
{
Path: "/home",
Fstype: "ext4",
Total: 256,
Free: 46,
InodesTotal: 2468,
InodesFree: 468,
},
}
mps.On("DiskUsage").Return(du, nil)
err = (&DiskStats{ps: &mps}).Gather(&acc)
require.NoError(t, err)
numDiskPoints := acc.NFields()
expectedAllDiskPoints := 12
assert.Equal(t, expectedAllDiskPoints, numDiskPoints)
tags1 := map[string]string{
"path": "/",
"fstype": "ext4",
}
tags2 := map[string]string{
"path": "/home",
"fstype": "ext4",
}
fields1 := map[string]interface{}{
"total": uint64(128), //tags1)
"used": uint64(105), //tags1)
"free": uint64(23), //tags1)
"inodes_total": uint64(1234), //tags1)
"inodes_free": uint64(234), //tags1)
"inodes_used": uint64(1000), //tags1)
}
fields2 := map[string]interface{}{
"total": uint64(256), //tags2)
"used": uint64(210), //tags2)
"free": uint64(46), //tags2)
"inodes_total": uint64(2468), //tags2)
"inodes_free": uint64(468), //tags2)
"inodes_used": uint64(2000), //tags2)
}
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
// We expect 6 more DiskPoints to show up with an explicit match on "/"
// and /home not matching the /dev in Mountpoints
err = (&DiskStats{ps: &mps, Mountpoints: []string{"/", "/dev"}}).Gather(&acc)
assert.Equal(t, expectedAllDiskPoints+6, acc.NFields())
// We should see all the diskpoints as Mountpoints includes both
// / and /home
err = (&DiskStats{ps: &mps, Mountpoints: []string{"/", "/home"}}).Gather(&acc)
assert.Equal(t, 2*expectedAllDiskPoints+6, acc.NFields())
}
// func TestDiskIOStats(t *testing.T) {
// var mps MockPS
// defer mps.AssertExpectations(t)
// var acc testutil.Accumulator
// var err error
// diskio1 := disk.DiskIOCountersStat{
// ReadCount: 888,
// WriteCount: 5341,
// ReadBytes: 100000,
// WriteBytes: 200000,
// ReadTime: 7123,
// WriteTime: 9087,
// Name: "sda1",
// IoTime: 123552,
// SerialNumber: "ab-123-ad",
// }
// diskio2 := disk.DiskIOCountersStat{
// ReadCount: 444,
// WriteCount: 2341,
// ReadBytes: 200000,
// WriteBytes: 400000,
// ReadTime: 3123,
// WriteTime: 6087,
// Name: "sdb1",
// IoTime: 246552,
// SerialNumber: "bb-123-ad",
// }
// mps.On("DiskIO").Return(
// map[string]disk.DiskIOCountersStat{"sda1": diskio1, "sdb1": diskio2},
// nil)
// err = (&DiskIOStats{ps: &mps}).Gather(&acc)
// require.NoError(t, err)
// numDiskIOPoints := acc.NFields()
// expectedAllDiskIOPoints := 14
// assert.Equal(t, expectedAllDiskIOPoints, numDiskIOPoints)
// dtags1 := map[string]string{
// "name": "sda1",
// "serial": "ab-123-ad",
// }
// dtags2 := map[string]string{
// "name": "sdb1",
// "serial": "bb-123-ad",
// }
// assert.True(t, acc.CheckTaggedValue("reads", uint64(888), dtags1))
// assert.True(t, acc.CheckTaggedValue("writes", uint64(5341), dtags1))
// assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(100000), dtags1))
// assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(200000), dtags1))
// assert.True(t, acc.CheckTaggedValue("read_time", uint64(7123), dtags1))
// assert.True(t, acc.CheckTaggedValue("write_time", uint64(9087), dtags1))
// assert.True(t, acc.CheckTaggedValue("io_time", uint64(123552), dtags1))
// assert.True(t, acc.CheckTaggedValue("reads", uint64(444), dtags2))
// assert.True(t, acc.CheckTaggedValue("writes", uint64(2341), dtags2))
// assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(200000), dtags2))
// assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(400000), dtags2))
// assert.True(t, acc.CheckTaggedValue("read_time", uint64(3123), dtags2))
// assert.True(t, acc.CheckTaggedValue("write_time", uint64(6087), dtags2))
// assert.True(t, acc.CheckTaggedValue("io_time", uint64(246552), dtags2))
// // We expect 7 more DiskIOPoints to show up with an explicit match on "sdb1"
// // and serial should be missing from the tags with SkipSerialNumber set
// err = (&DiskIOStats{ps: &mps, Devices: []string{"sdb1"}, SkipSerialNumber: true}).Gather(&acc)
// assert.Equal(t, expectedAllDiskIOPoints+7, acc.NFields())
// dtags3 := map[string]string{
// "name": "sdb1",
// }
// assert.True(t, acc.CheckTaggedValue("reads", uint64(444), dtags3))
// assert.True(t, acc.CheckTaggedValue("writes", uint64(2341), dtags3))
// assert.True(t, acc.CheckTaggedValue("read_bytes", uint64(200000), dtags3))
// assert.True(t, acc.CheckTaggedValue("write_bytes", uint64(400000), dtags3))
// assert.True(t, acc.CheckTaggedValue("read_time", uint64(3123), dtags3))
// assert.True(t, acc.CheckTaggedValue("write_time", uint64(6087), dtags3))
// assert.True(t, acc.CheckTaggedValue("io_time", uint64(246552), dtags3))
// }

View File

@@ -1,119 +0,0 @@
// +build linux
package system
import (
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/docker"
"github.com/stretchr/testify/require"
)
func TestDockerStats_GenerateStats(t *testing.T) {
var mps MockPS
var acc testutil.Accumulator
ds := &DockerContainerStat{
Name: "blah",
CPU: &cpu.CPUTimesStat{
CPU: "all",
User: 3.1,
System: 8.2,
Idle: 80.1,
Nice: 1.3,
Iowait: 0.2,
Irq: 0.1,
Softirq: 0.11,
Steal: 0.0001,
Guest: 8.1,
GuestNice: 0.324,
},
Mem: &docker.CgroupMemStat{
ContainerID: "blah",
Cache: 1,
RSS: 2,
RSSHuge: 3,
MappedFile: 4,
Pgpgin: 5,
Pgpgout: 6,
Pgfault: 7,
Pgmajfault: 8,
InactiveAnon: 9,
ActiveAnon: 10,
InactiveFile: 11,
ActiveFile: 12,
Unevictable: 13,
HierarchicalMemoryLimit: 14,
TotalCache: 15,
TotalRSS: 16,
TotalRSSHuge: 17,
TotalMappedFile: 18,
TotalPgpgIn: 19,
TotalPgpgOut: 20,
TotalPgFault: 21,
TotalPgMajFault: 22,
TotalInactiveAnon: 23,
TotalActiveAnon: 24,
TotalInactiveFile: 25,
TotalActiveFile: 26,
TotalUnevictable: 27,
},
}
mps.On("DockerStat").Return([]*DockerContainerStat{ds}, nil)
err := (&DockerStats{&mps}).Gather(&acc)
require.NoError(t, err)
dockertags := map[string]string{
"name": "blah",
"id": "",
"command": "",
}
fields := map[string]interface{}{
"user": 3.1,
"system": 8.2,
"idle": 80.1,
"nice": 1.3,
"iowait": 0.2,
"irq": 0.1,
"softirq": 0.11,
"steal": 0.0001,
"guest": 8.1,
"guest_nice": 0.324,
"cache": uint64(1),
"rss": uint64(2),
"rss_huge": uint64(3),
"mapped_file": uint64(4),
"swap_in": uint64(5),
"swap_out": uint64(6),
"page_fault": uint64(7),
"page_major_fault": uint64(8),
"inactive_anon": uint64(9),
"active_anon": uint64(10),
"inactive_file": uint64(11),
"active_file": uint64(12),
"unevictable": uint64(13),
"memory_limit": uint64(14),
"total_cache": uint64(15),
"total_rss": uint64(16),
"total_rss_huge": uint64(17),
"total_mapped_file": uint64(18),
"total_swap_in": uint64(19),
"total_swap_out": uint64(20),
"total_page_fault": uint64(21),
"total_page_major_fault": uint64(22),
"total_inactive_anon": uint64(23),
"total_active_anon": uint64(24),
"total_inactive_file": uint64(25),
"total_active_file": uint64(26),
"total_unevictable": uint64(27),
}
acc.AssertContainsTaggedFields(t, "docker", fields, dockertags)
}

View File

@@ -1,72 +0,0 @@
package system
import (
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/shirou/gopsutil/mem"
"github.com/stretchr/testify/require"
)
func TestMemStats(t *testing.T) {
var mps MockPS
var err error
defer mps.AssertExpectations(t)
var acc testutil.Accumulator
vms := &mem.VirtualMemoryStat{
Total: 12400,
Available: 7600,
Used: 5000,
Free: 1235,
// Active: 8134,
// Inactive: 1124,
// Buffers: 771,
// Cached: 4312,
// Wired: 134,
// Shared: 2142,
}
mps.On("VMStat").Return(vms, nil)
sms := &mem.SwapMemoryStat{
Total: 8123,
Used: 1232,
Free: 6412,
UsedPercent: 12.2,
Sin: 7,
Sout: 830,
}
mps.On("SwapStat").Return(sms, nil)
err = (&MemStats{&mps}).Gather(&acc)
require.NoError(t, err)
memfields := map[string]interface{}{
"total": uint64(12400),
"available": uint64(7600),
"used": uint64(5000),
"available_percent": float64(7600) / float64(12400) * 100,
"used_percent": float64(5000) / float64(12400) * 100,
"free": uint64(1235),
"cached": uint64(0),
"buffered": uint64(0),
}
acc.AssertContainsTaggedFields(t, "mem", memfields, make(map[string]string))
acc.Points = nil
err = (&SwapStats{&mps}).Gather(&acc)
require.NoError(t, err)
swapfields := map[string]interface{}{
"total": uint64(8123),
"used": uint64(1232),
"used_percent": float64(12.2),
"free": uint64(6412),
"in": uint64(7),
"out": uint64(830),
}
acc.AssertContainsTaggedFields(t, "swap", swapfields, make(map[string]string))
}

View File

@@ -1,171 +0,0 @@
package twemproxy
import (
"encoding/json"
"net"
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/require"
)
const sampleAddr = "127.0.0.1:22222"
const sampleStats = `{
"total_connections": 276448,
"uptime": 160657,
"version": "0.4.1",
"service": "nutcracker",
"curr_connections": 1322,
"source": "server1.website.com",
"demo": {
"client_connections": 1305,
"forward_error": 11684,
"client_err": 147942,
"server_ejects": 0,
"fragments": 0,
"client_eof": 126813,
"10.16.29.1:6379": {
"requests": 43604566,
"server_eof": 0,
"out_queue": 0,
"server_err": 0,
"out_queue_bytes": 0,
"in_queue": 0,
"server_timedout": 24,
"request_bytes": 2775840400,
"server_connections": 1,
"response_bytes": 7663182096,
"in_queue_bytes": 0,
"server_ejected_at": 0,
"responses": 43603900
},
"10.16.29.2:6379": {
"requests": 37870211,
"server_eof": 0,
"out_queue": 0,
"server_err": 0,
"out_queue_bytes": 0,
"in_queue": 0,
"server_timedout": 25,
"request_bytes": 2412114759,
"server_connections": 1,
"response_bytes": 5228980582,
"in_queue_bytes": 0,
"server_ejected_at": 0,
"responses": 37869551
}
},
"timestamp": 1447312436
}`
func mockTwemproxyServer() (net.Listener, error) {
listener, err := net.Listen("tcp", sampleAddr)
if err != nil {
return nil, err
}
go func(l net.Listener) {
for {
conn, _ := l.Accept()
conn.Write([]byte(sampleStats))
conn.Close()
break
}
}(listener)
return listener, nil
}
func TestGather(t *testing.T) {
mockServer, err := mockTwemproxyServer()
if err != nil {
panic(err)
}
defer mockServer.Close()
twemproxy := &Twemproxy{
Addr: sampleAddr,
Pools: []string{"demo"},
}
var acc testutil.Accumulator
acc.SetDebug(true)
err = twemproxy.Gather(&acc)
require.NoError(t, err)
var sourceData map[string]interface{}
if err := json.Unmarshal([]byte(sampleStats), &sourceData); err != nil {
panic(err)
}
fields := map[string]interface{}{
"total_connections": float64(276448),
"curr_connections": float64(1322),
"timestamp": float64(1.447312436e+09),
}
tags := map[string]string{
"twemproxy": sampleAddr,
"source": sourceData["source"].(string),
}
acc.AssertContainsTaggedFields(t, "twemproxy", fields, tags)
poolName := "demo"
poolFields := map[string]interface{}{
"client_connections": float64(1305),
"client_eof": float64(126813),
"client_err": float64(147942),
"forward_error": float64(11684),
"fragments": float64(0),
"server_ejects": float64(0),
}
tags["pool"] = poolName
acc.AssertContainsTaggedFields(t, "twemproxy_pool", poolFields, tags)
poolServerTags1 := map[string]string{
"pool": "demo",
"server": "10.16.29.2:6379",
"source": "server1.website.com",
"twemproxy": "127.0.0.1:22222",
}
poolServerFields1 := map[string]interface{}{
"in_queue": float64(0),
"in_queue_bytes": float64(0),
"out_queue": float64(0),
"out_queue_bytes": float64(0),
"request_bytes": float64(2.412114759e+09),
"requests": float64(3.7870211e+07),
"response_bytes": float64(5.228980582e+09),
"responses": float64(3.7869551e+07),
"server_connections": float64(1),
"server_ejected_at": float64(0),
"server_eof": float64(0),
"server_err": float64(0),
"server_timedout": float64(25),
}
acc.AssertContainsTaggedFields(t, "twemproxy_pool_server",
poolServerFields1, poolServerTags1)
poolServerTags2 := map[string]string{
"pool": "demo",
"server": "10.16.29.1:6379",
"source": "server1.website.com",
"twemproxy": "127.0.0.1:22222",
}
poolServerFields2 := map[string]interface{}{
"in_queue": float64(0),
"in_queue_bytes": float64(0),
"out_queue": float64(0),
"out_queue_bytes": float64(0),
"request_bytes": float64(2.7758404e+09),
"requests": float64(4.3604566e+07),
"response_bytes": float64(7.663182096e+09),
"responses": float64(4.36039e+07),
"server_connections": float64(1),
"server_ejected_at": float64(0),
"server_eof": float64(0),
"server_err": float64(0),
"server_timedout": float64(24),
}
acc.AssertContainsTaggedFields(t, "twemproxy_pool_server",
poolServerFields2, poolServerTags2)
}

View File

@@ -1,366 +0,0 @@
package zfs
import (
"io/ioutil"
"os"
"testing"
"github.com/influxdb/telegraf/testutil"
"github.com/stretchr/testify/require"
)
const arcstatsContents = `5 1 0x01 86 4128 23617128247 12081618582809582
name type data
hits 4 5968846374
misses 4 1659178751
demand_data_hits 4 4860247322
demand_data_misses 4 501499535
demand_metadata_hits 4 708608325
demand_metadata_misses 4 156591375
prefetch_data_hits 4 367047144
prefetch_data_misses 4 974529898
prefetch_metadata_hits 4 32943583
prefetch_metadata_misses 4 26557943
mru_hits 4 301176811
mru_ghost_hits 4 47066067
mfu_hits 4 5520612438
mfu_ghost_hits 4 45784009
deleted 4 1718937704
recycle_miss 4 481222994
mutex_miss 4 20575623
evict_skip 4 14655903906543
evict_l2_cached 4 145310202998272
evict_l2_eligible 4 16345402777088
evict_l2_ineligible 4 7437226893312
hash_elements 4 36617980
hash_elements_max 4 36618318
hash_collisions 4 554145157
hash_chains 4 4187651
hash_chain_max 4 26
p 4 13963222064
c 4 16381258376
c_min 4 4194304
c_max 4 16884125696
size 4 16319887096
hdr_size 4 42567864
data_size 4 60066304
meta_size 4 1701534208
other_size 4 1661543168
anon_size 4 94720
anon_evict_data 4 0
anon_evict_metadata 4 0
mru_size 4 973099008
mru_evict_data 4 9175040
mru_evict_metadata 4 32768
mru_ghost_size 4 32768
mru_ghost_evict_data 4 0
mru_ghost_evict_metadata 4 32768
mfu_size 4 788406784
mfu_evict_data 4 50881024
mfu_evict_metadata 4 81920
mfu_ghost_size 4 0
mfu_ghost_evict_data 4 0
mfu_ghost_evict_metadata 4 0
l2_hits 4 573868618
l2_misses 4 1085309718
l2_feeds 4 12182087
l2_rw_clash 4 9610
l2_read_bytes 4 32695938336768
l2_write_bytes 4 2826774778880
l2_writes_sent 4 4267687
l2_writes_done 4 4267687
l2_writes_error 4 0
l2_writes_hdr_miss 4 164
l2_evict_lock_retry 4 5
l2_evict_reading 4 0
l2_free_on_write 4 1606914
l2_cdata_free_on_write 4 1775
l2_abort_lowmem 4 83462
l2_cksum_bad 4 393860640
l2_io_error 4 53881460
l2_size 4 2471466648576
l2_asize 4 2461690072064
l2_hdr_size 4 12854175552
l2_compress_successes 4 12184849
l2_compress_zeros 4 0
l2_compress_failures 4 0
memory_throttle_count 4 0
duplicate_buffers 4 0
duplicate_buffers_size 4 0
duplicate_reads 4 0
memory_direct_count 4 5159942
memory_indirect_count 4 3034640
arc_no_grow 4 0
arc_tempreserve 4 0
arc_loaned_bytes 4 0
arc_prune 4 114554259559
arc_meta_used 4 16259820792
arc_meta_limit 4 12663094272
arc_meta_max 4 18327165696
`
const zfetchstatsContents = `3 1 0x01 11 528 23607270446 12081656848148208
name type data
hits 4 7812959060
misses 4 4154484207
colinear_hits 4 1366368
colinear_misses 4 4153117839
stride_hits 4 7309776732
stride_misses 4 222766182
reclaim_successes 4 107788388
reclaim_failures 4 4045329451
streams_resets 4 20989756
streams_noresets 4 503182328
bogus_streams 4 0
`
const vdev_cache_statsContents = `7 1 0x01 3 144 23617323692 12081684236238879
name type data
delegations 4 0
hits 4 0
misses 4 0
`
const pool_ioContents = `11 3 0x00 1 80 2225326830828 32953476980628
nread nwritten reads writes wtime wlentime wupdate rtime rlentime rupdate wcnt rcnt
1884160 6450688 22 978 272187126 2850519036 2263669418655 424226814 2850519036 2263669871823 0 0
`
var testKstatPath = os.TempDir() + "/telegraf/proc/spl/kstat/zfs"
func TestZfsPoolMetrics(t *testing.T) {
err := os.MkdirAll(testKstatPath, 0755)
require.NoError(t, err)
err = os.MkdirAll(testKstatPath+"/HOME", 0755)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/HOME/io", []byte(pool_ioContents), 0644)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/arcstats", []byte(arcstatsContents), 0644)
require.NoError(t, err)
poolMetrics := getPoolMetrics()
var acc testutil.Accumulator
z := &Zfs{KstatPath: testKstatPath, KstatMetrics: []string{"arcstats"}}
err = z.Gather(&acc)
require.NoError(t, err)
require.False(t, acc.HasMeasurement("zfs_pool"))
acc.Points = nil
z = &Zfs{KstatPath: testKstatPath, KstatMetrics: []string{"arcstats"}, PoolMetrics: true}
err = z.Gather(&acc)
require.NoError(t, err)
//one pool, all metrics
tags := map[string]string{
"pool": "HOME",
}
acc.AssertContainsTaggedFields(t, "zfs_pool", poolMetrics, tags)
err = os.RemoveAll(os.TempDir() + "/telegraf")
require.NoError(t, err)
}
func TestZfsGeneratesMetrics(t *testing.T) {
err := os.MkdirAll(testKstatPath, 0755)
require.NoError(t, err)
err = os.MkdirAll(testKstatPath+"/HOME", 0755)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/HOME/io", []byte(""), 0644)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/arcstats", []byte(arcstatsContents), 0644)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/zfetchstats", []byte(zfetchstatsContents), 0644)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/vdev_cache_stats", []byte(vdev_cache_statsContents), 0644)
require.NoError(t, err)
intMetrics := getKstatMetricsAll()
var acc testutil.Accumulator
//one pool, all metrics
tags := map[string]string{
"pools": "HOME",
}
z := &Zfs{KstatPath: testKstatPath}
err = z.Gather(&acc)
require.NoError(t, err)
acc.AssertContainsTaggedFields(t, "zfs", intMetrics, tags)
acc.Points = nil
//two pools, all metrics
err = os.MkdirAll(testKstatPath+"/STORAGE", 0755)
require.NoError(t, err)
err = ioutil.WriteFile(testKstatPath+"/STORAGE/io", []byte(""), 0644)
require.NoError(t, err)
tags = map[string]string{
"pools": "HOME::STORAGE",
}
z = &Zfs{KstatPath: testKstatPath}
acc = testutil.Accumulator{}
err = z.Gather(&acc)
require.NoError(t, err)
acc.AssertContainsTaggedFields(t, "zfs", intMetrics, tags)
acc.Points = nil
intMetrics = getKstatMetricsArcOnly()
//two pools, one metric
z = &Zfs{KstatPath: testKstatPath, KstatMetrics: []string{"arcstats"}}
acc = testutil.Accumulator{}
err = z.Gather(&acc)
require.NoError(t, err)
acc.AssertContainsTaggedFields(t, "zfs", intMetrics, tags)
err = os.RemoveAll(os.TempDir() + "/telegraf")
require.NoError(t, err)
}
func getKstatMetricsArcOnly() map[string]interface{} {
return map[string]interface{}{
"arcstats_hits": int64(5968846374),
"arcstats_misses": int64(1659178751),
"arcstats_demand_data_hits": int64(4860247322),
"arcstats_demand_data_misses": int64(501499535),
"arcstats_demand_metadata_hits": int64(708608325),
"arcstats_demand_metadata_misses": int64(156591375),
"arcstats_prefetch_data_hits": int64(367047144),
"arcstats_prefetch_data_misses": int64(974529898),
"arcstats_prefetch_metadata_hits": int64(32943583),
"arcstats_prefetch_metadata_misses": int64(26557943),
"arcstats_mru_hits": int64(301176811),
"arcstats_mru_ghost_hits": int64(47066067),
"arcstats_mfu_hits": int64(5520612438),
"arcstats_mfu_ghost_hits": int64(45784009),
"arcstats_deleted": int64(1718937704),
"arcstats_recycle_miss": int64(481222994),
"arcstats_mutex_miss": int64(20575623),
"arcstats_evict_skip": int64(14655903906543),
"arcstats_evict_l2_cached": int64(145310202998272),
"arcstats_evict_l2_eligible": int64(16345402777088),
"arcstats_evict_l2_ineligible": int64(7437226893312),
"arcstats_hash_elements": int64(36617980),
"arcstats_hash_elements_max": int64(36618318),
"arcstats_hash_collisions": int64(554145157),
"arcstats_hash_chains": int64(4187651),
"arcstats_hash_chain_max": int64(26),
"arcstats_p": int64(13963222064),
"arcstats_c": int64(16381258376),
"arcstats_c_min": int64(4194304),
"arcstats_c_max": int64(16884125696),
"arcstats_size": int64(16319887096),
"arcstats_hdr_size": int64(42567864),
"arcstats_data_size": int64(60066304),
"arcstats_meta_size": int64(1701534208),
"arcstats_other_size": int64(1661543168),
"arcstats_anon_size": int64(94720),
"arcstats_anon_evict_data": int64(0),
"arcstats_anon_evict_metadata": int64(0),
"arcstats_mru_size": int64(973099008),
"arcstats_mru_evict_data": int64(9175040),
"arcstats_mru_evict_metadata": int64(32768),
"arcstats_mru_ghost_size": int64(32768),
"arcstats_mru_ghost_evict_data": int64(0),
"arcstats_mru_ghost_evict_metadata": int64(32768),
"arcstats_mfu_size": int64(788406784),
"arcstats_mfu_evict_data": int64(50881024),
"arcstats_mfu_evict_metadata": int64(81920),
"arcstats_mfu_ghost_size": int64(0),
"arcstats_mfu_ghost_evict_data": int64(0),
"arcstats_mfu_ghost_evict_metadata": int64(0),
"arcstats_l2_hits": int64(573868618),
"arcstats_l2_misses": int64(1085309718),
"arcstats_l2_feeds": int64(12182087),
"arcstats_l2_rw_clash": int64(9610),
"arcstats_l2_read_bytes": int64(32695938336768),
"arcstats_l2_write_bytes": int64(2826774778880),
"arcstats_l2_writes_sent": int64(4267687),
"arcstats_l2_writes_done": int64(4267687),
"arcstats_l2_writes_error": int64(0),
"arcstats_l2_writes_hdr_miss": int64(164),
"arcstats_l2_evict_lock_retry": int64(5),
"arcstats_l2_evict_reading": int64(0),
"arcstats_l2_free_on_write": int64(1606914),
"arcstats_l2_cdata_free_on_write": int64(1775),
"arcstats_l2_abort_lowmem": int64(83462),
"arcstats_l2_cksum_bad": int64(393860640),
"arcstats_l2_io_error": int64(53881460),
"arcstats_l2_size": int64(2471466648576),
"arcstats_l2_asize": int64(2461690072064),
"arcstats_l2_hdr_size": int64(12854175552),
"arcstats_l2_compress_successes": int64(12184849),
"arcstats_l2_compress_zeros": int64(0),
"arcstats_l2_compress_failures": int64(0),
"arcstats_memory_throttle_count": int64(0),
"arcstats_duplicate_buffers": int64(0),
"arcstats_duplicate_buffers_size": int64(0),
"arcstats_duplicate_reads": int64(0),
"arcstats_memory_direct_count": int64(5159942),
"arcstats_memory_indirect_count": int64(3034640),
"arcstats_arc_no_grow": int64(0),
"arcstats_arc_tempreserve": int64(0),
"arcstats_arc_loaned_bytes": int64(0),
"arcstats_arc_prune": int64(114554259559),
"arcstats_arc_meta_used": int64(16259820792),
"arcstats_arc_meta_limit": int64(12663094272),
"arcstats_arc_meta_max": int64(18327165696),
}
}
func getKstatMetricsAll() map[string]interface{} {
otherMetrics := map[string]interface{}{
"zfetchstats_hits": int64(7812959060),
"zfetchstats_misses": int64(4154484207),
"zfetchstats_colinear_hits": int64(1366368),
"zfetchstats_colinear_misses": int64(4153117839),
"zfetchstats_stride_hits": int64(7309776732),
"zfetchstats_stride_misses": int64(222766182),
"zfetchstats_reclaim_successes": int64(107788388),
"zfetchstats_reclaim_failures": int64(4045329451),
"zfetchstats_streams_resets": int64(20989756),
"zfetchstats_streams_noresets": int64(503182328),
"zfetchstats_bogus_streams": int64(0),
"vdev_cache_stats_delegations": int64(0),
"vdev_cache_stats_hits": int64(0),
"vdev_cache_stats_misses": int64(0),
}
arcMetrics := getKstatMetricsArcOnly()
for k, v := range otherMetrics {
arcMetrics[k] = v
}
return arcMetrics
}
func getPoolMetrics() map[string]interface{} {
return map[string]interface{}{
"nread": int64(1884160),
"nwritten": int64(6450688),
"reads": int64(22),
"writes": int64(978),
"wtime": int64(272187126),
"wlentime": int64(2850519036),
"wupdate": int64(2263669418655),
"rtime": int64(424226814),
"rlentime": int64(2850519036),
"rupdate": int64(2263669871823),
"wcnt": int64(0),
"rcnt": int64(0),
}
}

View File

@@ -8,7 +8,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
) )
type Server struct { type Server struct {
@@ -49,7 +49,7 @@ func (j *Jolokia) SampleConfig() string {
context = "/jolokia/read" context = "/jolokia/read"
# List of servers exposing jolokia read service # List of servers exposing jolokia read service
[[inputs.jolokia.servers]] [[plugins.jolokia.servers]]
name = "stable" name = "stable"
host = "192.168.103.2" host = "192.168.103.2"
port = "8180" port = "8180"
@@ -59,7 +59,7 @@ func (j *Jolokia) SampleConfig() string {
# List of metrics collected on above servers # List of metrics collected on above servers
# Each metric consists in a name, a jmx path and either a pass or drop slice attributes # Each metric consists in a name, a jmx path and either a pass or drop slice attributes
# This collect all heap memory usage metrics # This collect all heap memory usage metrics
[[inputs.jolokia.metrics]] [[plugins.jolokia.metrics]]
name = "heap_memory_usage" name = "heap_memory_usage"
jmx = "/java.lang:type=Memory/HeapMemoryUsage" jmx = "/java.lang:type=Memory/HeapMemoryUsage"
` `
@@ -75,6 +75,7 @@ func (j *Jolokia) getAttr(requestUrl *url.URL) (map[string]interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer req.Body.Close()
resp, err := j.jClient.MakeRequest(req) resp, err := j.jClient.MakeRequest(req)
if err != nil { if err != nil {
@@ -108,7 +109,7 @@ func (j *Jolokia) getAttr(requestUrl *url.URL) (map[string]interface{}, error) {
return jsonOut, nil return jsonOut, nil
} }
func (j *Jolokia) Gather(acc inputs.Accumulator) error { func (j *Jolokia) Gather(acc plugins.Accumulator) error {
context := j.Context //"/jolokia/read" context := j.Context //"/jolokia/read"
servers := j.Servers servers := j.Servers
metrics := j.Metrics metrics := j.Metrics
@@ -157,7 +158,7 @@ func (j *Jolokia) Gather(acc inputs.Accumulator) error {
} }
func init() { func init() {
inputs.Add("jolokia", func() inputs.Input { plugins.Add("jolokia", func() plugins.Plugin {
return &Jolokia{jClient: &JolokiaClientImpl{client: &http.Client{}}} return &Jolokia{jClient: &JolokiaClientImpl{client: &http.Client{}}}
}) })
} }

View File

@@ -48,7 +48,7 @@ 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", Jmx: "/java.lang:type=Memory/HeapMemoryUsage"}
var UsedHeapMetric = Metric{Name: "heap_memory_usage", Jmx: "/java.lang:type=Memory/HeapMemoryUsage"} var UsedHeapMetric = Metric{Name: "heap_memory_usage", Jmx: "/java.lang:type=Memory/HeapMemoryUsage", Pass: []string{"used"}}
type jolokiaClientStub struct { type jolokiaClientStub struct {
responseBody string responseBody string
@@ -79,6 +79,7 @@ func genJolokiaClientStub(response string, statusCode int, servers []Server, met
// Test that the proper values are ignored or collected // Test that the proper values are ignored or collected
func TestHttpJsonMultiValue(t *testing.T) { func TestHttpJsonMultiValue(t *testing.T) {
jolokia := genJolokiaClientStub(validMultiValueJSON, 200, Servers, []Metric{HeapMetric}) jolokia := genJolokiaClientStub(validMultiValueJSON, 200, Servers, []Metric{HeapMetric})
var acc testutil.Accumulator var acc testutil.Accumulator
@@ -87,28 +88,58 @@ func TestHttpJsonMultiValue(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(acc.Points)) assert.Equal(t, 1, len(acc.Points))
fields := map[string]interface{}{ assert.True(t, acc.CheckFieldsValue("heap_memory_usage", map[string]interface{}{"init": 67108864.0,
"heap_memory_usage_init": 67108864.0, "committed": 456130560.0,
"heap_memory_usage_committed": 456130560.0, "max": 477626368.0,
"heap_memory_usage_max": 477626368.0, "used": 203288528.0}))
"heap_memory_usage_used": 203288528.0, }
}
tags := map[string]string{ // Test that the proper values are ignored or collected
"host": "127.0.0.1", func TestHttpJsonMultiValueWithPass(t *testing.T) {
"port": "8080",
"server": "as1", jolokia := genJolokiaClientStub(validMultiValueJSON, 200, Servers, []Metric{UsedHeapMetric})
}
acc.AssertContainsTaggedFields(t, "jolokia", fields, tags) var acc testutil.Accumulator
err := jolokia.Gather(&acc)
assert.Nil(t, err)
assert.Equal(t, 1, len(acc.Points))
assert.True(t, acc.CheckFieldsValue("heap_memory_usage", map[string]interface{}{"used": 203288528.0}))
}
// Test that the proper values are ignored or collected
func TestHttpJsonMultiValueTags(t *testing.T) {
jolokia := genJolokiaClientStub(validMultiValueJSON, 200, Servers, []Metric{UsedHeapMetric})
var acc testutil.Accumulator
err := jolokia.Gather(&acc)
assert.Nil(t, err)
assert.Equal(t, 1, len(acc.Points))
assert.NoError(t, acc.ValidateTaggedFieldsValue("heap_memory_usage", map[string]interface{}{"used": 203288528.0}, map[string]string{"host": "127.0.0.1", "port": "8080", "server": "as1"}))
}
// Test that the proper values are ignored or collected
func TestHttpJsonSingleValueTags(t *testing.T) {
jolokia := genJolokiaClientStub(validSingleValueJSON, 200, Servers, []Metric{UsedHeapMetric})
var acc testutil.Accumulator
err := jolokia.Gather(&acc)
assert.Nil(t, err)
assert.Equal(t, 1, len(acc.Points))
assert.NoError(t, acc.ValidateTaggedFieldsValue("heap_memory_usage", map[string]interface{}{"value": 209274376.0}, map[string]string{"host": "127.0.0.1", "port": "8080", "server": "as1"}))
} }
// Test that the proper values are ignored or collected // Test that the proper values are ignored or collected
func TestHttpJsonOn404(t *testing.T) { func TestHttpJsonOn404(t *testing.T) {
jolokia := genJolokiaClientStub(validMultiValueJSON, 404, Servers, jolokia := genJolokiaClientStub(validMultiValueJSON, 404, Servers, []Metric{UsedHeapMetric})
[]Metric{UsedHeapMetric})
var acc testutil.Accumulator var acc testutil.Accumulator
acc.SetDebug(true)
err := jolokia.Gather(&acc) err := jolokia.Gather(&acc)
assert.Nil(t, err) assert.Nil(t, err)

View File

@@ -6,7 +6,7 @@ import (
"sync" "sync"
"github.com/influxdb/influxdb/models" "github.com/influxdb/influxdb/models"
"github.com/influxdb/telegraf/plugins/inputs" "github.com/influxdb/telegraf/plugins"
"github.com/Shopify/sarama" "github.com/Shopify/sarama"
"github.com/wvanbergen/kafka/consumergroup" "github.com/wvanbergen/kafka/consumergroup"
@@ -148,7 +148,7 @@ func (k *Kafka) Stop() {
} }
} }
func (k *Kafka) Gather(acc inputs.Accumulator) error { func (k *Kafka) Gather(acc plugins.Accumulator) error {
k.Lock() k.Lock()
defer k.Unlock() defer k.Unlock()
npoints := len(k.pointChan) npoints := len(k.pointChan)
@@ -160,7 +160,7 @@ func (k *Kafka) Gather(acc inputs.Accumulator) error {
} }
func init() { func init() {
inputs.Add("kafka_consumer", func() inputs.Input { plugins.Add("kafka_consumer", func() plugins.Plugin {
return &Kafka{} return &Kafka{}
}) })
} }

View File

@@ -85,8 +85,7 @@ func TestRunParserAndGather(t *testing.T) {
k.Gather(&acc) k.Gather(&acc)
assert.Equal(t, len(acc.Points), 1) assert.Equal(t, len(acc.Points), 1)
acc.AssertContainsFields(t, "cpu_load_short", assert.True(t, acc.CheckValue("cpu_load_short", 23422.0))
map[string]interface{}{"value": float64(23422)})
} }
func saramaMsg(val string) *sarama.ConsumerMessage { func saramaMsg(val string) *sarama.ConsumerMessage {

Some files were not shown because too many files have changed in this diff Show More