diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..2ddcce1e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,145 @@ +--- +defaults: + defaults: &defaults + working_directory: '/go/src/github.com/influxdata/telegraf' + go-1_9: &go-1_9 + docker: + - image: 'quay.io/influxdb/telegraf-ci:1.9.7' + go-1_10: &go-1_10 + docker: + - image: 'quay.io/influxdb/telegraf-ci:1.10.3' + +version: 2 +jobs: + deps: + <<: [ *defaults, *go-1_10 ] + steps: + - checkout + - restore_cache: + key: vendor-{{ checksum "Gopkg.lock" }} + - run: 'make deps' + - save_cache: + name: 'vendored deps' + key: vendor-{{ checksum "Gopkg.lock" }} + paths: + - './vendor' + - persist_to_workspace: + root: '/go/src' + paths: + - '*' + + test-go-1.9: + <<: [ *defaults, *go-1_9 ] + steps: + - attach_workspace: + at: '/go/src' + - run: 'make check' + - run: 'make test' + test-go-1.10: + <<: [ *defaults, *go-1_10 ] + steps: + - attach_workspace: + at: '/go/src' + - run: 'make check' + - run: 'make test' + test-go-1.10-386: + <<: [ *defaults, *go-1_10 ] + steps: + - attach_workspace: + at: '/go/src' + - run: 'GOARCH=386 make check' + - run: 'GOARCH=386 make test' + + package: + <<: [ *defaults, *go-1_10 ] + steps: + - attach_workspace: + at: '/go/src' + - run: 'make package' + - store_artifacts: + path: './build' + destination: 'build' + release: + <<: [ *defaults, *go-1_10 ] + steps: + - attach_workspace: + at: '/go/src' + - run: 'make package-release' + - store_artifacts: + path: './build' + destination: 'build' + nightly: + <<: [ *defaults, *go-1_10 ] + steps: + - attach_workspace: + at: '/go/src' + - run: 'make package-nightly' + - store_artifacts: + path: './build' + destination: 'build' + +workflows: + version: 2 + check: + jobs: + - 'deps': + filters: + tags: + only: /.*/ + - 'test-go-1.9': + requires: + - 'deps' + filters: + tags: + only: /.*/ + - 'test-go-1.10': + requires: + - 'deps' + filters: + tags: + only: /.*/ + - 'test-go-1.10-386': + requires: + - 'deps' + filters: + tags: + only: /.*/ + - 'package': + requires: + - 'test-go-1.9' + - 'test-go-1.10' + - 'test-go-1.10-386' + - 'release': + requires: + - 'test-go-1.9' + - 'test-go-1.10' + - 'test-go-1.10-386' + filters: + tags: + only: /.*/ + branches: + ignore: /.*/ + nightly: + jobs: + - 'deps' + - 'test-go-1.9': + requires: + - 'deps' + - 'test-go-1.10': + requires: + - 'deps' + - 'test-go-1.10-386': + requires: + - 'deps' + - 'nightly': + requires: + - 'test-go-1.9' + - 'test-go-1.10' + - 'test-go-1.10-386' + triggers: + - schedule: + cron: "0 7 * * *" + filters: + branches: + only: + - master diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index f4190e3e..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,44 +0,0 @@ -## Directions - -GitHub Issues are reserved for actionable bug reports and feature requests. -General questions should be asked at the [InfluxData Community](https://community.influxdata.com) site. - -Before opening an issue, search for similar bug reports or feature requests on GitHub Issues. -If no similar issue can be found, fill out either the "Bug Report" or the "Feature Request" section below. -Erase the other section and everything on and above this line. - -*Please note, the quickest way to fix a bug is to open a Pull Request.* - -## Bug report - -### Relevant telegraf.conf: - -### System info: - -[Include Telegraf version, operating system name, and other relevant details] - -### Steps to reproduce: - -1. ... -2. ... - -### Expected behavior: - -### Actual behavior: - -### Additional info: - -[Include gist of relevant config, logs, etc.] - - -## Feature Request - -Opening a feature request kicks off a discussion. - -### Proposal: - -### Current behavior: - -### Desired behavior: - -### Use case: [Why is this important (helps with prioritizing requests)] diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md new file mode 100644 index 00000000..b84aad76 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +### Relevant telegraf.conf: + +### System info: + +[Include Telegraf version, operating system name, and other relevant details] + +### Steps to reproduce: + +1. ... +2. ... + +### Expected behavior: + +### Actual behavior: + +### Additional info: + +[Include gist of relevant config, logs, etc.] diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md new file mode 100644 index 00000000..84d45fcd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +## Feature Request + +Opening a feature request kicks off a discussion. + +### Proposal: + +### Current behavior: + +### Desired behavior: + +### Use case: [Why is this important (helps with prioritizing requests)] diff --git a/.gitignore b/.gitignore index 8269337d..4176a041 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -build -tivan -.vagrant +/build /telegraf -.idea -*~ -*# +/telegraf.exe +/telegraf.gz +/vendor diff --git a/CHANGELOG.md b/CHANGELOG.md index d02acae9..5c517ab6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,484 @@ -## v1.5 [unreleased] +## v1.9 [unreleased] + +### Features + +- [#4686](https://github.com/influxdata/telegraf/pull/4686): Add replace function to strings processor. +- [#4754](https://github.com/influxdata/telegraf/pull/4754): Query servers in parallel in dns_query input. +- [#4753](https://github.com/influxdata/telegraf/pull/4753): Add ability to define a custom service name when installing as a Windows service. + +## v1.8.1 [unreleased] + +### Bugfixes + +- [#4750](https://github.com/influxdata/telegraf/pull/4750): Fix hardware_type may be truncated in sqlserver input. +- [#4723](https://github.com/influxdata/telegraf/issues/4723): Improve performance in basicstats aggregator. +- [#4747](https://github.com/influxdata/telegraf/pull/4723): Add hostname to TLS config for SNI support. +- [#4675](https://github.com/influxdata/telegraf/issues/4675): Don't add tags with empty values to opentsdb output. +- [#4765](https://github.com/influxdata/telegraf/pull/4765): Fix panic during network error in vsphere input. + +## v1.8 [2018-09-21] + +### New Inputs + +- [activemq](./plugins/inputs/activemq/README.md) - Contributed by @mlabouardy +- [beanstalkd](./plugins/inputs/beanstalkd/README.md) - Contributed by @44px +- [filecount](./plugins/inputs/filecount/README.md) - Contributed by @sometimesfood +- [file](./plugins/inputs/file/README.md) - Contributed by @maxunt +- [icinga2](./plugins/inputs/icinga2/README.md) - Contributed by @mlabouardy +- [kibana](./plugins/inputs/kibana/README.md) - Contributed by @lpic10 +- [pgbouncer](./plugins/inputs/pgbouncer/README.md) - Contributed by @nerzhul +- [temp](./plugins/inputs/temp/README.md) - Contributed by @pytimer +- [tengine](./plugins/inputs/tengine/README.md) - Contributed by @ertaoxu +- [vsphere](./plugins/inputs/vsphere/README.md) - Contributed by @prydin +- [x509_cert](./plugins/inputs/x509_cert/README.md) - Contributed by @jtyr + +### New Processors + +- [enum](./plugins/processors/enum/README.md) - Contributed by @KarstenSchnitter +- [parser](./plugins/processors/parser/README.md) - Contributed by @Ayrdrie & @maxunt +- [rename](./plugins/processors/rename/README.md) - Contributed by @goldibex +- [strings](./plugins/processors/strings/README.md) - Contributed by @bsmaldon + +### New Aggregators + +- [valuecounter](./plugins/aggregators/valuecounter/README.md) - Contributed by @piotr1212 + +### New Outputs + +- [azure_monitor](./plugins/outputs/azure_monitor/README.md) - Contributed by @influxdata +- [influxdb_v2](./plugins/outputs/influxdb_v2/README.md) - Contributed by @influxdata + +### New Parsers + +- [csv](/docs/DATA_FORMATS_INPUT.md#csv) - Contributed by @maxunt +- [grok](/docs/DATA_FORMATS_INPUT.md#grok) - Contributed by @maxunt +- [logfmt](/docs/DATA_FORMATS_INPUT.md#logfmt) - Contributed by @Ayrdrie & @maxunt + +### New Serializers + +- [splunkmetric](/plugins/serializers/splunkmetric/README.md) - Contributed by @ronnocol + +### Features + +- [#4236](https://github.com/influxdata/telegraf/pull/4236): Add SSL/TLS support to redis input. +- [#4160](https://github.com/influxdata/telegraf/pull/4160): Add tengine input plugin. +- [#4262](https://github.com/influxdata/telegraf/pull/4262): Add power draw field to nvidia_smi plugin. +- [#4271](https://github.com/influxdata/telegraf/pull/4271): Add support for solr 7 to the solr input. +- [#4281](https://github.com/influxdata/telegraf/pull/4281): Add owner tag on partitions in burrow input. +- [#4259](https://github.com/influxdata/telegraf/pull/4259): Add container status tag to docker input. +- [#3523](https://github.com/influxdata/telegraf/pull/3523): Add valuecounter aggregator plugin. +- [#4307](https://github.com/influxdata/telegraf/pull/4307): Add new measurement with results of pgrep lookup to procstat input. +- [#4311](https://github.com/influxdata/telegraf/pull/4311): Add support for comma in logparser timestamp format. +- [#4292](https://github.com/influxdata/telegraf/pull/4292): Add path tag to tail input plugin. +- [#4322](https://github.com/influxdata/telegraf/pull/4322): Add log message when tail is added or removed from a file. +- [#4267](https://github.com/influxdata/telegraf/pull/4267): Add option to use of counter time in win perf counters. +- [#4343](https://github.com/influxdata/telegraf/pull/4343): Add energy and power field and device id tag to fibaro input. +- [#4347](https://github.com/influxdata/telegraf/pull/4347): Add http path configuration for OpenTSDB output. +- [#4352](https://github.com/influxdata/telegraf/pull/4352): Gather IPMI metrics concurrently. +- [#4362](https://github.com/influxdata/telegraf/pull/4362): Add mongo document and connection metrics. +- [#3772](https://github.com/influxdata/telegraf/pull/3772): Add enum processor plugin. +- [#4386](https://github.com/influxdata/telegraf/pull/4386): Add user tag to procstat input. +- [#4403](https://github.com/influxdata/telegraf/pull/4403): Add support for multivalue metrics to collectd parser. +- [#4418](https://github.com/influxdata/telegraf/pull/4418): Add support for setting kafka client id. +- [#4332](https://github.com/influxdata/telegraf/pull/4332): Add file input plugin and grok parser. +- [#4320](https://github.com/influxdata/telegraf/pull/4320): Improve cloudwatch output performance. +- [#3768](https://github.com/influxdata/telegraf/pull/3768): Add x509_cert input plugin. +- [#4471](https://github.com/influxdata/telegraf/pull/4471): Add IPSIpAddress syntax to ipaddr conversion in snmp plugin. +- [#4363](https://github.com/influxdata/telegraf/pull/4363): Add filecount input plugin. +- [#4485](https://github.com/influxdata/telegraf/pull/4485): Add support for configuring an AWS endpoint_url. +- [#4491](https://github.com/influxdata/telegraf/pull/4491): Send all messages before waiting for results in kafka output. +- [#4492](https://github.com/influxdata/telegraf/pull/4492): Add support for lz4 compression to kafka output. +- [#4450](https://github.com/influxdata/telegraf/pull/4450): Split multiple sensor keys in ipmi input. +- [#4364](https://github.com/influxdata/telegraf/pull/4364): Support StatisticValues in cloudwatch output plugin. +- [#4431](https://github.com/influxdata/telegraf/pull/4431): Add ip restriction for the prometheus_client output. +- [#3918](https://github.com/influxdata/telegraf/pull/3918): Add pgbouncer input plugin. +- [#2689](https://github.com/influxdata/telegraf/pull/2689): Add ActiveMQ input plugin. +- [#4402](https://github.com/influxdata/telegraf/pull/4402): Add wavefront parser plugin. +- [#4528](https://github.com/influxdata/telegraf/pull/4528): Add rename processor plugin. +- [#4537](https://github.com/influxdata/telegraf/pull/4537): Add message 'max_bytes' configuration to kafka input. +- [#4546](https://github.com/influxdata/telegraf/pull/4546): Add gopsutil meminfo fields to mem plugin. +- [#4285](https://github.com/influxdata/telegraf/pull/4285): Document how to parse telegraf logs. +- [#4542](https://github.com/influxdata/telegraf/pull/4542): Use dep v0.5.0. +- [#4433](https://github.com/influxdata/telegraf/pull/4433): Add ability to set measurement from matched text in grok parser. +- [#4565](https://github.com/influxdata/telegraf/pull/4465): Drop message batches in kafka output if too large. +- [#4579](https://github.com/influxdata/telegraf/pull/4579): Add support for static and random routing keys in kafka output. +- [#4539](https://github.com/influxdata/telegraf/pull/4539): Add logfmt parser plugin. +- [#4551](https://github.com/influxdata/telegraf/pull/4551): Add parser processor plugin. +- [#4559](https://github.com/influxdata/telegraf/pull/4559): Add Icinga2 input plugin. +- [#4351](https://github.com/influxdata/telegraf/pull/4351): Add name, time, path and string field options to JSON parser. +- [#4571](https://github.com/influxdata/telegraf/pull/4571): Add forwarded records to sqlserver input. +- [#4585](https://github.com/influxdata/telegraf/pull/4585): Add Kibana input plugin. +- [#4439](https://github.com/influxdata/telegraf/pull/4439): Add csv parser plugin. +- [#4598](https://github.com/influxdata/telegraf/pull/4598): Add read_buffer_size option to statsd input. +- [#4089](https://github.com/influxdata/telegraf/pull/4089): Add azure_monitor output plugin. +- [#4628](https://github.com/influxdata/telegraf/pull/4628): Add queue_durability parameter to amqp_consumer input. +- [#4476](https://github.com/influxdata/telegraf/pull/4476): Add strings processor. +- [#4536](https://github.com/influxdata/telegraf/pull/4536): Add OAuth2 support to HTTP output plugin. +- [#4633](https://github.com/influxdata/telegraf/pull/4633): Add Unix epoch timestamp support for JSON parser. +- [#4657](https://github.com/influxdata/telegraf/pull/4657): Add options for basic auth to haproxy input. +- [#4411](https://github.com/influxdata/telegraf/pull/4411): Add temp input plugin. +- [#4272](https://github.com/influxdata/telegraf/pull/4272): Add Beanstalkd input plugin. +- [#4669](https://github.com/influxdata/telegraf/pull/4669): Add means to specify server password for redis input. +- [#4339](https://github.com/influxdata/telegraf/pull/4339): Add Splunk Metrics serializer. +- [#4141](https://github.com/influxdata/telegraf/pull/4141): Add input plugin for VMware vSphere. +- [#4667](https://github.com/influxdata/telegraf/pull/4667): Align metrics window to interval in cloudwatch input. +- [#4642](https://github.com/influxdata/telegraf/pull/4642): Improve Azure Managed Instance support + more in sqlserver input. +- [#4682](https://github.com/influxdata/telegraf/pull/4682): Allow alternate binaries for iptables input plugin. +- [#4645](https://github.com/influxdata/telegraf/pull/4645): Add influxdb_v2 output plugin. + +### Bugfixes + +- [#3438](https://github.com/influxdata/telegraf/issues/3438): Fix divide by zero in logparser input. +- [#4499](https://github.com/influxdata/telegraf/issues/4499): Fix instance and object name in performance counters with backslashes. +- [#4646](https://github.com/influxdata/telegraf/issues/4646): Reset/flush saved contents from bad metric. +- [#4520](https://github.com/influxdata/telegraf/issues/4520): Document all supported cli arguments. +- [#4674](https://github.com/influxdata/telegraf/pull/4674): Log access denied opening a service at debug level in win_services. +- [#4588](https://github.com/influxdata/telegraf/issues/4588): Add support for Kafka 2.0. +- [#4087](https://github.com/influxdata/telegraf/issues/4087): Fix nagios parser does not support ranges in performance data. +- [#4088](https://github.com/influxdata/telegraf/issues/4088): Fix nagios parser does not strip quotes from performance data. +- [#4688](https://github.com/influxdata/telegraf/issues/4688): Fix null value crash in postgresql_extensible input. +- [#4681](https://github.com/influxdata/telegraf/pull/4681): Remove the startup authentication check from the cloudwatch output. +- [#4644](https://github.com/influxdata/telegraf/issues/4644): Support tailing files created after startup in tail input. +- [#4706](https://github.com/influxdata/telegraf/issues/4706): Fix csv format configuration loading. + +## v1.7.4 [2018-08-29] + +### Bugfixes + +- [#4534](https://github.com/influxdata/telegraf/pull/4534): Skip unserializable metric in influxDB UDP output. +- [#4554](https://github.com/influxdata/telegraf/pull/4554): Fix powerdns input tests. +- [#4584](https://github.com/influxdata/telegraf/pull/4584): Fix burrow_group offset calculation for burrow input. +- [#4550](https://github.com/influxdata/telegraf/pull/4550): Add result_code value for errors running ping command. +- [#4605](https://github.com/influxdata/telegraf/pull/4605): Remove timeout deadline for udp syslog input. +- [#4601](https://github.com/influxdata/telegraf/issues/4601): Ensure channel closed if an error occurs in cgroup input. +- [#4544](https://github.com/influxdata/telegraf/issues/4544): Fix sending of basic auth credentials in http output. +- [#4526](https://github.com/influxdata/telegraf/issues/4526): Use the correct GOARM value in the armel package. + +## v1.7.3 [2018-08-07] + +### Bugfixes + +- [#4434](https://github.com/influxdata/telegraf/issues/4434): Reduce required docker API version. +- [#4498](https://github.com/influxdata/telegraf/pull/4498): Keep leading whitespace for messages in syslog input. +- [#4470](https://github.com/influxdata/telegraf/issues/4470): Skip bad entries on interrupt input. +- [#4501](https://github.com/influxdata/telegraf/issues/4501): Preserve metric type when using filters in output plugins. +- [#3794](https://github.com/influxdata/telegraf/issues/3794): Fix error message if URL is unparseable in influxdb output. +- [#4059](https://github.com/influxdata/telegraf/issues/4059): Use explicit zpool properties to fix parse error on FreeBSD 11.2. +- [#4514](https://github.com/influxdata/telegraf/pull/4514): Lock buffer when adding metrics. + +## v1.7.2 [2018-07-18] + +### Bugfixes + +- [#4381](https://github.com/influxdata/telegraf/issues/4381): Use localhost as default server tag in zookeeper input. +- [#4374](https://github.com/influxdata/telegraf/issues/4374): Don't set values when pattern doesn't match in regex processor. +- [#4416](https://github.com/influxdata/telegraf/issues/4416): Fix output format of printer processor. +- [#4422](https://github.com/influxdata/telegraf/issues/4422): Fix metric can have duplicate field. +- [#4389](https://github.com/influxdata/telegraf/issues/4389): Return error if NewRequest fails in http output. +- [#4335](https://github.com/influxdata/telegraf/issues/4335): Reset read deadline for syslog input. +- [#4375](https://github.com/influxdata/telegraf/issues/4375): Exclude cached memory on docker input plugin. + +## v1.7.1 [2018-07-03] + +### Bugfixes + +- [#4277](https://github.com/influxdata/telegraf/pull/4277): Treat sigterm as a clean shutdown signal. +- [#4284](https://github.com/influxdata/telegraf/pull/4284): Fix selection of tags under nested objects in the JSON parser. +- [#4135](https://github.com/influxdata/telegraf/issues/4135): Fix postfix input handling multi-level queues. +- [#4334](https://github.com/influxdata/telegraf/pull/4334): Fix syslog timestamp parsing with single digit day of month. +- [#2910](https://github.com/influxdata/telegraf/issues/2910): Handle mysql input variations in the user_statistics collecting. +- [#4293](https://github.com/influxdata/telegraf/issues/4293): Fix minmax and basicstats aggregators to use uint64. +- [#4290](https://github.com/influxdata/telegraf/issues/4290): Document swap input plugin. +- [#4316](https://github.com/influxdata/telegraf/issues/4316): Fix incorrect precision being applied to metric in http_listener. + +## v1.7 [2018-06-12] + +### Release Notes + +- The `cassandra` input plugin has been deprecated in favor of the `jolokia2` + input plugin which is much more configurable and more performant. There is + an [example configuration](./plugins/inputs/jolokia2/examples) to help you + get started. + +- For plugins supporting TLS, you can now specify the certificate and keys + using `tls_ca`, `tls_cert`, `tls_key`. These options behave the same as + the, now deprecated, `ssl` forms. + +### New Inputs + +- [aurora](./plugins/inputs/aurora/README.md) - Contributed by @influxdata +- [burrow](./plugins/inputs/burrow/README.md) - Contributed by @arkady-emelyanov +- [fibaro](./plugins/inputs/fibaro/README.md) - Contributed by @dynek +- [jti_openconfig_telemetry](./plugins/inputs/jti_openconfig_telemetry/README.md) - Contributed by @ajhai +- [mcrouter](./plugins/inputs/mcrouter/README.md) - Contributed by @cthayer +- [nvidia_smi](./plugins/inputs/nvidia_smi/README.md) - Contributed by @jackzampolin +- [syslog](./plugins/inputs/syslog/README.md) - Contributed by @influxdata + +### New Processors + +- [converter](./plugins/processors/converter/README.md) - Contributed by @influxdata +- [regex](./plugins/processors/regex/README.md) - Contributed by @44px +- [topk](./plugins/processors/topk/README.md) - Contributed by @mirath + +### New Outputs + +- [http](./plugins/outputs/http/README.md) - Contributed by @Dark0096 +- [application_insights](./plugins/outputs/application_insights/README.md): Contribute by @karolz-ms + +### Features + +- [#3964](https://github.com/influxdata/telegraf/pull/3964): Add repl_oplog_window_sec metric to mongodb input. +- [#3819](https://github.com/influxdata/telegraf/pull/3819): Add per-host shard metrics in mongodb input. +- [#3999](https://github.com/influxdata/telegraf/pull/3999): Skip files with leading `..` in config directory. +- [#4021](https://github.com/influxdata/telegraf/pull/4021): Add TLS support to socket_writer and socket_listener plugins. +- [#4025](https://github.com/influxdata/telegraf/pull/4025): Add snmp input option to strip non fixed length index suffixes. +- [#4035](https://github.com/influxdata/telegraf/pull/4035): Add server version tag to docker input. +- [#4044](https://github.com/influxdata/telegraf/pull/4044): Add support for LeoFS 1.4 to leofs input. +- [#4068](https://github.com/influxdata/telegraf/pull/4068): Add parameter to force the interval of gather for sysstat. +- [#3877](https://github.com/influxdata/telegraf/pull/3877): Support busybox ping in the ping input. +- [#4077](https://github.com/influxdata/telegraf/pull/4077): Add input plugin for McRouter. +- [#4096](https://github.com/influxdata/telegraf/pull/4096): Add topk processor plugin. +- [#4114](https://github.com/influxdata/telegraf/pull/4114): Add cursor metrics to mongodb input. +- [#3455](https://github.com/influxdata/telegraf/pull/3455): Add tag/integer pair for result to net_response. +- [#4010](https://github.com/influxdata/telegraf/pull/3455): Add application_insights output plugin. +- [#4167](https://github.com/influxdata/telegraf/pull/4167): Added several important elasticsearch cluster health metrics. +- [#4094](https://github.com/influxdata/telegraf/pull/4094): Add batch mode to mqtt output. +- [#4158](https://github.com/influxdata/telegraf/pull/4158): Add aurora input plugin. +- [#3839](https://github.com/influxdata/telegraf/pull/3839): Add regex processor plugin. +- [#4165](https://github.com/influxdata/telegraf/pull/4165): Add support for Graphite 1.1 tags. +- [#4162](https://github.com/influxdata/telegraf/pull/4162): Add timeout option to sensors input. +- [#3489](https://github.com/influxdata/telegraf/pull/3489): Add burrow input plugin. +- [#3969](https://github.com/influxdata/telegraf/pull/3969): Add option to unbound module to use threads as tags. +- [#4183](https://github.com/influxdata/telegraf/pull/4183): Add support for TLS and username/password auth to aerospike input. +- [#4190](https://github.com/influxdata/telegraf/pull/4190): Add special syslog timestamp parser to grok parser that uses current year. +- [#4181](https://github.com/influxdata/telegraf/pull/4181): Add syslog input plugin. +- [#4212](https://github.com/influxdata/telegraf/pull/4212): Print the enabled aggregator and processor plugins on startup. +- [#3994](https://github.com/influxdata/telegraf/pull/3994): Add static routing_key option to amqp output. +- [#3995](https://github.com/influxdata/telegraf/pull/3995): Add passive mode exchange declaration option to amqp consumer input. +- [#4216](https://github.com/influxdata/telegraf/pull/4216): Add counter fields to pf input. + +### Bugfixes + +- [#4018](https://github.com/influxdata/telegraf/pull/4018): Write to working file outputs if any files are not writeable. +- [#4036](https://github.com/influxdata/telegraf/pull/4036): Add all win_perf_counters fields for a series in a single metric. +- [#4118](https://github.com/influxdata/telegraf/pull/4118): Report results of dns_query instead of 0ms on timeout. +- [#4155](https://github.com/influxdata/telegraf/pull/4155): Add consul service tags to metric. +- [#2879](https://github.com/influxdata/telegraf/issues/2879): Fix wildcards and multi instance processes in win_perf_counters. +- [#2468](https://github.com/influxdata/telegraf/issues/2468): Fix crash on 32-bit Windows in win_perf_counters. +- [#4198](https://github.com/influxdata/telegraf/issues/4198): Fix win_perf_counters not collecting at every interval. +- [#4227](https://github.com/influxdata/telegraf/issues/4227): Use same flags for all BSD family ping variants. +- [#4266](https://github.com/influxdata/telegraf/issues/4266): Remove tags with empty values from Wavefront output. + +## v1.6.4 [2018-06-05] + +### Bugfixes + +- [#4203](https://github.com/influxdata/telegraf/issues/4203): Fix snmp overriding of auto-configured table fields. +- [#4218](https://github.com/influxdata/telegraf/issues/4218): Fix uint support in cloudwatch output. +- [#4188](https://github.com/influxdata/telegraf/pull/4188): Fix documentation of instance_name option in varnish input. +- [#4195](https://github.com/influxdata/telegraf/pull/4195): Revert to previous aerospike library version due to memory leak. + +## v1.6.3 [2018-05-21] + +### Bugfixes + +- [#4127](https://github.com/influxdata/telegraf/issues/4127): Fix intermittent panic in aerospike input. +- [#4130](https://github.com/influxdata/telegraf/issues/4130): Fix connection leak in jolokia2_agent. +- [#4136](https://github.com/influxdata/telegraf/pull/4130): Fix jolokia2 timeout parsing. +- [#4142](https://github.com/influxdata/telegraf/pull/4142): Fix error parsing dropwizard metrics. +- [#4149](https://github.com/influxdata/telegraf/issues/4149): Fix librato output support for uint and bool. +- [#4176](https://github.com/influxdata/telegraf/pull/4176): Fix waitgroup deadlock if url is incorrect in apache input. + +## v1.6.2 [2018-05-08] + +### Bugfixes + +- [#4078](https://github.com/influxdata/telegraf/pull/4078): Use same timestamp for fields in system input. +- [#4091](https://github.com/influxdata/telegraf/pull/4091): Fix handling of uint64 in datadog output. +- [#4099](https://github.com/influxdata/telegraf/pull/4099): Ignore UTF8 BOM in JSON parser. +- [#4104](https://github.com/influxdata/telegraf/issues/4104): Fix case for slave metrics in mysql input. +- [#4110](https://github.com/influxdata/telegraf/issues/4110): Fix uint support in cratedb output. + +## v1.6.1 [2018-04-23] + +### Bugfixes + +- [#3835](https://github.com/influxdata/telegraf/issues/3835): Report mem input fields as gauges instead counters. +- [#4030](https://github.com/influxdata/telegraf/issues/4030): Fix graphite outputs unsigned integers in wrong format. +- [#4043](https://github.com/influxdata/telegraf/issues/4043): Report available fields if utmp is unreadable. +- [#4039](https://github.com/influxdata/telegraf/issues/4039): Fix potential "no fields" error writing to outputs. +- [#4037](https://github.com/influxdata/telegraf/issues/4037): Fix uptime reporting in system input when ran inside docker. +- [#3750](https://github.com/influxdata/telegraf/issues/3750): Fix mem input "cannot allocate memory" error on FreeBSD based systems. +- [#4056](https://github.com/influxdata/telegraf/pull/4056): Fix duplicate tags when overriding an existing tag. +- [#4062](https://github.com/influxdata/telegraf/pull/4062): Add server argument as first argument in unbound input. +- [#4063](https://github.com/influxdata/telegraf/issues/4063): Fix handling of floats with multiple leading zeroes. +- [#4064](https://github.com/influxdata/telegraf/issues/4064): Return errors in mongodb SSL/TLS configuration. + +## v1.6 [2018-04-16] + +### Release Notes + +- The `mysql` input plugin has been updated fix a number of type convertion + issues. This may cause a `field type error` when inserting into InfluxDB due + the change of types. + + To address this we have introduced a new `metric_version` option to control + enabling the new format. For in depth recommendations on upgrading please + reference the [mysql plugin documentation](./plugins/inputs/mysql/README.md#metric-version). + + It is encouraged to migrate to the new model when possible as the old version + is deprecated and will be removed in a future version. + +- The `postgresql` plugins now defaults to using a persistent connection to the database. + In environments where TCP connections are terminated the `max_lifetime` + setting should be set less than the collection `interval` to prevent errors. + +- The `sqlserver` input plugin has a new query and data model that can be enabled + by setting `query_version = 2`. It is encouraged to migrate to the new + model when possible as the old version is deprecated and will be removed in + a future version. + +- An option has been added to the `openldap` input plugin that reverses metric + name to improve grouping. This change is enabled when `reverse_metric_names = true` + is set. It is encouraged to enable this option when possible as the old + ordering is deprecated. + +- The new `http` input configured with `data_format = "json"` can perform the + same task as the, now deprecated, `httpjson` input. + + +### New Inputs + +- [http](./plugins/inputs/http/README.md) - Thanks to @grange74 +- [ipset](./plugins/inputs/ipset/README.md) - Thanks to @sajoupa +- [nats](./plugins/inputs/nats/README.md) - Thanks to @mjs & @levex + +### New Processors + +- [override](./plugins/processors/override/README.md) - Thanks to @KarstenSchnitter + +### New Parsers + +- [dropwizard](./docs/DATA_FORMATS_INPUT.md#dropwizard) - Thanks to @atzoum + +### Features + +- [#3551](https://github.com/influxdata/telegraf/pull/3551): Add health status mapping from string to int in elasticsearch input. +- [#3580](https://github.com/influxdata/telegraf/pull/3580): Add control over which stats to gather in basicstats aggregator. +- [#3596](https://github.com/influxdata/telegraf/pull/3596): Add messages_delivered_get to rabbitmq input. +- [#3632](https://github.com/influxdata/telegraf/pull/3632): Add wired field to mem input. +- [#3619](https://github.com/influxdata/telegraf/pull/3619): Add support for gathering exchange metrics to the rabbitmq input. +- [#3565](https://github.com/influxdata/telegraf/pull/3565): Add support for additional metrics on Linux in zfs input. +- [#3524](https://github.com/influxdata/telegraf/pull/3524): Add available_entropy field to kernel input plugin. +- [#3643](https://github.com/influxdata/telegraf/pull/3643): Add user privilege level setting to IPMI sensors. +- [#2701](https://github.com/influxdata/telegraf/pull/2701): Use persistent connection to postgresql database. +- [#2846](https://github.com/influxdata/telegraf/pull/2846): Add support for dropwizard input format. +- [#3666](https://github.com/influxdata/telegraf/pull/3666): Add container health metrics to docker input. +- [#3687](https://github.com/influxdata/telegraf/pull/3687): Add support for using globs in devices list of diskio input plugin. +- [#2754](https://github.com/influxdata/telegraf/pull/2754): Allow running as console application on Windows. +- [#3703](https://github.com/influxdata/telegraf/pull/3703): Add listener counts and node running status to rabbitmq input. +- [#3674](https://github.com/influxdata/telegraf/pull/3674): Add NATS Monitoring Input Plugin. +- [#3702](https://github.com/influxdata/telegraf/pull/3702): Add ability to select which queues will be gathered in rabbitmq input. +- [#3726](https://github.com/influxdata/telegraf/pull/3726): Add support for setting bsd source address to the ping input. +- [#3346](https://github.com/influxdata/telegraf/pull/3346): Add Ipset input plugin. +- [#3719](https://github.com/influxdata/telegraf/pull/3719): Add TLS and HTTP basic auth to prometheus_client output. +- [#3618](https://github.com/influxdata/telegraf/pull/3618): Add new sqlserver output data model. +- [#3559](https://github.com/influxdata/telegraf/pull/3559): Add native Go method for finding pids to procstat. +- [#3722](https://github.com/influxdata/telegraf/pull/3722): Add additional metrics and reverse metric names option to openldap. +- [#3769](https://github.com/influxdata/telegraf/pull/3769): Add TLS support to the mesos input plugin. +- [#3546](https://github.com/influxdata/telegraf/pull/3546): Add http input plugin. +- [#3781](https://github.com/influxdata/telegraf/pull/3781): Add keep alive support to the TCP mode of statsd. +- [#3783](https://github.com/influxdata/telegraf/pull/3783): Support deadline in ping plugin. +- [#3765](https://github.com/influxdata/telegraf/pull/3765): Add option to disable labels in prometheus output for string fields. +- [#3808](https://github.com/influxdata/telegraf/pull/3808): Add shard server stats to the mongodb input plugin. +- [#3713](https://github.com/influxdata/telegraf/pull/3713): Add server option to unbound plugin. +- [#3804](https://github.com/influxdata/telegraf/pull/3804): Convert boolean metric values to float in datadog output. +- [#3799](https://github.com/influxdata/telegraf/pull/3799): Add Solr 3 compatibility. +- [#3797](https://github.com/influxdata/telegraf/pull/3797): Add sum stat to basicstats aggregator. +- [#3626](https://github.com/influxdata/telegraf/pull/3626): Add ability to override proxy from environment in http response. +- [#3853](https://github.com/influxdata/telegraf/pull/3853): Add host to ping timeout log message. +- [#3773](https://github.com/influxdata/telegraf/pull/3773): Add override processor. +- [#3814](https://github.com/influxdata/telegraf/pull/3814): Add status_code and result tags and result_type field to http_response input. +- [#3880](https://github.com/influxdata/telegraf/pull/3880): Added config flag to skip collection of network protocol metrics. +- [#3927](https://github.com/influxdata/telegraf/pull/3927): Add TLS support to kapacitor input. +- [#3496](https://github.com/influxdata/telegraf/pull/3496): Add HTTP basic auth support to the http_listener input. +- [#3452](https://github.com/influxdata/telegraf/issues/3452): Tags in output InfluxDB Line Protocol are now sorted. +- [#3631](https://github.com/influxdata/telegraf/issues/3631): InfluxDB Line Protocol parser now accepts DOS line endings. +- [#2496](https://github.com/influxdata/telegraf/issues/2496): An option has been added to skip database creation in the InfluxDB output. +- [#3366](https://github.com/influxdata/telegraf/issues/3366): Add support for connecting to InfluxDB over a unix domain socket. +- [#3946](https://github.com/influxdata/telegraf/pull/3946): Add optional unsigned integer support to the influx data format. +- [#3811](https://github.com/influxdata/telegraf/pull/3811): Add TLS support to zookeeper input. +- [#2737](https://github.com/influxdata/telegraf/issues/2737): Add filters for container state to docker input. + +### Bugfixes + +- [#1896](https://github.com/influxdata/telegraf/issues/1896): Fix various mysql data type conversions. +- [#3810](https://github.com/influxdata/telegraf/issues/3810): Fix metric buffer limit in internal plugin after reload. +- [#3801](https://github.com/influxdata/telegraf/issues/3801): Fix panic in http_response on invalid regex. +- [#3973](https://github.com/influxdata/telegraf/issues/3873): Fix socket_listener setting ReadBufferSize on tcp sockets. +- [#1575](https://github.com/influxdata/telegraf/issues/1575): Add tag for target url to phpfpm input. +- [#3868](https://github.com/influxdata/telegraf/issues/3868): Fix cannot unmarshal object error in DC/OS input. +- [#3648](https://github.com/influxdata/telegraf/issues/3648): Fix InfluxDB output not able to reconnect when server address changes. +- [#3957](https://github.com/influxdata/telegraf/issues/3957): Fix parsing of dos line endings in the smart input. +- [#3754](https://github.com/influxdata/telegraf/issues/3754): Fix precision truncation when no timestamp included. +- [#3655](https://github.com/influxdata/telegraf/issues/3655): Fix SNMPv3 connection with Cisco ASA 5515 in snmp input. +- [#3981](https://github.com/influxdata/telegraf/pull/3981): Export all vars defined in /etc/default/telegraf. +- [#4004](https://github.com/influxdata/telegraf/issues/4004): Allow grok pattern to contain newlines. + +## v1.5.3 [2018-03-14] + +### Bugfixes + +- [#3729](https://github.com/influxdata/telegraf/issues/3729): Set path to / if HOST_MOUNT_PREFIX matches full path. +- [#3739](https://github.com/influxdata/telegraf/issues/3739): Remove userinfo from url tag in prometheus input. +- [#3778](https://github.com/influxdata/telegraf/issues/3778): Fix ping plugin not reporting zero durations. +- [#3697](https://github.com/influxdata/telegraf/issues/3697): Disable keepalive in mqtt output to prevent deadlock. +- [#3786](https://github.com/influxdata/telegraf/pull/3786): Fix collation difference in sqlserver input. +- [#3871](https://github.com/influxdata/telegraf/pull/3871): Fix uptime metric in passenger input plugin. +- [#3851](https://github.com/influxdata/telegraf/issues/3851): Add output of stderr in case of error to exec log message. + +## v1.5.2 [2018-01-30] + +### Bugfixes + +- [#3684](https://github.com/influxdata/telegraf/pull/3684): Ignore empty lines in Graphite plaintext. +- [#3604](https://github.com/influxdata/telegraf/issues/3604): Fix index out of bounds error in solr input plugin. +- [#3680](https://github.com/influxdata/telegraf/pull/3680): Reconnect before sending graphite metrics if disconnected. +- [#3693](https://github.com/influxdata/telegraf/pull/3693): Align aggregator period with internal ticker to avoid skipping metrics. +- [#3629](https://github.com/influxdata/telegraf/issues/3629): Fix a potential deadlock when using aggregators. +- [#3697](https://github.com/influxdata/telegraf/issues/3697): Limit wait time for writes in mqtt output. +- [#3698](https://github.com/influxdata/telegraf/issues/3698): Revert change in graphite output where dot in field key was replaced by underscore. +- [#3710](https://github.com/influxdata/telegraf/issues/3710): Add timeout to wavefront output write. +- [#3725](https://github.com/influxdata/telegraf/issues/3725): Exclude master_replid fields from redis input. + +## v1.5.1 [2018-01-10] + +### Bugfixes + +- [#3624](https://github.com/influxdata/telegraf/pull/3624): Fix name error in jolokia2_agent sample config. +- [#3625](https://github.com/influxdata/telegraf/pull/3625): Fix DC/OS login expiration time. +- [#3593](https://github.com/influxdata/telegraf/pull/3593): Set Content-Type charset in influxdb output and allow it be overridden. +- [#3594](https://github.com/influxdata/telegraf/pull/3594): Document permissions setup for postfix input. +- [#3633](https://github.com/influxdata/telegraf/pull/3633): Fix deliver_get field in rabbitmq input. +- [#3607](https://github.com/influxdata/telegraf/issues/3607): Escape environment variables during config toml parsing. + +## v1.5 [2017-12-14] ### New Plugins - [basicstats](./plugins/aggregators/basicstats/README.md) - Thanks to @toni-moreno -- [cratedb](./plugins/outputs/wavefront/README.md) - Thanks to @felixge +- [bond](./plugins/inputs/bond/README.md) - Thanks to @ildarsv +- [cratedb](./plugins/outputs/cratedb/README.md) - Thanks to @felixge +- [dcos](./plugins/inputs/dcos/README.md) - Thanks to @influxdata - [jolokia2](./plugins/inputs/jolokia2/README.md) - Thanks to @dylanmei - [nginx_plus](./plugins/inputs/nginx_plus/README.md) - Thanks to @mplonka & @poblahblahblah +- [opensmtpd](./plugins/inputs/opensmtpd/README.md) - Thanks to @aromeyer +- [particle](./plugins/inputs/webhooks/particle/README.md) - Thanks to @davidgs +- [pf](./plugins/inputs/pf/README.md) - Thanks to @nferch +- [postfix](./plugins/inputs/postfix/README.md) - Thanks to @phemmer - [smart](./plugins/inputs/smart/README.md) - Thanks to @rickard-von-essen - [solr](./plugins/inputs/solr/README.md) - Thanks to @ljagiello - [teamspeak](./plugins/inputs/teamspeak/README.md) - Thanks to @p4ddy1 +- [unbound](./plugins/inputs/unbound/README.md) - Thanks to @aromeyer - [wavefront](./plugins/outputs/wavefront/README.md) - Thanks to @puckpuck ### Release Notes @@ -21,6 +492,11 @@ plugin is deprecated and will be removed in a future release. Users of this plugin are encouraged to update to the new `jolokia2` plugin. +- In the `postgresql` and `postgresql_extensible` plugins, the type of the oid + data type has changed from string to integer. It is recommended to drop + affected fields until a new shard is started. For details on how to + workaround this issue please see [#3622](https://github.com/influxdata/telegraf/issues/3622). + ### Features - [#3170](https://github.com/influxdata/telegraf/pull/3170): Add support for sharding based on metric name. @@ -57,6 +533,21 @@ - [#3305](https://github.com/influxdata/telegraf/pull/3305): Add modification_time field to filestat input plugin. - [#2019](https://github.com/influxdata/telegraf/pull/2019): Add Solr input plugin. - [#3210](https://github.com/influxdata/telegraf/pull/3210): Add CrateDB output plugin. +- [#3459](https://github.com/influxdata/telegraf/pull/3459): Add systemd unit pid and cgroup matching to procstat. +- [#3477](https://github.com/influxdata/telegraf/pull/3477): Add Particle Webhook Plugin. +- [#3471](https://github.com/influxdata/telegraf/pull/3471): Use MAX() instead of SUM() for latency measurements in sqlserver. +- [#3490](https://github.com/influxdata/telegraf/pull/3490): Add index by week number to Elasticsearch output. +- [#3434](https://github.com/influxdata/telegraf/pull/3434): Add unbound input plugin. +- [#3449](https://github.com/influxdata/telegraf/pull/3449): Add opensmtpd input plugin. +- [#3470](https://github.com/influxdata/telegraf/pull/3470): Add support for tags in the index name in elasticsearch output. +- [#2553](https://github.com/influxdata/telegraf/pull/2553): Add postfix input plugin. +- [#3424](https://github.com/influxdata/telegraf/pull/3424): Add bond input plugin. +- [#3518](https://github.com/influxdata/telegraf/pull/3518): Add slab to mem plugin. +- [#3519](https://github.com/influxdata/telegraf/pull/3519): Add input plugin for DC/OS. +- [#3140](https://github.com/influxdata/telegraf/pull/3140): Add support for glob patterns in net input plugin. +- [#3405](https://github.com/influxdata/telegraf/pull/3405): Add input plugin for OpenBSD/FreeBSD pf. +- [#3528](https://github.com/influxdata/telegraf/pull/3528): Add option to amqp output to publish persistent messages. +- [#3530](https://github.com/influxdata/telegraf/pull/3530): Support I (idle) process state on procfs+Linux. ### Bugfixes @@ -65,9 +556,28 @@ - [#3319](https://github.com/influxdata/telegraf/issues/3319): Fix cloudwatch output requires unneeded permissions. - [#3351](https://github.com/influxdata/telegraf/issues/3351): Fix prometheus passthrough for existing value types. - [#3430](https://github.com/influxdata/telegraf/issues/3430): Always ignore autofs filesystems in disk input. +- [#3326](https://github.com/influxdata/telegraf/issues/3326): Fail metrics parsing on unescaped quotes. +- [#3473](https://github.com/influxdata/telegraf/pull/3473): Whitelist allowed char classes for graphite output. +- [#3488](https://github.com/influxdata/telegraf/pull/3488): Use hexadecimal ids and lowercase names in zipkin input. +- [#3263](https://github.com/influxdata/telegraf/issues/3263): Fix snmp-tools output parsing with Windows EOLs. +- [#3447](https://github.com/influxdata/telegraf/issues/3447): Add shadow-utils dependency to rpm package. +- [#3448](https://github.com/influxdata/telegraf/issues/3448): Use deb-systemd-invoke to restart service. +- [#3553](https://github.com/influxdata/telegraf/issues/3553): Fix kafka_consumer outside range of offsets error. +- [#3568](https://github.com/influxdata/telegraf/issues/3568): Fix separation of multiple prometheus_client outputs. +- [#3577](https://github.com/influxdata/telegraf/issues/3577): Don't add system input uptime_format as a counter. + +## v1.4.5 [2017-12-01] + +### Bugfixes + +- [#3500](https://github.com/influxdata/telegraf/issues/3500): Fix global variable collection when using interval_slow option in mysql input. +- [#3486](https://github.com/influxdata/telegraf/issues/3486): Fix error getting net connections info in netstat input. +- [#3529](https://github.com/influxdata/telegraf/issues/3529): Fix HOST_MOUNT_PREFIX in docker with disk input. ## v1.4.4 [2017-11-08] +### Bugfixes + - [#3401](https://github.com/influxdata/telegraf/pull/3401): Use schema specified in mqtt_consumer input. - [#3419](https://github.com/influxdata/telegraf/issues/3419): Redact datadog API key in log output. - [#3311](https://github.com/influxdata/telegraf/issues/3311): Fix error getting pids in netstat input. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21ae5738..55cc7f11 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,9 +30,8 @@ which can be found [on our website](http://influxdb.com/community/cla.html) Assuming you can already build the project, run these in the telegraf directory: -1. `go get github.com/sparrc/gdm` -1. `gdm restore` -1. `GOOS=linux gdm save` +1. `dep ensure -vendor-only` +2. `dep ensure -add github.com/[dependency]/[new-package]` ## Input Plugins @@ -52,7 +51,9 @@ See below for a quick example. * Input Plugins must be added to the `github.com/influxdata/telegraf/plugins/inputs/all/all.go` file. * The `SampleConfig` function should return valid toml that describes how the -plugin can be configured. This is include in `telegraf config`. +plugin can be configured. This is included in `telegraf config`. Please +consult the [SampleConfig](https://github.com/influxdata/telegraf/wiki/SampleConfig) +page for the latest style guidelines. * The `Description` function should say in one line what this plugin does. Let's say you've written a plugin that emits metrics about processes on the @@ -79,7 +80,10 @@ func (s *Simple) Description() string { } func (s *Simple) SampleConfig() string { - return "ok = true # indicate if everything is fine" + return ` + ## Indicate if everything is fine + ok = true +` } func (s *Simple) Gather(acc telegraf.Accumulator) error { @@ -97,6 +101,13 @@ func init() { } ``` +### Input Plugin Development + +* Run `make static` followed by `make plugin-[pluginName]` to spin up a docker dev environment +using docker-compose. +* ***[Optional]*** When developing a plugin, add a `dev` directory with a `docker-compose.yml` and `telegraf.conf` +as well as any other supporting files, where sensible. + ## Adding Typed Metrics In addition the the `AddFields` function, the accumulator also supports an @@ -167,7 +178,7 @@ and `Stop()` methods. ### Service Plugin Guidelines * Same as the `Plugin` guidelines, except that they must conform to the -`inputs.ServiceInput` interface. +[`telegraf.ServiceInput`](https://godoc.org/github.com/influxdata/telegraf#ServiceInput) interface. ## Output Plugins @@ -183,7 +194,9 @@ See below for a quick example. * To be available within Telegraf itself, plugins must add themselves to the `github.com/influxdata/telegraf/plugins/outputs/all/all.go` file. * The `SampleConfig` function should return valid toml that describes how the -output can be configured. This is include in `telegraf config`. +plugin can be configured. This is included in `telegraf config`. Please +consult the [SampleConfig](https://github.com/influxdata/telegraf/wiki/SampleConfig) +page for the latest style guidelines. * The `Description` function should say in one line what this output does. ### Output Example @@ -207,7 +220,9 @@ func (s *Simple) Description() string { } func (s *Simple) SampleConfig() string { - return "url = localhost" + return ` + ok = true +` } func (s *Simple) Connect() error { diff --git a/Godeps b/Godeps deleted file mode 100644 index 7e90dd06..00000000 --- a/Godeps +++ /dev/null @@ -1,91 +0,0 @@ -collectd.org 2ce144541b8903101fb8f1483cc0497a68798122 -github.com/aerospike/aerospike-client-go 95e1ad7791bdbca44707fedbb29be42024900d9c -github.com/amir/raidman c74861fe6a7bb8ede0a010ce4485bdbb4fc4c985 -github.com/apache/thrift 4aaa92ece8503a6da9bc6701604f69acf2b99d07 -github.com/aws/aws-sdk-go c861d27d0304a79f727e9a8a4e2ac1e74602fdc0 -github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 -github.com/bsm/sarama-cluster ccdc0803695fbce22f1706d04ded46cd518fd832 -github.com/cenkalti/backoff b02f2bbce11d7ea6b97f282ef1771b0fe2f65ef3 -github.com/couchbase/go-couchbase bfe555a140d53dc1adf390f1a1d4b0fd4ceadb28 -github.com/couchbase/gomemcached 4a25d2f4e1dea9ea7dd76dfd943407abf9b07d29 -github.com/couchbase/goutils 5823a0cbaaa9008406021dc5daf80125ea30bba6 -github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 -github.com/docker/docker f5ec1e2936dcbe7b5001c2b817188b095c700c27 -github.com/docker/go-connections 990a1a1a70b0da4c4cb70e117971a4f0babfbf1a -github.com/eapache/go-resiliency b86b1ec0dd4209a588dc1285cdd471e73525c0b3 -github.com/eapache/go-xerial-snappy bb955e01b9346ac19dc29eb16586c90ded99a98c -github.com/eapache/queue 44cc805cf13205b55f69e14bcb69867d1ae92f98 -github.com/eclipse/paho.mqtt.golang d4f545eb108a2d19f9b1a735689dbfb719bc21fb -github.com/go-logfmt/logfmt 390ab7935ee28ec6b286364bba9b4dd6410cb3d5 -github.com/go-sql-driver/mysql 2e00b5cd70399450106cec6431c2e2ce3cae5034 -github.com/gobwas/glob bea32b9cd2d6f55753d94a28e959b13f0244797a -github.com/go-ini/ini 9144852efba7c4daf409943ee90767da62d55438 -github.com/gogo/protobuf 7b6c6391c4ff245962047fc1e2c6e08b1cdfa0e8 -github.com/golang/protobuf 8ee79997227bf9b34611aee7946ae64735e6fd93 -github.com/golang/snappy 7db9049039a047d955fe8c19b83c8ff5abd765c7 -github.com/go-ole/go-ole be49f7c07711fcb603cff39e1de7c67926dc0ba7 -github.com/google/go-cmp f94e52cad91c65a63acc1e75d4be223ea22e99bc -github.com/gorilla/mux 392c28fe23e1c45ddba891b0320b3b5df220beea -github.com/go-sql-driver/mysql 2e00b5cd70399450106cec6431c2e2ce3cae5034 -github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478 -github.com/hashicorp/consul 63d2fc68239b996096a1c55a0d4b400ea4c2583f -github.com/influxdata/tail a395bf99fe07c233f41fba0735fa2b13b58588ea -github.com/influxdata/toml 5d1d907f22ead1cd47adde17ceec5bda9cacaf8f -github.com/influxdata/wlog 7c63b0a71ef8300adc255344d275e10e5c3a71ec -github.com/jackc/pgx 63f58fd32edb5684b9e9f4cfaac847c6b42b3917 -github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d -github.com/kardianos/osext c2c54e542fb797ad986b31721e1baedf214ca413 -github.com/kardianos/service 6d3a0ee7d3425d9d835debc51a0ca1ffa28f4893 -github.com/kballard/go-shellquote d8ec1a69a250a17bb0e419c386eac1f3711dc142 -github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c -github.com/Microsoft/go-winio ce2922f643c8fd76b46cadc7f404a06282678b34 -github.com/miekg/dns 99f84ae56e75126dd77e5de4fae2ea034a468ca1 -github.com/mitchellh/mapstructure d0303fe809921458f417bcf828397a65db30a7e4 -github.com/multiplay/go-ts3 07477f49b8dfa3ada231afc7b7b17617d42afe8e -github.com/naoina/go-stringutil 6b638e95a32d0c1131db0e7fe83775cbea4a0d0b -github.com/nats-io/go-nats ea9585611a4ab58a205b9b125ebd74c389a6b898 -github.com/nats-io/nats ea9585611a4ab58a205b9b125ebd74c389a6b898 -github.com/nats-io/nuid 289cccf02c178dc782430d534e3c1f5b72af807f -github.com/nsqio/go-nsq eee57a3ac4174c55924125bb15eeeda8cffb6e6f -github.com/opencontainers/runc 89ab7f2ccc1e45ddf6485eaa802c35dcf321dfc8 -github.com/opentracing-contrib/go-observer a52f2342449246d5bcc273e65cbdcfa5f7d6c63c -github.com/opentracing/opentracing-go 06f47b42c792fef2796e9681353e1d908c417827 -github.com/openzipkin/zipkin-go-opentracing 1cafbdfde94fbf2b373534764e0863aa3bd0bf7b -github.com/pierrec/lz4 5c9560bfa9ace2bf86080bf40d46b34ae44604df -github.com/pierrec/xxHash 5a004441f897722c627870a981d02b29924215fa -github.com/pkg/errors 645ef00459ed84a119197bfb8d8205042c6df63d -github.com/pmezard/go-difflib/difflib 792786c7400a136282c1664665ae0a8db921c6c2 -github.com/prometheus/client_golang c317fb74746eac4fc65fe3909195f4cf67c5562a -github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 -github.com/prometheus/common dd2f054febf4a6c00f2343686efb775948a8bff4 -github.com/prometheus/procfs 1878d9fbb537119d24b21ca07effd591627cd160 -github.com/rcrowley/go-metrics 1f30fe9094a513ce4c700b9a54458bbb0c96996c -github.com/samuel/go-zookeeper 1d7be4effb13d2d908342d349d71a284a7542693 -github.com/satori/go.uuid 5bf94b69c6b68ee1b541973bb8e1144db23a194b -github.com/shirou/gopsutil 48fc5612898a1213aa5d6a0fb2d4f7b968e898fb -github.com/shirou/w32 3c9377fc6748f222729a8270fe2775d149a249ad -github.com/Shopify/sarama c01858abb625b73a3af51d0798e4ad42c8147093 -github.com/Sirupsen/logrus 61e43dc76f7ee59a82bdf3d71033dc12bea4c77d -github.com/soniah/gosnmp 5ad50dc75ab389f8a1c9f8a67d3a1cd85f67ed15 -github.com/StackExchange/wmi f3e2bae1e0cb5aef83e319133eabfee30013a4a5 -github.com/streadway/amqp 63795daa9a446c920826655f26ba31c81c860fd6 -github.com/stretchr/objx 1a9d0bb9f541897e62256577b352fdbc1fb4fd94 -github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987 -github.com/vjeantet/grok d73e972b60935c7fec0b4ffbc904ed39ecaf7efe -github.com/wvanbergen/kafka bc265fedb9ff5b5c5d3c0fdcef4a819b3523d3ee -github.com/wvanbergen/kazoo-go 968957352185472eacb69215fa3dbfcfdbac1096 -github.com/yuin/gopher-lua 66c871e454fcf10251c61bf8eff02d0978cae75a -github.com/zensqlmonitor/go-mssqldb ffe5510c6fa5e15e6d983210ab501c815b56b363 -golang.org/x/crypto dc137beb6cce2043eb6b5f223ab8bf51c32459f4 -golang.org/x/net f2499483f923065a842d38eb4c7f1927e6fc6e6d -golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f -golang.org/x/text 506f9d5c962f284575e88337e7d9296d27e729d3 -gopkg.in/asn1-ber.v1 4e86f4367175e39f69d9358a5f17b4dda270378d -gopkg.in/fatih/pool.v2 6e328e67893eb46323ad06f0e92cb9536babbabc -gopkg.in/fsnotify.v1 a8a77c9133d2d6fd8334f3260d06f60e8d80a5fb -gopkg.in/gorethink/gorethink.v3 7ab832f7b65573104a555d84a27992ae9ea1f659 -gopkg.in/ldap.v2 8168ee085ee43257585e50c6441aadf54ecb2c9f -gopkg.in/mgo.v2 3f83fa5005286a7fe593b055f0d7771a7dce4655 -gopkg.in/olivere/elastic.v5 3113f9b9ad37509fe5f8a0e5e91c96fdc4435e26 -gopkg.in/tomb.v1 dd632973f1e7218eb1089048e0798ec9ae7dceb8 -gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6 diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 00000000..80a6277b --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,1414 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:972f38a9c879a4920d1e3a3d3438104b6c06163bfa3e6f4064adb00468d40587" + name = "cloud.google.com/go" + packages = ["civil"] + pruneopts = "" + revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad" + version = "v0.27.0" + +[[projects]] + branch = "master" + digest = "1:fc0802104acded1f48e4860a9f2db85b82b4a754fca9eae750ff4e8b8cdf2116" + name = "code.cloudfoundry.org/clock" + packages = ["."] + pruneopts = "" + revision = "02e53af36e6c978af692887ed449b74026d76fec" + +[[projects]] + digest = "1:ca3acef20fd660d4df327accbf3ca2df9a12213d914f3113305dcd56579324b9" + name = "collectd.org" + packages = [ + "api", + "cdtime", + "network", + ] + pruneopts = "" + revision = "2ce144541b8903101fb8f1483cc0497a68798122" + version = "v0.3.0" + +[[projects]] + digest = "1:5923e22a060ab818a015593422f9e8a35b9d881d4cfcfed0669a82959b11c7ee" + name = "github.com/Azure/go-autorest" + packages = [ + "autorest", + "autorest/adal", + "autorest/azure", + "autorest/azure/auth", + "autorest/date", + ] + pruneopts = "" + revision = "1f7cd6cfe0adea687ad44a512dfe76140f804318" + version = "v10.12.0" + +[[projects]] + branch = "master" + digest = "1:298712a3ee36b59c3ca91f4183bd75d174d5eaa8b4aed5072831f126e2e752f6" + name = "github.com/Microsoft/ApplicationInsights-Go" + packages = [ + "appinsights", + "appinsights/contracts", + ] + pruneopts = "" + revision = "d2df5d440eda5372f24fcac03839a64d6cb5f7e5" + +[[projects]] + digest = "1:45ec6eb579713a01991ad07f538fed3b576ee55f5ce9f248320152a9270d9258" + name = "github.com/Microsoft/go-winio" + packages = ["."] + pruneopts = "" + revision = "a6d595ae73cf27a1b8fc32930668708f45ce1c85" + version = "v0.4.9" + +[[projects]] + digest = "1:213b41361ad1cb4768add9d26c2e27794c65264eefdb24ed6ea34cdfeeff3f3c" + name = "github.com/Shopify/sarama" + packages = ["."] + pruneopts = "" + revision = "a6144ae922fd99dd0ea5046c8137acfb7fab0914" + version = "v1.18.0" + +[[projects]] + digest = "1:f82b8ac36058904227087141017bb82f4b0fc58272990a4cdae3e2d6d222644e" + name = "github.com/StackExchange/wmi" + packages = ["."] + pruneopts = "" + revision = "5d049714c4a64225c3c79a7cf7d02f7fb5b96338" + version = "1.0.0" + +[[projects]] + digest = "1:f296e8b29c60c94efed3b8cfae08d793cb95149cdd7343e6a9834b4ac7136475" + name = "github.com/aerospike/aerospike-client-go" + packages = [ + ".", + "internal/lua", + "internal/lua/resources", + "logger", + "pkg/bcrypt", + "pkg/ripemd160", + "types", + "types/atomic", + "types/particle_type", + "types/rand", + "utils/buffer", + ] + pruneopts = "" + revision = "1dc8cf203d24cd454e71ce40ab4cd0bf3112df90" + version = "v1.27.0" + +[[projects]] + branch = "master" + digest = "1:a74730e052a45a3fab1d310fdef2ec17ae3d6af16228421e238320846f2aaec8" + name = "github.com/alecthomas/template" + packages = [ + ".", + "parse", + ] + pruneopts = "" + revision = "a0175ee3bccc567396460bf5acd36800cb10c49c" + +[[projects]] + branch = "master" + digest = "1:8483994d21404c8a1d489f6be756e25bfccd3b45d65821f25695577791a08e68" + name = "github.com/alecthomas/units" + packages = ["."] + pruneopts = "" + revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" + +[[projects]] + branch = "master" + digest = "1:7f21a8f175ee7f91c659f919c61032e11889fba5dc25c0cec555087cbb87435a" + name = "github.com/amir/raidman" + packages = [ + ".", + "proto", + ] + pruneopts = "" + revision = "1ccc43bfb9c93cb401a4025e49c64ba71e5e668b" + +[[projects]] + branch = "master" + digest = "1:0828d8c0f95689f832cf348fe23827feb7640cd698d612ef59e2f9d041f54c68" + name = "github.com/apache/thrift" + packages = ["lib/go/thrift"] + pruneopts = "" + revision = "f2867c24984aa53edec54a138c03db934221bdea" + +[[projects]] + digest = "1:65a05bde9b02f645c73afa61c9f6af92d94d726c81a268f45cc70218bd58de65" + name = "github.com/aws/aws-sdk-go" + packages = [ + "aws", + "aws/awserr", + "aws/awsutil", + "aws/client", + "aws/client/metadata", + "aws/corehandlers", + "aws/credentials", + "aws/credentials/ec2rolecreds", + "aws/credentials/endpointcreds", + "aws/credentials/stscreds", + "aws/csm", + "aws/defaults", + "aws/ec2metadata", + "aws/endpoints", + "aws/request", + "aws/session", + "aws/signer/v4", + "internal/sdkio", + "internal/sdkrand", + "internal/sdkuri", + "internal/shareddefaults", + "private/protocol", + "private/protocol/json/jsonutil", + "private/protocol/jsonrpc", + "private/protocol/query", + "private/protocol/query/queryutil", + "private/protocol/rest", + "private/protocol/xml/xmlutil", + "service/cloudwatch", + "service/kinesis", + "service/sts", + ] + pruneopts = "" + revision = "8cf662a972fa7fba8f2c1ec57648cf840e2bb401" + version = "v1.14.30" + +[[projects]] + branch = "master" + digest = "1:c0bec5f9b98d0bc872ff5e834fac186b807b656683bd29cb82fb207a1513fabb" + name = "github.com/beorn7/perks" + packages = ["quantile"] + pruneopts = "" + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + +[[projects]] + digest = "1:c5978131c797af795972c27c25396c81d1bf53b7b6e8e3e0259e58375765c071" + name = "github.com/bsm/sarama-cluster" + packages = ["."] + pruneopts = "" + revision = "cf455bc755fe41ac9bb2861e7a961833d9c2ecc3" + version = "v2.1.13" + +[[projects]] + digest = "1:f619cb9b07aebe5416262cdd8b86082e8d5bdc5264cb3b615ff858df0b645f97" + name = "github.com/cenkalti/backoff" + packages = ["."] + pruneopts = "" + revision = "2ea60e5f094469f9e65adb9cd103795b73ae743e" + version = "v2.0.0" + +[[projects]] + branch = "master" + digest = "1:298e42868718da06fc0899ae8fdb99c48a14477045234c9274d81caa79af6a8f" + name = "github.com/couchbase/go-couchbase" + packages = ["."] + pruneopts = "" + revision = "16db1f1fe037412f12738fa4d8448c549c4edd77" + +[[projects]] + branch = "master" + digest = "1:c734658274a6be88870a36742fdea96a3fce4fc99a7b90946c9e84335ceae71a" + name = "github.com/couchbase/gomemcached" + packages = [ + ".", + "client", + ] + pruneopts = "" + revision = "0da75df145308b9a4e6704d762ca9d9b77752efc" + +[[projects]] + branch = "master" + digest = "1:c1195c02bc8fbf5307cfb95bc79eddaa1351ee3587cc4a7bbe6932e2fb966ff2" + name = "github.com/couchbase/goutils" + packages = [ + "logging", + "scramsha", + ] + pruneopts = "" + revision = "e865a1461c8ac0032bd37e2d4dab3289faea3873" + +[[projects]] + digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "" + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + branch = "master" + digest = "1:7fdc54859cd901c25b9d8db964410a4e0d98fa0dca267fe4cf49c0eede5e06c2" + name = "github.com/denisenkom/go-mssqldb" + packages = [ + ".", + "internal/cp", + ] + pruneopts = "" + revision = "1eb28afdf9b6e56cf673badd47545f844fe81103" + +[[projects]] + digest = "1:6098222470fe0172157ce9bbef5d2200df4edde17ee649c5d6e48330e4afa4c6" + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + pruneopts = "" + revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" + version = "v3.2.0" + +[[projects]] + branch = "master" + digest = "1:654ac9799e7a8a586d8690bb2229a4f3408bbfe2c5494bf4dfe043053eeb5496" + name = "github.com/dimchansky/utfbom" + packages = ["."] + pruneopts = "" + revision = "6c6132ff69f0f6c088739067407b5d32c52e1d0f" + +[[projects]] + digest = "1:522eff2a1f014a64fb403db60fc0110653e4dc5b59779894d208e697b0708ddc" + name = "github.com/docker/distribution" + packages = [ + "digestset", + "reference", + ] + pruneopts = "" + revision = "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c" + +[[projects]] + digest = "1:d149605f1b00713fdc48150122892d77d49d30c825f690dd92f497aeb6cf18f5" + name = "github.com/docker/docker" + packages = [ + "api", + "api/types", + "api/types/blkiodev", + "api/types/container", + "api/types/events", + "api/types/filters", + "api/types/image", + "api/types/mount", + "api/types/network", + "api/types/registry", + "api/types/strslice", + "api/types/swarm", + "api/types/swarm/runtime", + "api/types/time", + "api/types/versions", + "api/types/volume", + "client", + ] + pruneopts = "" + revision = "ed7b6428c133e7c59404251a09b7d6b02fa83cc2" + +[[projects]] + digest = "1:a5ecc2e70260a87aa263811281465a5effcfae8a54bac319cee87c4625f04d63" + name = "github.com/docker/go-connections" + packages = [ + "nat", + "sockets", + "tlsconfig", + ] + pruneopts = "" + revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d" + version = "v0.3.0" + +[[projects]] + digest = "1:582d54fcb7233da8dde1dfd2210a5b9675d0685f84246a8d317b07d680c18b1b" + name = "github.com/docker/go-units" + packages = ["."] + pruneopts = "" + revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" + version = "v0.3.3" + +[[projects]] + digest = "1:6d6672f85a84411509885eaa32f597577873de00e30729b9bb0eb1e1faa49c12" + name = "github.com/eapache/go-resiliency" + packages = ["breaker"] + pruneopts = "" + revision = "ea41b0fad31007accc7f806884dcdf3da98b79ce" + version = "v1.1.0" + +[[projects]] + branch = "master" + digest = "1:7b12ea8b50040c6c2378ec5b5a1ab722730b2bfb46e8724ded57f2c3905431fa" + name = "github.com/eapache/go-xerial-snappy" + packages = ["."] + pruneopts = "" + revision = "040cc1a32f578808623071247fdbd5cc43f37f5f" + +[[projects]] + digest = "1:d8d46d21073d0f65daf1740ebf4629c65e04bf92e14ce93c2201e8624843c3d3" + name = "github.com/eapache/queue" + packages = ["."] + pruneopts = "" + revision = "44cc805cf13205b55f69e14bcb69867d1ae92f98" + version = "v1.1.0" + +[[projects]] + digest = "1:3fa846cb3feb4e65371fe3c347c299de9b5bc3e71e256c0d940cd19b767a6ba0" + name = "github.com/eclipse/paho.mqtt.golang" + packages = [ + ".", + "packets", + ] + pruneopts = "" + revision = "36d01c2b4cbeb3d2a12063e4880ce30800af9560" + version = "v1.1.1" + +[[projects]] + digest = "1:858b7fe7b0f4bc7ef9953926828f2816ea52d01a88d72d1c45bc8c108f23c356" + name = "github.com/go-ini/ini" + packages = ["."] + pruneopts = "" + revision = "358ee7663966325963d4e8b2e1fbd570c5195153" + version = "v1.38.1" + +[[projects]] + digest = "1:6a4a01d58b227c4b6b11111b9f172ec5c17682b82724e58e6daf3f19f4faccd8" + name = "github.com/go-logfmt/logfmt" + packages = ["."] + pruneopts = "" + revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" + version = "v0.3.0" + +[[projects]] + digest = "1:96c4a6ff4206086347bfe28e96e092642882128f45ecb8dc8f15f3e6f6703af0" + name = "github.com/go-ole/go-ole" + packages = [ + ".", + "oleutil", + ] + pruneopts = "" + revision = "a41e3c4b706f6ae8dfbff342b06e40fa4d2d0506" + version = "v1.2.1" + +[[projects]] + digest = "1:3dfd659219b6f63dc0677a62b8d4e8f10b5cf53900aef40858db10a19407e41d" + name = "github.com/go-redis/redis" + packages = [ + ".", + "internal", + "internal/consistenthash", + "internal/hashtag", + "internal/pool", + "internal/proto", + "internal/singleflight", + "internal/util", + ] + pruneopts = "" + revision = "83fb42932f6145ce52df09860384a4653d2d332a" + version = "v6.12.0" + +[[projects]] + digest = "1:c07de423ca37dc2765396d6971599ab652a339538084b9b58c9f7fc533b28525" + name = "github.com/go-sql-driver/mysql" + packages = ["."] + pruneopts = "" + revision = "d523deb1b23d913de5bdada721a6071e71283618" + version = "v1.4.0" + +[[projects]] + digest = "1:9ab1b1c637d7c8f49e39d8538a650d7eb2137b076790cff69d160823b505964c" + name = "github.com/gobwas/glob" + packages = [ + ".", + "compiler", + "match", + "syntax", + "syntax/ast", + "syntax/lexer", + "util/runes", + "util/strings", + ] + pruneopts = "" + revision = "5ccd90ef52e1e632236f7326478d4faa74f99438" + version = "v0.2.3" + +[[projects]] + digest = "1:6e73003ecd35f4487a5e88270d3ca0a81bc80dc88053ac7e4dcfec5fba30d918" + name = "github.com/gogo/protobuf" + packages = ["proto"] + pruneopts = "" + revision = "636bf0302bc95575d69441b25a2603156ffdddf1" + version = "v1.1.1" + +[[projects]] + digest = "1:f958a1c137db276e52f0b50efee41a1a389dcdded59a69711f3e872757dab34b" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + ] + pruneopts = "" + revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" + version = "v1.1.0" + +[[projects]] + branch = "master" + digest = "1:2a5888946cdbc8aa360fd43301f9fc7869d663f60d5eedae7d4e6e5e4f06f2bf" + name = "github.com/golang/snappy" + packages = ["."] + pruneopts = "" + revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" + +[[projects]] + digest = "1:f9f45f75f332e03fc7e9fe9188ea4e1ce4d14779ef34fa1b023da67518e36327" + name = "github.com/google/go-cmp" + packages = [ + "cmp", + "cmp/internal/diff", + "cmp/internal/function", + "cmp/internal/value", + ] + pruneopts = "" + revision = "3af367b6b30c263d47e8895973edcca9a49cf029" + version = "v0.2.0" + +[[projects]] + digest = "1:c1d7e883c50a26ea34019320d8ae40fad86c9e5d56e63a1ba2cb618cef43e986" + name = "github.com/google/uuid" + packages = ["."] + pruneopts = "" + revision = "064e2069ce9c359c118179501254f67d7d37ba24" + version = "0.2" + +[[projects]] + digest = "1:dbbeb8ddb0be949954c8157ee8439c2adfd8dc1c9510eb44a6e58cb68c3dce28" + name = "github.com/gorilla/context" + packages = ["."] + pruneopts = "" + revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" + version = "v1.1.1" + +[[projects]] + digest = "1:c2c8666b4836c81a1d247bdf21c6a6fc1ab586538ab56f74437c2e0df5c375e1" + name = "github.com/gorilla/mux" + packages = ["."] + pruneopts = "" + revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" + version = "v1.6.2" + +[[projects]] + branch = "master" + digest = "1:60b7bc5e043a11213472ae05252527287d20e0a6ccc18f6ae67fad88e41004de" + name = "github.com/hailocab/go-hostpool" + packages = ["."] + pruneopts = "" + revision = "e80d13ce29ede4452c43dea11e79b9bc8a15b478" + +[[projects]] + digest = "1:e7224669901bab4094e6d6697c136557b7177db6ceb01b7fc8b20d08f4b5aacd" + name = "github.com/hashicorp/consul" + packages = ["api"] + pruneopts = "" + revision = "39f93f011e591c842acc8053a7f5972aa6e592fd" + version = "v1.2.1" + +[[projects]] + branch = "master" + digest = "1:f5d25fd7bdda08e39e01193ef94a1ebf7547b1b931bcdec785d08050598f306c" + name = "github.com/hashicorp/go-cleanhttp" + packages = ["."] + pruneopts = "" + revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d" + +[[projects]] + branch = "master" + digest = "1:ff65bf6fc4d1116f94ac305342725c21b55c16819c2606adc8f527755716937f" + name = "github.com/hashicorp/go-rootcerts" + packages = ["."] + pruneopts = "" + revision = "6bb64b370b90e7ef1fa532be9e591a81c3493e00" + +[[projects]] + digest = "1:f72168ea995f398bab88e84bd1ff58a983466ba162fb8d50d47420666cd57fad" + name = "github.com/hashicorp/serf" + packages = ["coordinate"] + pruneopts = "" + revision = "d6574a5bb1226678d7010325fb6c985db20ee458" + version = "v0.8.1" + +[[projects]] + digest = "1:a39ef049cdeee03a57b132e7d60e32711b9d949c78458da78e702d9864c54369" + name = "github.com/influxdata/go-syslog" + packages = [ + "rfc5424", + "rfc5425", + ] + pruneopts = "" + revision = "eecd51df3ad85464a2bab9b7d3a45bc1e299059e" + version = "v1.0.1" + +[[projects]] + branch = "master" + digest = "1:bc3eb5ddfd59781ea1183f2b3d1eb105a1495d421f09b2ccd360c7fced0b612d" + name = "github.com/influxdata/tail" + packages = [ + ".", + "ratelimiter", + "util", + "watch", + "winfile", + ] + pruneopts = "" + revision = "c43482518d410361b6c383d7aebce33d0471d7bc" + +[[projects]] + branch = "master" + digest = "1:7fb6cc9607eaa6ef309edebc42b57f704244bd4b9ab23bff128829c4ad09b95d" + name = "github.com/influxdata/toml" + packages = [ + ".", + "ast", + ] + pruneopts = "" + revision = "2a2e3012f7cfbef64091cc79776311e65dfa211b" + +[[projects]] + branch = "master" + digest = "1:a0c157916be0b4de1d4565b1f094b8d746109f94968140dff40a42780fa6ccef" + name = "github.com/influxdata/wlog" + packages = ["."] + pruneopts = "" + revision = "7c63b0a71ef8300adc255344d275e10e5c3a71ec" + +[[projects]] + digest = "1:2de1791b9e43f26c696e36950e42676565e7da7499a870bc02213da4b59b1d14" + name = "github.com/jackc/pgx" + packages = [ + ".", + "chunkreader", + "internal/sanitize", + "pgio", + "pgproto3", + "pgtype", + "stdlib", + ] + pruneopts = "" + revision = "da3231b0b66e2e74cdb779f1d46c5e958ba8be27" + version = "v3.1.0" + +[[projects]] + digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e" + name = "github.com/jmespath/go-jmespath" + packages = ["."] + pruneopts = "" + revision = "0b12d6b5" + +[[projects]] + branch = "master" + digest = "1:2c5ad58492804c40bdaf5d92039b0cde8b5becd2b7feeb37d7d1cc36a8aa8dbe" + name = "github.com/kardianos/osext" + packages = ["."] + pruneopts = "" + revision = "ae77be60afb1dcacde03767a8c37337fad28ac14" + +[[projects]] + branch = "master" + digest = "1:fed90fa725d3b1bac0a760de64426834dfef4546474cf182f2ec94285afa74a8" + name = "github.com/kardianos/service" + packages = ["."] + pruneopts = "" + revision = "615a14ed75099c9eaac6949e22ac2341bf9d3197" + +[[projects]] + branch = "master" + digest = "1:63e7368fcf6b54804076eaec26fd9cf0c4466166b272393db4b93102e1e962df" + name = "github.com/kballard/go-shellquote" + packages = ["."] + pruneopts = "" + revision = "95032a82bc518f77982ea72343cc1ade730072f0" + +[[projects]] + branch = "master" + digest = "1:1ed9eeebdf24aadfbca57eb50e6455bd1d2474525e0f0d4454de8c8e9bc7ee9a" + name = "github.com/kr/logfmt" + packages = ["."] + pruneopts = "" + revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" + +[[projects]] + branch = "master" + digest = "1:7e9956922e349af0190afa0b6621befcd201072679d8e51a9047ff149f2afe93" + name = "github.com/mailru/easyjson" + packages = [ + ".", + "buffer", + "jlexer", + "jwriter", + ] + pruneopts = "" + revision = "efc7eb8984d6655c26b5c9d2e65c024e5767c37c" + +[[projects]] + digest = "1:63722a4b1e1717be7b98fc686e0b30d5e7f734b9e93d7dee86293b6deab7ea28" + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + pruneopts = "" + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + +[[projects]] + digest = "1:4c8d8358c45ba11ab7bb15df749d4df8664ff1582daead28bae58cf8cbe49890" + name = "github.com/miekg/dns" + packages = ["."] + pruneopts = "" + revision = "5a2b9fab83ff0f8bfc99684bd5f43a37abe560f1" + version = "v1.0.8" + +[[projects]] + branch = "master" + digest = "1:99651e95333755cbe5c9768c1b80031300acca64a80870b40309202b32585a5a" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + pruneopts = "" + revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66" + +[[projects]] + branch = "master" + digest = "1:f43ed2c836208c14f45158fd01577c985688a4d11cf9fd475a939819fef3b321" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + pruneopts = "" + revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac" + +[[projects]] + digest = "1:ee2e62b00a9ccc2dba1525f93396e35c847f90f87939df6f361b86315ea5f69a" + name = "github.com/multiplay/go-ts3" + packages = ["."] + pruneopts = "" + revision = "d0d44555495c8776880a17e439399e715a4ef319" + version = "v1.0.0" + +[[projects]] + digest = "1:ccd0def9f0b82b61c5e54fcbfccf528eabb13b489d008e46dc16b808c2e1f765" + name = "github.com/naoina/go-stringutil" + packages = ["."] + pruneopts = "" + revision = "6b638e95a32d0c1131db0e7fe83775cbea4a0d0b" + version = "v0.1.0" + +[[projects]] + digest = "1:e5ec850ce66beb0014fc40d8e64b7482172eee71d86d734d66def5e9eac16797" + name = "github.com/nats-io/gnatsd" + packages = [ + "conf", + "logger", + "server", + "server/pse", + "util", + ] + pruneopts = "" + revision = "6608e9ac3be979dcb0614b772cc86a87b71acaa3" + version = "v1.2.0" + +[[projects]] + digest = "1:665af347df4c5d1ae4c3eacd0754f5337a301f6a3f2444c9993b996605c8c02b" + name = "github.com/nats-io/go-nats" + packages = [ + ".", + "encoders/builtin", + "util", + ] + pruneopts = "" + revision = "062418ea1c2181f52dc0f954f6204370519a868b" + version = "v1.5.0" + +[[projects]] + digest = "1:be61e8224b84064109eaba8157cbb4bbe6ca12443e182b6624fdfa1c0dcf53d9" + name = "github.com/nats-io/nuid" + packages = ["."] + pruneopts = "" + revision = "289cccf02c178dc782430d534e3c1f5b72af807f" + version = "v1.0.0" + +[[projects]] + digest = "1:7a69f6a3a33929f8b66aa39c93868ad1698f06417fe627ae067559beb94504bd" + name = "github.com/nsqio/go-nsq" + packages = ["."] + pruneopts = "" + revision = "eee57a3ac4174c55924125bb15eeeda8cffb6e6f" + version = "v1.0.7" + +[[projects]] + digest = "1:5d9b668b0b4581a978f07e7d2e3314af18eb27b3fb5d19b70185b7c575723d11" + name = "github.com/opencontainers/go-digest" + packages = ["."] + pruneopts = "" + revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf" + version = "v1.0.0-rc1" + +[[projects]] + digest = "1:f26c8670b11e29a49c8e45f7ec7f2d5bac62e8fd4e3c0ae1662baa4a697f984a" + name = "github.com/opencontainers/image-spec" + packages = [ + "specs-go", + "specs-go/v1", + ] + pruneopts = "" + revision = "d60099175f88c47cd379c4738d158884749ed235" + version = "v1.0.1" + +[[projects]] + branch = "master" + digest = "1:2da0e5077ed40453dc281b9a2428d84cf6ad14063aed189f6296ca5dd25cf13d" + name = "github.com/opentracing-contrib/go-observer" + packages = ["."] + pruneopts = "" + revision = "a52f2342449246d5bcc273e65cbdcfa5f7d6c63c" + +[[projects]] + digest = "1:78fb99d6011c2ae6c72f3293a83951311147b12b06a5ffa43abf750c4fab6ac5" + name = "github.com/opentracing/opentracing-go" + packages = [ + ".", + "ext", + "log", + ] + pruneopts = "" + revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" + version = "v1.0.2" + +[[projects]] + digest = "1:fea0e67285d900e5a0a7ec19ff4b4c82865a28dddbee8454c5360ad908f7069c" + name = "github.com/openzipkin/zipkin-go-opentracing" + packages = [ + ".", + "flag", + "thrift/gen-go/scribe", + "thrift/gen-go/zipkincore", + "types", + "wire", + ] + pruneopts = "" + revision = "26cf9707480e6b90e5eff22cf0bbf05319154232" + version = "v0.3.4" + +[[projects]] + digest = "1:29e34e58f26655c4d73135cdfc0517ea2ff1483eff34e5d5ef4b6fddbb81e31b" + name = "github.com/pierrec/lz4" + packages = [ + ".", + "internal/xxh32", + ] + pruneopts = "" + revision = "1958fd8fff7f115e79725b1288e0b878b3e06b00" + version = "v2.0.3" + +[[projects]] + digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "" + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + digest = "1:4142d94383572e74b42352273652c62afec5b23f325222ed09198f46009022d1" + name = "github.com/prometheus/client_golang" + packages = [ + "prometheus", + "prometheus/promhttp", + ] + pruneopts = "" + revision = "c5b7fccd204277076155f10851dad72b76a49317" + version = "v0.8.0" + +[[projects]] + branch = "master" + digest = "1:185cf55b1f44a1bf243558901c3f06efa5c64ba62cfdcbb1bf7bbe8c3fb68561" + name = "github.com/prometheus/client_model" + packages = ["go"] + pruneopts = "" + revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" + +[[projects]] + branch = "master" + digest = "1:bfbc121ef802d245ef67421cff206615357d9202337a3d492b8f668906b485a8" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "log", + "model", + ] + pruneopts = "" + revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" + +[[projects]] + branch = "master" + digest = "1:b694a6bdecdace488f507cff872b30f6f490fdaf988abd74d87ea56406b23b6e" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs", + ] + pruneopts = "" + revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a" + +[[projects]] + branch = "master" + digest = "1:15bcdc717654ef21128e8af3a63eec39a6d08a830e297f93d65163f87c8eb523" + name = "github.com/rcrowley/go-metrics" + packages = ["."] + pruneopts = "" + revision = "e2704e165165ec55d062f5919b4b29494e9fa790" + +[[projects]] + branch = "master" + digest = "1:7fc2f428767a2521abc63f1a663d981f61610524275d6c0ea645defadd4e916f" + name = "github.com/samuel/go-zookeeper" + packages = ["zk"] + pruneopts = "" + revision = "c4fab1ac1bec58281ad0667dc3f0907a9476ac47" + +[[projects]] + digest = "1:7f569d906bdd20d906b606415b7d794f798f91a62fcfb6a4daa6d50690fb7a3f" + name = "github.com/satori/go.uuid" + packages = ["."] + pruneopts = "" + revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" + version = "v1.2.0" + +[[projects]] + digest = "1:02715a2fb4b9279af36651a59a51dd4164eb689bd6785874811899f43eeb2a54" + name = "github.com/shirou/gopsutil" + packages = [ + "cpu", + "disk", + "host", + "internal/common", + "load", + "mem", + "net", + "process", + ] + pruneopts = "" + revision = "8048a2e9c5773235122027dd585cf821b2af1249" + version = "v2.18.07" + +[[projects]] + branch = "master" + digest = "1:99c6a6dab47067c9b898e8c8b13d130c6ab4ffbcc4b7cc6236c2cd0b1e344f5b" + name = "github.com/shirou/w32" + packages = ["."] + pruneopts = "" + revision = "bb4de0191aa41b5507caa14b0650cdbddcd9280b" + +[[projects]] + digest = "1:8cf46b6c18a91068d446e26b67512cf16f1540b45d90b28b9533706a127f0ca6" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "" + revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" + version = "v1.0.5" + +[[projects]] + branch = "master" + digest = "1:4b0cabe65ca903a7b2a3e6272c5304eb788ce196d35ecb901c6563e5e7582443" + name = "github.com/soniah/gosnmp" + packages = ["."] + pruneopts = "" + revision = "96b86229e9b3ffb4b954144cdc7f98fe3ee1003f" + +[[projects]] + branch = "master" + digest = "1:4e8f1cae8e6d83af9000d82566efb8823907dae77ba4f1d76ff28fdd197c3c90" + name = "github.com/streadway/amqp" + packages = ["."] + pruneopts = "" + revision = "e5adc2ada8b8efff032bf61173a233d143e9318e" + +[[projects]] + digest = "1:711eebe744c0151a9d09af2315f0bb729b2ec7637ef4c410fa90a18ef74b65b6" + name = "github.com/stretchr/objx" + packages = ["."] + pruneopts = "" + revision = "477a77ecc69700c7cdeb1fa9e129548e1c1c393c" + version = "v0.1.1" + +[[projects]] + digest = "1:c587772fb8ad29ad4db67575dad25ba17a51f072ff18a22b4f0257a4d9c24f75" + name = "github.com/stretchr/testify" + packages = [ + "assert", + "mock", + "require", + ] + pruneopts = "" + revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" + version = "v1.2.2" + +[[projects]] + digest = "1:e139a0dfe24e723193005b291ed82a975041718cfcab9136aa6c9540df70a4ff" + name = "github.com/tidwall/gjson" + packages = ["."] + pruneopts = "" + revision = "f123b340873a0084cb27267eddd8ff615115fbff" + version = "v1.1.2" + +[[projects]] + branch = "master" + digest = "1:4db4f92bb9cb04cfc4fccb36aba2598b02a988008c4cc0692b241214ad8ac96e" + name = "github.com/tidwall/match" + packages = ["."] + pruneopts = "" + revision = "1731857f09b1f38450e2c12409748407822dc6be" + +[[projects]] + digest = "1:343f20460c11a0d0529fe532553bfef9446918d1a1fda6d8661eb27d5b1a68b8" + name = "github.com/vjeantet/grok" + packages = ["."] + pruneopts = "" + revision = "ce01e59abcf6fbc9833b7deb5e4b8ee1769bcc53" + version = "v1.0.0" + +[[projects]] + digest = "1:f9fe29bf856d49f9a51d6001588cb5ee5d65c8a7ff5e8b0dd5423c3a510f0833" + name = "github.com/vmware/govmomi" + packages = [ + ".", + "find", + "list", + "nfc", + "object", + "performance", + "property", + "session", + "simulator", + "simulator/esx", + "simulator/vpx", + "task", + "view", + "vim25", + "vim25/debug", + "vim25/methods", + "vim25/mo", + "vim25/progress", + "vim25/soap", + "vim25/types", + "vim25/xml", + ] + pruneopts = "" + revision = "e3a01f9611c32b2362366434bcd671516e78955d" + version = "v0.18.0" + +[[projects]] + branch = "master" + digest = "1:98ed05e9796df287b90c1d96854e3913c8e349dbc546412d3cabb472ecf4b417" + name = "github.com/wvanbergen/kafka" + packages = ["consumergroup"] + pruneopts = "" + revision = "e2edea948ddfee841ea9a263b32ccca15f7d6c2f" + +[[projects]] + branch = "master" + digest = "1:12aff3cc417907bf9f683a6bf1dc78ffb08e41bc69f829491e593ea9b951a3cf" + name = "github.com/wvanbergen/kazoo-go" + packages = ["."] + pruneopts = "" + revision = "f72d8611297a7cf105da904c04198ad701a60101" + +[[projects]] + branch = "master" + digest = "1:c5918689b7e187382cc1066bf0260de54ba9d1b323105f46ed2551d2fb4a17c7" + name = "github.com/yuin/gopher-lua" + packages = [ + ".", + "ast", + "parse", + "pm", + ] + pruneopts = "" + revision = "46796da1b0b4794e1e341883a399f12cc7574b55" + +[[projects]] + branch = "master" + digest = "1:0773b5c3be42874166670a20aa177872edb450cd9fc70b1df97303d977702a50" + name = "golang.org/x/crypto" + packages = [ + "bcrypt", + "blowfish", + "ed25519", + "ed25519/internal/edwards25519", + "md4", + "pbkdf2", + "pkcs12", + "pkcs12/internal/rc2", + "ssh/terminal", + ] + pruneopts = "" + revision = "a2144134853fc9a27a7b1e3eb4f19f1a76df13c9" + +[[projects]] + branch = "master" + digest = "1:00ff990baae4665bb0a8174af5ff78228574227ed96c89671247a56852a50e21" + name = "golang.org/x/net" + packages = [ + "bpf", + "context", + "context/ctxhttp", + "html", + "html/atom", + "html/charset", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/iana", + "internal/socket", + "internal/socks", + "internal/timeseries", + "ipv4", + "ipv6", + "proxy", + "trace", + "websocket", + ] + pruneopts = "" + revision = "a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1" + +[[projects]] + branch = "master" + digest = "1:b697592485cb412be4188c08ca0beed9aab87f36b86418e21acc4a3998f63734" + name = "golang.org/x/oauth2" + packages = [ + ".", + "clientcredentials", + "internal", + ] + pruneopts = "" + revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9" + +[[projects]] + branch = "master" + digest = "1:677e38cad6833ad266ec843739d167755eda1e6f2d8af1c63102b0426ad820db" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + "windows/registry", + "windows/svc", + "windows/svc/debug", + "windows/svc/eventlog", + "windows/svc/mgr", + ] + pruneopts = "" + revision = "ac767d655b305d4e9612f5f6e33120b9176c4ad4" + +[[projects]] + digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "encoding", + "encoding/charmap", + "encoding/htmlindex", + "encoding/internal", + "encoding/internal/identifier", + "encoding/japanese", + "encoding/korean", + "encoding/simplifiedchinese", + "encoding/traditionalchinese", + "encoding/unicode", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "internal/utf8internal", + "language", + "runes", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:c1771ca6060335f9768dff6558108bc5ef6c58506821ad43377ee23ff059e472" + name = "google.golang.org/appengine" + packages = [ + "cloudsql", + "internal", + "internal/base", + "internal/datastore", + "internal/log", + "internal/remote_api", + "internal/urlfetch", + "urlfetch", + ] + pruneopts = "" + revision = "b1f26356af11148e710935ed1ac8a7f5702c7612" + version = "v1.1.0" + +[[projects]] + branch = "master" + digest = "1:b1443b4e3cc990c84d27fcdece9d3302158c67dba870e33a6937a2c0076388c2" + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + pruneopts = "" + revision = "fedd2861243fd1a8152376292b921b394c7bef7e" + +[[projects]] + digest = "1:5f31b45ee9da7a87f140bef3ed0a7ca34ea2a6d38eb888123b8e28170e8aa4f2" + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "codes", + "connectivity", + "credentials", + "encoding", + "encoding/proto", + "grpclog", + "internal", + "internal/backoff", + "internal/channelz", + "internal/grpcrand", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + "transport", + ] + pruneopts = "" + revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + version = "v1.13.0" + +[[projects]] + digest = "1:15d017551627c8bb091bde628215b2861bed128855343fdd570c62d08871f6e1" + name = "gopkg.in/alecthomas/kingpin.v2" + packages = ["."] + pruneopts = "" + revision = "947dcec5ba9c011838740e680966fd7087a71d0d" + version = "v2.2.6" + +[[projects]] + digest = "1:3cad99e0d1f94b8c162787c12e59d0a0b9df1ef75590eb145cdd625479091efe" + name = "gopkg.in/asn1-ber.v1" + packages = ["."] + pruneopts = "" + revision = "379148ca0225df7a432012b8df0355c2a2063ac0" + version = "v1.2" + +[[projects]] + digest = "1:581450ae66d7970d91ef9132459fa583e937c6e502f1b96e4ee7783a56fa0b44" + name = "gopkg.in/fatih/pool.v2" + packages = ["."] + pruneopts = "" + revision = "010e0b745d12eaf8426c95f9c3924d81dd0b668f" + version = "v2.0.0" + +[[projects]] + digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd" + name = "gopkg.in/fsnotify.v1" + packages = ["."] + pruneopts = "" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + source = "https://github.com/fsnotify/fsnotify/archive/v1.4.7.tar.gz" + version = "v1.4.7" + +[[projects]] + digest = "1:960720207d3d0992995f4576e1366fd9e9b1483473b07fb7243144f75f5b1546" + name = "gopkg.in/gorethink/gorethink.v3" + packages = [ + ".", + "encoding", + "ql2", + "types", + ] + pruneopts = "" + revision = "7f5bdfd858bb064d80559b2a32b86669c5de5d3b" + version = "v3.0.5" + +[[projects]] + digest = "1:367baf06b7dbd0ef0bbdd785f6a79f929c96b0c18e9d3b29c0eed1ac3f5db133" + name = "gopkg.in/ldap.v2" + packages = ["."] + pruneopts = "" + revision = "bb7a9ca6e4fbc2129e3db588a34bc970ffe811a9" + version = "v2.5.1" + +[[projects]] + branch = "v2" + digest = "1:f54ba71a035aac92ced3e902d2bff3734a15d1891daff73ec0f90ef236750139" + name = "gopkg.in/mgo.v2" + packages = [ + ".", + "bson", + "internal/json", + "internal/sasl", + "internal/scram", + ] + pruneopts = "" + revision = "9856a29383ce1c59f308dd1cf0363a79b5bef6b5" + +[[projects]] + digest = "1:b49c4d3115800eace659c9a6a5c384a922f5b210178b24a01abb10731f404ea2" + name = "gopkg.in/olivere/elastic.v5" + packages = [ + ".", + "config", + "uritemplates", + ] + pruneopts = "" + revision = "52741dc2ce53629cbe1e673869040d886cba2cd5" + version = "v5.0.70" + +[[projects]] + branch = "v1" + digest = "1:a96d16bd088460f2e0685d46c39bcf1208ba46e0a977be2df49864ec7da447dd" + name = "gopkg.in/tomb.v1" + packages = ["."] + pruneopts = "" + revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8" + +[[projects]] + digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "" + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "collectd.org/api", + "collectd.org/network", + "github.com/Azure/go-autorest/autorest", + "github.com/Azure/go-autorest/autorest/azure/auth", + "github.com/Microsoft/ApplicationInsights-Go/appinsights", + "github.com/Shopify/sarama", + "github.com/StackExchange/wmi", + "github.com/aerospike/aerospike-client-go", + "github.com/amir/raidman", + "github.com/apache/thrift/lib/go/thrift", + "github.com/aws/aws-sdk-go/aws", + "github.com/aws/aws-sdk-go/aws/client", + "github.com/aws/aws-sdk-go/aws/credentials", + "github.com/aws/aws-sdk-go/aws/credentials/stscreds", + "github.com/aws/aws-sdk-go/aws/session", + "github.com/aws/aws-sdk-go/service/cloudwatch", + "github.com/aws/aws-sdk-go/service/kinesis", + "github.com/bsm/sarama-cluster", + "github.com/couchbase/go-couchbase", + "github.com/denisenkom/go-mssqldb", + "github.com/dgrijalva/jwt-go", + "github.com/docker/docker/api/types", + "github.com/docker/docker/api/types/container", + "github.com/docker/docker/api/types/filters", + "github.com/docker/docker/api/types/registry", + "github.com/docker/docker/api/types/swarm", + "github.com/docker/docker/client", + "github.com/eclipse/paho.mqtt.golang", + "github.com/go-logfmt/logfmt", + "github.com/go-redis/redis", + "github.com/go-sql-driver/mysql", + "github.com/gobwas/glob", + "github.com/golang/protobuf/proto", + "github.com/google/go-cmp/cmp", + "github.com/gorilla/mux", + "github.com/hashicorp/consul/api", + "github.com/influxdata/go-syslog/rfc5424", + "github.com/influxdata/go-syslog/rfc5425", + "github.com/influxdata/tail", + "github.com/influxdata/toml", + "github.com/influxdata/toml/ast", + "github.com/influxdata/wlog", + "github.com/jackc/pgx", + "github.com/jackc/pgx/pgtype", + "github.com/jackc/pgx/stdlib", + "github.com/kardianos/service", + "github.com/kballard/go-shellquote", + "github.com/matttproud/golang_protobuf_extensions/pbutil", + "github.com/miekg/dns", + "github.com/multiplay/go-ts3", + "github.com/nats-io/gnatsd/server", + "github.com/nats-io/go-nats", + "github.com/nsqio/go-nsq", + "github.com/openzipkin/zipkin-go-opentracing", + "github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/zipkincore", + "github.com/pkg/errors", + "github.com/prometheus/client_golang/prometheus", + "github.com/prometheus/client_golang/prometheus/promhttp", + "github.com/prometheus/client_model/go", + "github.com/prometheus/common/expfmt", + "github.com/prometheus/common/log", + "github.com/satori/go.uuid", + "github.com/shirou/gopsutil/cpu", + "github.com/shirou/gopsutil/disk", + "github.com/shirou/gopsutil/host", + "github.com/shirou/gopsutil/load", + "github.com/shirou/gopsutil/mem", + "github.com/shirou/gopsutil/net", + "github.com/shirou/gopsutil/process", + "github.com/soniah/gosnmp", + "github.com/streadway/amqp", + "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/mock", + "github.com/stretchr/testify/require", + "github.com/tidwall/gjson", + "github.com/vjeantet/grok", + "github.com/vmware/govmomi", + "github.com/vmware/govmomi/object", + "github.com/vmware/govmomi/performance", + "github.com/vmware/govmomi/session", + "github.com/vmware/govmomi/simulator", + "github.com/vmware/govmomi/view", + "github.com/vmware/govmomi/vim25", + "github.com/vmware/govmomi/vim25/methods", + "github.com/vmware/govmomi/vim25/mo", + "github.com/vmware/govmomi/vim25/soap", + "github.com/vmware/govmomi/vim25/types", + "github.com/wvanbergen/kafka/consumergroup", + "golang.org/x/net/context", + "golang.org/x/net/html/charset", + "golang.org/x/oauth2", + "golang.org/x/oauth2/clientcredentials", + "golang.org/x/sys/unix", + "golang.org/x/sys/windows", + "golang.org/x/sys/windows/svc", + "golang.org/x/sys/windows/svc/mgr", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/credentials", + "google.golang.org/grpc/status", + "gopkg.in/gorethink/gorethink.v3", + "gopkg.in/ldap.v2", + "gopkg.in/mgo.v2", + "gopkg.in/mgo.v2/bson", + "gopkg.in/olivere/elastic.v5", + "gopkg.in/yaml.v2", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 00000000..2fa3e4c4 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,235 @@ +[[constraint]] + name = "collectd.org" + version = "0.3.0" + +[[constraint]] + name = "github.com/aerospike/aerospike-client-go" + version = "<=1.27.0" + +[[constraint]] + name = "github.com/amir/raidman" + branch = "master" + +[[constraint]] + name = "github.com/apache/thrift" + branch = "master" + +[[constraint]] + name = "github.com/aws/aws-sdk-go" + version = "1.14.8" + +[[constraint]] + name = "github.com/bsm/sarama-cluster" + version = "2.1.13" + +[[constraint]] + name = "github.com/couchbase/go-couchbase" + branch = "master" + +[[constraint]] + name = "github.com/dgrijalva/jwt-go" + version = "3.2.0" + +[[constraint]] + name = "github.com/docker/docker" + revision = "ed7b6428c133e7c59404251a09b7d6b02fa83cc2" # v18.05.0-ce + +[[override]] + name = "github.com/docker/distribution" + revision = "edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c" # v18.05.0-ce + +[[constraint]] + name = "github.com/eclipse/paho.mqtt.golang" + version = "~1.1.1" + +[[constraint]] + name = "github.com/go-sql-driver/mysql" + version = "1.4.0" + +[[constraint]] + name = "github.com/gobwas/glob" + version = "0.2.3" + +[[constraint]] + name = "github.com/golang/protobuf" + version = "1.1.0" + +[[constraint]] + name = "github.com/google/go-cmp" + version = "0.2.0" + +[[constraint]] + name = "github.com/gorilla/mux" + version = "1.6.2" + +[[constraint]] + name = "github.com/go-redis/redis" + version = "6.12.0" + +[[constraint]] + name = "github.com/hashicorp/consul" + version = "1.1.0" + +[[constraint]] + name = "github.com/influxdata/go-syslog" + version = "1.0.1" + +[[constraint]] + name = "github.com/influxdata/tail" + branch = "master" + +[[constraint]] + name = "github.com/influxdata/toml" + branch = "master" + +[[constraint]] + name = "github.com/influxdata/wlog" + branch = "master" + +[[constraint]] + name = "github.com/jackc/pgx" + version = "3.1.0" + +[[constraint]] + name = "github.com/kardianos/service" + branch = "master" + +[[constraint]] + name = "github.com/kballard/go-shellquote" + branch = "master" + +[[constraint]] + name = "github.com/matttproud/golang_protobuf_extensions" + version = "1.0.1" + +[[constraint]] + name = "github.com/Microsoft/ApplicationInsights-Go" + branch = "master" + +[[constraint]] + name = "github.com/miekg/dns" + version = "1.0.8" + +[[constraint]] + name = "github.com/multiplay/go-ts3" + version = "1.0.0" + +[[constraint]] + name = "github.com/nats-io/gnatsd" + version = "1.1.0" + +[[constraint]] + name = "github.com/nats-io/go-nats" + version = "1.5.0" + +[[constraint]] + name = "github.com/nsqio/go-nsq" + version = "1.0.7" + +[[constraint]] + name = "github.com/openzipkin/zipkin-go-opentracing" + version = "0.3.4" + +[[constraint]] + name = "github.com/prometheus/client_golang" + version = "0.8.0" + +[[constraint]] + name = "github.com/prometheus/client_model" + branch = "master" + +[[constraint]] + name = "github.com/prometheus/common" + branch = "master" + +[[constraint]] + name = "github.com/satori/go.uuid" + version = "1.2.0" + +[[constraint]] + name = "github.com/shirou/gopsutil" + version = "2.18.07" + +[[constraint]] + name = "github.com/Shopify/sarama" + version = "1.18.0" + +[[constraint]] + name = "github.com/soniah/gosnmp" + branch = "master" + +[[constraint]] + name = "github.com/StackExchange/wmi" + version = "1.0.0" + +[[constraint]] + name = "github.com/streadway/amqp" + branch = "master" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.2" + +[[constraint]] + name = "github.com/tidwall/gjson" + version = "1.1.1" + +[[constraint]] + name = "github.com/vjeantet/grok" + version = "1.0.0" + +[[constraint]] + name = "github.com/wvanbergen/kafka" + branch = "master" + +[[constraint]] + name = "github.com/denisenkom/go-mssqldb" + branch = "master" + +[[constraint]] + name = "golang.org/x/net" + branch = "master" + +[[constraint]] + name = "golang.org/x/sys" + branch = "master" + +[[constraint]] + name = "google.golang.org/grpc" + version = "1.12.2" + +[[constraint]] + name = "gopkg.in/gorethink/gorethink.v3" + version = "3.0.5" + +[[constraint]] + name = "gopkg.in/ldap.v2" + version = "2.5.1" + +[[constraint]] + name = "gopkg.in/mgo.v2" + branch = "v2" + +[[constraint]] + name = "gopkg.in/olivere/elastic.v5" + version = "^5.0.69" + +[[constraint]] + name = "gopkg.in/yaml.v2" + version = "^2.2.1" + +[[override]] + source = "https://github.com/fsnotify/fsnotify/archive/v1.4.7.tar.gz" + name = "gopkg.in/fsnotify.v1" + +[[constraint]] + name = "github.com/vmware/govmomi" + version = "0.18.0" + + [[constraint]] + name = "github.com/Azure/go-autorest" + version = "10.12.0" + +[[constraint]] + branch = "master" + name = "golang.org/x/oauth2" diff --git a/Makefile b/Makefile index e7fcfdf1..8bb1a2c0 100644 --- a/Makefile +++ b/Makefile @@ -1,136 +1,148 @@ +ifeq ($(SHELL), cmd) + VERSION := $(shell git describe --exact-match --tags 2>nil) + HOME := $(HOMEPATH) +else ifeq ($(SHELL), sh.exe) + VERSION := $(shell git describe --exact-match --tags 2>nil) + HOME := $(HOMEPATH) +else + VERSION := $(shell git describe --exact-match --tags 2>/dev/null) +endif + PREFIX := /usr/local -VERSION := $(shell git describe --exact-match --tags 2>/dev/null) BRANCH := $(shell git rev-parse --abbrev-ref HEAD) COMMIT := $(shell git rev-parse --short HEAD) +GOFILES ?= $(shell git ls-files '*.go') +GOFMT ?= $(shell gofmt -l $(filter-out plugins/parsers/influx/machine.go, $(GOFILES))) +BUILDFLAGS ?= + ifdef GOBIN PATH := $(GOBIN):$(PATH) else -PATH := $(subst :,/bin:,$(GOPATH))/bin:$(PATH) +PATH := $(subst :,/bin:,$(shell go env GOPATH))/bin:$(PATH) endif -TELEGRAF := telegraf$(shell go tool dist env | grep -q 'GOOS=.windows.' && echo .exe) - LDFLAGS := $(LDFLAGS) -X main.commit=$(COMMIT) -X main.branch=$(BRANCH) ifdef VERSION LDFLAGS += -X main.version=$(VERSION) endif +.PHONY: all all: - $(MAKE) deps - $(MAKE) telegraf + @$(MAKE) --no-print-directory deps + @$(MAKE) --no-print-directory telegraf +.PHONY: deps deps: - go get github.com/sparrc/gdm - gdm restore + dep ensure -vendor-only +.PHONY: telegraf telegraf: - go build -i -o $(TELEGRAF) -ldflags "$(LDFLAGS)" ./cmd/telegraf/telegraf.go + go build -ldflags "$(LDFLAGS)" ./cmd/telegraf +.PHONY: go-install go-install: go install -ldflags "-w -s $(LDFLAGS)" ./cmd/telegraf +.PHONY: install install: telegraf mkdir -p $(DESTDIR)$(PREFIX)/bin/ - cp $(TELEGRAF) $(DESTDIR)$(PREFIX)/bin/ + cp telegraf $(DESTDIR)$(PREFIX)/bin/ + +.PHONY: test test: go test -short ./... +.PHONY: fmt +fmt: + @gofmt -w $(filter-out plugins/parsers/influx/machine.go, $(GOFILES)) + +.PHONY: fmtcheck +fmtcheck: + @if [ ! -z "$(GOFMT)" ]; then \ + echo "[ERROR] gofmt has found errors in the following files:" ; \ + echo "$(GOFMT)" ; \ + echo "" ;\ + echo "Run make fmt to fix them." ; \ + exit 1 ;\ + fi + +.PHONY: test-windows test-windows: - go test ./plugins/inputs/ping/... - go test ./plugins/inputs/win_perf_counters/... - go test ./plugins/inputs/win_services/... + go test -short ./plugins/inputs/ping/... + go test -short ./plugins/inputs/win_perf_counters/... + go test -short ./plugins/inputs/win_services/... + go test -short ./plugins/inputs/procstat/... + go test -short ./plugins/inputs/ntpq/... -lint: - go vet ./... +.PHONY: vet +vet: + @echo 'go vet $$(go list ./... | grep -v ./plugins/parsers/influx)' + @go vet $$(go list ./... | grep -v ./plugins/parsers/influx) ; if [ $$? -ne 0 ]; then \ + echo ""; \ + echo "go vet has found suspicious constructs. Please remediate any reported errors"; \ + echo "to fix them before submitting code for review."; \ + exit 1; \ + fi -test-all: lint +.PHONY: check +check: fmtcheck vet + +.PHONY: test-all +test-all: fmtcheck vet go test ./... +.PHONY: package package: ./scripts/build.py --package --platform=all --arch=all +.PHONY: package-windows package-windows: ./scripts/build.py --package --platform=windows --arch=all -clean: - -rm -f telegraf - -rm -f telegraf.exe +.PHONY: package-release +package-release: + ./scripts/build.py --release --package --platform=all --arch=all \ + --upload --bucket=dl.influxdata.com/telegraf/releases +.PHONY: package-nightly +package-nightly: + ./scripts/build.py --nightly --package --platform=all --arch=all \ + --upload --bucket=dl.influxdata.com/telegraf/nightlies + +.PHONY: clean +clean: + rm -f telegraf + rm -f telegraf.exe + +.PHONY: docker-image docker-image: ./scripts/build.py --package --platform=linux --arch=amd64 cp build/telegraf*$(COMMIT)*.deb . docker build -f scripts/dev.docker --build-arg "package=telegraf*$(COMMIT)*.deb" -t "telegraf-dev:$(COMMIT)" . -# Run all docker containers necessary for integration tests -docker-run: - docker run --name aerospike -p "3000:3000" -d aerospike/aerospike-server:3.9.0 - docker run --name zookeeper -p "2181:2181" -d wurstmeister/zookeeper - docker run --name kafka \ - --link zookeeper:zookeeper \ - -e KAFKA_ADVERTISED_HOST_NAME=localhost \ - -e KAFKA_ADVERTISED_PORT=9092 \ - -e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \ - -e KAFKA_CREATE_TOPICS="test:1:1" \ - -p "9092:9092" \ - -d wurstmeister/kafka - docker run --name elasticsearch -p "9200:9200" -p "9300:9300" -d elasticsearch:5 - docker run --name mysql -p "3306:3306" -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d mysql - docker run --name memcached -p "11211:11211" -d memcached - docker run --name postgres -p "5432:5432" -d postgres - docker run --name rabbitmq -p "15672:15672" -p "5672:5672" -d rabbitmq:3-management - docker run --name redis -p "6379:6379" -d redis - docker run --name nsq -p "4150:4150" -d nsqio/nsq /nsqd - docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt - docker run --name riemann -p "5555:5555" -d stealthly/docker-riemann - docker run --name nats -p "4222:4222" -d nats - docker run --name openldap \ - -e SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" \ - -e SLAPD_CONFIG_ROOTPW="secret" \ - -p "389:389" -p "636:636" \ - -d cobaugh/openldap-alpine - docker run --name cratedb \ - -p "6543:5432" \ - -d crate crate \ - -Cnetwork.host=0.0.0.0 \ - -Ctransport.host=localhost \ - -Clicense.enterprise=false +plugins/parsers/influx/machine.go: plugins/parsers/influx/machine.go.rl + ragel -Z -G2 $^ -o $@ -# Run docker containers necessary for integration tests; skipping services provided -# by CircleCI -docker-run-circle: - docker run --name aerospike -p "3000:3000" -d aerospike/aerospike-server:3.9.0 - docker run --name zookeeper -p "2181:2181" -d wurstmeister/zookeeper - docker run --name kafka \ - --link zookeeper:zookeeper \ - -e KAFKA_ADVERTISED_HOST_NAME=localhost \ - -e KAFKA_ADVERTISED_PORT=9092 \ - -e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \ - -e KAFKA_CREATE_TOPICS="test:1:1" \ - -p "9092:9092" \ - -d wurstmeister/kafka - docker run --name elasticsearch -p "9200:9200" -p "9300:9300" -d elasticsearch:5 - docker run --name nsq -p "4150:4150" -d nsqio/nsq /nsqd - docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt - docker run --name riemann -p "5555:5555" -d stealthly/docker-riemann - docker run --name nats -p "4222:4222" -d nats - docker run --name openldap \ - -e SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" \ - -e SLAPD_CONFIG_ROOTPW="secret" \ - -p "389:389" -p "636:636" \ - -d cobaugh/openldap-alpine - docker run --name cratedb \ - -p "6543:5432" \ - -d crate crate \ - -Cnetwork.host=0.0.0.0 \ - -Ctransport.host=localhost \ - -Clicense.enterprise=false +.PHONY: static +static: + @echo "Building static linux binary..." + @CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 \ + go build -ldflags "$(LDFLAGS)" ./cmd/telegraf -docker-kill: - -docker kill aerospike elasticsearch kafka memcached mqtt mysql nats nsq \ - openldap postgres rabbitmq redis riemann zookeeper cratedb - -docker rm aerospike elasticsearch kafka memcached mqtt mysql nats nsq \ - openldap postgres rabbitmq redis riemann zookeeper cratedb +.PHONY: plugin-% +plugin-%: + @echo "Starting dev environment for $${$(@)} input plugin..." + @docker-compose -f plugins/inputs/$${$(@)}/dev/docker-compose.yml up -.PHONY: deps telegraf telegraf.exe install test test-windows lint test-all \ - package clean docker-run docker-run-circle docker-kill docker-image +.PHONY: ci-1.10 +ci-1.10: + docker build -t quay.io/influxdb/telegraf-ci:1.10.3 - < scripts/ci-1.10.docker + docker push quay.io/influxdb/telegraf-ci:1.10.3 + +.PHONY: ci-1.9 +ci-1.9: + docker build -t quay.io/influxdb/telegraf-ci:1.9.7 - < scripts/ci-1.9.docker + docker push quay.io/influxdb/telegraf-ci:1.9.7 diff --git a/README.md b/README.md index c013e4af..4ba1a66c 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,19 @@ # Telegraf [![Circle CI](https://circleci.com/gh/influxdata/telegraf.svg?style=svg)](https://circleci.com/gh/influxdata/telegraf) [![Docker pulls](https://img.shields.io/docker/pulls/library/telegraf.svg)](https://hub.docker.com/_/telegraf/) -Telegraf is an agent written in Go for collecting, processing, aggregating, -and writing metrics. +Telegraf is an agent for collecting, processing, aggregating, and writing metrics. 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 -from local or remote services. +that developers in the community can easily add support for collecting +metrics. -Telegraf is plugin-driven and has the concept of 4 distinct plugins: +Telegraf is plugin-driven and has the concept of 4 distinct plugin types: 1. [Input Plugins](#input-plugins) collect metrics from the system, services, or 3rd party APIs 2. [Processor Plugins](#processor-plugins) transform, decorate, and/or filter metrics 3. [Aggregator Plugins](#aggregator-plugins) create aggregate metrics (e.g. mean, min, max, quantiles, etc.) 4. [Output Plugins](#output-plugins) write metrics to various destinations -For more information on Processor and Aggregator plugins please [read this](./docs/AGGREGATORS_AND_PROCESSORS.md). - -New plugins are designed to be easy to contribute, -we'll eagerly accept pull +New plugins are designed to be easy to contribute, we'll eagerly accept pull requests and will manage the set of plugins that Telegraf supports. ## Contributing @@ -26,7 +22,7 @@ There are many ways to contribute: - Fix and [report bugs](https://github.com/influxdata/telegraf/issues/new) - [Improve documentation](https://github.com/influxdata/telegraf/issues?q=is%3Aopen+label%3Adocumentation) - [Review code and feature proposals](https://github.com/influxdata/telegraf/pulls) -- Answer questions on github and on the [Community Site](https://community.influxdata.com/) +- Answer questions and discuss here on github and on the [Community Site](https://community.influxdata.com/) - [Contribute plugins](CONTRIBUTING.md) ## Installation: @@ -40,16 +36,19 @@ Ansible role: https://github.com/rossmcdonald/telegraf ### From Source: -Telegraf requires golang version 1.8+, the Makefile requires GNU make. +Telegraf requires golang version 1.9 or newer, the Makefile requires GNU make. -Dependencies are managed with [gdm](https://github.com/sparrc/gdm), -which is installed by the Makefile if you don't have it already. - -1. [Install Go](https://golang.org/doc/install) -2. [Setup your GOPATH](https://golang.org/doc/code.html#GOPATH) -3. Run `go get -d github.com/influxdata/telegraf` -4. Run `cd $GOPATH/src/github.com/influxdata/telegraf` -5. Run `make` +1. [Install Go](https://golang.org/doc/install) >=1.9 (1.10 recommended) +2. [Install dep](https://golang.github.io/dep/docs/installation.html) ==v0.5.0 +3. Download Telegraf source: + ``` + go get -d github.com/influxdata/telegraf + ``` +4. Run make from the source directory + ``` + cd "$HOME/go/src/github.com/influxdata/telegraf" + make + ``` ### Nightly Builds @@ -83,60 +82,72 @@ These builds are generated from the master branch: See usage with: ``` -./telegraf --help +telegraf --help ``` #### Generate a telegraf config file: ``` -./telegraf config > telegraf.conf +telegraf config > telegraf.conf ``` #### Generate config with only cpu input & influxdb output plugins defined: ``` -./telegraf --input-filter cpu --output-filter influxdb config +telegraf --input-filter cpu --output-filter influxdb config ``` #### Run a single telegraf collection, outputing metrics to stdout: ``` -./telegraf --config telegraf.conf --test +telegraf --config telegraf.conf --test ``` #### Run telegraf with all plugins defined in config file: ``` -./telegraf --config telegraf.conf +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 +telegraf --config telegraf.conf --input-filter cpu:mem --output-filter influxdb ``` +## Documentation -## Configuration +[Latest Release Documentation][release docs]. -See the [configuration guide](docs/CONFIGURATION.md) for a rundown of the more advanced -configuration options. +For documentation on the latest development code see the [documentation index][devel docs]. + +[release docs]: https://docs.influxdata.com/telegraf +[devel docs]: docs ## Input Plugins +* [activemq](./plugins/inputs/activemq) * [aerospike](./plugins/inputs/aerospike) * [amqp_consumer](./plugins/inputs/amqp_consumer) (rabbitmq) * [apache](./plugins/inputs/apache) +* [aurora](./plugins/inputs/aurora) * [aws cloudwatch](./plugins/inputs/cloudwatch) * [bcache](./plugins/inputs/bcache) -* [cassandra](./plugins/inputs/cassandra) +* [beanstalkd](./plugins/inputs/beanstalkd) +* [bond](./plugins/inputs/bond) +* [burrow](./plugins/inputs/burrow) +* [cassandra](./plugins/inputs/cassandra) (deprecated, use [jolokia2](./plugins/inputs/jolokia2)) * [ceph](./plugins/inputs/ceph) * [cgroup](./plugins/inputs/cgroup) * [chrony](./plugins/inputs/chrony) -* [consul](./plugins/inputs/consul) * [conntrack](./plugins/inputs/conntrack) +* [consul](./plugins/inputs/consul) * [couchbase](./plugins/inputs/couchbase) * [couchdb](./plugins/inputs/couchdb) +* [cpu](./plugins/inputs/cpu) +* [DC/OS](./plugins/inputs/dcos) +* [diskio](./plugins/inputs/diskio) +* [disk](./plugins/inputs/disk) * [disque](./plugins/inputs/disque) * [dmcache](./plugins/inputs/dmcache) * [dns query time](./plugins/inputs/dns_query) @@ -145,43 +156,72 @@ configuration options. * [elasticsearch](./plugins/inputs/elasticsearch) * [exec](./plugins/inputs/exec) (generic executable plugin, support JSON, influx, graphite and nagios) * [fail2ban](./plugins/inputs/fail2ban) +* [fibaro](./plugins/inputs/fibaro) +* [file](./plugins/inputs/file) * [filestat](./plugins/inputs/filestat) +* [filecount](./plugins/inputs/filecount) * [fluentd](./plugins/inputs/fluentd) * [graylog](./plugins/inputs/graylog) * [haproxy](./plugins/inputs/haproxy) * [hddtemp](./plugins/inputs/hddtemp) -* [http_response](./plugins/inputs/http_response) * [httpjson](./plugins/inputs/httpjson) (generic JSON-emitting http service plugin) -* [internal](./plugins/inputs/internal) +* [http_listener](./plugins/inputs/http_listener) +* [http](./plugins/inputs/http) (generic HTTP plugin, supports using input data formats) +* [http_response](./plugins/inputs/http_response) +* [icinga2](./plugins/inputs/icinga2) * [influxdb](./plugins/inputs/influxdb) +* [influxdb_v2](./plugins/inputs/influxdb_v2) +* [internal](./plugins/inputs/internal) * [interrupts](./plugins/inputs/interrupts) * [ipmi_sensor](./plugins/inputs/ipmi_sensor) +* [ipset](./plugins/inputs/ipset) * [iptables](./plugins/inputs/iptables) +* [jolokia2](./plugins/inputs/jolokia2) (java, cassandra, kafka) * [jolokia](./plugins/inputs/jolokia) (deprecated, use [jolokia2](./plugins/inputs/jolokia2)) -* [jolokia2](./plugins/inputs/jolokia2) +* [jti_openconfig_telemetry](./plugins/inputs/jti_openconfig_telemetry) +* [kafka_consumer](./plugins/inputs/kafka_consumer) * [kapacitor](./plugins/inputs/kapacitor) +* [kernel](./plugins/inputs/kernel) +* [kernel_vmstat](./plugins/inputs/kernel_vmstat) +* [kibana](./plugins/inputs/kibana) * [kubernetes](./plugins/inputs/kubernetes) * [leofs](./plugins/inputs/leofs) +* [linux_sysctl_fs](./plugins/inputs/linux_sysctl_fs) +* [logparser](./plugins/inputs/logparser) * [lustre2](./plugins/inputs/lustre2) * [mailchimp](./plugins/inputs/mailchimp) +* [mcrouter](./plugins/inputs/mcrouter) * [memcached](./plugins/inputs/memcached) +* [mem](./plugins/inputs/mem) * [mesos](./plugins/inputs/mesos) * [minecraft](./plugins/inputs/minecraft) * [mongodb](./plugins/inputs/mongodb) +* [mqtt_consumer](./plugins/inputs/mqtt_consumer) * [mysql](./plugins/inputs/mysql) +* [nats_consumer](./plugins/inputs/nats_consumer) +* [nats](./plugins/inputs/nats) +* [net](./plugins/inputs/net) * [net_response](./plugins/inputs/net_response) +* [netstat](./plugins/inputs/net) * [nginx](./plugins/inputs/nginx) * [nginx_plus](./plugins/inputs/nginx_plus) +* [nsq_consumer](./plugins/inputs/nsq_consumer) * [nsq](./plugins/inputs/nsq) * [nstat](./plugins/inputs/nstat) * [ntpq](./plugins/inputs/ntpq) +* [nvidia_smi](./plugins/inputs/nvidia_smi) * [openldap](./plugins/inputs/openldap) +* [opensmtpd](./plugins/inputs/opensmtpd) +* [pf](./plugins/inputs/pf) +* [pgbouncer](./plugins/inputs/pgbouncer) * [phpfpm](./plugins/inputs/phpfpm) * [phusion passenger](./plugins/inputs/passenger) * [ping](./plugins/inputs/ping) -* [postgresql](./plugins/inputs/postgresql) +* [postfix](./plugins/inputs/postfix) * [postgresql_extensible](./plugins/inputs/postgresql_extensible) +* [postgresql](./plugins/inputs/postgresql) * [powerdns](./plugins/inputs/powerdns) +* [processes](./plugins/inputs/processes) * [procstat](./plugins/inputs/procstat) * [prometheus](./plugins/inputs/prometheus) (can be used for [Caddy server](./plugins/inputs/prometheus/README.md#usage-for-caddy-http-server)) * [puppetagent](./plugins/inputs/puppetagent) @@ -193,52 +233,39 @@ configuration options. * [salesforce](./plugins/inputs/salesforce) * [sensors](./plugins/inputs/sensors) * [smart](./plugins/inputs/smart) -* [snmp](./plugins/inputs/snmp) * [snmp_legacy](./plugins/inputs/snmp_legacy) +* [snmp](./plugins/inputs/snmp) +* [socket_listener](./plugins/inputs/socket_listener) * [solr](./plugins/inputs/solr) * [sql server](./plugins/inputs/sqlserver) (microsoft) -* [teamspeak](./plugins/inputs/teamspeak) -* [tomcat](./plugins/inputs/tomcat) -* [twemproxy](./plugins/inputs/twemproxy) -* [varnish](./plugins/inputs/varnish) -* [zfs](./plugins/inputs/zfs) -* [zookeeper](./plugins/inputs/zookeeper) -* [win_perf_counters](./plugins/inputs/win_perf_counters) (windows performance counters) -* [win_services](./plugins/inputs/win_services) +* [statsd](./plugins/inputs/statsd) +* [swap](./plugins/inputs/swap) +* [syslog](./plugins/inputs/syslog) * [sysstat](./plugins/inputs/sysstat) * [system](./plugins/inputs/system) - * cpu - * mem - * net - * netstat - * disk - * diskio - * swap - * processes - * kernel (/proc/stat) - * kernel (/proc/vmstat) - * linux_sysctl_fs (/proc/sys/fs) - -Telegraf can also collect metrics via the following service plugins: - -* [http_listener](./plugins/inputs/http_listener) -* [kafka_consumer](./plugins/inputs/kafka_consumer) -* [mqtt_consumer](./plugins/inputs/mqtt_consumer) -* [nats_consumer](./plugins/inputs/nats_consumer) -* [nsq_consumer](./plugins/inputs/nsq_consumer) -* [logparser](./plugins/inputs/logparser) -* [statsd](./plugins/inputs/statsd) -* [socket_listener](./plugins/inputs/socket_listener) * [tail](./plugins/inputs/tail) +* [temp](./plugins/inputs/temp) * [tcp_listener](./plugins/inputs/socket_listener) +* [teamspeak](./plugins/inputs/teamspeak) +* [tengine](./plugins/inputs/tengine) +* [tomcat](./plugins/inputs/tomcat) +* [twemproxy](./plugins/inputs/twemproxy) * [udp_listener](./plugins/inputs/socket_listener) +* [unbound](./plugins/inputs/unbound) +* [varnish](./plugins/inputs/varnish) +* [vsphere](./plugins/inputs/vsphere) VMware vSphere * [webhooks](./plugins/inputs/webhooks) * [filestack](./plugins/inputs/webhooks/filestack) * [github](./plugins/inputs/webhooks/github) * [mandrill](./plugins/inputs/webhooks/mandrill) - * [rollbar](./plugins/inputs/webhooks/rollbar) * [papertrail](./plugins/inputs/webhooks/papertrail) + * [particle](./plugins/inputs/webhooks/particle) + * [rollbar](./plugins/inputs/webhooks/rollbar) +* [win_perf_counters](./plugins/inputs/win_perf_counters) (windows performance counters) +* [win_services](./plugins/inputs/win_services) +* [zfs](./plugins/inputs/zfs) * [zipkin](./plugins/inputs/zipkin) +* [zookeeper](./plugins/inputs/zookeeper) Telegraf is able to parse the following input data formats into metrics, these formats may be used with input plugins supporting the `data_format` option: @@ -249,24 +276,33 @@ formats may be used with input plugins supporting the `data_format` option: * [Value](./docs/DATA_FORMATS_INPUT.md#value) * [Nagios](./docs/DATA_FORMATS_INPUT.md#nagios) * [Collectd](./docs/DATA_FORMATS_INPUT.md#collectd) +* [Dropwizard](./docs/DATA_FORMATS_INPUT.md#dropwizard) ## Processor Plugins +* [converter](./plugins/processors/converter) +* [override](./plugins/processors/override) * [printer](./plugins/processors/printer) +* [regex](./plugins/processors/regex) +* [rename](./plugins/processors/rename) +* [topk](./plugins/processors/topk) ## Aggregator Plugins * [basicstats](./plugins/aggregators/basicstats) * [minmax](./plugins/aggregators/minmax) * [histogram](./plugins/aggregators/histogram) +* [valuecounter](./plugins/aggregators/valuecounter) ## Output Plugins * [influxdb](./plugins/outputs/influxdb) * [amon](./plugins/outputs/amon) * [amqp](./plugins/outputs/amqp) (rabbitmq) +* [application_insights](./plugins/outputs/application_insights) * [aws kinesis](./plugins/outputs/kinesis) * [aws cloudwatch](./plugins/outputs/cloudwatch) +* [azure_monitor](./plugins/outputs/azure_monitor) * [cratedb](./plugins/outputs/cratedb) * [datadog](./plugins/outputs/datadog) * [discard](./plugins/outputs/discard) @@ -274,6 +310,7 @@ formats may be used with input plugins supporting the `data_format` option: * [file](./plugins/outputs/file) * [graphite](./plugins/outputs/graphite) * [graylog](./plugins/outputs/graylog) +* [http](./plugins/outputs/http) * [instrumental](./plugins/outputs/instrumental) * [kafka](./plugins/outputs/kafka) * [librato](./plugins/outputs/librato) diff --git a/agent/accumulator.go b/agent/accumulator.go index 1fa9b13e..05e99350 100644 --- a/agent/accumulator.go +++ b/agent/accumulator.go @@ -5,6 +5,7 @@ import ( "time" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/selfstat" ) @@ -14,19 +15,19 @@ var ( type MetricMaker interface { Name() string - MakeMetric( - measurement string, - fields map[string]interface{}, - tags map[string]string, - mType telegraf.ValueType, - t time.Time, - ) telegraf.Metric + MakeMetric(metric telegraf.Metric) telegraf.Metric +} + +type accumulator struct { + maker MetricMaker + metrics chan telegraf.Metric + precision time.Duration } func NewAccumulator( maker MetricMaker, metrics chan telegraf.Metric, -) *accumulator { +) telegraf.Accumulator { acc := accumulator{ maker: maker, metrics: metrics, @@ -35,23 +36,13 @@ func NewAccumulator( return &acc } -type accumulator struct { - metrics chan telegraf.Metric - - maker MetricMaker - - precision time.Duration -} - func (ac *accumulator) AddFields( measurement string, fields map[string]interface{}, tags map[string]string, t ...time.Time, ) { - if m := ac.maker.MakeMetric(measurement, fields, tags, telegraf.Untyped, ac.getTime(t)); m != nil { - ac.metrics <- m - } + ac.addMetric(measurement, tags, fields, telegraf.Untyped, t...) } func (ac *accumulator) AddGauge( @@ -60,9 +51,7 @@ func (ac *accumulator) AddGauge( tags map[string]string, t ...time.Time, ) { - if m := ac.maker.MakeMetric(measurement, fields, tags, telegraf.Gauge, ac.getTime(t)); m != nil { - ac.metrics <- m - } + ac.addMetric(measurement, tags, fields, telegraf.Gauge, t...) } func (ac *accumulator) AddCounter( @@ -71,9 +60,7 @@ func (ac *accumulator) AddCounter( tags map[string]string, t ...time.Time, ) { - if m := ac.maker.MakeMetric(measurement, fields, tags, telegraf.Counter, ac.getTime(t)); m != nil { - ac.metrics <- m - } + ac.addMetric(measurement, tags, fields, telegraf.Counter, t...) } func (ac *accumulator) AddSummary( @@ -82,9 +69,7 @@ func (ac *accumulator) AddSummary( tags map[string]string, t ...time.Time, ) { - if m := ac.maker.MakeMetric(measurement, fields, tags, telegraf.Summary, ac.getTime(t)); m != nil { - ac.metrics <- m - } + ac.addMetric(measurement, tags, fields, telegraf.Summary, t...) } func (ac *accumulator) AddHistogram( @@ -93,7 +78,21 @@ func (ac *accumulator) AddHistogram( tags map[string]string, t ...time.Time, ) { - if m := ac.maker.MakeMetric(measurement, fields, tags, telegraf.Histogram, ac.getTime(t)); m != nil { + ac.addMetric(measurement, tags, fields, telegraf.Histogram, t...) +} + +func (ac *accumulator) addMetric( + measurement string, + tags map[string]string, + fields map[string]interface{}, + tp telegraf.ValueType, + t ...time.Time, +) { + m, err := metric.New(measurement, tags, fields, ac.getTime(t), tp) + if err != nil { + return + } + if m := ac.maker.MakeMetric(m); m != nil { ac.metrics <- m } } @@ -105,7 +104,6 @@ func (ac *accumulator) AddError(err error) { return } NErrors.Incr(1) - //TODO suppress/throttle consecutive duplicate errors? log.Printf("E! Error in plugin [%s]: %s", ac.maker.Name(), err) } diff --git a/agent/accumulator_test.go b/agent/accumulator_test.go index e13446ba..2bb08920 100644 --- a/agent/accumulator_test.go +++ b/agent/accumulator_test.go @@ -9,69 +9,41 @@ import ( "time" "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/metric" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestAdd(t *testing.T) { - now := time.Now() - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - - testm := <-metrics - actual := testm.String() - assert.Contains(t, actual, "acctest value=101") - - testm = <-metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test value=101") - - testm = <-metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", now.UnixNano()), - actual) -} - func TestAddFields(t *testing.T) { - now := time.Now() metrics := make(chan telegraf.Metric, 10) defer close(metrics) a := NewAccumulator(&TestMetricMaker{}, metrics) + tags := map[string]string{"foo": "bar"} fields := map[string]interface{}{ "usage": float64(99), } - a.AddFields("acctest", fields, map[string]string{}) - a.AddGauge("acctest", fields, map[string]string{"acc": "test"}) - a.AddCounter("acctest", fields, map[string]string{"acc": "test"}, now) + now := time.Now() + a.AddCounter("acctest", fields, tags, now) testm := <-metrics - actual := testm.String() - assert.Contains(t, actual, "acctest usage=99") - testm = <-metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test usage=99") + require.Equal(t, "acctest", testm.Name()) + actual, ok := testm.GetField("usage") - testm = <-metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test usage=99 %d\n", now.UnixNano()), - actual) + require.True(t, ok) + require.Equal(t, float64(99), actual) + + actual, ok = testm.GetTag("foo") + require.True(t, ok) + require.Equal(t, "bar", actual) + + tm := testm.Time() + // okay if monotonic clock differs + require.True(t, now.Equal(tm)) + + tp := testm.Type() + require.Equal(t, telegraf.Counter, tp) } func TestAccAddError(t *testing.T) { @@ -98,215 +70,61 @@ func TestAccAddError(t *testing.T) { assert.Contains(t, string(errs[2]), "baz") } -func TestAddNoIntervalWithPrecision(t *testing.T) { - now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC) - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - a.SetPrecision(0, time.Second) +func TestSetPrecision(t *testing.T) { + tests := []struct { + name string + unset bool + precision time.Duration + interval time.Duration + timestamp time.Time + expected time.Time + }{ + { + name: "default precision is nanosecond", + unset: true, + timestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + }, + { + name: "second interval", + interval: time.Second, + timestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 0, 0, time.UTC), + }, + { + name: "microsecond interval", + interval: time.Microsecond, + timestamp: time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 0, 82913000, time.UTC), + }, + { + name: "2 second precision", + precision: 2 * time.Second, + timestamp: time.Date(2006, time.February, 10, 12, 0, 2, 4, time.UTC), + expected: time.Date(2006, time.February, 10, 12, 0, 2, 0, time.UTC), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + metrics := make(chan telegraf.Metric, 10) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) + a := NewAccumulator(&TestMetricMaker{}, metrics) + if !tt.unset { + a.SetPrecision(tt.precision, tt.interval) + } - testm := <-a.metrics - actual := testm.String() - assert.Contains(t, actual, "acctest value=101") + a.AddFields("acctest", + map[string]interface{}{"value": float64(101)}, + map[string]string{}, + tt.timestamp, + ) - testm = <-a.metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test value=101") + testm := <-metrics + require.Equal(t, tt.expected, testm.Time()) - testm = <-a.metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800000000000)), - actual) -} - -func TestAddDisablePrecision(t *testing.T) { - now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC) - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - - a.SetPrecision(time.Nanosecond, 0) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - - testm := <-a.metrics - actual := testm.String() - assert.Contains(t, actual, "acctest value=101") - - testm = <-a.metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test value=101") - - testm = <-a.metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800082912748)), - actual) -} - -func TestAddNoPrecisionWithInterval(t *testing.T) { - now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC) - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - - a.SetPrecision(0, time.Second) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - - testm := <-a.metrics - actual := testm.String() - assert.Contains(t, actual, "acctest value=101") - - testm = <-a.metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test value=101") - - testm = <-a.metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800000000000)), - actual) -} - -func TestDifferentPrecisions(t *testing.T) { - now := time.Date(2006, time.February, 10, 12, 0, 0, 82912748, time.UTC) - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - - a.SetPrecision(0, time.Second) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - testm := <-a.metrics - actual := testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800000000000)), - actual) - - a.SetPrecision(0, time.Millisecond) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - testm = <-a.metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800083000000)), - actual) - - a.SetPrecision(0, time.Microsecond) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - testm = <-a.metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800082913000)), - actual) - - a.SetPrecision(0, time.Nanosecond) - a.AddFields("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - testm = <-a.metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", int64(1139572800082912748)), - actual) -} - -func TestAddGauge(t *testing.T) { - now := time.Now() - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - - a.AddGauge("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{}) - a.AddGauge("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}) - a.AddGauge("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - - testm := <-metrics - actual := testm.String() - assert.Contains(t, actual, "acctest value=101") - assert.Equal(t, testm.Type(), telegraf.Gauge) - - testm = <-metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test value=101") - assert.Equal(t, testm.Type(), telegraf.Gauge) - - testm = <-metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", now.UnixNano()), - actual) - assert.Equal(t, testm.Type(), telegraf.Gauge) -} - -func TestAddCounter(t *testing.T) { - now := time.Now() - metrics := make(chan telegraf.Metric, 10) - defer close(metrics) - a := NewAccumulator(&TestMetricMaker{}, metrics) - - a.AddCounter("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{}) - a.AddCounter("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}) - a.AddCounter("acctest", - map[string]interface{}{"value": float64(101)}, - map[string]string{"acc": "test"}, now) - - testm := <-metrics - actual := testm.String() - assert.Contains(t, actual, "acctest value=101") - assert.Equal(t, testm.Type(), telegraf.Counter) - - testm = <-metrics - actual = testm.String() - assert.Contains(t, actual, "acctest,acc=test value=101") - assert.Equal(t, testm.Type(), telegraf.Counter) - - testm = <-metrics - actual = testm.String() - assert.Equal(t, - fmt.Sprintf("acctest,acc=test value=101 %d\n", now.UnixNano()), - actual) - assert.Equal(t, testm.Type(), telegraf.Counter) + close(metrics) + }) + } } type TestMetricMaker struct { @@ -315,26 +133,7 @@ type TestMetricMaker struct { func (tm *TestMetricMaker) Name() string { return "TestPlugin" } -func (tm *TestMetricMaker) MakeMetric( - measurement string, - fields map[string]interface{}, - tags map[string]string, - mType telegraf.ValueType, - t time.Time, -) telegraf.Metric { - switch mType { - case telegraf.Untyped: - if m, err := metric.New(measurement, tags, fields, t); err == nil { - return m - } - case telegraf.Counter: - if m, err := metric.New(measurement, tags, fields, t, telegraf.Counter); err == nil { - return m - } - case telegraf.Gauge: - if m, err := metric.New(measurement, tags, fields, t, telegraf.Gauge); err == nil { - return m - } - } - return nil + +func (tm *TestMetricMaker) MakeMetric(metric telegraf.Metric) telegraf.Metric { + return metric } diff --git a/agent/agent.go b/agent/agent.go index af96718c..6f7b540f 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -143,7 +143,7 @@ func (a *Agent) gatherer( func gatherWithTimeout( shutdown chan struct{}, input *models.RunningInput, - acc *accumulator, + acc telegraf.Accumulator, timeout time.Duration, ) { ticker := time.NewTicker(timeout) @@ -203,11 +203,6 @@ func (a *Agent) Test() error { input.SetTrace(true) input.SetDefaultTags(a.Config.Tags) - fmt.Printf("* Plugin: %s, Collection 1\n", input.Name()) - if input.Config.Interval != 0 { - fmt.Printf("* Internal: %s\n", input.Config.Interval) - } - if err := input.Input.Gather(acc); err != nil { return err } @@ -217,7 +212,6 @@ func (a *Agent) Test() error { switch input.Name() { case "inputs.cpu", "inputs.mongodb", "inputs.procstat": time.Sleep(500 * time.Millisecond) - fmt.Printf("* Plugin: %s, Collection 2\n", input.Name()) if err := input.Input.Gather(acc); err != nil { return err } @@ -247,14 +241,12 @@ func (a *Agent) flush() { } // flusher monitors the metrics input channel and flushes on the minimum interval -func (a *Agent) flusher(shutdown chan struct{}, metricC chan telegraf.Metric, aggC chan telegraf.Metric) error { - // Inelegant, but this sleep is to allow the Gather threads to run, so that - // the flusher will flush after metrics are collected. - time.Sleep(time.Millisecond * 300) - - // create an output metric channel and a gorouting that continuously passes - // each metric onto the output plugins & aggregators. - outMetricC := make(chan telegraf.Metric, 100) +func (a *Agent) flusher( + shutdown chan struct{}, + metricC chan telegraf.Metric, + aggMetricC chan telegraf.Metric, + outMetricC chan telegraf.Metric, +) error { var wg sync.WaitGroup wg.Add(1) go func() { @@ -263,52 +255,67 @@ func (a *Agent) flusher(shutdown chan struct{}, metricC chan telegraf.Metric, ag select { case <-shutdown: if len(outMetricC) > 0 { - // keep going until outMetricC is flushed + // keep going until channel is empty continue } return - case m := <-outMetricC: - // if dropOriginal is set to true, then we will only send this - // metric to the aggregators, not the outputs. - var dropOriginal bool - if !m.IsAggregate() { - for _, agg := range a.Config.Aggregators { - if ok := agg.Add(m.Copy()); ok { - dropOriginal = true - } - } - } - if !dropOriginal { - for i, o := range a.Config.Outputs { - if i == len(a.Config.Outputs)-1 { - o.AddMetric(m) - } else { - o.AddMetric(m.Copy()) - } + case metric := <-outMetricC: + for i, o := range a.Config.Outputs { + if i == len(a.Config.Outputs)-1 { + o.AddMetric(metric) + } else { + o.AddMetric(metric.Copy()) } } } } }() + wg.Add(1) + go func() { + defer wg.Done() + for metric := range aggMetricC { + // Apply Processors + metrics := []telegraf.Metric{metric} + for _, processor := range a.Config.Processors { + metrics = processor.Apply(metrics...) + } + outMetricC <- metric + } + }() + wg.Add(1) go func() { defer wg.Done() for { select { case <-shutdown: - if len(aggC) > 0 { - // keep going until aggC is flushed + if len(metricC) > 0 { + // keep going until channel is empty continue } + close(aggMetricC) return - case metric := <-aggC: + case metric := <-metricC: + // Apply Processors metrics := []telegraf.Metric{metric} for _, processor := range a.Config.Processors { metrics = processor.Apply(metrics...) } - for _, m := range metrics { - outMetricC <- m + + for _, metric := range metrics { + // Apply Aggregators + var dropOriginal bool + for _, agg := range a.Config.Aggregators { + if ok := agg.Add(metric.Copy()); ok { + dropOriginal = true + } + } + + // Forward metric to Outputs + if !dropOriginal { + outMetricC <- metric + } } } } @@ -337,16 +344,6 @@ func (a *Agent) flusher(shutdown chan struct{}, metricC chan telegraf.Metric, ag " already a flush ongoing.") } }() - case metric := <-metricC: - // NOTE potential bottleneck here as we put each metric through the - // processors serially. - mS := []telegraf.Metric{metric} - for _, processor := range a.Config.Processors { - mS = processor.Apply(mS...) - } - for _, m := range mS { - outMetricC <- m - } } } } @@ -360,13 +357,46 @@ func (a *Agent) Run(shutdown chan struct{}) error { a.Config.Agent.Interval.Duration, a.Config.Agent.Quiet, a.Config.Agent.Hostname, a.Config.Agent.FlushInterval.Duration) - // channel shared between all input threads for accumulating metrics + // Channel shared between all input threads for accumulating metrics metricC := make(chan telegraf.Metric, 100) - aggC := make(chan telegraf.Metric, 100) - now := time.Now() + // Channel for metrics ready to be output + outMetricC := make(chan telegraf.Metric, 100) - // Start all ServicePlugins + // Channel for aggregated metrics + aggMetricC := make(chan telegraf.Metric, 100) + + // Round collection to nearest interval by sleeping + if a.Config.Agent.RoundInterval { + i := int64(a.Config.Agent.Interval.Duration) + time.Sleep(time.Duration(i - (time.Now().UnixNano() % i))) + } + + wg.Add(1) + go func() { + defer wg.Done() + if err := a.flusher(shutdown, metricC, aggMetricC, outMetricC); err != nil { + log.Printf("E! Flusher routine failed, exiting: %s\n", err.Error()) + close(shutdown) + } + }() + + wg.Add(len(a.Config.Aggregators)) + for _, aggregator := range a.Config.Aggregators { + go func(agg *models.RunningAggregator) { + defer wg.Done() + acc := NewAccumulator(agg, aggMetricC) + acc.SetPrecision(a.Config.Agent.Precision.Duration, + a.Config.Agent.Interval.Duration) + agg.Run(acc, shutdown) + }(aggregator) + } + + // Service inputs may immediately add metrics, if metrics are added before + // the aggregator starts they will be dropped. Generally this occurs + // only during testing but it is an outstanding issue. + // + // https://github.com/influxdata/telegraf/issues/4394 for _, input := range a.Config.Inputs { input.SetDefaultTags(a.Config.Tags) switch p := input.Input.(type) { @@ -384,32 +414,6 @@ func (a *Agent) Run(shutdown chan struct{}) error { } } - // Round collection to nearest interval by sleeping - if a.Config.Agent.RoundInterval { - i := int64(a.Config.Agent.Interval.Duration) - time.Sleep(time.Duration(i - (time.Now().UnixNano() % i))) - } - - wg.Add(1) - go func() { - defer wg.Done() - if err := a.flusher(shutdown, metricC, aggC); err != nil { - log.Printf("E! Flusher routine failed, exiting: %s\n", err.Error()) - close(shutdown) - } - }() - - wg.Add(len(a.Config.Aggregators)) - for _, aggregator := range a.Config.Aggregators { - go func(agg *models.RunningAggregator) { - defer wg.Done() - acc := NewAccumulator(agg, aggC) - acc.SetPrecision(a.Config.Agent.Precision.Duration, - a.Config.Agent.Interval.Duration) - agg.Run(acc, now, shutdown) - }(aggregator) - } - wg.Add(len(a.Config.Inputs)) for _, input := range a.Config.Inputs { interval := a.Config.Agent.Interval.Duration diff --git a/appveyor.yml b/appveyor.yml index 18c0361a..455b3ee2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,15 +12,21 @@ platform: x64 install: - IF NOT EXIST "C:\Cache" mkdir C:\Cache - - IF NOT EXIST "C:\Cache\go1.8.1.msi" curl -o "C:\Cache\go1.8.1.msi" https://storage.googleapis.com/golang/go1.8.1.windows-amd64.msi + - IF NOT EXIST "C:\Cache\go1.10.3.msi" curl -o "C:\Cache\go1.10.3.msi" https://storage.googleapis.com/golang/go1.10.3.windows-amd64.msi - IF NOT EXIST "C:\Cache\wix311-binaries.zip" curl -L -o "C:\Cache\wix311-binaries.zip" https://github.com/wixtoolset/wix3/releases/download/wix311rtm/wix311-binaries.zip - IF NOT EXIST "C:\Cache\gnuwin32-bin.zip" curl -o "C:\Cache\gnuwin32-bin.zip" https://dl.influxdata.com/telegraf/ci/make-3.81-bin.zip - IF NOT EXIST "C:\Cache\gnuwin32-dep.zip" curl -o "C:\Cache\gnuwin32-dep.zip" https://dl.influxdata.com/telegraf/ci/make-3.81-dep.zip - IF EXIST "C:\Go" rmdir /S /Q C:\Go - - msiexec.exe /i "C:\Cache\go1.8.1.msi" /quiet + - msiexec.exe /i "C:\Cache\go1.10.3.msi" /quiet - 7z x "C:\Cache\wix311-binaries.zip" -oC:\wix -y - 7z x "C:\Cache\gnuwin32-bin.zip" -oC:\GnuWin32 -y - 7z x "C:\Cache\gnuwin32-dep.zip" -oC:\GnuWin32 -y + - go get -d github.com/golang/dep + - cd "%GOPATH%\src\github.com\golang\dep" + - git checkout -q v0.5.0 + - go install -ldflags="-X main.version=v0.5.0" ./cmd/dep + - cd "%GOPATH%\src\github.com\influxdata\telegraf" + - git config --system core.longpaths true - go version - go env @@ -28,6 +34,7 @@ build_script: - cmd: C:\GnuWin32\bin\make package-windows test_script: + - cmd: C:\GnuWin32\bin\make check - cmd: C:\GnuWin32\bin\make test-windows artifacts: diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 314903e9..00000000 --- a/circle.yml +++ /dev/null @@ -1,19 +0,0 @@ -machine: - services: - - docker - - memcached - - redis - - rabbitmq-server - post: - - sudo rm -rf /usr/local/go - - wget https://storage.googleapis.com/golang/go1.9.1.linux-amd64.tar.gz - - sudo tar -C /usr/local -xzf go1.9.1.linux-amd64.tar.gz - - go version - -dependencies: - override: - - docker info - -test: - override: - - bash scripts/circle-test.sh diff --git a/cmd/telegraf/telegraf.go b/cmd/telegraf/telegraf.go index 9e286e36..93336ffb 100644 --- a/cmd/telegraf/telegraf.go +++ b/cmd/telegraf/telegraf.go @@ -13,6 +13,7 @@ import ( "syscall" "github.com/influxdata/telegraf/agent" + "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/internal/config" "github.com/influxdata/telegraf/logger" _ "github.com/influxdata/telegraf/plugins/aggregators/all" @@ -34,7 +35,7 @@ var fTest = flag.Bool("test", false, "gather metrics, print them out, and exit") var fConfig = flag.String("config", "", "configuration file to load") var fConfigDirectory = flag.String("config-directory", "", "directory containing additional *.conf files") -var fVersion = flag.Bool("version", false, "display the version") +var fVersion = flag.Bool("version", false, "display the version and exit") var fSampleConfig = flag.Bool("sample-config", false, "print out full sample configuration") var fPidfile = flag.String("pidfile", "", "file to write our pid to") @@ -53,67 +54,16 @@ var fProcessorFilters = flag.String("processor-filter", "", var fUsage = flag.String("usage", "", "print usage for a plugin, ie, 'telegraf --usage mysql'") var fService = flag.String("service", "", - "operate on the service") + "operate on the service (windows only)") +var fServiceName = flag.String("service-name", "telegraf", "service name (windows only)") +var fRunAsConsole = flag.Bool("console", false, "run as console application (windows only)") var ( - nextVersion = "1.5.0" - version string - commit string - branch string + version string + commit string + branch string ) -func init() { - // If commit or branch are not set, make that clear. - if commit == "" { - commit = "unknown" - } - if branch == "" { - branch = "unknown" - } -} - -const usage = `Telegraf, The plugin-driven server agent for collecting and reporting metrics. - -Usage: - - telegraf [commands|flags] - -The commands & flags are: - - config print out full sample configuration to stdout - version print the version to stdout - - --config configuration file to load - --test gather metrics once, print them to stdout, and exit - --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' - --debug print metrics as they're generated to stdout - --pprof-addr pprof address to listen on, format: localhost:6060 or :6060 - --quiet run in quiet mode - -Examples: - - # generate a telegraf config file: - telegraf config > telegraf.conf - - # generate config with only cpu input & influxdb output plugins defined - telegraf --input-filter cpu --output-filter influxdb config - - # 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 - - # run telegraf with pprof - telegraf --config telegraf.conf --pprof-addr localhost:6060 -` - var stop chan struct{} func reloadLoop( @@ -187,11 +137,11 @@ func reloadLoop( shutdown := make(chan struct{}) signals := make(chan os.Signal) - signal.Notify(signals, os.Interrupt, syscall.SIGHUP) + signal.Notify(signals, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM) go func() { select { case sig := <-signals: - if sig == os.Interrupt { + if sig == os.Interrupt || sig == syscall.SIGTERM { close(shutdown) } if sig == syscall.SIGHUP { @@ -205,9 +155,11 @@ func reloadLoop( } }() - log.Printf("I! Starting Telegraf %s\n", displayVersion()) - log.Printf("I! Loaded outputs: %s", strings.Join(c.OutputNames(), " ")) + log.Printf("I! Starting Telegraf %s\n", version) log.Printf("I! Loaded inputs: %s", strings.Join(c.InputNames(), " ")) + log.Printf("I! Loaded aggregators: %s", strings.Join(c.AggregatorNames(), " ")) + log.Printf("I! Loaded processors: %s", strings.Join(c.ProcessorNames(), " ")) + log.Printf("I! Loaded outputs: %s", strings.Join(c.OutputNames(), " ")) log.Printf("I! Tags enabled: %s", c.ListTags()) if *fPidfile != "" { @@ -233,7 +185,7 @@ func reloadLoop( } func usageExit(rc int) { - fmt.Println(usage) + fmt.Println(internal.Usage) os.Exit(rc) } @@ -263,11 +215,27 @@ func (p *program) Stop(s service.Service) error { return nil } -func displayVersion() string { - if version == "" { - return fmt.Sprintf("v%s~%s", nextVersion, commit) +func formatFullVersion() string { + var parts = []string{"Telegraf"} + + if version != "" { + parts = append(parts, version) + } else { + parts = append(parts, "unknown") } - return "v" + version + + if branch != "" || commit != "" { + if branch == "" { + branch = "unknown" + } + if commit == "" { + commit = "unknown" + } + git := fmt.Sprintf("(git: %s %s)", branch, commit) + parts = append(parts, git) + } + + return strings.Join(parts, " ") } func main() { @@ -311,7 +279,7 @@ func main() { if len(args) > 0 { switch args[0] { case "version": - fmt.Printf("Telegraf %s (git: %s %s)\n", displayVersion(), branch, commit) + fmt.Println(formatFullVersion()) return case "config": config.PrintSampleConfig( @@ -339,7 +307,7 @@ func main() { } return case *fVersion: - fmt.Printf("Telegraf %s (git: %s %s)\n", displayVersion(), branch, commit) + fmt.Println(formatFullVersion()) return case *fSampleConfig: config.PrintSampleConfig( @@ -358,13 +326,13 @@ func main() { return } - if runtime.GOOS == "windows" { + if runtime.GOOS == "windows" && !(*fRunAsConsole) { svcConfig := &service.Config{ - Name: "telegraf", + Name: *fServiceName, DisplayName: "Telegraf Data Collector Service", Description: "Collects data using a series of plugins and publishes it to" + "another series of plugins.", - Arguments: []string{"-config", "C:\\Program Files\\Telegraf\\telegraf.conf"}, + Arguments: []string{"--config", "C:\\Program Files\\Telegraf\\telegraf.conf"}, } prg := &program{ @@ -377,14 +345,14 @@ func main() { if err != nil { log.Fatal("E! " + err.Error()) } - // Handle the -service flag here to prevent any issues with tooling that + // Handle the --service flag here to prevent any issues with tooling that // may not have an interactive session, e.g. installing from Ansible. if *fService != "" { if *fConfig != "" { - (*svcConfig).Arguments = []string{"-config", *fConfig} + (*svcConfig).Arguments = []string{"--config", *fConfig} } if *fConfigDirectory != "" { - (*svcConfig).Arguments = append((*svcConfig).Arguments, "-config-directory", *fConfigDirectory) + (*svcConfig).Arguments = append((*svcConfig).Arguments, "--config-directory", *fConfigDirectory) } err := service.Control(s, *fService) if err != nil { diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..5ac47089 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,100 @@ +version: '3' + +services: + aerospike: + image: aerospike/aerospike-server:3.9.0 + ports: + - "3000:3000" + zookeeper: + image: wurstmeister/zookeeper + environment: + - JAVA_OPTS="-Xms256m -Xmx256m" + ports: + - "2181:2181" + kafka: + image: wurstmeister/kafka + environment: + - KAFKA_ADVERTISED_HOST_NAME=localhost + - KAFKA_ADVERTISED_PORT=9092 + - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 + - KAFKA_CREATE_TOPICS="test:1:1" + - JAVA_OPTS="-Xms256m -Xmx256m" + ports: + - "9092:9092" + depends_on: + - zookeeper + elasticsearch: + image: elasticsearch:5 + environment: + - JAVA_OPTS="-Xms256m -Xmx256m" + ports: + - "9200:9200" + - "9300:9300" + mysql: + image: mysql + environment: + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + ports: + - "3306:3306" + memcached: + image: memcached + ports: + - "11211:11211" + pgbouncer: + image: mbed/pgbouncer + environment: + PG_ENV_POSTGRESQL_USER: pgbouncer + PG_ENV_POSTGRESQL_PASS: pgbouncer + ports: + - "6432:6432" + postgres: + image: postgres:alpine + ports: + - "5432:5432" + rabbitmq: + image: rabbitmq:3-management + ports: + - "15672:15672" + - "5672:5672" + redis: + image: redis:alpine + ports: + - "6379:6379" + nsq: + image: nsqio/nsq + ports: + - "4150:4150" + command: "/nsqd" + mqtt: + image: ncarlier/mqtt + ports: + - "1883:1883" + riemann: + image: stealthly/docker-riemann + ports: + - "5555:5555" + nats: + image: nats + ports: + - "4222:4222" + openldap: + image: cobaugh/openldap-alpine + environment: + - SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" + - SLAPD_CONFIG_ROOTPW="secret" + ports: + - "389:389" + - "636:636" + crate: + image: crate/crate + ports: + - "4200:4200" + - "4230:4230" + - "5432:5432" + command: + - crate + - -Cnetwork.host=0.0.0.0 + - -Ctransport.host=localhost + - -Clicense.enterprise=false + environment: + - CRATE_HEAP_SIZE=128m diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index bf8b4ebf..0698721e 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -1,11 +1,14 @@ -# Telegraf Configuration +# Configuration -You can see the latest config file with all available plugins here: -[telegraf.conf](https://github.com/influxdata/telegraf/blob/master/etc/telegraf.conf) +Telegraf's configuration file is written using +[TOML](https://github.com/toml-lang/toml#toml). + +[View the telegraf.conf config file with all available +plugins](/etc/telegraf.conf). ## Generating a Configuration File -A default Telegraf config file can be auto-generated by telegraf: +A default config file can be generated by telegraf: ``` telegraf config > telegraf.conf @@ -18,7 +21,7 @@ To generate a file with specific inputs and outputs, you can use the telegraf --input-filter cpu:mem:net:swap --output-filter influxdb:kafka config ``` -## Environment Variables +### Environment Variables Environment variables can be used anywhere in the config file, simply prepend them with $. For strings the variable must be within quotes (ie, "$STR_VAR"), @@ -27,7 +30,7 @@ for numbers and booleans they should be plain (ie, $INT_VAR, $BOOL_VAR) When using the `.deb` or `.rpm` packages, you can define environment variables in the `/etc/default/telegraf` file. -## Configuration file locations +### Configuration file locations The location of the configuration file can be set via the `--config` command line flag. @@ -40,13 +43,13 @@ On most systems, the default locations are `/etc/telegraf/telegraf.conf` for the main configuration file and `/etc/telegraf/telegraf.d` for the directory of configuration files. -# Global Tags +### Global Tags Global tags can be specified in the `[global_tags]` section of the config file in key="value" format. All metrics being gathered on this host will be tagged with the tags specified here. -## Agent Configuration +### Agent Configuration Telegraf has a few options you can configure under the `[agent]` section of the config. @@ -85,7 +88,7 @@ ie, a jitter of 5s and flush_interval 10s means flushes will happen every 10-15s * **hostname**: Override default hostname, if empty use os.Hostname(). * **omit_hostname**: If true, do no set the "host" tag in the telegraf agent. -## Input Configuration +### Input Configuration The following config parameters are available for all inputs: @@ -98,15 +101,15 @@ you can configure that here. * **name_suffix**: Specifies a suffix to attach to the measurement name. * **tags**: A map of tags to apply to a specific input's measurements. -The [measurement filtering](#measurement-filtering) parameters can be used to -limit what metrics are emitted from the input plugin. +The [metric filtering](#metric-filtering) parameters can be used to limit what metrics are +emitted from the input plugin. -## Output Configuration +### Output Configuration -The [measurement filtering](#measurement-filtering) parameters can be used to -limit what metrics are emitted from the output plugin. +The [metric filtering](#metric-filtering) parameters can be used to limit what metrics are +emitted from the output plugin. -## Aggregator Configuration +### Aggregator Configuration The following config parameters are available for all aggregators: @@ -125,63 +128,77 @@ aggregator and will not get sent to the output plugins. * **name_suffix**: Specifies a suffix to attach to the measurement name. * **tags**: A map of tags to apply to a specific input's measurements. -The [measurement filtering](#measurement-filtering) parameters be used to -limit what metrics are handled by the aggregator. Excluded metrics are passed -downstream to the next aggregator. +The [metric filtering](#metric-filtering) parameters can be used to limit what metrics are +handled by the aggregator. Excluded metrics are passed downstream to the next +aggregator. -## Processor Configuration +### Processor Configuration The following config parameters are available for all processors: * **order**: This is the order in which the processor(s) get executed. If this is not specified then processor execution order will be random. -The [measurement filtering](#measurement-filtering) can parameters may be used -to limit what metrics are handled by the processor. Excluded metrics are -passed downstream to the next processor. +The [metric filtering](#metric-filtering) parameters can be used to limit what metrics are +handled by the processor. Excluded metrics are passed downstream to the next +processor. -#### Measurement Filtering + +### Metric Filtering -Filters can be configured per input, output, processor, or aggregator, -see below for examples. +Metric filtering can be configured per plugin on any input, output, processor, +and aggregator plugin. Filters fall under two categories: Selectors and +Modifiers. -* **namepass**: -An array of glob pattern strings. Only points whose measurement name matches +#### Selectors + +Selector filters include or exclude entire metrics. When a metric is excluded +from a Input or an Output plugin, the metric is dropped. If a metric is +excluded from a Processor or Aggregator plugin, it is skips the plugin and is +sent onwards to the next stage of processing. + +- **namepass**: +An array of glob pattern strings. Only metrics whose measurement name matches a pattern in this list are emitted. -* **namedrop**: -The inverse of `namepass`. If a match is found the point is discarded. This -is tested on points after they have passed the `namepass` test. -* **fieldpass**: -An array of glob pattern strings. Only fields whose field key matches a -pattern in this list are emitted. Not available for outputs. -* **fielddrop**: -The inverse of `fieldpass`. Fields with a field key matching one of the -patterns will be discarded from the point. This is tested on points after -they have passed the `fieldpass` test. Not available for outputs. -* **tagpass**: -A table mapping tag keys to arrays of glob pattern strings. Only points + +- **namedrop**: +The inverse of `namepass`. If a match is found the metric is discarded. This +is tested on metrics after they have passed the `namepass` test. + +- **tagpass**: +A table mapping tag keys to arrays of glob pattern strings. Only metrics that contain a tag key in the table and a tag value matching one of its patterns is emitted. -* **tagdrop**: -The inverse of `tagpass`. If a match is found the point is discarded. This -is tested on points after they have passed the `tagpass` test. -* **taginclude**: + +- **tagdrop**: +The inverse of `tagpass`. If a match is found the metric is discarded. This +is tested on metrics after they have passed the `tagpass` test. + +#### Modifiers + +Modifier filters remove tags and fields from a metric. If all fields are +removed the metric is removed. + +- **fieldpass**: +An array of glob pattern strings. Only fields whose field key matches a +pattern in this list are emitted. + +- **fielddrop**: +The inverse of `fieldpass`. Fields with a field key matching one of the +patterns will be discarded from the metric. This is tested on metrics after +they have passed the `fieldpass` test. + +- **taginclude**: An array of glob pattern strings. Only tags with a tag key matching one of the patterns are emitted. In contrast to `tagpass`, which will pass an entire -point based on its tag, `taginclude` removes all non matching tags from the -point. This filter can be used on both inputs & outputs, but it is -_recommended_ to be used on inputs, as it is more efficient to filter out tags -at the ingestion point. -* **tagexclude**: +metric based on its tag, `taginclude` removes all non matching tags from the +metric. + +- **tagexclude**: The inverse of `taginclude`. Tags with a tag key matching one of the patterns -will be discarded from the point. +will be discarded from the metric. -**NOTE** Due to the way TOML is parsed, `tagpass` and `tagdrop` parameters -must be defined at the _end_ of the plugin definition, otherwise subsequent -plugin config options will be interpreted as part of the tagpass/tagdrop -tables. - -#### Input Configuration Examples +### Input Configuration Examples This is a full working config that will output CPU data to an InfluxDB instance at 192.168.59.103:8086, tagging measurements with dc="denver-1". It will output diff --git a/docs/DATA_FORMATS_INPUT.md b/docs/DATA_FORMATS_INPUT.md index 1b6c0b68..b7165016 100644 --- a/docs/DATA_FORMATS_INPUT.md +++ b/docs/DATA_FORMATS_INPUT.md @@ -1,36 +1,24 @@ -# Telegraf Input Data Formats +# Input Data Formats -Telegraf is able to parse the following input data formats into metrics: +Telegraf contains many general purpose plugins that support parsing input data +using a configurable parser into [metrics][]. This allows, for example, the +`kafka_consumer` input plugin to process messages in either InfluxDB Line +Protocol or in JSON format. -1. [InfluxDB Line Protocol](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#influx) -1. [JSON](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#json) -1. [Graphite](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#graphite) -1. [Value](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#value), ie: 45 or "booyah" -1. [Nagios](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#nagios) (exec input only) -1. [Collectd](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#collectd) +- [InfluxDB Line Protocol](/plugins/parsers/influx) +- [Collectd](/plugins/parsers/collectd) +- [CSV](/plugins/parsers/csv) +- [Dropwizard](/plugins/parsers/dropwizard) +- [Graphite](/plugins/parsers/graphite) +- [Grok](/plugins/parsers/grok) +- [JSON](/plugins/parsers/json) +- [Logfmt](/plugins/parsers/logfmt) +- [Nagios](/plugins/parsers/nagios) +- [Value](/plugins/parsers/value), ie: 45 or "booyah" +- [Wavefront](/plugins/parsers/wavefront) -Telegraf metrics, like InfluxDB -[points](https://docs.influxdata.com/influxdb/v0.10/write_protocols/line/), -are a combination of four basic parts: - -1. Measurement Name -1. Tags -1. Fields -1. Timestamp - -These four parts are easily defined when using InfluxDB line-protocol as a -data format. But there are other data formats that users may want to use which -require more advanced configuration to create usable Telegraf metrics. - -Plugins such as `exec` and `kafka_consumer` parse textual data. Up until now, -these plugins were statically configured to parse just a single -data format. `exec` mostly only supported parsing JSON, and `kafka_consumer` only -supported data in InfluxDB line-protocol. - -But now we are normalizing the parsing of various data formats across all -plugins that can support it. You will be able to identify a plugin that supports -different data formats by the presence of a `data_format` config option, for -example, in the exec plugin: +Any input plugin containing the `data_format` option can use it to select the +desired parser: ```toml [[inputs.exec]] @@ -45,437 +33,6 @@ example, in the exec plugin: ## more about them here: ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md data_format = "json" - - ## Additional configuration options go here ``` -Each data_format has an additional set of configuration options available, which -I'll go over below. - -# Influx: - -There are no additional configuration options for InfluxDB line-protocol. The -metrics are parsed directly into Telegraf metrics. - -#### Influx Configuration: - -```toml -[[inputs.exec]] - ## Commands array - commands = ["/tmp/test.sh", "/usr/bin/mycollector --foo=bar"] - - ## measurement name suffix (for separating different commands) - name_suffix = "_mycollector" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "influx" -``` - -# JSON: - -The JSON data format flattens JSON into metric _fields_. -NOTE: Only numerical values are converted to fields, and they are converted -into a float. strings are ignored unless specified as a tag_key (see below). - -So for example, this JSON: - -```json -{ - "a": 5, - "b": { - "c": 6 - }, - "ignored": "I'm a string" -} -``` - -Would get translated into _fields_ of a measurement: - -``` -myjsonmetric a=5,b_c=6 -``` - -The _measurement_ _name_ is usually the name of the plugin, -but can be overridden using the `name_override` config option. - -#### JSON Configuration: - -The JSON data format supports specifying "tag keys". If specified, keys -will be searched for in the root-level of the JSON blob. If the key(s) exist, -they will be applied as tags to the Telegraf metrics. - -For example, if you had this configuration: - -```toml -[[inputs.exec]] - ## Commands array - commands = ["/tmp/test.sh", "/usr/bin/mycollector --foo=bar"] - - ## measurement name suffix (for separating different commands) - name_suffix = "_mycollector" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "json" - - ## List of tag names to extract from top-level of JSON server response - tag_keys = [ - "my_tag_1", - "my_tag_2" - ] -``` - -with this JSON output from a command: - -```json -{ - "a": 5, - "b": { - "c": 6 - }, - "my_tag_1": "foo" -} -``` - -Your Telegraf metrics would get tagged with "my_tag_1" - -``` -exec_mycollector,my_tag_1=foo a=5,b_c=6 -``` - -If the JSON data is an array, then each element of the array is parsed with the configured settings. -Each resulting metric will be output with the same timestamp. - -For example, if the following configuration: - -```toml -[[inputs.exec]] - ## Commands array - commands = ["/usr/bin/mycollector --foo=bar"] - - ## measurement name suffix (for separating different commands) - name_suffix = "_mycollector" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "json" - - ## List of tag names to extract from top-level of JSON server response - tag_keys = [ - "my_tag_1", - "my_tag_2" - ] -``` - -with this JSON output from a command: - -```json -[ - { - "a": 5, - "b": { - "c": 6 - }, - "my_tag_1": "foo", - "my_tag_2": "baz" - }, - { - "a": 7, - "b": { - "c": 8 - }, - "my_tag_1": "bar", - "my_tag_2": "baz" - } -] -``` - -Your Telegraf metrics would get tagged with "my_tag_1" and "my_tag_2" - -``` -exec_mycollector,my_tag_1=foo,my_tag_2=baz a=5,b_c=6 -exec_mycollector,my_tag_1=bar,my_tag_2=baz a=7,b_c=8 -``` - -# Value: - -The "value" data format translates single values into Telegraf metrics. This -is done by assigning a measurement name and setting a single field ("value") -as the parsed metric. - -#### Value Configuration: - -You **must** tell Telegraf what type of metric to collect by using the -`data_type` configuration option. Available options are: - -1. integer -2. float or long -3. string -4. boolean - -**Note:** It is also recommended that you set `name_override` to a measurement -name that makes sense for your metric, otherwise it will just be set to the -name of the plugin. - -```toml -[[inputs.exec]] - ## Commands array - commands = ["cat /proc/sys/kernel/random/entropy_avail"] - - ## override the default metric name of "exec" - name_override = "entropy_available" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "value" - data_type = "integer" # required -``` - -# Graphite: - -The Graphite data format translates graphite _dot_ buckets directly into -telegraf measurement names, with a single value field, and without any tags. -By default, the separator is left as ".", but this can be changed using the -"separator" argument. For more advanced options, -Telegraf supports specifying "templates" to translate -graphite buckets into Telegraf metrics. - -Templates are of the form: - -``` -"host.mytag.mytag.measurement.measurement.field*" -``` - -Where the following keywords exist: - -1. `measurement`: specifies that this section of the graphite bucket corresponds -to the measurement name. This can be specified multiple times. -2. `field`: specifies that this section of the graphite bucket corresponds -to the field name. This can be specified multiple times. -3. `measurement*`: specifies that all remaining elements of the graphite bucket -correspond to the measurement name. -4. `field*`: specifies that all remaining elements of the graphite bucket -correspond to the field name. - -Any part of the template that is not a keyword is treated as a tag key. This -can also be specified multiple times. - -NOTE: `field*` cannot be used in conjunction with `measurement*`! - -#### Measurement & Tag Templates: - -The most basic template is to specify a single transformation to apply to all -incoming metrics. So the following template: - -```toml -templates = [ - "region.region.measurement*" -] -``` - -would result in the following Graphite -> Telegraf transformation. - -``` -us.west.cpu.load 100 -=> cpu.load,region=us.west value=100 -``` - -Multiple templates can also be specified, but these should be differentiated -using _filters_ (see below for more details) - -```toml -templates = [ - "*.*.* region.region.measurement", # <- all 3-part measurements will match this one. - "*.*.*.* region.region.host.measurement", # <- all 4-part measurements will match this one. -] -``` - -#### Field Templates: - -The field keyword tells Telegraf to give the metric that field name. -So the following template: - -```toml -separator = "_" -templates = [ - "measurement.measurement.field.field.region" -] -``` - -would result in the following Graphite -> Telegraf transformation. - -``` -cpu.usage.idle.percent.eu-east 100 -=> cpu_usage,region=eu-east idle_percent=100 -``` - -The field key can also be derived from all remaining elements of the graphite -bucket by specifying `field*`: - -```toml -separator = "_" -templates = [ - "measurement.measurement.region.field*" -] -``` - -which would result in the following Graphite -> Telegraf transformation. - -``` -cpu.usage.eu-east.idle.percentage 100 -=> cpu_usage,region=eu-east idle_percentage=100 -``` - -#### Filter Templates: - -Users can also filter the template(s) to use based on the name of the bucket, -using glob matching, like so: - -```toml -templates = [ - "cpu.* measurement.measurement.region", - "mem.* measurement.measurement.host" -] -``` - -which would result in the following transformation: - -``` -cpu.load.eu-east 100 -=> cpu_load,region=eu-east value=100 - -mem.cached.localhost 256 -=> mem_cached,host=localhost value=256 -``` - -#### Adding Tags: - -Additional tags can be added to a metric that don't exist on the received metric. -You can add additional tags by specifying them after the pattern. -Tags have the same format as the line protocol. -Multiple tags are separated by commas. - -```toml -templates = [ - "measurement.measurement.field.region datacenter=1a" -] -``` - -would result in the following Graphite -> Telegraf transformation. - -``` -cpu.usage.idle.eu-east 100 -=> cpu_usage,region=eu-east,datacenter=1a idle=100 -``` - -There are many more options available, -[More details can be found here](https://github.com/influxdata/influxdb/tree/master/services/graphite#templates) - -#### Graphite Configuration: - -```toml -[[inputs.exec]] - ## Commands array - commands = ["/tmp/test.sh", "/usr/bin/mycollector --foo=bar"] - - ## measurement name suffix (for separating different commands) - name_suffix = "_mycollector" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "graphite" - - ## This string will be used to join the matched values. - separator = "_" - - ## Each template line requires a template pattern. It can have an optional - ## filter before the template and separated by spaces. It can also have optional extra - ## tags following the template. Multiple tags should be separated by commas and no spaces - ## similar to the line protocol format. There can be only one default template. - ## Templates support below format: - ## 1. filter + template - ## 2. filter + template + extra tag(s) - ## 3. filter + template with field key - ## 4. default template - templates = [ - "*.app env.service.resource.measurement", - "stats.* .host.measurement* region=eu-east,agent=sensu", - "stats2.* .host.measurement.field", - "measurement*" - ] -``` - -# Nagios: - -There are no additional configuration options for Nagios line-protocol. The -metrics are parsed directly into Telegraf metrics. - -Note: Nagios Input Data Formats is only supported in `exec` input plugin. - -#### Nagios Configuration: - -```toml -[[inputs.exec]] - ## Commands array - commands = ["/usr/lib/nagios/plugins/check_load -w 5,6,7 -c 7,8,9"] - - ## measurement name suffix (for separating different commands) - name_suffix = "_mycollector" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "nagios" -``` - -# Collectd: - -The collectd format parses the collectd binary network protocol. Tags are -created for host, instance, type, and type instance. All collectd values are -added as float64 fields. - -For more information about the binary network protocol see -[here](https://collectd.org/wiki/index.php/Binary_protocol). - -You can control the cryptographic settings with parser options. Create an -authentication file and set `collectd_auth_file` to the path of the file, then -set the desired security level in `collectd_security_level`. - -Additional information including client setup can be found -[here](https://collectd.org/wiki/index.php/Networking_introduction#Cryptographic_setup). - -You can also change the path to the typesdb or add additional typesdb using -`collectd_typesdb`. - -#### Collectd Configuration: - -```toml -[[inputs.socket_listener]] - service_address = "udp://127.0.0.1:25826" - name_prefix = "collectd_" - - ## Data format to consume. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "collectd" - - ## Authentication file for cryptographic security levels - collectd_auth_file = "/etc/collectd/auth_file" - ## One of none (default), sign, or encrypt - collectd_security_level = "encrypt" - ## Path of to TypesDB specifications - collectd_typesdb = ["/usr/share/collectd/types.db"] -``` +[metrics]: /docs/METRICS.md diff --git a/docs/DATA_FORMATS_OUTPUT.md b/docs/DATA_FORMATS_OUTPUT.md index 13678038..c06ab471 100644 --- a/docs/DATA_FORMATS_OUTPUT.md +++ b/docs/DATA_FORMATS_OUTPUT.md @@ -1,34 +1,16 @@ -# Telegraf Output Data Formats +# Output Data Formats -Telegraf is able to serialize metrics into the following output data formats: +In addition to output specific data formats, Telegraf supports a set of +standard data formats that may be selected from when configuring many output +plugins. -1. [InfluxDB Line Protocol](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md#influx) -1. [JSON](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md#json) -1. [Graphite](https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md#graphite) +1. [InfluxDB Line Protocol](/plugins/serializers/influx) +1. [JSON](/plugins/serializers/json) +1. [Graphite](/plugins/serializers/graphite) +1. [SplunkMetric](/plugins/serializers/splunkmetric) -Telegraf metrics, like InfluxDB -[points](https://docs.influxdata.com/influxdb/v0.10/write_protocols/line/), -are a combination of four basic parts: - -1. Measurement Name -1. Tags -1. Fields -1. Timestamp - -In InfluxDB line protocol, these 4 parts are easily defined in textual form: - -``` -measurement_name[,tag1=val1,...] field1=val1[,field2=val2,...] [timestamp] -``` - -For Telegraf outputs that write textual data (such as `kafka`, `mqtt`, and `file`), -InfluxDB line protocol was originally the only available output format. But now -we are normalizing telegraf metric "serializers" into a -[plugin-like interface](https://github.com/influxdata/telegraf/tree/master/plugins/serializers) -across all output plugins that can support it. -You will be able to identify a plugin that supports different data formats -by the presence of a `data_format` -config option, for example, in the `file` output plugin: +You will be able to identify the plugins with support by the presence of a +`data_format` config option, for example, in the `file` output plugin: ```toml [[outputs.file]] @@ -40,124 +22,4 @@ config option, for example, in the `file` output plugin: ## more about them here: ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md data_format = "influx" - - ## Additional configuration options go here ``` - -Each data_format has an additional set of configuration options available, which -I'll go over below. - -# Influx: - -There are no additional configuration options for InfluxDB line-protocol. The -metrics are serialized directly into InfluxDB line-protocol. - -### Influx Configuration: - -```toml -[[outputs.file]] - ## Files to write to, "stdout" is a specially handled file. - files = ["stdout", "/tmp/metrics.out"] - - ## Data format to output. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md - data_format = "influx" -``` - -# Graphite: - -The Graphite data format translates Telegraf metrics into _dot_ buckets. A -template can be specified for the output of Telegraf metrics into Graphite -buckets. The default template is: - -``` -template = "host.tags.measurement.field" -``` - -In the above template, we have four parts: - -1. _host_ is a tag key. This can be any tag key that is in the Telegraf -metric(s). If the key doesn't exist, it will be ignored. If it does exist, the -tag value will be filled in. -1. _tags_ is a special keyword that outputs all remaining tag values, separated -by dots and in alphabetical order (by tag key). These will be filled after all -tag keys are filled. -1. _measurement_ is a special keyword that outputs the measurement name. -1. _field_ is a special keyword that outputs the field name. - -Which means the following influx metric -> graphite conversion would happen: - -``` -cpu,cpu=cpu-total,dc=us-east-1,host=tars usage_idle=98.09,usage_user=0.89 1455320660004257758 -=> -tars.cpu-total.us-east-1.cpu.usage_user 0.89 1455320690 -tars.cpu-total.us-east-1.cpu.usage_idle 98.09 1455320690 -``` - -Fields with string values will be skipped. Boolean fields will be converted -to 1 (true) or 0 (false). - -### Graphite Configuration: - -```toml -[[outputs.file]] - ## Files to write to, "stdout" is a specially handled file. - files = ["stdout", "/tmp/metrics.out"] - - ## Data format to output. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md - data_format = "graphite" - - # prefix each graphite bucket - prefix = "telegraf" - # graphite template - template = "host.tags.measurement.field" -``` - -# JSON: - -The JSON data format serialized Telegraf metrics in json format. The format is: - -```json -{ - "fields":{ - "field_1":30, - "field_2":4, - "field_N":59, - "n_images":660 - }, - "name":"docker", - "tags":{ - "host":"raynor" - }, - "timestamp":1458229140 -} -``` - -### JSON Configuration: - -```toml -[[outputs.file]] - ## Files to write to, "stdout" is a specially handled file. - files = ["stdout", "/tmp/metrics.out"] - - ## Data format to output. - ## Each data format has its own unique set of configuration options, read - ## more about them here: - ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md - data_format = "json" - json_timestamp_units = "1ns" -``` - -By default, the timestamp that is output in JSON data format serialized Telegraf -metrics is in seconds. The precision of this timestamp can be adjusted for any output -by adding the optional `json_timestamp_units` parameter to the configuration for -that output. This parameter can be used to set the timestamp units to nanoseconds (`ns`), -microseconds (`us` or `µs`), milliseconds (`ms`), or seconds (`s`). Note that this -parameter will be truncated to the nearest power of 10 that, so if the `json_timestamp_units` -are set to `15ms` the timestamps for the JSON format serialized Telegraf metrics will be -output in hundredths of a second (`10ms`). diff --git a/docs/FAQ.md b/docs/FAQ.md index 58396cbc..1d1c490a 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -1,5 +1,24 @@ # Frequently Asked Questions +### Q: How can I monitor the Docker Engine Host from within a container? + +You will need to setup several volume mounts as well as some environment +variables: +``` +docker run --name telegraf + -v /:/hostfs:ro + -v /etc:/hostfs/etc:ro + -v /proc:/hostfs/proc:ro + -v /sys:/hostfs/sys:ro + -v /var/run/utmp:/var/run/utmp:ro + -e HOST_ETC=/hostfs/etc + -e HOST_PROC=/hostfs/proc + -e HOST_SYS=/hostfs/sys + -e HOST_MOUNT_PREFIX=/hostfs + telegraf +``` + + ### Q: Why do I get a "no such host" error resolving hostnames that other programs can resolve? diff --git a/docs/LICENSE_OF_DEPENDENCIES.md b/docs/LICENSE_OF_DEPENDENCIES.md index ffd9751d..2333650f 100644 --- a/docs/LICENSE_OF_DEPENDENCIES.md +++ b/docs/LICENSE_OF_DEPENDENCIES.md @@ -3,10 +3,12 @@ When distributed in a binary form, Telegraf may contain portions of the following works: +- code.cloudfoundry.org/clock [APACHE](https://github.com/cloudfoundry/clock/blob/master/LICENSE) - collectd.org [MIT](https://github.com/collectd/go-collectd/blob/master/LICENSE) - github.com/aerospike/aerospike-client-go [APACHE](https://github.com/aerospike/aerospike-client-go/blob/master/LICENSE) - github.com/amir/raidman [PUBLIC DOMAIN](https://github.com/amir/raidman/blob/master/UNLICENSE) - github.com/armon/go-metrics [MIT](https://github.com/armon/go-metrics/blob/master/LICENSE) +- github.com/Azure/go-autorest [APACHE](https://github.com/Azure/go-autorest/blob/master/LICENSE) - github.com/aws/aws-sdk-go [APACHE](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt) - github.com/beorn7/perks [MIT](https://github.com/beorn7/perks/blob/master/LICENSE) - github.com/boltdb/bolt [MIT](https://github.com/boltdb/bolt/blob/master/LICENSE) @@ -18,12 +20,14 @@ following works: - github.com/couchbase/goutils [MIT](https://github.com/couchbase/go-couchbase/blob/master/LICENSE) - github.com/dancannon/gorethink [APACHE](https://github.com/dancannon/gorethink/blob/master/LICENSE) - github.com/davecgh/go-spew [ISC](https://github.com/davecgh/go-spew/blob/master/LICENSE) +- github.com/dimchansky/utfbom [APACHE](https://github.com/dimchansky/utfbom/blob/master/LICENSE) - github.com/docker/docker [APACHE](https://github.com/docker/docker/blob/master/LICENSE) - github.com/docker/cli [APACHE](https://github.com/docker/cli/blob/master/LICENSE) - github.com/eapache/go-resiliency [MIT](https://github.com/eapache/go-resiliency/blob/master/LICENSE) - github.com/eapache/go-xerial-snappy [MIT](https://github.com/eapache/go-xerial-snappy/blob/master/LICENSE) - github.com/eapache/queue [MIT](https://github.com/eapache/queue/blob/master/LICENSE) - github.com/eclipse/paho.mqtt.golang [ECLIPSE](https://github.com/eclipse/paho.mqtt.golang/blob/master/LICENSE) +- github.com/fsnotify/fsnotify [BSD](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) - github.com/fsouza/go-dockerclient [BSD](https://github.com/fsouza/go-dockerclient/blob/master/LICENSE) - github.com/gobwas/glob [MIT](https://github.com/gobwas/glob/blob/master/LICENSE) - github.com/google/go-cmp [BSD](https://github.com/google/go-cmp/blob/master/LICENSE) @@ -33,7 +37,7 @@ following works: - github.com/go-logfmt/logfmt [MIT](https://github.com/go-logfmt/logfmt/blob/master/LICENSE) - github.com/gorilla/mux [BSD](https://github.com/gorilla/mux/blob/master/LICENSE) - github.com/go-ini/ini [APACHE](https://github.com/go-ini/ini/blob/master/LICENSE) -- github.com/go-ole/go-ole [MPL](http://mattn.mit-license.org/2013) +- github.com/go-ole/go-ole [MIT](https://github.com/go-ole/go-ole/blob/master/LICENSE) - github.com/go-sql-driver/mysql [MPL](https://github.com/go-sql-driver/mysql/blob/master/LICENSE) - github.com/hailocab/go-hostpool [MIT](https://github.com/hailocab/go-hostpool/blob/master/LICENSE) - github.com/hashicorp/consul [MPL](https://github.com/hashicorp/consul/blob/master/LICENSE) @@ -42,6 +46,7 @@ following works: - github.com/hashicorp/raft [MPL](https://github.com/hashicorp/raft/blob/master/LICENSE) - github.com/influxdata/tail [MIT](https://github.com/influxdata/tail/blob/master/LICENSE.txt) - github.com/influxdata/toml [MIT](https://github.com/influxdata/toml/blob/master/LICENSE) +- github.com/influxdata/go-syslog [MIT](https://github.com/influxdata/go-syslog/blob/develop/LICENSE) - github.com/influxdata/wlog [MIT](https://github.com/influxdata/wlog/blob/master/LICENSE) - github.com/jackc/pgx [MIT](https://github.com/jackc/pgx/blob/master/LICENSE) - github.com/jmespath/go-jmespath [APACHE](https://github.com/jmespath/go-jmespath/blob/master/LICENSE) @@ -50,10 +55,12 @@ following works: - github.com/kballard/go-shellquote [MIT](https://github.com/kballard/go-shellquote/blob/master/LICENSE) - github.com/lib/pq [MIT](https://github.com/lib/pq/blob/master/LICENSE.md) - github.com/matttproud/golang_protobuf_extensions [APACHE](https://github.com/matttproud/golang_protobuf_extensions/blob/master/LICENSE) +- github.com/Microsoft/ApplicationInsights-Go [APACHE](https://github.com/Microsoft/ApplicationInsights-Go/blob/master/LICENSE) - github.com/Microsoft/go-winio [MIT](https://github.com/Microsoft/go-winio/blob/master/LICENSE) - github.com/miekg/dns [BSD](https://github.com/miekg/dns/blob/master/LICENSE) - github.com/naoina/go-stringutil [MIT](https://github.com/naoina/go-stringutil/blob/master/LICENSE) - github.com/naoina/toml [MIT](https://github.com/naoina/toml/blob/master/LICENSE) +- github.com/nats-io/gnatsd [MIT](https://github.com/nats-io/gnatsd/blob/master/LICENSE) - github.com/nats-io/go-nats [MIT](https://github.com/nats-io/go-nats/blob/master/LICENSE) - github.com/nats-io/nats [MIT](https://github.com/nats-io/nats/blob/master/LICENSE) - github.com/nats-io/nuid [MIT](https://github.com/nats-io/nuid/blob/master/LICENSE) @@ -82,6 +89,8 @@ following works: - github.com/streadway/amqp [BSD](https://github.com/streadway/amqp/blob/master/LICENSE) - github.com/stretchr/objx [MIT](https://github.com/stretchr/objx/blob/master/LICENSE.md) - github.com/stretchr/testify [MIT](https://github.com/stretchr/testify/blob/master/LICENCE.txt) +- github.com/tidwall/gjson [MIT](https://github.com/tidwall/gjson/blob/master/LICENSE) +- github.com/tidwall/match [MIT](https://github.com/tidwall/match/blob/master/LICENSE) - github.com/mitchellh/mapstructure [MIT](https://github.com/mitchellh/mapstructure/blob/master/LICENSE) - github.com/multiplay/go-ts3 [BSD](https://github.com/multiplay/go-ts3/blob/master/LICENSE) - github.com/vjeantet/grok [APACHE](https://github.com/vjeantet/grok/blob/master/LICENSE) @@ -91,12 +100,14 @@ following works: - github.com/zensqlmonitor/go-mssqldb [BSD](https://github.com/zensqlmonitor/go-mssqldb/blob/master/LICENSE.txt) - golang.org/x/crypto [BSD](https://github.com/golang/crypto/blob/master/LICENSE) - golang.org/x/net [BSD](https://go.googlesource.com/net/+/master/LICENSE) +- golang.org/x/oauth2 [BSD](https://go.googlesource.com/oauth2/+/master/LICENSE) - golang.org/x/text [BSD](https://go.googlesource.com/text/+/master/LICENSE) - golang.org/x/sys [BSD](https://go.googlesource.com/sys/+/master/LICENSE) +- google.golang.org/grpc [APACHE](https://github.com/google/grpc-go/blob/master/LICENSE) +- google.golang.org/genproto [APACHE](https://github.com/google/go-genproto/blob/master/LICENSE) - gopkg.in/asn1-ber.v1 [MIT](https://github.com/go-asn1-ber/asn1-ber/blob/v1.2/LICENSE) - gopkg.in/dancannon/gorethink.v1 [APACHE](https://github.com/dancannon/gorethink/blob/v1.1.2/LICENSE) - gopkg.in/fatih/pool.v2 [MIT](https://github.com/fatih/pool/blob/v2.0.0/LICENSE) -- gopkg.in/fsnotify.v1 [BSD](https://github.com/fsnotify/fsnotify/blob/v1.4.2/LICENSE) - gopkg.in/ldap.v2 [MIT](https://github.com/go-ldap/ldap/blob/v2.5.0/LICENSE) - gopkg.in/mgo.v2 [BSD](https://github.com/go-mgo/mgo/blob/v2/LICENSE) - gopkg.in/olivere/elastic.v5 [MIT](https://github.com/olivere/elastic/blob/v5.0.38/LICENSE) diff --git a/docs/METRICS.md b/docs/METRICS.md new file mode 100644 index 00000000..1c238e30 --- /dev/null +++ b/docs/METRICS.md @@ -0,0 +1,22 @@ +# Metrics + +Telegraf metrics are the internal representation used to model data during +processing. Metrics are closely based on InfluxDB's data model and contain +four main components: + +- **Measurement Name**: Description and namespace for the metric. +- **Tags**: Key/Value string pairs and usually used to identify the + metric. +- **Fields**: Key/Value pairs that are typed and usually contain the + metric data. +- **Timestamp**: Date and time associated with the fields. + +This metric type exists only in memory and must be converted to a concrete +representation in order to be transmitted or viewed. To acheive this we +provide several [output data formats][] sometimes referred to as +*serializers*. Our default serializer converts to [InfluxDB Line +Protocol][line protocol] which provides a high performance and one-to-one +direct mapping from Telegraf metrics. + +[output data formats]: /docs/DATA_FORMATS_OUTPUT.md +[line protocol]: /plugins/serializers/influx diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..b7b55336 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,21 @@ +# Telegraf + +- Concepts + - [Metrics][metrics] + - [Input Data Formats][parsers] + - [Output Data Formats][serializers] + - [Aggregators & Processors][aggproc] +- Administration + - [Configuration][conf] + - [Profiling][profiling] + - [Windows Service][winsvc] + - [FAQ][faq] + +[conf]: /docs/CONFIGURATION.md +[metrics]: /docs/METRICS.md +[parsers]: /docs/DATA_FORMATS_INPUT.md +[serializers]: /docs/DATA_FORMATS_OUTPUT.md +[aggproc]: /docs/AGGREGATORS_AND_PROCESSORS.md +[profiling]: /docs/PROFILING.md +[winsvc]: /docs/WINDOWS_SERVICE.md +[faq]: /docs/FAQ.md diff --git a/docs/TEMPLATE_PATTERN.md b/docs/TEMPLATE_PATTERN.md new file mode 100644 index 00000000..4244369d --- /dev/null +++ b/docs/TEMPLATE_PATTERN.md @@ -0,0 +1,135 @@ +# Template Patterns + +Template patterns are a mini language that describes how a dot delimited +string should be mapped to and from [metrics][]. + +A template has the form: +``` +"host.mytag.mytag.measurement.measurement.field*" +``` + +Where the following keywords can be set: + +1. `measurement`: specifies that this section of the graphite bucket corresponds +to the measurement name. This can be specified multiple times. +2. `field`: specifies that this section of the graphite bucket corresponds +to the field name. This can be specified multiple times. +3. `measurement*`: specifies that all remaining elements of the graphite bucket +correspond to the measurement name. +4. `field*`: specifies that all remaining elements of the graphite bucket +correspond to the field name. + +Any part of the template that is not a keyword is treated as a tag key. This +can also be specified multiple times. + +**NOTE:** `field*` cannot be used in conjunction with `measurement*`. + +### Examples + +#### Measurement & Tag Templates + +The most basic template is to specify a single transformation to apply to all +incoming metrics. So the following template: + +```toml +templates = [ + "region.region.measurement*" +] +``` + +would result in the following Graphite -> Telegraf transformation. + +``` +us.west.cpu.load 100 +=> cpu.load,region=us.west value=100 +``` + +Multiple templates can also be specified, but these should be differentiated +using _filters_ (see below for more details) + +```toml +templates = [ + "*.*.* region.region.measurement", # <- all 3-part measurements will match this one. + "*.*.*.* region.region.host.measurement", # <- all 4-part measurements will match this one. +] +``` + +#### Field Templates + +The field keyword tells Telegraf to give the metric that field name. +So the following template: + +```toml +separator = "_" +templates = [ + "measurement.measurement.field.field.region" +] +``` + +would result in the following Graphite -> Telegraf transformation. + +``` +cpu.usage.idle.percent.eu-east 100 +=> cpu_usage,region=eu-east idle_percent=100 +``` + +The field key can also be derived from all remaining elements of the graphite +bucket by specifying `field*`: + +```toml +separator = "_" +templates = [ + "measurement.measurement.region.field*" +] +``` + +which would result in the following Graphite -> Telegraf transformation. + +``` +cpu.usage.eu-east.idle.percentage 100 +=> cpu_usage,region=eu-east idle_percentage=100 +``` + +#### Filter Templates + +Users can also filter the template(s) to use based on the name of the bucket, +using glob matching, like so: + +```toml +templates = [ + "cpu.* measurement.measurement.region", + "mem.* measurement.measurement.host" +] +``` + +which would result in the following transformation: + +``` +cpu.load.eu-east 100 +=> cpu_load,region=eu-east value=100 + +mem.cached.localhost 256 +=> mem_cached,host=localhost value=256 +``` + +#### Adding Tags + +Additional tags can be added to a metric that don't exist on the received metric. +You can add additional tags by specifying them after the pattern. +Tags have the same format as the line protocol. +Multiple tags are separated by commas. + +```toml +templates = [ + "measurement.measurement.field.region datacenter=1a" +] +``` + +would result in the following Graphite -> Telegraf transformation. + +``` +cpu.usage.idle.eu-east 100 +=> cpu_usage,region=eu-east,datacenter=1a idle=100 +``` + +[metrics]: /docs/METRICS.md diff --git a/docs/WINDOWS_SERVICE.md b/docs/WINDOWS_SERVICE.md index 2b4d4f0e..51ce6a7a 100644 --- a/docs/WINDOWS_SERVICE.md +++ b/docs/WINDOWS_SERVICE.md @@ -5,7 +5,7 @@ the general steps to set it up. 1. Obtain the telegraf windows distribution 2. Create the directory `C:\Program Files\Telegraf` (if you install in a different - location simply specify the `-config` parameter with the desired location) + location simply specify the `--config` parameter with the desired location) 3. Place the telegraf.exe and the telegraf.conf config file into `C:\Program Files\Telegraf` 4. To install the service into the Windows Service Manager, run the following in PowerShell as an administrator (If necessary, you can wrap any spaces in the file paths in double quotes ""): @@ -26,6 +26,15 @@ the general steps to set it up. > net start telegraf ``` +## Config Directory + +You can also specify a `--config-directory` for the service to use: +1. Create a directory for config snippets: `C:\Program Files\Telegraf\telegraf.d` +2. Include the `--config-directory` option when registering the service: + ``` + > C:\"Program Files"\Telegraf\telegraf.exe --service install --config C:\"Program Files"\Telegraf\telegraf.conf --config-directory C:\"Program Files"\Telegraf\telegraf.d + ``` + ## Other supported operations Telegraf can manage its own service through the --service flag: @@ -37,6 +46,15 @@ Telegraf can manage its own service through the --service flag: | `telegraf.exe --service start` | Start the telegraf service | | `telegraf.exe --service stop` | Stop the telegraf service | +## Install multiple services + +You can install multiple telegraf instances with --service-name flag: + +``` + > C:\"Program Files"\Telegraf\telegraf.exe --service install --service-name telegraf-1 + > C:\"Program Files"\Telegraf\telegraf.exe --service install --service-name telegraf-2 + > C:\"Program Files"\Telegraf\telegraf.exe --service uninstall --service-name telegraf-1 +``` Troubleshooting common error #1067 diff --git a/etc/telegraf.conf b/etc/telegraf.conf index 3ab0afd5..d81e1b99 100644 --- a/etc/telegraf.conf +++ b/etc/telegraf.conf @@ -47,8 +47,8 @@ ## same time, which can have a measurable effect on the system. collection_jitter = "0s" - ## Default flushing interval for all outputs. You shouldn't set this below - ## interval. Maximum flush_interval will be flush_interval + flush_jitter + ## Default flushing interval for all outputs. Maximum flush_interval will be + ## flush_interval + flush_jitter flush_interval = "10s" ## Jitter the flush interval by a random amount. This is primarily to avoid ## large write spikes for users running a large number of telegraf instances. @@ -82,48 +82,68 @@ # OUTPUT PLUGINS # ############################################################################### -# Configuration for influxdb server to send metrics to +# Configuration for sending metrics to InfluxDB [[outputs.influxdb]] ## The full HTTP or UDP URL for your InfluxDB instance. ## - ## Multiple urls can be specified as part of the same cluster, - ## this means that only ONE of the urls will be written to each interval. - # urls = ["udp://127.0.0.1:8089"] # UDP endpoint example - urls = ["http://127.0.0.1:8086"] # required - ## The target database for metrics (telegraf will create it if not exists). - database = "telegraf" # required + ## Multiple URLs can be specified for a single cluster, only ONE of the + ## urls will be written to each interval. + # urls = ["unix:///var/run/influxdb.sock"] + # urls = ["udp://127.0.0.1:8089"] + # urls = ["http://127.0.0.1:8086"] + + ## The target database for metrics; will be created as needed. + # database = "telegraf" + + ## If true, no CREATE DATABASE queries will be sent. Set to true when using + ## Telegraf with a user without permissions to create databases or when the + ## database already exists. + # skip_database_creation = false ## Name of existing retention policy to write to. Empty string writes to - ## the default retention policy. - retention_policy = "" - ## Write consistency (clusters only), can be: "any", "one", "quorum", "all" - write_consistency = "any" + ## the default retention policy. Only takes effect when using HTTP. + # retention_policy = "" - ## Write timeout (for the InfluxDB client), formatted as a string. - ## If not provided, will default to 5s. 0s means no timeout (not recommended). - timeout = "5s" + ## Write consistency (clusters only), can be: "any", "one", "quorum", "all". + ## Only takes effect when using HTTP. + # write_consistency = "any" + + ## Timeout for HTTP messages. + # timeout = "5s" + + ## HTTP Basic Auth # username = "telegraf" # password = "metricsmetricsmetricsmetrics" - ## Set the user agent for HTTP POSTs (can be useful for log differentiation) + + ## HTTP User-Agent # user_agent = "telegraf" - ## Set UDP payload size, defaults to InfluxDB UDP Client default (512 bytes) + + ## UDP payload size is the maximum packet size to send. # udp_payload = 512 - ## Optional SSL Config - # ssl_ca = "/etc/telegraf/ca.pem" - # ssl_cert = "/etc/telegraf/cert.pem" - # ssl_key = "/etc/telegraf/key.pem" - ## Use SSL but skip chain & host verification + ## Optional TLS Config for use on HTTP connections. + # tls_ca = "/etc/telegraf/ca.pem" + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Use TLS but skip chain & host verification # insecure_skip_verify = false - ## HTTP Proxy Config + ## HTTP Proxy override, if unset values the standard proxy environment + ## variables are consulted to determine which proxy, if any, should be used. # http_proxy = "http://corporate.proxy:3128" - ## Optional HTTP headers + ## Additional HTTP headers # http_headers = {"X-Special-Header" = "Special-Value"} - ## Compress each HTTP request payload using GZIP. - # content_encoding = "gzip" + ## HTTP Content-Encoding for write request body, can be set to "gzip" to + ## compress body or "identity" to apply no encoding. + # content_encoding = "identity" + + ## When true, Telegraf will output unsigned integers as unsigned values, + ## i.e.: "42u". You will need a version of InfluxDB supporting unsigned + ## integer values. Enabling this option will result in field type errors if + ## existing data has been written. + # influx_uint_support = false # # Configuration for Amon Server to send metrics to. @@ -138,41 +158,139 @@ # # timeout = "5s" -# # Configuration for the AMQP server to send metrics to +# # Publishes metrics to an AMQP broker # [[outputs.amqp]] -# ## AMQP url -# url = "amqp://localhost:5672/influxdb" -# ## AMQP exchange +# ## Broker to publish to. +# ## deprecated in 1.7; use the brokers option +# # url = "amqp://localhost:5672/influxdb" +# +# ## Brokers to publish to. If multiple brokers are specified a random broker +# ## will be selected anytime a connection is established. This can be +# ## helpful for load balancing when not using a dedicated load balancer. +# brokers = ["amqp://localhost:5672/influxdb"] +# +# ## Maximum messages to send over a connection. Once this is reached, the +# ## connection is closed and a new connection is made. This can be helpful for +# ## load balancing when not using a dedicated load balancer. +# # max_messages = 0 +# +# ## Exchange to declare and publish to. # exchange = "telegraf" +# +# ## Exchange type; common types are "direct", "fanout", "topic", "header", "x-consistent-hash". +# # exchange_type = "topic" +# +# ## If true, exchange will be passively declared. +# # exchange_declare_passive = false +# +# ## Exchange durability can be either "transient" or "durable". +# # exchange_durability = "durable" +# +# ## Additional exchange arguments. +# # exchange_arguments = { } +# # exchange_arguments = {"hash_propery" = "timestamp"} +# +# ## Authentication credentials for the PLAIN auth_method. +# # username = "" +# # password = "" +# # ## Auth method. PLAIN and EXTERNAL are supported # ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as # ## described here: https://www.rabbitmq.com/plugins.html # # auth_method = "PLAIN" -# ## Telegraf tag to use as a routing key -# ## ie, if this tag exists, its value will be used as the routing key -# routing_tag = "host" # -# ## InfluxDB retention policy -# # retention_policy = "default" -# ## InfluxDB database +# ## Metric tag to use as a routing key. +# ## ie, if this tag exists, its value will be used as the routing key +# # routing_tag = "host" +# +# ## Static routing key. Used when no routing_tag is set or as a fallback +# ## when the tag specified in routing tag is not found. +# # routing_key = "" +# # routing_key = "telegraf" +# +# ## Delivery Mode controls if a published message is persistent. +# ## One of "transient" or "persistent". +# # delivery_mode = "transient" +# +# ## InfluxDB database added as a message header. +# ## deprecated in 1.7; use the headers option # # database = "telegraf" # -# ## Write timeout, formatted as a string. If not provided, will default -# ## to 5s. 0s means no timeout (not recommended). +# ## InfluxDB retention policy added as a message header +# ## deprecated in 1.7; use the headers option +# # retention_policy = "default" +# +# ## Static headers added to each published message. +# # headers = { } +# # headers = {"database" = "telegraf", "retention_policy" = "default"} +# +# ## Connection timeout. If not provided, will default to 5s. 0s means no +# ## timeout (not recommended). # # timeout = "5s" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # +# ## If true use batch serialization format instead of line based delimiting. +# ## Only applies to data formats which are not line based such as JSON. +# ## Recommended to set to true. +# # use_batch_format = false +# # ## Data format to output. # ## Each data format has its own unique set of configuration options, read # ## more about them here: # ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md -# data_format = "influx" +# # data_format = "influx" + + +# # Send metrics to Azure Application Insights +# [[outputs.application_insights]] +# ## Instrumentation key of the Application Insights resource. +# instrumentation_key = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx" +# +# ## Timeout for closing (default: 5s). +# # timeout = "5s" +# +# ## Enable additional diagnostic logging. +# # enable_diagnostic_logging = false +# +# ## Context Tag Sources add Application Insights context tags to a tag value. +# ## +# ## For list of allowed context tag keys see: +# ## https://github.com/Microsoft/ApplicationInsights-Go/blob/master/appinsights/contracts/contexttagkeys.go +# # [outputs.application_insights.context_tag_sources] +# # "ai.cloud.role" = "kubernetes_container_name" +# # "ai.cloud.roleInstance" = "kubernetes_pod_name" + + +# # Send aggregate metrics to Azure Monitor +# [[outputs.azure_monitor]] +# ## Timeout for HTTP writes. +# # timeout = "20s" +# +# ## Set the namespace prefix, defaults to "Telegraf/". +# # namespace_prefix = "Telegraf/" +# +# ## Azure Monitor doesn't have a string value type, so convert string +# ## fields to dimensions (a.k.a. tags) if enabled. Azure Monitor allows +# ## a maximum of 10 dimensions so Telegraf will only send the first 10 +# ## alphanumeric dimensions. +# # strings_as_dimensions = false +# +# ## Both region and resource_id must be set or be available via the +# ## Instance Metadata service on Azure Virtual Machines. +# # +# ## Azure Region to publish metrics against. +# ## ex: region = "southcentralus" +# # region = "" +# # +# ## The Azure Resource ID against which metric will be logged, e.g. +# ## ex: resource_id = "/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/" +# # resource_id = "" # # Configuration for AWS CloudWatch output. @@ -195,8 +313,22 @@ # #profile = "" # #shared_credential_file = "" # +# ## Endpoint to make request against, the correct endpoint is automatically +# ## determined and this option should only be set if you wish to override the +# ## default. +# ## ex: endpoint_url = "http://localhost:8000" +# # endpoint_url = "" +# # ## Namespace for the CloudWatch MetricDatums # namespace = "InfluxData/Telegraf" +# +# ## If you have a large amount of metrics, you should consider to send statistic +# ## values instead of raw metrics which could not only improve performance but +# ## also save AWS API cost. If enable this flag, this plugin would parse the required +# ## CloudWatch statistic fields (count, min, max, and sum) and send them to CloudWatch. +# ## You could use basicstats aggregator to calculate those fields. If not all statistic +# ## fields are available, all fields would still be sent as raw metrics. +# # write_statistics = false # # Configuration for CrateDB to send metrics to. @@ -253,8 +385,21 @@ # # %m - month (01..12) # # %d - day of month (e.g., 01) # # %H - hour (00..23) +# # %V - week of the year (ISO week) (01..53) +# ## Additionally, you can specify a tag name using the notation {{tag_name}} +# ## which will be used as part of the index name. If the tag does not exist, +# ## the default tag value will be used. +# # index_name = "telegraf-{{host}}-%Y.%m.%d" +# # default_tag_value = "none" # index_name = "telegraf-%Y.%m.%d" # required. # +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false +# # ## Template Config # ## Set to true if you want telegraf to manage its index template. # ## If enabled it will create a recommended index template for telegraf indexes @@ -288,14 +433,18 @@ # ## Graphite output template # ## see https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md # template = "host.tags.measurement.field" +# +# ## Enable Graphite tags support +# # graphite_tag_support = false +# # ## timeout in seconds for the write connection to graphite # timeout = 2 # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -305,6 +454,91 @@ # servers = ["127.0.0.1:12201", "192.168.1.1:12201"] +# # A plugin that can transmit metrics over HTTP +# [[outputs.http]] +# ## URL is the address to send metrics to +# url = "http://127.0.0.1:8080/metric" +# +# ## Timeout for HTTP message +# # timeout = "5s" +# +# ## HTTP method, one of: "POST" or "PUT" +# # method = "POST" +# +# ## HTTP Basic Auth credentials +# # username = "username" +# # password = "pa$$word" +# +# ## OAuth2 Client Credentials Grant +# # client_id = "clientid" +# # client_secret = "secret" +# # token_url = "https://indentityprovider/oauth2/v1/token" +# # scopes = ["urn:opc:idm:__myscopes__"] +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false +# +# ## Data format to output. +# ## Each data format has it's own unique set of configuration options, read +# ## more about them here: +# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md +# # data_format = "influx" +# +# ## Additional HTTP headers +# # [outputs.http.headers] +# # # Should be set manually to "application/json" for json data_format +# # Content-Type = "text/plain; charset=utf-8" + + +# # Configuration for sending metrics to InfluxDB +# [[outputs.influxdb_v2]] +# ## The URLs of the InfluxDB cluster nodes. +# ## +# ## Multiple URLs can be specified for a single cluster, only ONE of the +# ## urls will be written to each interval. +# urls = ["http://127.0.0.1:9999"] +# +# ## Token for authentication. +# token = "" +# +# ## Organization is the name of the organization you wish to write to; must exist. +# organization = "" +# +# ## Bucket to the name fo the bucketwrite into; must exist. +# bucket = "" +# +# ## Timeout for HTTP messages. +# # timeout = "5s" +# +# ## Additional HTTP headers +# # http_headers = {"X-Special-Header" = "Special-Value"} +# +# ## HTTP Proxy override, if unset values the standard proxy environment +# ## variables are consulted to determine which proxy, if any, should be used. +# # http_proxy = "http://corporate.proxy:3128" +# +# ## HTTP User-Agent +# # user_agent = "telegraf" +# +# ## Content-Encoding for write request body, can be set to "gzip" to +# ## compress body or "identity" to apply no encoding. +# # content_encoding = "gzip" +# +# ## Enable or disable uint support for writing uints influxdb 2.0. +# # influx_uint_support = false +# +# ## Optional TLS Config for use on HTTP connections. +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false + + # # Configuration for sending metrics to an Instrumental project # [[outputs.instrumental]] # ## Project API Token (required) @@ -327,6 +561,15 @@ # ## Kafka topic for producer messages # topic = "telegraf" # +# ## Optional Client id +# # client_id = "Telegraf" +# +# ## Set the minimal supported Kafka version. Setting this enables the use of new +# ## Kafka features and APIs. Of particular interest, lz4 compression +# ## requires at least version 0.10.0.0. +# ## ex: version = "1.1.0" +# # version = "" +# # ## Optional topic suffix configuration. # ## If the section is omitted, no suffix is used. # ## Following topic suffix methods are supported: @@ -358,12 +601,20 @@ # ## ie, if this tag exists, its value will be used as the routing key # routing_tag = "host" # +# ## Static routing key. Used when no routing_tag is set or as a fallback +# ## when the tag specified in routing tag is not found. If set to "random", +# ## a random value will be generated for each message. +# ## ex: routing_key = "random" +# ## routing_key = "telegraf" +# # routing_key = "" +# # ## CompressionCodec represents the various compression codecs recognized by # ## Kafka in messages. # ## 0 : No compression # ## 1 : Gzip compression # ## 2 : Snappy compression -# compression_codec = 0 +# ## 3 : LZ4 compression +# # compression_codec = 0 # # ## RequiredAcks is used in Produce Requests to tell the broker how many # ## replica acknowledgements it must see before responding @@ -379,16 +630,21 @@ # ## received the data. This option provides the best durability, we # ## guarantee that no messages will be lost as long as at least one in # ## sync replica remains. -# required_acks = -1 +# # required_acks = -1 # -# ## The total number of times to retry sending a message -# max_retry = 3 +# ## The maximum number of times to retry sending a metric before failing +# ## until the next flush. +# # max_retry = 3 # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## The maximum permitted size of a message. Should be set equal to or +# ## smaller than the broker's 'message.max.bytes'. +# # max_message_bytes = 1000000 +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## Optional SASL Config @@ -399,7 +655,7 @@ # ## Each data format has its own unique set of configuration options, read # ## more about them here: # ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md -# data_format = "influx" +# # data_format = "influx" # # Configuration for the AWS Kinesis output. @@ -422,6 +678,12 @@ # #profile = "" # #shared_credential_file = "" # +# ## Endpoint to make request against, the correct endpoint is automatically +# ## determined and this option should only be set if you wish to override the +# ## default. +# ## ex: endpoint_url = "http://localhost:8000" +# # endpoint_url = "" +# # ## Kinesis StreamName must exist prior to starting telegraf. # streamname = "StreamName" # ## DEPRECATED: PartitionKey as used for sharding data. @@ -490,6 +752,12 @@ # ## ex: prefix/web01.example.com/mem # topic_prefix = "telegraf" # +# ## QoS policy for messages +# ## 0 = at most once +# ## 1 = at least once +# ## 2 = exactly once +# # qos = 2 +# # ## username and password to connect MQTT server. # # username = "telegraf" # # password = "metricsmetricsmetricsmetrics" @@ -497,13 +765,20 @@ # ## client ID, if not set a random ID is generated # # client_id = "" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Timeout for write operations. default: 5s +# # timeout = "5s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # +# ## When true, metrics will be sent in one MQTT message per flush. Otherwise, +# ## metrics are written one metric per MQTT message. +# # batch = false +# # ## Data format to output. # ## Each data format has its own unique set of configuration options, read # ## more about them here: @@ -521,11 +796,11 @@ # ## NATS subject for producer messages # subject = "telegraf" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## Data format to output. @@ -564,7 +839,11 @@ # # ## Number of data points to send to OpenTSDB in Http requests. # ## Not used with telnet API. -# httpBatchSize = 50 +# http_batch_size = 50 +# +# ## URI Path for Http requests to OpenTSDB. +# ## Used in cases where OpenTSDB is located behind a reverse proxy. +# http_path = "/api/put" # # ## Debug true - Prints OpenTSDB communication # debug = false @@ -576,10 +855,33 @@ # # Configuration for the Prometheus client to spawn # [[outputs.prometheus_client]] # ## Address to listen on -# # listen = ":9273" +# listen = ":9273" # -# ## Interval to expire metrics and not deliver to prometheus, 0 == no expiration +# ## Use HTTP Basic Authentication. +# # basic_username = "Foo" +# # basic_password = "Bar" +# +# ## If set, the IP Ranges which are allowed to access metrics. +# ## ex: ip_range = ["192.168.0.0/24", "192.168.1.0/30"] +# # ip_range = [] +# +# ## Path to publish the metrics on. +# # path = "/metrics" +# +# ## Expiration interval for each metric. 0 == no expiration # # expiration_interval = "60s" +# +# ## Collectors to enable, valid entries are "gocollector" and "process". +# ## If unset, both are enabled. +# # collectors_exclude = ["gocollector", "process"] +# +# ## Send string metrics as Prometheus labels. +# ## Unless set to false all string metrics will be sent as labels. +# # string_as_label = true +# +# ## If set, enable TLS with the given certificate. +# # tls_cert = "/etc/ssl/telegraf.crt" +# # tls_key = "/etc/ssl/telegraf.key" # # Configuration for the Riemann server to send metrics to @@ -640,6 +942,13 @@ # # address = "unix:///tmp/telegraf.sock" # # address = "unixgram:///tmp/telegraf.sock" # +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false +# # ## Period between keep alive probes. # ## Only applies to TCP sockets. # ## 0 disables keep alive probes. @@ -653,20 +962,271 @@ # # data_format = "influx" +# # Configuration for Wavefront server to send metrics to +# [[outputs.wavefront]] +# ## DNS name of the wavefront proxy server +# host = "wavefront.example.com" +# +# ## Port that the Wavefront proxy server listens on +# port = 2878 +# +# ## prefix for metrics keys +# #prefix = "my.specific.prefix." +# +# ## whether to use "value" for name of simple fields +# #simple_fields = false +# +# ## character to use between metric and field name. defaults to . (dot) +# #metric_separator = "." +# +# ## Convert metric name paths to use metricSeperator character +# ## When true (default) will convert all _ (underscore) chartacters in final metric name +# #convert_paths = true +# +# ## Use Regex to sanitize metric and tag names from invalid characters +# ## Regex is more thorough, but significantly slower +# #use_regex = false +# +# ## point tags to use as the source name for Wavefront (if none found, host will be used) +# #source_override = ["hostname", "agent_host", "node_host"] +# +# ## whether to convert boolean values to numeric values, with false -> 0.0 and true -> 1.0. default true +# #convert_bool = true +# +# ## Define a mapping, namespaced by metric prefix, from string values to numeric values +# ## The example below maps "green" -> 1.0, "yellow" -> 0.5, "red" -> 0.0 for +# ## any metrics beginning with "elasticsearch" +# #[[outputs.wavefront.string_to_number.elasticsearch]] +# # green = 1.0 +# # yellow = 0.5 +# # red = 0.0 + + ############################################################################### # PROCESSOR PLUGINS # ############################################################################### +# # Convert values to another metric value type +# [[processors.converter]] +# ## Tags to convert +# ## +# ## The table key determines the target type, and the array of key-values +# ## select the keys to convert. The array may contain globs. +# ## = [...] +# [processors.converter.tags] +# string = [] +# integer = [] +# unsigned = [] +# boolean = [] +# float = [] +# +# ## Fields to convert +# ## +# ## The table key determines the target type, and the array of key-values +# ## select the keys to convert. The array may contain globs. +# ## = [...] +# [processors.converter.fields] +# tag = [] +# string = [] +# integer = [] +# unsigned = [] +# boolean = [] +# float = [] + + +# # Map enum values according to given table. +# [[processors.enum]] +# [[processors.enum.mapping]] +# ## Name of the field to map +# field = "status" +# +# ## Destination field to be used for the mapped value. By default the source +# ## field is used, overwriting the original value. +# # dest = "status_code" +# +# ## Default value to be used for all values not contained in the mapping +# ## table. When unset, the unmodified value for the field will be used if no +# ## match is found. +# # default = 0 +# +# ## Table of mappings +# [processors.enum.mapping.value_mappings] +# green = 1 +# yellow = 2 +# red = 3 + + +# # Apply metric modifications using override semantics. +# [[processors.override]] +# ## All modifications on inputs and aggregators can be overridden: +# # name_override = "new_name" +# # name_prefix = "new_name_prefix" +# # name_suffix = "new_name_suffix" +# +# ## Tags to be added (all values must be strings) +# # [processors.override.tags] +# # additional_tag = "tag_value" + + +# # Parse a value in a specified field/tag(s) and add the result in a new metric +# [[processors.parser]] +# ## The name of the fields whose value will be parsed. +# parse_fields = [] +# +# ## If true, incoming metrics are not emitted. +# drop_original = false +# +# ## If set to override, emitted metrics will be merged by overriding the +# ## original metric using the newly parsed metrics. +# merge = "override" +# +# ## The dataformat to be read from files +# ## Each data format has its own unique set of configuration options, read +# ## more about them here: +# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md +# data_format = "influx" + + # # Print all metrics that pass through this filter. # [[processors.printer]] +# # Transforms tag and field values with regex pattern +# [[processors.regex]] +# ## Tag and field conversions defined in a separate sub-tables +# # [[processors.regex.tags]] +# # ## Tag to change +# # key = "resp_code" +# # ## Regular expression to match on a tag value +# # pattern = "^(\\d)\\d\\d$" +# # ## Pattern for constructing a new value (${1} represents first subgroup) +# # replacement = "${1}xx" +# +# # [[processors.regex.fields]] +# # key = "request" +# # ## All the power of the Go regular expressions available here +# # ## For example, named subgroups +# # pattern = "^/api(?P/[\\w/]+)\\S*" +# # replacement = "${method}" +# # ## If result_key is present, a new field will be created +# # ## instead of changing existing field +# # result_key = "method" +# +# ## Multiple conversions may be applied for one field sequentially +# ## Let's extract one more value +# # [[processors.regex.fields]] +# # key = "request" +# # pattern = ".*category=(\\w+).*" +# # replacement = "${1}" +# # result_key = "search_category" + + +# # Rename measurements, tags, and fields that pass through this filter. +# [[processors.rename]] + + +# # Perform string processing on tags, fields, and measurements +# [[processors.strings]] +# ## Convert a tag value to uppercase +# # [[processors.strings.uppercase]] +# # tag = "method" +# +# ## Convert a field value to lowercase and store in a new field +# # [[processors.strings.lowercase]] +# # field = "uri_stem" +# # dest = "uri_stem_normalised" +# +# ## Trim leading and trailing whitespace using the default cutset +# # [[processors.strings.trim]] +# # field = "message" +# +# ## Trim leading characters in cutset +# # [[processors.strings.trim_left]] +# # field = "message" +# # cutset = "\t" +# +# ## Trim trailing characters in cutset +# # [[processors.strings.trim_right]] +# # field = "message" +# # cutset = "\r\n" +# +# ## Trim the given prefix from the field +# # [[processors.strings.trim_prefix]] +# # field = "my_value" +# # prefix = "my_" +# +# ## Trim the given suffix from the field +# # [[processors.strings.trim_suffix]] +# # field = "read_count" +# # suffix = "_count" + + +# # Print all metrics that pass through this filter. +# [[processors.topk]] +# ## How many seconds between aggregations +# # period = 10 +# +# ## How many top metrics to return +# # k = 10 +# +# ## Over which tags should the aggregation be done. Globs can be specified, in +# ## which case any tag matching the glob will aggregated over. If set to an +# ## empty list is no aggregation over tags is done +# # group_by = ['*'] +# +# ## Over which fields are the top k are calculated +# # fields = ["value"] +# +# ## What aggregation to use. Options: sum, mean, min, max +# # aggregation = "mean" +# +# ## Instead of the top k largest metrics, return the bottom k lowest metrics +# # bottomk = false +# +# ## The plugin assigns each metric a GroupBy tag generated from its name and +# ## tags. If this setting is different than "" the plugin will add a +# ## tag (which name will be the value of this setting) to each metric with +# ## the value of the calculated GroupBy tag. Useful for debugging +# # add_groupby_tag = "" +# +# ## These settings provide a way to know the position of each metric in +# ## the top k. The 'add_rank_field' setting allows to specify for which +# ## fields the position is required. If the list is non empty, then a field +# ## will be added to each and every metric for each string present in this +# ## setting. This field will contain the ranking of the group that +# ## the metric belonged to when aggregated over that field. +# ## The name of the field will be set to the name of the aggregation field, +# ## suffixed with the string '_topk_rank' +# # add_rank_fields = [] +# +# ## These settings provide a way to know what values the plugin is generating +# ## when aggregating metrics. The 'add_agregate_field' setting allows to +# ## specify for which fields the final aggregation value is required. If the +# ## list is non empty, then a field will be added to each every metric for +# ## each field present in this setting. This field will contain +# ## the computed aggregation for the group that the metric belonged to when +# ## aggregated over that field. +# ## The name of the field will be set to the name of the aggregation field, +# ## suffixed with the string '_topk_aggregate' +# # add_aggregate_fields = [] + + ############################################################################### # AGGREGATOR PLUGINS # ############################################################################### +# # Keep the aggregate basicstats of each metric passing through. +# [[aggregators.basicstats]] +# ## General Aggregator Arguments: +# ## The period on which to flush & clear the aggregator. +# period = "30s" +# ## If true, the original metric will be dropped by the +# ## aggregator and will not get sent to the output plugins. +# drop_original = false + + # # Create aggregate histograms. # [[aggregators.histogram]] # ## The period in which to flush the aggregator. @@ -703,6 +1263,18 @@ # drop_original = false +# # Count the occurance of values in fields. +# [[aggregators.valuecounter]] +# ## General Aggregator Arguments: +# ## The period on which to flush & clear the aggregator. +# period = "30s" +# ## If true, the original metric will be dropped by the +# ## aggregator and will not get sent to the output plugins. +# drop_original = false +# ## The fields for which the values will be counted +# fields = [] + + ############################################################################### # INPUT PLUGINS # @@ -722,13 +1294,12 @@ # Read metrics about disk usage by mount point [[inputs.disk]] - ## By default, telegraf gather stats for all mountpoints. - ## Setting mountpoints will restrict the stats to the specified mountpoints. + ## By default stats will be gathered for all mount points. + ## Set mount_points will restrict the stats to only the specified mount points. # mount_points = ["/"] - ## Ignore some mountpoints by filesystem type. For example (dev)tmpfs (usually - ## present on /run, /var/run, /dev/shm or /dev). - ignore_fs = ["tmpfs", "devtmpfs", "devfs"] + ## Ignore mount points by filesystem type. + ignore_fs = ["tmpfs", "devtmpfs", "devfs", "overlay", "aufs", "squashfs"] # Read metrics about disk IO by device @@ -736,7 +1307,7 @@ ## By default, telegraf will gather stats for all devices including ## disk partitions. ## Setting devices will restrict the stats to the specified devices. - # devices = ["sda", "sdb"] + # devices = ["sda", "sdb", "vd*"] ## Uncomment the following line if you need disk serial numbers. # skip_serial_number = false # @@ -783,12 +1354,48 @@ # no configuration +# # Gather ActiveMQ metrics +# [[inputs.activemq]] +# ## Required ActiveMQ Endpoint +# # server = "192.168.50.10" +# +# ## Required ActiveMQ port +# # port = 8161 +# +# ## Credentials for basic HTTP authentication +# # username = "admin" +# # password = "admin" +# +# ## Required ActiveMQ webadmin root path +# # webadmin = "admin" +# +# ## Maximum time to receive response. +# # response_timeout = "5s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification + + # # Read stats from aerospike server(s) # [[inputs.aerospike]] # ## Aerospike servers to connect to (with port) # ## This plugin will query all namespaces the aerospike # ## server has configured and get stats for them. # servers = ["localhost:3000"] +# +# # username = "telegraf" +# # password = "pa$$word" +# +# ## Optional TLS Config +# # enable_tls = false +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## If false, skip chain & host verification +# # insecure_skip_verify = true # # Read Apache status information (mod_status) @@ -805,11 +1412,37 @@ # ## Maximum time to receive response. # # response_timeout = "5s" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false + + +# # Gather metrics from Apache Aurora schedulers +# [[inputs.aurora]] +# ## Schedulers are the base addresses of your Aurora Schedulers +# schedulers = ["http://127.0.0.1:8081"] +# +# ## Set of role types to collect metrics from. +# ## +# ## The scheduler roles are checked each interval by contacting the +# ## scheduler nodes; zookeeper is not contacted. +# # roles = ["leader", "follower"] +# +# ## Timeout is the max time for total network operations. +# # timeout = "5s" +# +# ## Username and password are sent using HTTP Basic Auth. +# # username = "username" +# # password = "pa$$word" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -825,22 +1458,69 @@ # bcacheDevs = ["bcache0"] -# # Read Cassandra metrics through Jolokia -# [[inputs.cassandra]] -# # This is the context root used to compose the jolokia url -# context = "/jolokia/read" -# ## List of cassandra servers exposing jolokia read service -# servers = ["myuser:mypassword@10.10.10.1:8778","10.10.10.2:8778",":8778"] -# ## List of metrics collected on above servers -# ## Each metric consists of a jmx path. -# ## This will collect all heap memory usage metrics from the jvm and -# ## ReadLatency metrics for all keyspaces and tables. -# ## "type=Table" in the query works with Cassandra3.0. Older versions might -# ## need to use "type=ColumnFamily" -# metrics = [ -# "/java.lang:type=Memory/HeapMemoryUsage", -# "/org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency" -# ] +# # Collects Beanstalkd server and tubes stats +# [[inputs.beanstalkd]] +# ## Server to collect data from +# server = "localhost:11300" +# +# ## List of tubes to gather stats about. +# ## If no tubes specified then data gathered for each tube on server reported by list-tubes command +# tubes = ["notifications"] + + +# # Collect bond interface status, slaves statuses and failures count +# [[inputs.bond]] +# ## Sets 'proc' directory path +# ## If not specified, then default is /proc +# # host_proc = "/proc" +# +# ## By default, telegraf gather stats for all bond interfaces +# ## Setting interfaces will restrict the stats to the specified +# ## bond interfaces. +# # bond_interfaces = ["bond0"] + + +# # Collect Kafka topics and consumers status from Burrow HTTP API. +# [[inputs.burrow]] +# ## Burrow API endpoints in format "schema://host:port". +# ## Default is "http://localhost:8000". +# servers = ["http://localhost:8000"] +# +# ## Override Burrow API prefix. +# ## Useful when Burrow is behind reverse-proxy. +# # api_prefix = "/v3/kafka" +# +# ## Maximum time to receive response. +# # response_timeout = "5s" +# +# ## Limit per-server concurrent connections. +# ## Useful in case of large number of topics or consumer groups. +# # concurrent_connections = 20 +# +# ## Filter clusters, default is no filtering. +# ## Values can be specified as glob patterns. +# # clusters_include = [] +# # clusters_exclude = [] +# +# ## Filter consumer groups, default is no filtering. +# ## Values can be specified as glob patterns. +# # groups_include = [] +# # groups_exclude = [] +# +# ## Filter topics, default is no filtering. +# ## Values can be specified as glob patterns. +# # topics_include = [] +# # topics_exclude = [] +# +# ## Credentials for basic HTTP authentication. +# # username = "" +# # password = "" +# +# ## Optional SSL config +# # ssl_ca = "/etc/telegraf/ca.pem" +# # ssl_cert = "/etc/telegraf/cert.pem" +# # ssl_key = "/etc/telegraf/key.pem" +# # insecure_skip_verify = false # # Collects performance metrics from the MON and OSD nodes in a Ceph storage cluster. @@ -919,6 +1599,12 @@ # #profile = "" # #shared_credential_file = "" # +# ## Endpoint to make request against, the correct endpoint is automatically +# ## determined and this option should only be set if you wish to override the +# ## default. +# ## ex: endpoint_url = "http://localhost:8000" +# # endpoint_url = "" +# # # The minimum period for Cloudwatch metrics is 1 minute (60s). However not all # # metrics are made available to the 1 minute period. Some are collected at # # 3 minute, 5 minute, or larger intervals. See https://aws.amazon.com/cloudwatch/faqs/#monitoring. @@ -932,7 +1618,7 @@ # ## Collection Delay (required - must account for metrics availability via CloudWatch API) # delay = "5m" # -# ## Recomended: use metric 'interval' that is a multiple of 'period' to avoid +# ## Recommended: use metric 'interval' that is a multiple of 'period' to avoid # ## gaps or overlap in pulled data # interval = "5m" # @@ -955,7 +1641,9 @@ # #[[inputs.cloudwatch.metrics]] # # names = ["Latency", "RequestCount"] # # -# # ## Dimension filters for Metric (optional) +# # ## Dimension filters for Metric. These are optional however all dimensions +# # ## defined for the metric names must be specified in order to retrieve +# # ## the metric statistics. # # [[inputs.cloudwatch.metrics.dimensions]] # # name = "LoadBalancerName" # # value = "p-example" @@ -979,19 +1667,33 @@ # # Gather health check statuses from services registered in Consul # [[inputs.consul]] -# ## Most of these values defaults to the one configured on a Consul's agent level. -# ## Optional Consul server address (default: "localhost") +# ## Consul server address # # address = "localhost" -# ## Optional URI scheme for the Consul server (default: "http") +# +# ## URI scheme for the Consul server, one of "http", "https" # # scheme = "http" -# ## Optional ACL token used in every request (default: "") +# +# ## ACL token used in every request # # token = "" -# ## Optional username used for request HTTP Basic Authentication (default: "") +# +# ## HTTP Basic Authentication username and password. # # username = "" -# ## Optional password used for HTTP Basic Authentication (default: "") # # password = "" -# ## Optional data centre to query the health checks from (default: "") +# +# ## Data centre to query the health checks from # # datacentre = "" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = true +# +# ## Consul checks' tag splitting +# # When tags are formatted like "key:value" with ":" as a delimiter then +# # they will be splitted and reported as proper key:value in Telegraf +# # tag_delimiter = ":" # # Read metrics from one or many couchbase clusters @@ -1003,7 +1705,7 @@ # ## http://admin:secret@couchbase-0.example.com:8091/ # ## # ## If no servers are specified, then localhost is used as the host. -# ## If no protocol is specifed, HTTP is used. +# ## If no protocol is specified, HTTP is used. # ## If no port is specified, 8091 is used. # servers = ["http://localhost:8091"] @@ -1011,10 +1713,54 @@ # # Read CouchDB Stats from one or more servers # [[inputs.couchdb]] # ## Works with CouchDB stats endpoints out of the box -# ## Multiple HOSTs from which to read CouchDB stats: +# ## Multiple Hosts from which to read CouchDB stats: # hosts = ["http://localhost:8086/_stats"] +# # Input plugin for DC/OS metrics +# [[inputs.dcos]] +# ## The DC/OS cluster URL. +# cluster_url = "https://dcos-ee-master-1" +# +# ## The ID of the service account. +# service_account_id = "telegraf" +# ## The private key file for the service account. +# service_account_private_key = "/etc/telegraf/telegraf-sa-key.pem" +# +# ## Path containing login token. If set, will read on every gather. +# # token_file = "/home/dcos/.dcos/token" +# +# ## In all filter options if both include and exclude are empty all items +# ## will be collected. Arrays may contain glob patterns. +# ## +# ## Node IDs to collect metrics from. If a node is excluded, no metrics will +# ## be collected for its containers or apps. +# # node_include = [] +# # node_exclude = [] +# ## Container IDs to collect container metrics from. +# # container_include = [] +# # container_exclude = [] +# ## Container IDs to collect app metrics from. +# # app_include = [] +# # app_exclude = [] +# +# ## Maximum concurrent connections to the cluster. +# # max_connections = 10 +# ## Maximum time to receive a response from cluster. +# # response_timeout = "20s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## If false, skip chain & host verification +# # insecure_skip_verify = true +# +# ## Recommended filtering to reduce series cardinality. +# # [inputs.dcos.tagdrop] +# # path = ["/var/lib/mesos/slave/slaves/*"] + + # # Read metrics from one or many disque servers # [[inputs.disque]] # ## An array of URI to gather stats about. Specify an ip or hostname @@ -1059,6 +1805,9 @@ # ## To use environment variables (ie, docker-machine), set endpoint = "ENV" # endpoint = "unix:///var/run/docker.sock" # +# ## Set to true to collect Swarm metrics(desired_replicas, running_replicas) +# gather_services = false +# # ## Only collect metrics for these containers, collect all if empty # container_names = [] # @@ -1067,6 +1816,11 @@ # container_name_include = [] # container_name_exclude = [] # +# ## Container states to include and exclude. Globs accepted. +# ## When empty only containers in the "running" state will be captured. +# # container_state_include = [] +# # container_state_exclude = [] +# # ## Timeout for docker list, info, and stats commands # timeout = "5s" # @@ -1083,11 +1837,11 @@ # docker_label_include = [] # docker_label_exclude = [] # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -1124,15 +1878,26 @@ # ## Set cluster_health to true when you want to also obtain cluster health stats # cluster_health = false # +# ## Adjust cluster_health_level when you want to also obtain detailed health stats +# ## The options are +# ## - indices (default) +# ## - cluster +# # cluster_health_level = "indices" +# # ## Set cluster_stats to true when you want to also obtain cluster stats from the # ## Master node. # cluster_stats = false # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## node_stats is a list of sub-stats that you want to have gathered. Valid options +# ## are "indices", "os", "process", "jvm", "thread_pool", "fs", "transport", "http", +# ## "breaker". Per default, all stats are gathered. +# # node_stats = ["jvm", "http"] +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -1164,6 +1929,62 @@ # use_sudo = false +# # Read devices value(s) from a Fibaro controller +# [[inputs.fibaro]] +# ## Required Fibaro controller address/hostname. +# ## Note: at the time of writing this plugin, Fibaro only implemented http - no https available +# url = "http://:80" +# +# ## Required credentials to access the API (http://) +# username = "" +# password = "" +# +# ## Amount of time allowed to complete the HTTP request +# # timeout = "5s" + + +# # Reload and gather from file[s] on telegraf's interval. +# [[inputs.file]] +# ## Files to parse each interval. +# ## These accept standard unix glob matching rules, but with the addition of +# ## ** as a "super asterisk". ie: +# ## /var/log/**.log -> recursively find all .log files in /var/log +# ## /var/log/*/*.log -> find all .log files with a parent dir in /var/log +# ## /var/log/apache.log -> only read the apache log file +# files = ["/var/log/apache/access.log"] +# +# ## The dataformat to be read from files +# ## Each data format has its own unique set of configuration options, read +# ## more about them here: +# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md +# data_format = "influx" + + +# # Count files in a directory +# [[inputs.filecount]] +# ## Directory to gather stats about. +# directory = "/var/cache/apt/archives" +# +# ## Only count files that match the name pattern. Defaults to "*". +# name = "*.deb" +# +# ## Count files in subdirectories. Defaults to true. +# recursive = false +# +# ## Only count regular files. Defaults to true. +# regular_only = true +# +# ## Only count files that are at least this size in bytes. If size is +# ## a negative number, only count files that are smaller than the +# ## absolute value of size. Defaults to 0. +# size = 0 +# +# ## Only count files that have not been touched for at least this +# ## duration. If mtime is negative, only count files that have been +# ## touched in this duration. Defaults to "0s". +# mtime = "0s" + + # # Read stats about given file(s) # [[inputs.filestat]] # ## Files to gather stats about. @@ -1225,11 +2046,11 @@ # username = "" # password = "" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -1243,6 +2064,10 @@ # ## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats # servers = ["http://myhaproxy.com:1936/haproxy?stats"] # +# ## Credentials for basic HTTP authentication +# # username = "admin" +# # password = "admin" +# # ## You can also use local socket with standard wildcard globbing. # ## Server address not starting with 'http' will be treated as a possible # ## socket, so both examples below are valid. @@ -1251,13 +2076,13 @@ # ## By default, some of the fields are renamed from what haproxy calls them. # ## Setting this option to true results in the plugin keeping the original # ## field names. -# # keep_field_names = true +# # keep_field_names = false # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -1274,11 +2099,48 @@ # # devices = ["sda", "*"] +# # Read formatted metrics from one or more HTTP endpoints +# [[inputs.http]] +# ## One or more URLs from which to read formatted metrics +# urls = [ +# "http://localhost/metrics" +# ] +# +# ## HTTP method +# # method = "GET" +# +# ## Optional HTTP headers +# # headers = {"X-Special-Header" = "Special-Value"} +# +# ## Optional HTTP Basic Auth Credentials +# # username = "username" +# # password = "pa$$word" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false +# +# ## Amount of time allowed to complete the HTTP request +# # timeout = "5s" +# +# ## Data format to consume. +# ## Each data format has its own unique set of configuration options, read +# ## more about them here: +# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md +# # data_format = "influx" + + # # HTTP/HTTPS request given an address a method and a timeout # [[inputs.http_response]] # ## Server address (default http://localhost) # # address = "http://localhost" # +# ## Set http_proxy (telegraf uses the system wide proxy settings if it's is not set) +# # http_proxy = "http://localhost:8888" +# # ## Set response_timeout (default 5 seconds) # # response_timeout = "5s" # @@ -1298,11 +2160,11 @@ # # response_string_match = "ok" # # response_string_match = "\".*_status\".?:.?\"up\"" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## HTTP Request Headers (all values must be strings) @@ -1338,6 +2200,13 @@ # # "my_tag_2" # # ] # +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false +# # ## HTTP parameters (all values must be strings). For "GET" requests, data # ## will be included in the query. For "POST" requests, data will be included # ## in the request body as "x-www-form-urlencoded". @@ -1349,13 +2218,29 @@ # # [inputs.httpjson.headers] # # X-Auth-Token = "my-xauth-token" # # apiVersion = "v1" + + +# # Gather Icinga2 status +# [[inputs.icinga2]] +# ## Required Icinga2 server address (default: "https://localhost:5665") +# # server = "https://localhost:5665" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification -# # insecure_skip_verify = false +# ## Required Icinga2 object type ("services" or "hosts, default "services") +# # object_type = "services" +# +# ## Credentials for basic HTTP authentication +# # username = "admin" +# # password = "admin" +# +# ## Maximum time to receive response. +# # response_timeout = "5s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = true # # Read InfluxDB-formatted JSON metrics from one or more HTTP endpoints @@ -1370,11 +2255,11 @@ # "http://localhost:8086/debug/vars" # ] # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## http request & header timeout @@ -1398,7 +2283,10 @@ # [[inputs.ipmi_sensor]] # ## optionally specify the path to the ipmitool executable # # path = "/usr/bin/ipmitool" -# # +# ## +# ## optionally force session privilege level. Can be CALLBACK, USER, OPERATOR, ADMINISTRATOR +# # privilege = "ADMINISTRATOR" +# ## # ## optionally specify one or more servers via a url matching # ## [username[:password]@][protocol[(address)]] # ## e.g. @@ -1408,12 +2296,26 @@ # ## # # servers = ["USERID:PASSW0RD@lan(192.168.1.1)"] # -# ## Recomended: use metric 'interval' that is a multiple of 'timeout' to avoid +# ## Recommended: use metric 'interval' that is a multiple of 'timeout' to avoid # ## gaps or overlap in pulled data # interval = "30s" # # ## Timeout for the ipmitool command to complete # timeout = "20s" +# +# ## Schema Version: (Optional, defaults to version 1) +# metric_version = 2 + + +# # Gather packets and bytes counters from Linux ipsets +# [[inputs.ipset]] +# ## By default, we only show sets which have already matched at least 1 packet. +# ## set include_unmatched_sets = true to gather them all. +# include_unmatched_sets = false +# ## Adjust your sudo settings appropriately if using this option ("sudo ipset save") +# use_sudo = false +# ## The default timeout of 1s for ipset execution can be overridden here: +# # timeout = "1s" # # Gather packets and bytes throughput from iptables @@ -1426,6 +2328,8 @@ # ## Setting 'use_lock' to true runs iptables with the "-w" option. # ## Adjust your sudo settings appropriately if using this option ("iptables -wnvl") # use_lock = false +# ## Define an alternate executable, such as "ip6tables". Default is "iptables". +# # binary = "ip6tables" # ## defines the table to monitor: # table = "filter" # ## defines the chains to monitor. @@ -1514,14 +2418,14 @@ # # password = "" # # response_timeout = "5s" # -# ## Optional SSL config -# # ssl_ca = "/var/private/ca.pem" -# # ssl_cert = "/var/private/client.pem" -# # ssl_key = "/var/private/client-key.pem" +# ## Optional TLS config +# # tls_ca = "/var/private/ca.pem" +# # tls_cert = "/var/private/client.pem" +# # tls_key = "/var/private/client-key.pem" # # insecure_skip_verify = false # # ## Add metrics to read -# [[inputs.jolokia2.metric]] +# [[inputs.jolokia2_agent.metric]] # name = "java_runtime" # mbean = "java.lang:type=Runtime" # paths = ["Uptime"] @@ -1539,22 +2443,22 @@ # # password = "" # # response_timeout = "5s" # -# ## Optional SSL config -# # ssl_ca = "/var/private/ca.pem" -# # ssl_cert = "/var/private/client.pem" -# # ssl_key = "/var/private/client-key.pem" +# ## Optional TLS config +# # tls_ca = "/var/private/ca.pem" +# # tls_cert = "/var/private/client.pem" +# # tls_key = "/var/private/client-key.pem" # # insecure_skip_verify = false # # ## Add proxy targets to query # # default_target_username = "" # # default_target_password = "" -# [[inputs.jolokia_proxy.target]] +# [[inputs.jolokia2_proxy.target]] # url = "service:jmx:rmi:///jndi/rmi://targethost:9999/jmxrmi" -# # username = "" -# # password = "" +# # username = "" +# # password = "" # # ## Add metrics to read -# [[inputs.jolokia_proxy.metric]] +# [[inputs.jolokia2_proxy.metric]] # name = "java_runtime" # mbean = "java.lang:type=Runtime" # paths = ["Uptime"] @@ -1570,6 +2474,13 @@ # # ## Time limit for http requests # timeout = "5s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false # # Get kernel statistics from /proc/vmstat @@ -1577,6 +2488,26 @@ # # no configuration +# # Read status information from one or more Kibana servers +# [[inputs.kibana]] +# ## specify a list of one or more Kibana servers +# servers = ["http://localhost:5601"] +# +# ## Timeout for HTTP requests +# timeout = "5s" +# +# ## HTTP Basic Auth credentials +# # username = "username" +# # password = "pa$$word" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false + + # # Read metrics from the kubernetes kubelet api # [[inputs.kubernetes]] # ## URL for the kubelet @@ -1588,11 +2519,11 @@ # ## Set response_timeout (default 5 seconds) # # response_timeout = "5s" # -# ## Optional SSL Config -# # ssl_ca = /path/to/cafile -# # ssl_cert = /path/to/certfile -# # ssl_key = /path/to/keyfile -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = /path/to/cafile +# # tls_cert = /path/to/certfile +# # tls_key = /path/to/keyfile +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -1636,6 +2567,16 @@ # # campaign_id = "" +# # Read metrics from one or many mcrouter servers +# [[inputs.mcrouter]] +# ## An array of address to gather stats about. Specify an ip or hostname +# ## with port. ie tcp://localhost:11211, tcp://10.0.0.1:11211, etc. +# servers = ["tcp://localhost:11211", "unix:///var/run/mcrouter.sock"] +# +# ## Timeout for metric collections from all servers. Minimum timeout is "1s". +# # timeout = "5s" + + # # Read metrics from one or many memcached servers # [[inputs.memcached]] # ## An array of address to gather stats about. Specify an ip on hostname @@ -1649,7 +2590,7 @@ # ## Timeout, in ms. # timeout = 100 # ## A list of Mesos masters. -# masters = ["localhost:5050"] +# masters = ["http://localhost:5050"] # ## Master metrics groups to be collected, by default, all enabled. # master_collections = [ # "resources", @@ -1673,6 +2614,13 @@ # # "tasks", # # "messages", # # ] +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false # # Collects scores from a minecraft server's scoreboard using the RCON protocol @@ -1693,13 +2641,15 @@ # ## mongodb://user:auth_key@10.10.3.30:27017, # ## mongodb://10.10.3.33:18832, # servers = ["mongodb://127.0.0.1:27017"] -# gather_perdb_stats = false # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## When true, collect per database stats +# # gather_perdb_stats = false +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -1714,6 +2664,20 @@ # # # ## If no servers are specified, then localhost is used as the host. # servers = ["tcp(127.0.0.1:3306)/"] +# +# ## Selects the metric output format. +# ## +# ## This option exists to maintain backwards compatibility, if you have +# ## existing metrics do not set or change this value until you are ready to +# ## migrate to the new format. +# ## +# ## If you do not have existing metrics from this plugin set to the latest +# ## version. +# ## +# ## Telegraf >=1.6: metric_version = 2 +# ## <1.6: metric_version = 1 (or unset) +# metric_version = 2 +# # ## the limits for metrics form perf_events_statements # perf_events_statements_digest_text_limit = 120 # perf_events_statements_limit = 250 @@ -1728,7 +2692,7 @@ # ## gather thread state counts from INFORMATION_SCHEMA.PROCESSLIST # gather_process_list = true # # -# ## gather thread state counts from INFORMATION_SCHEMA.USER_STATISTICS +# ## gather user statistics from INFORMATION_SCHEMA.USER_STATISTICS # gather_user_statistics = true # # # ## gather auto_increment columns and max values from information schema @@ -1764,10 +2728,21 @@ # ## Some queries we may want to run less often (such as SHOW GLOBAL VARIABLES) # interval_slow = "30m" # -# ## Optional SSL Config (will be used if tls=custom parameter specified in server uri) -# ssl_ca = "/etc/telegraf/ca.pem" -# ssl_cert = "/etc/telegraf/cert.pem" -# ssl_key = "/etc/telegraf/key.pem" +# ## Optional TLS Config (will be used if tls=custom parameter specified in server uri) +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false + + +# # Provides metrics about the state of a NATS server +# [[inputs.nats]] +# ## The address of the monitoring endpoint of the NATS server +# server = "http://localhost:8222" +# +# ## Maximum time to receive response +# # response_timeout = "5s" # # Read metrics about network interface usage @@ -1777,9 +2752,15 @@ # ## regardless of status. # ## # # interfaces = ["eth0"] +# ## +# ## On linux systems telegraf also collects protocol stats. +# ## Setting ignore_protocol_stats to true will skip reporting of protocol metrics. +# ## +# # ignore_protocol_stats = false +# ## -# # TCP or UDP 'ping' given url and collect response time in seconds +# # Collect response time of a TCP or UDP connection # [[inputs.net_response]] # ## Protocol, must be "tcp" or "udp" # ## NOTE: because the "udp" protocol does not respond to requests, it requires @@ -1787,11 +2768,12 @@ # protocol = "tcp" # ## Server address (default localhost) # address = "localhost:80" +# # ## Set timeout -# timeout = "1s" +# # timeout = "1s" # # ## Set read timeout (only used if expecting a response) -# read_timeout = "1s" +# # read_timeout = "1s" # # ## The following options are required for UDP checks. For TCP, they are # ## optional. The plugin will send the given string to the server and then @@ -1800,6 +2782,9 @@ # # send = "ssh" # ## expected string in answer # # expect = "ssh" +# +# ## Uncomment to remove deprecated fields +# # fieldexclude = ["result_type", "string_found"] # # Read TCP metrics such as established, time wait and sockets counts. @@ -1812,10 +2797,11 @@ # # An array of Nginx stub_status URI to gather stats. # urls = ["http://localhost/server_status"] # -# # TLS/SSL configuration -# ssl_ca = "/etc/telegraf/ca.pem" -# ssl_cert = "/etc/telegraf/cert.cer" -# ssl_key = "/etc/telegraf/key.key" +# ## Optional TLS Config +# tls_ca = "/etc/telegraf/ca.pem" +# tls_cert = "/etc/telegraf/cert.cer" +# tls_key = "/etc/telegraf/key.key" +# ## Use TLS but skip chain & host verification # insecure_skip_verify = false # # # HTTP response timeout (default: 5s) @@ -1855,6 +2841,15 @@ # dns_lookup = true +# # Pulls statistics from nvidia GPUs attached to the host +# [[inputs.nvidia_smi]] +# ## Optional: path to nvidia-smi binary, defaults to $PATH via exec.LookPath +# # bin_path = "/usr/bin/nvidia-smi" +# +# ## Optional: timeout for GPU polling +# # timeout = "5s" + + # # OpenLDAP cn=Monitor plugin # [[inputs.openldap]] # host = "localhost" @@ -1863,17 +2858,33 @@ # # ldaps, starttls, or no encryption. default is an empty string, disabling all encryption. # # note that port will likely need to be changed to 636 for ldaps # # valid options: "" | "starttls" | "ldaps" -# ssl = "" +# tls = "" # # # skip peer certificate verification. Default is false. # insecure_skip_verify = false # # # Path to PEM-encoded Root certificate to use to verify server certificate -# ssl_ca = "/etc/ssl/certs.pem" +# tls_ca = "/etc/ssl/certs.pem" # # # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed. # bind_dn = "" # bind_password = "" +# +# # Reverse metric names so they sort more naturally. Recommended. +# # This defaults to false if unset, but is set to true when generating a new config +# reverse_metric_names = true + + +# # A plugin to collect stats from Opensmtpd - a validating, recursive, and caching DNS resolver +# [[inputs.opensmtpd]] +# ## If running as a restricted user you can prepend sudo for additional access: +# #use_sudo = false +# +# ## The default location of the smtpctl binary can be overridden with: +# binary = "/usr/sbin/smtpctl" +# +# ## The default timeout of 1000ms can be overriden with (in milliseconds): +# timeout = 1000 # # Read metrics of passenger using passenger-status @@ -1889,6 +2900,15 @@ # command = "passenger-status -v --show=xml" +# # Gather counters from PF +# [[inputs.pf]] +# ## PF require root access on most systems. +# ## Setting 'use_sudo' to true will make use of sudo to run pfctl. +# ## Users must configure sudo to allow telegraf user to run pfctl with no password. +# ## pfctl can be restricted to only list command "pfctl -s info". +# use_sudo = false + + # # Read metrics of phpfpm, via HTTP status page or socket # [[inputs.phpfpm]] # ## An array of addresses to gather stats about. Specify an ip or hostname @@ -1915,103 +2935,32 @@ # # Ping given url(s) and return statistics # [[inputs.ping]] -# ## NOTE: this plugin forks the ping command. You may need to set capabilities -# ## via setcap cap_net_raw+p /bin/ping -# # # ## List of urls to ping -# urls = ["www.google.com"] # required -# ## number of pings to send per collection (ping -c ) +# urls = ["example.org"] +# +# ## Number of pings to send per collection (ping -c ) # # count = 1 -# ## interval, in s, at which to ping. 0 == default (ping -i ) +# +# ## Interval, in s, at which to ping. 0 == default (ping -i ) +# ## Not available in Windows. # # ping_interval = 1.0 -# ## per-ping timeout, in s. 0 == no timeout (ping -W ) +# +# ## Per-ping timeout, in s. 0 == no timeout (ping -W ) # # timeout = 1.0 -# ## interface to send ping from (ping -I ) +# +# ## Total-ping deadline, in s. 0 == no deadline (ping -w ) +# # deadline = 10 +# +# ## Interface or source address to send ping from (ping -I ) +# ## on Darwin and Freebsd only source address possible: (ping -S ) # # interface = "" -# # Read metrics from one or many postgresql servers -# [[inputs.postgresql]] -# ## specify address via a url matching: -# ## postgres://[pqgotest[:password]]@localhost[/dbname]\ -# ## ?sslmode=[disable|verify-ca|verify-full] -# ## or a simple string: -# ## host=localhost user=pqotest password=... sslmode=... dbname=app_production -# ## -# ## All connection parameters are optional. -# ## -# ## Without the dbname parameter, the driver will default to a database -# ## with the same name as the user. This dbname is just for instantiating a -# ## connection with the server and doesn't restrict the databases we are trying -# ## to grab metrics for. -# ## -# address = "host=localhost user=postgres sslmode=disable" -# -# ## A list of databases to explicitly ignore. If not specified, metrics for all -# ## databases are gathered. Do NOT use with the 'databases' option. -# # ignored_databases = ["postgres", "template0", "template1"] -# -# ## A list of databases to pull metrics about. If not specified, metrics for all -# ## databases are gathered. Do NOT use with the 'ignored_databases' option. -# # databases = ["app_production", "testing"] - - -# # Read metrics from one or many postgresql servers -# [[inputs.postgresql_extensible]] -# ## specify address via a url matching: -# ## postgres://[pqgotest[:password]]@localhost[/dbname]\ -# ## ?sslmode=[disable|verify-ca|verify-full] -# ## or a simple string: -# ## host=localhost user=pqotest password=... sslmode=... dbname=app_production -# # -# ## All connection parameters are optional. # -# ## Without the dbname parameter, the driver will default to a database -# ## with the same name as the user. This dbname is just for instantiating a -# ## connection with the server and doesn't restrict the databases we are trying -# ## to grab metrics for. -# # -# address = "host=localhost user=postgres sslmode=disable" -# ## A list of databases to pull metrics about. If not specified, metrics for all -# ## databases are gathered. -# ## databases = ["app_production", "testing"] -# # -# # outputaddress = "db01" -# ## A custom name for the database that will be used as the "server" tag in the -# ## measurement output. If not specified, a default one generated from -# ## the connection address is used. -# # -# ## Define the toml config where the sql queries are stored -# ## New queries can be added, if the withdbname is set to true and there is no -# ## databases defined in the 'databases field', the sql query is ended by a -# ## 'is not null' in order to make the query succeed. -# ## Example : -# ## The sqlquery : "SELECT * FROM pg_stat_database where datname" become -# ## "SELECT * FROM pg_stat_database where datname IN ('postgres', 'pgbench')" -# ## because the databases variable was set to ['postgres', 'pgbench' ] and the -# ## withdbname was true. Be careful that if the withdbname is set to false you -# ## don't have to define the where clause (aka with the dbname) the tagvalue -# ## field is used to define custom tags (separated by commas) -# ## The optional "measurement" value can be used to override the default -# ## output measurement name ("postgresql"). -# # -# ## Structure : -# ## [[inputs.postgresql_extensible.query]] -# ## sqlquery string -# ## version string -# ## withdbname boolean -# ## tagvalue string (comma separated) -# ## measurement string -# [[inputs.postgresql_extensible.query]] -# sqlquery="SELECT * FROM pg_stat_database" -# version=901 -# withdbname=false -# tagvalue="" -# measurement="" -# [[inputs.postgresql_extensible.query]] -# sqlquery="SELECT * FROM pg_stat_bgwriter" -# version=901 -# withdbname=false -# tagvalue="postgresql.stats" +# # Measure postfix queue statistics +# [[inputs.postfix]] +# ## Postfix queue directory. If not provided, telegraf will try to use +# ## 'postconf -h queue_directory' to determine it. +# # queue_directory = "/var/spool/postfix" # # Read metrics from one or many PowerDNS servers @@ -2023,7 +2972,6 @@ # # Monitor process cpu and memory usage # [[inputs.procstat]] -# ## Must specify one of: pid_file, exe, or pattern # ## PID file to monitor process # pid_file = "/var/run/nginx.pid" # ## executable name (ie, pgrep ) @@ -2032,16 +2980,28 @@ # # pattern = "nginx" # ## user as argument for pgrep (ie, pgrep -u ) # # user = "nginx" +# ## Systemd unit name +# # systemd_unit = "nginx.service" +# ## CGroup name or path +# # cgroup = "systemd/system.slice/nginx.service" # # ## override for process_name # ## This is optional; default is sourced from /proc//status # # process_name = "bar" +# # ## Field name prefix -# prefix = "" -# ## comment this out if you want raw cpu_time stats -# fielddrop = ["cpu_time_*"] -# ## This is optional; moves pid into a tag instead of a field -# pid_tag = false +# # prefix = "" +# +# ## Add PID as a tag instead of a field; useful to differentiate between +# ## processes whose tags are otherwise the same. Can create a large number +# ## of series, use judiciously. +# # pid_tag = false +# +# ## Method to use when finding process IDs. Can be one of 'pgrep', or +# ## 'native'. The pgrep finder calls the pgrep executable in the PATH while +# ## the native finder performs the search directly in a manor dependent on the +# ## platform. Default is 'pgrep' +# # pid_finder = "pgrep" # # Read metrics from one or many prometheus clients @@ -2058,11 +3018,11 @@ # ## Specify timeout duration for slower prometheus clients (default is 3s) # # response_timeout = "3s" # -# ## Optional SSL Config -# # ssl_ca = /path/to/cafile -# # ssl_cert = /path/to/certfile -# # ssl_key = /path/to/keyfile -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = /path/to/cafile +# # tls_cert = /path/to/certfile +# # tls_key = /path/to/keyfile +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -2082,11 +3042,11 @@ # # username = "guest" # # password = "guest" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## Optional request timeouts @@ -2106,6 +3066,15 @@ # ## A list of queues to gather as the rabbitmq_queue measurement. If not # ## specified, metrics for all queues are gathered. # # queues = ["telegraf"] +# +# ## A list of exchanges to gather as the rabbitmq_exchange measurement. If not +# ## specified, metrics for all exchanges are gathered. +# # exchanges = ["telegraf"] +# +# ## Queues to include and exclude. Globs accepted. +# ## Note that an empty array for both will include all queues +# queue_name_include = [] +# queue_name_exclude = [] # # Read raindrops stats (raindrops - real-time stats for preforking Rack servers) @@ -2126,6 +3095,16 @@ # ## If no servers are specified, then localhost is used as the host. # ## If no port is specified, 6379 is used # servers = ["tcp://localhost:6379"] +# +# ## specify server password +# # password = "s#cr@t%" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = true # # Read metrics from one or many RethinkDB servers @@ -2177,6 +3156,43 @@ # ## Remove numbers from field names. # ## If true, a field name like 'temp1_input' will be changed to 'temp_input'. # # remove_numbers = true +# +# ## Timeout is the maximum amount of time that the sensors command can run. +# # timeout = "5s" + + +# # Read metrics from storage devices supporting S.M.A.R.T. +# [[inputs.smart]] +# ## Optionally specify the path to the smartctl executable +# # path = "/usr/bin/smartctl" +# # +# ## On most platforms smartctl requires root access. +# ## Setting 'use_sudo' to true will make use of sudo to run smartctl. +# ## Sudo must be configured to to allow the telegraf user to run smartctl +# ## with out password. +# # use_sudo = false +# # +# ## Skip checking disks in this power mode. Defaults to +# ## "standby" to not wake up disks that have stoped rotating. +# ## See --nocheck in the man pages for smartctl. +# ## smartctl version 5.41 and 5.42 have faulty detection of +# ## power mode and might require changing this value to +# ## "never" depending on your disks. +# # nocheck = "standby" +# # +# ## Gather detailed metrics for each SMART Attribute. +# ## Defaults to "false" +# ## +# # attributes = false +# # +# ## Optionally specify devices to exclude from reporting. +# # excludes = [ "/dev/pass6" ] +# # +# ## Optionally specify devices and device type, if unset +# ## a scan (smartctl --scan) for S.M.A.R.T. devices will +# ## done and all found will be included except for the +# ## excluded in excludes. +# # devices = [ "/dev/ada0 -d atacam" ] # # Retrieves SNMP values from remote agents @@ -2342,11 +3358,11 @@ # sub_tables=[".1.3.6.1.2.1.2.2.1.13", "bytes_recv", "bytes_send"] -# # Read metrics from Solr Server +# # Read stats from one or more Solr servers or cores # [[inputs.solr]] # ## specify a list of one or more Solr servers # servers = ["http://localhost:8983"] -# ## +# # ## specify a list of one or more Solr cores (default - all) # # cores = ["main"] @@ -2362,6 +3378,28 @@ # # servers = [ # # "Server=192.168.1.10;Port=1433;User Id=;Password=;app name=telegraf;log=1;", # # ] +# +# ## Optional parameter, setting this to 2 will use a new version +# ## of the collection queries that break compatibility with the original +# ## dashboards. +# query_version = 2 +# +# ## If you are using AzureDB, setting this to true will gather resource utilization metrics +# # azuredb = false +# +# ## If you would like to exclude some of the metrics queries, list them here +# ## Possible choices: +# ## - PerformanceCounters +# ## - WaitStatsCategorized +# ## - DatabaseIO +# ## - DatabaseProperties +# ## - CPUHistory +# ## - DatabaseSize +# ## - DatabaseStats +# ## - MemoryClerk +# ## - VolumeSpace +# ## - PerformanceMetrics +# # exclude_query = [ 'DatabaseIO' ] # # Sysstat metrics collector @@ -2395,7 +3433,7 @@ # # # # # ## Options for the sadf command. The values on the left represent the sadf -# ## options and the values on the right their description (wich are used for +# ## options and the values on the right their description (which are used for # ## grouping and prefixing metrics). # ## # ## Run 'sar -h' or 'man sar' to find out the supported options for your @@ -2426,6 +3464,39 @@ # # vg = "rootvg" +# # Reads metrics from a Teamspeak 3 Server via ServerQuery +# [[inputs.teamspeak]] +# ## Server address for Teamspeak 3 ServerQuery +# # server = "127.0.0.1:10011" +# ## Username for ServerQuery +# username = "serverqueryuser" +# ## Password for ServerQuery +# password = "secret" +# ## Array of virtual servers +# # virtual_servers = [1] + + +# # Read metrics about temperature +# [[inputs.temp]] +# # no configuration + + +# # Read Tengine's basic status information (ngx_http_reqstat_module) +# [[inputs.tengine]] +# # An array of Tengine reqstat module URI to gather stats. +# urls = ["http://127.0.0.1/us"] +# +# # HTTP response timeout (default: 5s) +# # response_timeout = "5s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.cer" +# # tls_key = "/etc/telegraf/key.key" +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false + + # # Gather metrics from the Tomcat server status page. # [[inputs.tomcat]] # ## URL of the Tomcat server status @@ -2438,11 +3509,11 @@ # ## Request timeout # # timeout = "5s" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false @@ -2460,6 +3531,29 @@ # pools = ["redis_pool", "mc_pool"] +# # A plugin to collect stats from the Unbound DNS resolver +# [[inputs.unbound]] +# ## Address of server to connect to, read from unbound conf default, optionally ':port' +# ## Will lookup IP if given a hostname +# server = "127.0.0.1:8953" +# +# ## If running as a restricted user you can prepend sudo for additional access: +# # use_sudo = false +# +# ## The default location of the unbound-control binary can be overridden with: +# # binary = "/usr/sbin/unbound-control" +# +# ## The default timeout of 1s can be overriden with: +# # timeout = "1s" +# +# ## When set to true, thread metrics are tagged with the thread id. +# ## +# ## The default is false for backwards compatibility, and will be change to +# ## true in a future version. It is recommended to set to true on new +# ## deployments. +# thread_as_tag = false + + # # A plugin to collect stats from Varnish HTTP Cache # [[inputs.varnish]] # ## If running as a restricted user you can prepend sudo for additional access: @@ -2473,6 +3567,27 @@ # ## Glob matching can be used, ie, stats = ["MAIN.*"] # ## stats may also be set to ["*"], which will collect all stats # stats = ["MAIN.cache_hit", "MAIN.cache_miss", "MAIN.uptime"] +# +# ## Optional name for the varnish instance (or working directory) to query +# ## Usually appened after -n in varnish cli +# # instance_name = instanceName + + +# # Reads metrics from a SSL certificate +# [[inputs.x509_cert]] +# ## List certificate sources +# sources = ["/etc/ssl/certs/ssl-cert-snakeoil.pem", "tcp://example.org:443"] +# +# ## Timeout for SSL connection +# # timeout = "5s" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# +# ## Use TLS but skip chain & host verification +# # insecure_skip_verify = false # # Read metrics of ZFS from arcstats, zfetchstats, vdev_cache_stats, and pools @@ -2484,7 +3599,9 @@ # ## By default, telegraf gather all zfs stats # ## If not specified, then default is: # # kstatMetrics = ["arcstats", "zfetchstats", "vdev_cache_stats"] -# +# ## For Linux, the default is: +# # kstatMetrics = ["abdstats", "arcstats", "dnodestats", "dbufcachestats", +# # "dmu_tx", "fm", "vdev_mirror_stats", "zfetchstats", "zil"] # ## By default, don't gather zpool stats # # poolMetrics = false @@ -2497,6 +3614,17 @@ # ## If no servers are specified, then localhost is used as the host. # ## If no port is specified, 2181 is used # servers = [":2181"] +# +# ## Timeout for metric collections from all servers. Minimum timeout is "1s". +# # timeout = "5s" +# +# ## Optional TLS Config +# # enable_tls = true +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## If false, skip chain & host verification +# # insecure_skip_verify = true @@ -2506,28 +3634,57 @@ # # AMQP consumer plugin # [[inputs.amqp_consumer]] -# ## AMQP url -# url = "amqp://localhost:5672/influxdb" -# ## AMQP exchange +# ## Broker to consume from. +# ## deprecated in 1.7; use the brokers option +# # url = "amqp://localhost:5672/influxdb" +# +# ## Brokers to consume from. If multiple brokers are specified a random broker +# ## will be selected anytime a connection is established. This can be +# ## helpful for load balancing when not using a dedicated load balancer. +# brokers = ["amqp://localhost:5672/influxdb"] +# +# ## Authentication credentials for the PLAIN auth_method. +# # username = "" +# # password = "" +# +# ## Exchange to declare and consume from. # exchange = "telegraf" -# ## AMQP queue name +# +# ## Exchange type; common types are "direct", "fanout", "topic", "header", "x-consistent-hash". +# # exchange_type = "topic" +# +# ## If true, exchange will be passively declared. +# # exchange_passive = false +# +# ## Exchange durability can be either "transient" or "durable". +# # exchange_durability = "durable" +# +# ## Additional exchange arguments. +# # exchange_arguments = { } +# # exchange_arguments = {"hash_propery" = "timestamp"} +# +# ## AMQP queue name. # queue = "telegraf" -# ## Binding Key +# +# ## AMQP queue durability can be "transient" or "durable". +# queue_durability = "durable" +# +# ## Binding Key. # binding_key = "#" # # ## Maximum number of messages server should give to the worker. -# prefetch_count = 50 +# # prefetch_count = 50 # # ## Auth method. PLAIN and EXTERNAL are supported # ## Using EXTERNAL requires enabling the rabbitmq_auth_mechanism_ssl plugin as # ## described here: https://www.rabbitmq.com/plugins.html # # auth_method = "PLAIN" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## Data format to consume. @@ -2537,6 +3694,28 @@ # data_format = "influx" +# # Read Cassandra metrics through Jolokia +# [[inputs.cassandra]] +# ## DEPRECATED: The cassandra plugin has been deprecated. Please use the +# ## jolokia2 plugin instead. +# ## +# ## see https://github.com/influxdata/telegraf/tree/master/plugins/inputs/jolokia2 +# +# context = "/jolokia/read" +# ## List of cassandra servers exposing jolokia read service +# servers = ["myuser:mypassword@10.10.10.1:8778","10.10.10.2:8778",":8778"] +# ## List of metrics collected on above servers +# ## Each metric consists of a jmx path. +# ## This will collect all heap memory usage metrics from the jvm and +# ## ReadLatency metrics for all keyspaces and tables. +# ## "type=Table" in the query works with Cassandra3.0. Older versions might +# ## need to use "type=ColumnFamily" +# metrics = [ +# "/java.lang:type=Memory/HeapMemoryUsage", +# "/org.apache.cassandra.metrics:type=Table,keyspace=*,scope=*,name=ReadLatency" +# ] + + # # Influx HTTP write listener # [[inputs.http_listener]] # ## Address and port to host HTTP listener on @@ -2562,6 +3741,58 @@ # ## Add service certificate and key # tls_cert = "/etc/telegraf/cert.pem" # tls_key = "/etc/telegraf/key.pem" +# +# ## Optional username and password to accept for HTTP basic authentication. +# ## You probably want to make sure you have TLS configured above for this. +# # basic_username = "foobar" +# # basic_password = "barfoo" + + +# # Read JTI OpenConfig Telemetry from listed sensors +# [[inputs.jti_openconfig_telemetry]] +# ## List of device addresses to collect telemetry from +# servers = ["localhost:1883"] +# +# ## Authentication details. Username and password are must if device expects +# ## authentication. Client ID must be unique when connecting from multiple instances +# ## of telegraf to the same device +# username = "user" +# password = "pass" +# client_id = "telegraf" +# +# ## Frequency to get data +# sample_frequency = "1000ms" +# +# ## Sensors to subscribe for +# ## A identifier for each sensor can be provided in path by separating with space +# ## Else sensor path will be used as identifier +# ## When identifier is used, we can provide a list of space separated sensors. +# ## A single subscription will be created with all these sensors and data will +# ## be saved to measurement with this identifier name +# sensors = [ +# "/interfaces/", +# "collection /components/ /lldp", +# ] +# +# ## We allow specifying sensor group level reporting rate. To do this, specify the +# ## reporting rate in Duration at the beginning of sensor paths / collection +# ## name. For entries without reporting rate, we use configured sample frequency +# sensors = [ +# "1000ms customReporting /interfaces /lldp", +# "2000ms collection /components", +# "/interfaces", +# ] +# +# ## x509 Certificate to use with TLS connection. If it is not provided, an insecure +# ## channel will be opened with server +# ssl_cert = "/etc/telegraf/cert.pem" +# +# ## Delay between retry attempts of failed RPC calls or streams. Defaults to 1000ms. +# ## Failed streams/calls will not be retried if 0 is provided +# retry_delay = "1000ms" +# +# ## To treat all string values as tags, set this to true +# str_as_tags = false # # Read metrics from Kafka topic(s) @@ -2571,11 +3802,20 @@ # ## topic(s) to consume # topics = ["telegraf"] # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional Client id +# # client_id = "Telegraf" +# +# ## Set the minimal supported Kafka version. Setting this enables the use of new +# ## Kafka features and APIs. Of particular interest, lz4 compression +# ## requires at least version 0.10.0.0. +# ## ex: version = "1.1.0" +# # version = "" +# +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## Optional SASL Config @@ -2595,7 +3835,7 @@ # # ## Maximum length of a message to consume, in bytes (default 0/unlimited); # ## larger messages are dropped -# max_message_len = 65536 +# max_message_len = 1000000 # # Read metrics from Kafka topic(s) @@ -2641,7 +3881,6 @@ # # watch_method = "inotify" # # ## Parse logstash-style "grok" patterns: -# ## Telegraf built-in parsing patterns: https://goo.gl/dkay10 # [inputs.logparser.grok] # ## This is a list of patterns to check the given log file(s) for. # ## Note that adding patterns here increases processing time. The most @@ -2675,7 +3914,10 @@ # # Read metrics from MQTT topic(s) # [[inputs.mqtt_consumer]] -# servers = ["localhost:1883"] +# ## MQTT broker URLs to be used. The format should be scheme://host:port, +# ## schema can be tcp, ssl, or ws. +# servers = ["tcp://localhost:1883"] +# # ## MQTT QoS, must be 0, 1, or 2 # qos = 0 # ## Connection timeout for initial connection in seconds @@ -2699,11 +3941,11 @@ # # username = "telegraf" # # password = "metricsmetricsmetricsmetrics" # -# ## Optional SSL Config -# # ssl_ca = "/etc/telegraf/ca.pem" -# # ssl_cert = "/etc/telegraf/cert.pem" -# # ssl_key = "/etc/telegraf/key.pem" -# ## Use SSL but skip chain & host verification +# ## Optional TLS Config +# # tls_ca = "/etc/telegraf/ca.pem" +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Use TLS but skip chain & host verification # # insecure_skip_verify = false # # ## Data format to consume. @@ -2755,6 +3997,118 @@ # data_format = "influx" +# # Read metrics from one or many pgbouncer servers +# [[inputs.pgbouncer]] +# ## specify address via a url matching: +# ## postgres://[pqgotest[:password]]@localhost[/dbname]\ +# ## ?sslmode=[disable|verify-ca|verify-full] +# ## or a simple string: +# ## host=localhost user=pqotest password=... sslmode=... dbname=app_production +# ## +# ## All connection parameters are optional. +# ## +# address = "host=localhost user=pgbouncer sslmode=disable" + + +# # Read metrics from one or many postgresql servers +# [[inputs.postgresql]] +# ## specify address via a url matching: +# ## postgres://[pqgotest[:password]]@localhost[/dbname]\ +# ## ?sslmode=[disable|verify-ca|verify-full] +# ## or a simple string: +# ## host=localhost user=pqotest password=... sslmode=... dbname=app_production +# ## +# ## All connection parameters are optional. +# ## +# ## Without the dbname parameter, the driver will default to a database +# ## with the same name as the user. This dbname is just for instantiating a +# ## connection with the server and doesn't restrict the databases we are trying +# ## to grab metrics for. +# ## +# address = "host=localhost user=postgres sslmode=disable" +# ## A custom name for the database that will be used as the "server" tag in the +# ## measurement output. If not specified, a default one generated from +# ## the connection address is used. +# # outputaddress = "db01" +# +# ## connection configuration. +# ## maxlifetime - specify the maximum lifetime of a connection. +# ## default is forever (0s) +# max_lifetime = "0s" +# +# ## A list of databases to explicitly ignore. If not specified, metrics for all +# ## databases are gathered. Do NOT use with the 'databases' option. +# # ignored_databases = ["postgres", "template0", "template1"] +# +# ## A list of databases to pull metrics about. If not specified, metrics for all +# ## databases are gathered. Do NOT use with the 'ignored_databases' option. +# # databases = ["app_production", "testing"] + + +# # Read metrics from one or many postgresql servers +# [[inputs.postgresql_extensible]] +# ## specify address via a url matching: +# ## postgres://[pqgotest[:password]]@localhost[/dbname]\ +# ## ?sslmode=[disable|verify-ca|verify-full] +# ## or a simple string: +# ## host=localhost user=pqotest password=... sslmode=... dbname=app_production +# # +# ## All connection parameters are optional. # +# ## Without the dbname parameter, the driver will default to a database +# ## with the same name as the user. This dbname is just for instantiating a +# ## connection with the server and doesn't restrict the databases we are trying +# ## to grab metrics for. +# # +# address = "host=localhost user=postgres sslmode=disable" +# +# ## connection configuration. +# ## maxlifetime - specify the maximum lifetime of a connection. +# ## default is forever (0s) +# max_lifetime = "0s" +# +# ## A list of databases to pull metrics about. If not specified, metrics for all +# ## databases are gathered. +# ## databases = ["app_production", "testing"] +# # +# ## A custom name for the database that will be used as the "server" tag in the +# ## measurement output. If not specified, a default one generated from +# ## the connection address is used. +# # outputaddress = "db01" +# # +# ## Define the toml config where the sql queries are stored +# ## New queries can be added, if the withdbname is set to true and there is no +# ## databases defined in the 'databases field', the sql query is ended by a +# ## 'is not null' in order to make the query succeed. +# ## Example : +# ## The sqlquery : "SELECT * FROM pg_stat_database where datname" become +# ## "SELECT * FROM pg_stat_database where datname IN ('postgres', 'pgbench')" +# ## because the databases variable was set to ['postgres', 'pgbench' ] and the +# ## withdbname was true. Be careful that if the withdbname is set to false you +# ## don't have to define the where clause (aka with the dbname) the tagvalue +# ## field is used to define custom tags (separated by commas) +# ## The optional "measurement" value can be used to override the default +# ## output measurement name ("postgresql"). +# # +# ## Structure : +# ## [[inputs.postgresql_extensible.query]] +# ## sqlquery string +# ## version string +# ## withdbname boolean +# ## tagvalue string (comma separated) +# ## measurement string +# [[inputs.postgresql_extensible.query]] +# sqlquery="SELECT * FROM pg_stat_database" +# version=901 +# withdbname=false +# tagvalue="" +# measurement="" +# [[inputs.postgresql_extensible.query]] +# sqlquery="SELECT * FROM pg_stat_bgwriter" +# version=901 +# withdbname=false +# tagvalue="postgresql.stats" + + # # Generic socket listener capable of handling multiple socket types. # [[inputs.socket_listener]] # ## URL to listen on @@ -2779,6 +4133,13 @@ # ## 0 (default) is unlimited. # # read_timeout = "30s" # +# ## Optional TLS configuration. +# ## Only applies to stream sockets (e.g. TCP). +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# ## Enables client authentication if set. +# # tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] +# # ## Maximum socket buffer size in bytes. # ## For stream sockets, once the buffer fills up, the sender will start backing up. # ## For datagram sockets, once the buffer fills up, metrics will start dropping. @@ -2800,12 +4161,20 @@ # # Statsd UDP/TCP Server # [[inputs.statsd]] -# ## Protocol, must be "tcp" or "udp" (default=udp) +# ## Protocol, must be "tcp", "udp", "udp4" or "udp6" (default=udp) # protocol = "udp" # # ## MaxTCPConnection - applicable when protocol is set to tcp (default=250) # max_tcp_connections = 250 # +# ## Enable TCP keep alive probes (default=false) +# tcp_keep_alive = false +# +# ## Specifies the keep-alive period for an active network connection. +# ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false. +# ## Defaults to the OS configuration. +# # tcp_keep_alive_period = "2h" +# # ## Address and port to host UDP listener on # service_address = ":8125" # @@ -2832,7 +4201,7 @@ # parse_data_dog_tags = false # # ## Statsd data translation templates, more info can be read here: -# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#graphite +# ## https://github.com/influxdata/telegraf/blob/master/docs/TEMPLATE_PATTERN.md # # templates = [ # # "cpu.* measurement*" # # ] @@ -2847,6 +4216,46 @@ # percentile_limit = 1000 +# # Accepts syslog messages per RFC5425 +# [[inputs.syslog]] +# ## Specify an ip or hostname with port - eg., tcp://localhost:6514, tcp://10.0.0.1:6514 +# ## Protocol, address and port to host the syslog receiver. +# ## If no host is specified, then localhost is used. +# ## If no port is specified, 6514 is used (RFC5425#section-4.1). +# server = "tcp://:6514" +# +# ## TLS Config +# # tls_allowed_cacerts = ["/etc/telegraf/ca.pem"] +# # tls_cert = "/etc/telegraf/cert.pem" +# # tls_key = "/etc/telegraf/key.pem" +# +# ## Period between keep alive probes. +# ## 0 disables keep alive probes. +# ## Defaults to the OS configuration. +# ## Only applies to stream sockets (e.g. TCP). +# # keep_alive_period = "5m" +# +# ## Maximum number of concurrent connections (default = 0). +# ## 0 means unlimited. +# ## Only applies to stream sockets (e.g. TCP). +# # max_connections = 1024 +# +# ## Read timeout is the maximum time allowed for reading a single message (default = 5s). +# ## 0 means unlimited. +# # read_timeout = "5s" +# +# ## Whether to parse in best effort mode or not (default = false). +# ## By default best effort parsing is off. +# # best_effort = false +# +# ## Character to prepend to SD-PARAMs (default = "_"). +# ## A syslog message can contain multiple parameters and multiple identifiers within structured data section. +# ## Eg., [id1 name1="val1" name2="val2"][id2 name1="val1" nameA="valA"] +# ## For each combination a field is created. +# ## Its name is created concatenating identifier, sdparam_separator, and parameter name. +# # sdparam_separator = "_" + + # # Stream a log file, like the tail -f command # [[inputs.tail]] # ## files to tail. @@ -2888,6 +4297,158 @@ # # see https://github.com/influxdata/telegraf/tree/master/plugins/inputs/socket_listener +# # Read metrics from VMware vCenter +# [[inputs.vsphere]] +# ## List of vCenter URLs to be monitored. These three lines must be uncommented +# ## and edited for the plugin to work. +# vcenters = [ "https://vcenter.local/sdk" ] +# username = "user@corp.local" +# password = "secret" +# +# ## VMs +# ## Typical VM metrics (if omitted or empty, all metrics are collected) +# vm_metric_include = [ +# "cpu.demand.average", +# "cpu.idle.summation", +# "cpu.latency.average", +# "cpu.readiness.average", +# "cpu.ready.summation", +# "cpu.run.summation", +# "cpu.usagemhz.average", +# "cpu.used.summation", +# "cpu.wait.summation", +# "mem.active.average", +# "mem.granted.average", +# "mem.latency.average", +# "mem.swapin.average", +# "mem.swapinRate.average", +# "mem.swapout.average", +# "mem.swapoutRate.average", +# "mem.usage.average", +# "mem.vmmemctl.average", +# "net.bytesRx.average", +# "net.bytesTx.average", +# "net.droppedRx.summation", +# "net.droppedTx.summation", +# "net.usage.average", +# "power.power.average", +# "virtualDisk.numberReadAveraged.average", +# "virtualDisk.numberWriteAveraged.average", +# "virtualDisk.read.average", +# "virtualDisk.readOIO.latest", +# "virtualDisk.throughput.usage.average", +# "virtualDisk.totalReadLatency.average", +# "virtualDisk.totalWriteLatency.average", +# "virtualDisk.write.average", +# "virtualDisk.writeOIO.latest", +# "sys.uptime.latest", +# ] +# # vm_metric_exclude = [] ## Nothing is excluded by default +# # vm_instances = true ## true by default +# +# ## Hosts +# ## Typical host metrics (if omitted or empty, all metrics are collected) +# host_metric_include = [ +# "cpu.coreUtilization.average", +# "cpu.costop.summation", +# "cpu.demand.average", +# "cpu.idle.summation", +# "cpu.latency.average", +# "cpu.readiness.average", +# "cpu.ready.summation", +# "cpu.swapwait.summation", +# "cpu.usage.average", +# "cpu.usagemhz.average", +# "cpu.used.summation", +# "cpu.utilization.average", +# "cpu.wait.summation", +# "disk.deviceReadLatency.average", +# "disk.deviceWriteLatency.average", +# "disk.kernelReadLatency.average", +# "disk.kernelWriteLatency.average", +# "disk.numberReadAveraged.average", +# "disk.numberWriteAveraged.average", +# "disk.read.average", +# "disk.totalReadLatency.average", +# "disk.totalWriteLatency.average", +# "disk.write.average", +# "mem.active.average", +# "mem.latency.average", +# "mem.state.latest", +# "mem.swapin.average", +# "mem.swapinRate.average", +# "mem.swapout.average", +# "mem.swapoutRate.average", +# "mem.totalCapacity.average", +# "mem.usage.average", +# "mem.vmmemctl.average", +# "net.bytesRx.average", +# "net.bytesTx.average", +# "net.droppedRx.summation", +# "net.droppedTx.summation", +# "net.errorsRx.summation", +# "net.errorsTx.summation", +# "net.usage.average", +# "power.power.average", +# "storageAdapter.numberReadAveraged.average", +# "storageAdapter.numberWriteAveraged.average", +# "storageAdapter.read.average", +# "storageAdapter.write.average", +# "sys.uptime.latest", +# ] +# # host_metric_exclude = [] ## Nothing excluded by default +# # host_instances = true ## true by default +# +# ## Clusters +# # cluster_metric_include = [] ## if omitted or empty, all metrics are collected +# # cluster_metric_exclude = [] ## Nothing excluded by default +# # cluster_instances = true ## true by default +# +# ## Datastores +# # datastore_metric_include = [] ## if omitted or empty, all metrics are collected +# # datastore_metric_exclude = [] ## Nothing excluded by default +# # datastore_instances = false ## false by default for Datastores only +# +# ## Datacenters +# datacenter_metric_include = [] ## if omitted or empty, all metrics are collected +# datacenter_metric_exclude = [ "*" ] ## Datacenters are not collected by default. +# # datacenter_instances = false ## false by default for Datastores only +# +# ## Plugin Settings +# ## separator character to use for measurement and field names (default: "_") +# # separator = "_" +# +# ## number of objects to retreive per query for realtime resources (vms and hosts) +# ## set to 64 for vCenter 5.5 and 6.0 (default: 256) +# # max_query_objects = 256 +# +# ## number of metrics to retreive per query for non-realtime resources (clusters and datastores) +# ## set to 64 for vCenter 5.5 and 6.0 (default: 256) +# # max_query_metrics = 256 +# +# ## number of go routines to use for collection and discovery of objects and metrics +# # collect_concurrency = 1 +# # discover_concurrency = 1 +# +# ## whether or not to force discovery of new objects on initial gather call before collecting metrics +# ## when true for large environments this may cause errors for time elapsed while collecting metrics +# ## when false (default) the first collection cycle may result in no or limited metrics while objects are discovered +# # force_discover_on_init = false +# +# ## the interval before (re)discovering objects subject to metrics collection (default: 300s) +# # object_discovery_interval = "300s" +# +# ## timeout applies to any of the api request made to vcenter +# # timeout = "20s" +# +# ## Optional SSL Config +# # ssl_ca = "/path/to/cafile" +# # ssl_cert = "/path/to/certfile" +# # ssl_key = "/path/to/keyfile" +# ## Use SSL but skip chain & host verification +# # insecure_skip_verify = false + + # # A Webhooks Event collector # [[inputs.webhooks]] # ## Address and port to host Webhook listener on @@ -2908,6 +4469,9 @@ # # [inputs.webhooks.papertrail] # path = "/papertrail" +# +# [inputs.webhooks.particle] +# path = "/particle" # # This plugin implements the Zipkin http server to gather trace and timing data needed to troubleshoot latency problems in microservice architectures. diff --git a/etc/telegraf_windows.conf b/etc/telegraf_windows.conf index ed5ce1fb..220944d4 100644 --- a/etc/telegraf_windows.conf +++ b/etc/telegraf_windows.conf @@ -205,20 +205,6 @@ Instances = ["_Total"] Measurement = "win_swap" - [[inputs.win_perf_counters.object]] - ObjectName = "Network Interface" - Instances = ["*"] - Counters = [ - "Bytes Sent/sec", - "Bytes Received/sec", - "Packets Sent/sec", - "Packets Received/sec", - "Packets Received Discarded", - "Packets Received Errors", - "Packets Outbound Discarded", - "Packets Outbound Errors", - ] - # Windows system plugins using WMI (disabled by default, using @@ -242,7 +228,7 @@ # # ## Ignore some mountpoints by filesystem type. For example (dev)tmpfs (usually # ## present on /run, /var/run, /dev/shm or /dev). -# # ignore_fs = ["tmpfs", "devtmpfs"] +# # ignore_fs = ["tmpfs", "devtmpfs", "devfs", "overlay", "aufs", "squashfs"] # # Read metrics about disk IO by device diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index cdc81fed..6a460ecc 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -14,9 +14,12 @@ var ( // Buffer is an object for storing metrics in a circular buffer. type Buffer struct { - buf chan telegraf.Metric - - mu sync.Mutex + sync.Mutex + buf []telegraf.Metric + first int + last int + size int + empty bool } // NewBuffer returns a Buffer @@ -24,33 +27,58 @@ type Buffer struct { // called when the buffer is full, then the oldest metric(s) will be dropped. func NewBuffer(size int) *Buffer { return &Buffer{ - buf: make(chan telegraf.Metric, size), + buf: make([]telegraf.Metric, size), + first: 0, + last: 0, + size: size, + empty: true, } } // IsEmpty returns true if Buffer is empty. func (b *Buffer) IsEmpty() bool { - return len(b.buf) == 0 + return b.empty } // Len returns the current length of the buffer. func (b *Buffer) Len() int { - return len(b.buf) + if b.empty { + return 0 + } else if b.first <= b.last { + return b.last - b.first + 1 + } + // Spans the end of array. + // size - gap in the middle + return b.size - (b.first - b.last - 1) // size - gap +} + +func (b *Buffer) push(m telegraf.Metric) { + // Empty + if b.empty { + b.last = b.first // Reset + b.buf[b.last] = m + b.empty = false + return + } + + b.last++ + b.last %= b.size + + // Full + if b.first == b.last { + MetricsDropped.Incr(1) + b.first = (b.first + 1) % b.size + } + b.buf[b.last] = m } // Add adds metrics to the buffer. func (b *Buffer) Add(metrics ...telegraf.Metric) { - for i, _ := range metrics { + b.Lock() + defer b.Unlock() + for i := range metrics { MetricsWritten.Incr(1) - select { - case b.buf <- metrics[i]: - default: - b.mu.Lock() - MetricsDropped.Incr(1) - <-b.buf - b.buf <- metrics[i] - b.mu.Unlock() - } + b.push(metrics[i]) } } @@ -58,13 +86,39 @@ func (b *Buffer) Add(metrics ...telegraf.Metric) { // the batch will be of maximum length batchSize. It can be less than batchSize, // if the length of Buffer is less than batchSize. func (b *Buffer) Batch(batchSize int) []telegraf.Metric { - b.mu.Lock() - n := min(len(b.buf), batchSize) - out := make([]telegraf.Metric, n) - for i := 0; i < n; i++ { - out[i] = <-b.buf + b.Lock() + defer b.Unlock() + outLen := min(b.Len(), batchSize) + out := make([]telegraf.Metric, outLen) + if outLen == 0 { + return out + } + + // We copy everything right of first up to last, count or end + // b.last >= rightInd || b.last < b.first + // therefore wont copy past b.last + rightInd := min(b.size, b.first+outLen) - 1 + + copyCount := copy(out, b.buf[b.first:rightInd+1]) + + // We've emptied the ring + if rightInd == b.last { + b.empty = true + } + b.first = rightInd + 1 + b.first %= b.size + + // We circle back for the rest + if copyCount < outLen { + right := min(b.last, outLen-copyCount) + copy(out[copyCount:], b.buf[b.first:right+1]) + // We've emptied the ring + if right == b.last { + b.empty = true + } + b.first = right + 1 + b.first %= b.size } - b.mu.Unlock() return out } diff --git a/internal/buffer/buffer_test.go b/internal/buffer/buffer_test.go index f84d8c66..b3f666fd 100644 --- a/internal/buffer/buffer_test.go +++ b/internal/buffer/buffer_test.go @@ -1,6 +1,8 @@ package buffer import ( + "sync" + "sync/atomic" "testing" "github.com/influxdata/telegraf" @@ -17,6 +19,107 @@ var metricList = []telegraf.Metric{ testutil.TestMetric(8, "mymetric5"), } +func makeBench5(b *testing.B, freq, batchSize int) { + const k = 1000 + var wg sync.WaitGroup + buf := NewBuffer(10000) + m := testutil.TestMetric(1, "mymetric") + + for i := 0; i < b.N; i++ { + buf.Add(m, m, m, m, m) + if i%(freq*k) == 0 { + wg.Add(1) + go func() { + buf.Batch(batchSize * k) + wg.Done() + }() + } + } + // Flush + buf.Batch(b.N) + wg.Wait() + +} +func makeBenchStrict(b *testing.B, freq, batchSize int) { + const k = 1000 + var count uint64 + var wg sync.WaitGroup + buf := NewBuffer(10000) + m := testutil.TestMetric(1, "mymetric") + + for i := 0; i < b.N; i++ { + buf.Add(m) + if i%(freq*k) == 0 { + wg.Add(1) + go func() { + defer wg.Done() + l := len(buf.Batch(batchSize * k)) + atomic.AddUint64(&count, uint64(l)) + }() + } + } + // Flush + wg.Add(1) + go func() { + l := len(buf.Batch(b.N)) + atomic.AddUint64(&count, uint64(l)) + wg.Done() + }() + + wg.Wait() + if count != uint64(b.N) { + b.Errorf("not all metrics came out. %d of %d", count, b.N) + } +} +func makeBench(b *testing.B, freq, batchSize int) { + const k = 1000 + var wg sync.WaitGroup + buf := NewBuffer(10000) + m := testutil.TestMetric(1, "mymetric") + + for i := 0; i < b.N; i++ { + buf.Add(m) + if i%(freq*k) == 0 { + wg.Add(1) + go func() { + buf.Batch(batchSize * k) + wg.Done() + }() + } + } + wg.Wait() + // Flush + buf.Batch(b.N) +} + +func BenchmarkBufferBatch5Add(b *testing.B) { + makeBench5(b, 100, 101) +} +func BenchmarkBufferBigInfrequentBatchCatchup(b *testing.B) { + makeBench(b, 100, 101) +} +func BenchmarkBufferOftenBatch(b *testing.B) { + makeBench(b, 1, 1) +} +func BenchmarkBufferAlmostBatch(b *testing.B) { + makeBench(b, 10, 9) +} +func BenchmarkBufferSlowBatch(b *testing.B) { + makeBench(b, 10, 1) +} +func BenchmarkBufferBatchNoDrop(b *testing.B) { + makeBenchStrict(b, 1, 4) +} +func BenchmarkBufferCatchup(b *testing.B) { + buf := NewBuffer(10000) + m := testutil.TestMetric(1, "mymetric") + + for i := 0; i < b.N; i++ { + buf.Add(m) + } + buf.Batch(b.N) +} + func BenchmarkAddMetrics(b *testing.B) { buf := NewBuffer(10000) m := testutil.TestMetric(1, "mymetric") diff --git a/internal/config/aws/credentials.go b/internal/config/aws/credentials.go index b1f57fce..1e4f91b1 100644 --- a/internal/config/aws/credentials.go +++ b/internal/config/aws/credentials.go @@ -9,13 +9,14 @@ import ( ) type CredentialConfig struct { - Region string - AccessKey string - SecretKey string - RoleARN string - Profile string - Filename string - Token string + Region string + AccessKey string + SecretKey string + RoleARN string + Profile string + Filename string + Token string + EndpointURL string } func (c *CredentialConfig) Credentials() client.ConfigProvider { @@ -28,7 +29,8 @@ func (c *CredentialConfig) Credentials() client.ConfigProvider { func (c *CredentialConfig) rootCredentials() client.ConfigProvider { config := &aws.Config{ - Region: aws.String(c.Region), + Region: aws.String(c.Region), + Endpoint: &c.EndpointURL, } if c.AccessKey != "" || c.SecretKey != "" { config.Credentials = credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token) @@ -42,7 +44,8 @@ func (c *CredentialConfig) rootCredentials() client.ConfigProvider { func (c *CredentialConfig) assumeCredentials() client.ConfigProvider { rootCredentials := c.rootCredentials() config := &aws.Config{ - Region: aws.String(c.Region), + Region: aws.String(c.Region), + Endpoint: &c.EndpointURL, } config.Credentials = stscreds.NewCredentials(rootCredentials, c.RoleARN) return session.New(config) diff --git a/internal/config/config.go b/internal/config/config.go index 98d68f9e..3d051097 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -9,6 +9,7 @@ import ( "math" "os" "path/filepath" + "regexp" "runtime" "sort" @@ -40,6 +41,11 @@ var ( // envVarRe is a regex to find environment variables in the config file envVarRe = regexp.MustCompile(`\$\w+`) + + envVarEscaper = strings.NewReplacer( + `"`, `\"`, + `\`, `\\`, + ) ) // Config specifies the URL/user/password for the database that telegraf @@ -150,6 +156,24 @@ func (c *Config) InputNames() []string { return name } +// Outputs returns a list of strings of the configured aggregators. +func (c *Config) AggregatorNames() []string { + var name []string + for _, aggregator := range c.Aggregators { + name = append(name, aggregator.Name()) + } + return name +} + +// Outputs returns a list of strings of the configured processors. +func (c *Config) ProcessorNames() []string { + var name []string + for _, processor := range c.Processors { + name = append(name, processor.Name) + } + return name +} + // Outputs returns a list of strings of the configured outputs. func (c *Config) OutputNames() []string { var name []string @@ -222,8 +246,8 @@ var header = `# Telegraf Configuration ## same time, which can have a measurable effect on the system. collection_jitter = "0s" - ## Default flushing interval for all outputs. You shouldn't set this below - ## interval. Maximum flush_interval will be flush_interval + flush_jitter + ## Default flushing interval for all outputs. Maximum flush_interval will be + ## flush_interval + flush_jitter flush_interval = "10s" ## Jitter the flush interval by a random amount. This is primarily to avoid ## large write spikes for users running a large number of telegraf instances. @@ -513,7 +537,13 @@ func (c *Config) LoadDirectory(path string) error { log.Printf("W! Telegraf is not permitted to read %s", thispath) return nil } + if info.IsDir() { + if strings.HasPrefix(info.Name(), "..") { + // skip Kubernetes mounts, prevening loading the same config twice + return filepath.SkipDir + } + return nil } name := info.Name() @@ -689,6 +719,11 @@ func trimBOM(f []byte) []byte { return bytes.TrimPrefix(f, []byte("\xef\xbb\xbf")) } +// escapeEnv escapes a value for inserting into a TOML string. +func escapeEnv(value string) string { + return envVarEscaper.Replace(value) +} + // parseFile loads a TOML configuration from a provided path and // returns the AST produced from the TOML parser. When loading the file, it // will find environment variables and replace them. @@ -702,8 +737,9 @@ func parseFile(fpath string) (*ast.Table, error) { env_vars := envVarRe.FindAll(contents, -1) for _, env_var := range env_vars { - env_val := os.Getenv(strings.TrimPrefix(string(env_var), "$")) - if env_val != "" { + env_val, ok := os.LookupEnv(strings.TrimPrefix(string(env_var), "$")) + if ok { + env_val = escapeEnv(env_val) contents = bytes.Replace(contents, env_var, []byte(env_val), 1) } } @@ -819,6 +855,17 @@ func (c *Config) addInput(name string, table *ast.Table) error { t.SetParser(parser) } + switch t := input.(type) { + case parsers.ParserFuncInput: + config, err := getParserConfig(name, table) + if err != nil { + return err + } + t.SetParserFunc(func() (parsers.Parser, error) { + return parsers.NewParser(config) + }) + } + pluginConfig, err := buildInput(name, table) if err != nil { return err @@ -837,14 +884,6 @@ func (c *Config) addInput(name string, table *ast.Table) error { // builds the filter and returns a // models.AggregatorConfig to be inserted into models.RunningAggregator func buildAggregator(name string, tbl *ast.Table) (*models.AggregatorConfig, error) { - unsupportedFields := []string{"tagexclude", "taginclude"} - for _, field := range unsupportedFields { - if _, ok := tbl.Fields[field]; ok { - return nil, fmt.Errorf("%s is not supported for aggregator plugins (%s).", - field, name) - } - } - conf := &models.AggregatorConfig{ Name: name, Delay: time.Millisecond * 100, @@ -942,13 +981,6 @@ func buildAggregator(name string, tbl *ast.Table) (*models.AggregatorConfig, err // models.ProcessorConfig to be inserted into models.RunningProcessor func buildProcessor(name string, tbl *ast.Table) (*models.ProcessorConfig, error) { conf := &models.ProcessorConfig{Name: name} - unsupportedFields := []string{"tagexclude", "taginclude", "fielddrop", "fieldpass"} - for _, field := range unsupportedFields { - if _, ok := tbl.Fields[field]; ok { - return nil, fmt.Errorf("%s is not supported for processor plugins (%s).", - field, name) - } - } if node, ok := tbl.Fields["order"]; ok { if kv, ok := node.(*ast.KeyValue); ok { @@ -1176,6 +1208,14 @@ func buildInput(name string, tbl *ast.Table) (*models.InputConfig, error) { // a parsers.Parser object, and creates it, which can then be added onto // an Input object. func buildParser(name string, tbl *ast.Table) (parsers.Parser, error) { + config, err := getParserConfig(name, tbl) + if err != nil { + return nil, err + } + return parsers.NewParser(config) +} + +func getParserConfig(name string, tbl *ast.Table) (*parsers.Config, error) { c := &parsers.Config{} if node, ok := tbl.Fields["data_format"]; ok { @@ -1225,6 +1265,50 @@ func buildParser(name string, tbl *ast.Table) (parsers.Parser, error) { } } + if node, ok := tbl.Fields["json_string_fields"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + c.JSONStringFields = append(c.JSONStringFields, str.Value) + } + } + } + } + } + + if node, ok := tbl.Fields["json_name_key"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.JSONNameKey = str.Value + } + } + } + + if node, ok := tbl.Fields["json_query"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.JSONQuery = str.Value + } + } + } + + if node, ok := tbl.Fields["json_time_key"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.JSONTimeKey = str.Value + } + } + } + + if node, ok := tbl.Fields["json_time_format"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.JSONTimeFormat = str.Value + } + } + } + if node, ok := tbl.Fields["data_type"]; ok { if kv, ok := node.(*ast.KeyValue); ok { if str, ok := kv.Value.(*ast.String); ok { @@ -1249,6 +1333,14 @@ func buildParser(name string, tbl *ast.Table) (parsers.Parser, error) { } } + if node, ok := tbl.Fields["collectd_parse_multivalue"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.CollectdSplit = str.Value + } + } + } + if node, ok := tbl.Fields["collectd_typesdb"]; ok { if kv, ok := node.(*ast.KeyValue); ok { if ary, ok := kv.Value.(*ast.Array); ok { @@ -1261,18 +1353,254 @@ func buildParser(name string, tbl *ast.Table) (parsers.Parser, error) { } } + if node, ok := tbl.Fields["dropwizard_metric_registry_path"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.DropwizardMetricRegistryPath = str.Value + } + } + } + if node, ok := tbl.Fields["dropwizard_time_path"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.DropwizardTimePath = str.Value + } + } + } + if node, ok := tbl.Fields["dropwizard_time_format"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.DropwizardTimeFormat = str.Value + } + } + } + if node, ok := tbl.Fields["dropwizard_tags_path"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.DropwizardTagsPath = str.Value + } + } + } + c.DropwizardTagPathsMap = make(map[string]string) + if node, ok := tbl.Fields["dropwizard_tag_paths"]; ok { + if subtbl, ok := node.(*ast.Table); ok { + for name, val := range subtbl.Fields { + if kv, ok := val.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.DropwizardTagPathsMap[name] = str.Value + } + } + } + } + } + + //for grok data_format + if node, ok := tbl.Fields["grok_named_patterns"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + c.GrokNamedPatterns = append(c.GrokNamedPatterns, str.Value) + } + } + } + } + } + + if node, ok := tbl.Fields["grok_patterns"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + c.GrokPatterns = append(c.GrokPatterns, str.Value) + } + } + } + } + } + + if node, ok := tbl.Fields["grok_custom_patterns"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.GrokCustomPatterns = str.Value + } + } + } + + if node, ok := tbl.Fields["grok_custom_pattern_files"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + c.GrokCustomPatternFiles = append(c.GrokCustomPatternFiles, str.Value) + } + } + } + } + } + + if node, ok := tbl.Fields["grok_timezone"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.GrokTimeZone = str.Value + } + } + } + + //for csv parser + if node, ok := tbl.Fields["csv_column_names"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + c.CSVColumnNames = append(c.CSVColumnNames, str.Value) + } + } + } + } + } + + if node, ok := tbl.Fields["csv_tag_columns"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if ary, ok := kv.Value.(*ast.Array); ok { + for _, elem := range ary.Value { + if str, ok := elem.(*ast.String); ok { + c.CSVTagColumns = append(c.CSVTagColumns, str.Value) + } + } + } + } + } + + if node, ok := tbl.Fields["csv_delimiter"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.CSVDelimiter = str.Value + } + } + } + + if node, ok := tbl.Fields["csv_comment"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.CSVComment = str.Value + } + } + } + + if node, ok := tbl.Fields["csv_measurement_column"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.CSVMeasurementColumn = str.Value + } + } + } + + if node, ok := tbl.Fields["csv_timestamp_column"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.CSVTimestampColumn = str.Value + } + } + } + + if node, ok := tbl.Fields["csv_timestamp_format"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.String); ok { + c.CSVTimestampFormat = str.Value + } + } + } + + if node, ok := tbl.Fields["csv_header_row_count"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if integer, ok := kv.Value.(*ast.Integer); ok { + v, err := integer.Int() + if err != nil { + return nil, err + } + c.CSVHeaderRowCount = int(v) + } + } + } + + if node, ok := tbl.Fields["csv_skip_rows"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if integer, ok := kv.Value.(*ast.Integer); ok { + v, err := integer.Int() + if err != nil { + return nil, err + } + c.CSVHeaderRowCount = int(v) + } + } + } + + if node, ok := tbl.Fields["csv_skip_columns"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if integer, ok := kv.Value.(*ast.Integer); ok { + v, err := integer.Int() + if err != nil { + return nil, err + } + c.CSVHeaderRowCount = int(v) + } + } + } + + if node, ok := tbl.Fields["csv_trim_space"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if str, ok := kv.Value.(*ast.Boolean); ok { + //for config with no quotes + val, err := strconv.ParseBool(str.Value) + c.CSVTrimSpace = val + if err != nil { + return nil, fmt.Errorf("E! parsing to bool: %v", err) + } + } + } + } + c.MetricName = name delete(tbl.Fields, "data_format") delete(tbl.Fields, "separator") delete(tbl.Fields, "templates") delete(tbl.Fields, "tag_keys") + delete(tbl.Fields, "json_name_key") + delete(tbl.Fields, "json_query") + delete(tbl.Fields, "json_string_fields") + delete(tbl.Fields, "json_time_format") + delete(tbl.Fields, "json_time_key") delete(tbl.Fields, "data_type") delete(tbl.Fields, "collectd_auth_file") delete(tbl.Fields, "collectd_security_level") delete(tbl.Fields, "collectd_typesdb") + delete(tbl.Fields, "collectd_parse_multivalue") + delete(tbl.Fields, "dropwizard_metric_registry_path") + delete(tbl.Fields, "dropwizard_time_path") + delete(tbl.Fields, "dropwizard_time_format") + delete(tbl.Fields, "dropwizard_tags_path") + delete(tbl.Fields, "dropwizard_tag_paths") + delete(tbl.Fields, "grok_named_patterns") + delete(tbl.Fields, "grok_patterns") + delete(tbl.Fields, "grok_custom_patterns") + delete(tbl.Fields, "grok_custom_pattern_files") + delete(tbl.Fields, "grok_timezone") + delete(tbl.Fields, "csv_column_names") + delete(tbl.Fields, "csv_comment") + delete(tbl.Fields, "csv_delimiter") + delete(tbl.Fields, "csv_field_columns") + delete(tbl.Fields, "csv_header_row_count") + delete(tbl.Fields, "csv_measurement_column") + delete(tbl.Fields, "csv_skip_columns") + delete(tbl.Fields, "csv_skip_rows") + delete(tbl.Fields, "csv_tag_columns") + delete(tbl.Fields, "csv_timestamp_column") + delete(tbl.Fields, "csv_timestamp_format") + delete(tbl.Fields, "csv_trim_space") - return parsers.NewParser(c) + return c, nil } // buildSerializer grabs the necessary entries from the ast.Table for creating @@ -1309,6 +1637,54 @@ func buildSerializer(name string, tbl *ast.Table) (serializers.Serializer, error } } + if node, ok := tbl.Fields["influx_max_line_bytes"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if integer, ok := kv.Value.(*ast.Integer); ok { + v, err := integer.Int() + if err != nil { + return nil, err + } + c.InfluxMaxLineBytes = int(v) + } + } + } + + if node, ok := tbl.Fields["influx_sort_fields"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if b, ok := kv.Value.(*ast.Boolean); ok { + var err error + c.InfluxSortFields, err = b.Boolean() + if err != nil { + return nil, err + } + } + } + } + + if node, ok := tbl.Fields["influx_uint_support"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if b, ok := kv.Value.(*ast.Boolean); ok { + var err error + c.InfluxUintSupport, err = b.Boolean() + if err != nil { + return nil, err + } + } + } + } + + if node, ok := tbl.Fields["graphite_tag_support"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if b, ok := kv.Value.(*ast.Boolean); ok { + var err error + c.GraphiteTagSupport, err = b.Boolean() + if err != nil { + return nil, err + } + } + } + } + if node, ok := tbl.Fields["json_timestamp_units"]; ok { if kv, ok := node.(*ast.KeyValue); ok { if str, ok := kv.Value.(*ast.String); ok { @@ -1325,10 +1701,27 @@ func buildSerializer(name string, tbl *ast.Table) (serializers.Serializer, error } } + if node, ok := tbl.Fields["splunkmetric_hec_routing"]; ok { + if kv, ok := node.(*ast.KeyValue); ok { + if b, ok := kv.Value.(*ast.Boolean); ok { + var err error + c.HecRouting, err = b.Boolean() + if err != nil { + return nil, err + } + } + } + } + + delete(tbl.Fields, "influx_max_line_bytes") + delete(tbl.Fields, "influx_sort_fields") + delete(tbl.Fields, "influx_uint_support") + delete(tbl.Fields, "graphite_tag_support") delete(tbl.Fields, "data_format") delete(tbl.Fields, "prefix") delete(tbl.Fields, "template") delete(tbl.Fields, "json_timestamp_units") + delete(tbl.Fields, "splunkmetric_hec_routing") return serializers.NewSerializer(c) } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 3498d815..b136fec8 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -143,7 +143,10 @@ func TestConfig_LoadDirectory(t *testing.T) { "Testdata did not produce correct memcached metadata.") ex := inputs.Inputs["exec"]().(*exec.Exec) - p, err := parsers.NewJSONParser("exec", nil, nil) + p, err := parsers.NewParser(&parsers.Config{ + MetricName: "exec", + DataFormat: "json", + }) assert.NoError(t, err) ex.SetParser(p) ex.Command = "/usr/bin/myothercollector --foo=bar" diff --git a/internal/config/testdata/subconfig/..4984_10_04_08_28_06.119/invalid-config.conf b/internal/config/testdata/subconfig/..4984_10_04_08_28_06.119/invalid-config.conf new file mode 100644 index 00000000..aee9abdf --- /dev/null +++ b/internal/config/testdata/subconfig/..4984_10_04_08_28_06.119/invalid-config.conf @@ -0,0 +1,4 @@ +# This invalid config file should be skipped during testing +# as it is an ..data folder + +[[outputs.influxdb diff --git a/internal/internal.go b/internal/internal.go index aae7aa77..f7d75dfb 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -4,17 +4,14 @@ import ( "bufio" "bytes" "crypto/rand" - "crypto/tls" - "crypto/x509" "errors" - "fmt" - "io/ioutil" "log" "math/big" "os" "os/exec" "strconv" "strings" + "syscall" "time" "unicode" ) @@ -112,49 +109,6 @@ func RandomString(n int) string { return string(bytes) } -// GetTLSConfig gets a tls.Config object from the given certs, key, and CA files. -// you must give the full path to the files. -// If all files are blank and InsecureSkipVerify=false, returns a nil pointer. -func GetTLSConfig( - SSLCert, SSLKey, SSLCA string, - InsecureSkipVerify bool, -) (*tls.Config, error) { - if SSLCert == "" && SSLKey == "" && SSLCA == "" && !InsecureSkipVerify { - return nil, nil - } - - t := &tls.Config{ - InsecureSkipVerify: InsecureSkipVerify, - } - - if SSLCA != "" { - caCert, err := ioutil.ReadFile(SSLCA) - if err != nil { - return nil, errors.New(fmt.Sprintf("Could not load TLS CA: %s", - err)) - } - - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - t.RootCAs = caCertPool - } - - if SSLCert != "" && SSLKey != "" { - cert, err := tls.LoadX509KeyPair(SSLCert, SSLKey) - if err != nil { - return nil, errors.New(fmt.Sprintf( - "Could not load TLS client key/certificate from %s:%s: %s", - SSLKey, SSLCert, err)) - } - - t.Certificates = []tls.Certificate{cert} - t.BuildNameToCertificate() - } - - // will be nil by default if nothing is provided - return t, nil -} - // SnakeCase converts the given string to snake case following the Golang format: // acronyms are converted to lower-case and preceded by an underscore. func SnakeCase(in string) string { @@ -199,22 +153,24 @@ func RunTimeout(c *exec.Cmd, timeout time.Duration) error { // It assumes the command has already been started. // If the command times out, it attempts to kill the process. func WaitTimeout(c *exec.Cmd, timeout time.Duration) error { - timer := time.NewTimer(timeout) - done := make(chan error) - go func() { done <- c.Wait() }() - select { - case err := <-done: - timer.Stop() - return err - case <-timer.C: - if err := c.Process.Kill(); err != nil { + timer := time.AfterFunc(timeout, func() { + err := c.Process.Kill() + if err != nil { log.Printf("E! FATAL error killing process: %s", err) - return err + return } - // wait for the command to return after killing it - <-done + }) + + err := c.Wait() + isTimeout := timer.Stop() + + if err != nil { + return err + } else if isTimeout == false { return TimeoutErr } + + return err } // RandomSleep will sleep for a random amount of time up to max. @@ -240,3 +196,15 @@ func RandomSleep(max time.Duration, shutdown chan struct{}) { return } } + +// Exit status takes the error from exec.Command +// and returns the exit status and true +// if error is not exit status, will return 0 and false +func ExitStatus(err error) (int, bool) { + if exiterr, ok := err.(*exec.ExitError); ok { + if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { + return status.ExitStatus(), true + } + } + return 0, false +} diff --git a/internal/internal_test.go b/internal/internal_test.go index 5be5b08d..ee1d2441 100644 --- a/internal/internal_test.go +++ b/internal/internal_test.go @@ -44,6 +44,9 @@ var ( ) func TestRunTimeout(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test due to random failures.") + } if sleepbin == "" { t.Skip("'sleep' binary not available on OS, skipping.") } @@ -58,6 +61,8 @@ func TestRunTimeout(t *testing.T) { } func TestCombinedOutputTimeout(t *testing.T) { + // TODO: Fix this test + t.Skip("Test failing too often, skip for now and revisit later.") if sleepbin == "" { t.Skip("'sleep' binary not available on OS, skipping.") } @@ -109,6 +114,8 @@ func TestRunError(t *testing.T) { } func TestRandomSleep(t *testing.T) { + // TODO: Fix this test + t.Skip("Test failing too often, skip for now and revisit later.") // test that zero max returns immediately s := time.Now() RandomSleep(time.Duration(0), make(chan struct{})) diff --git a/internal/limiter/limiter_test.go b/internal/limiter/limiter_test.go deleted file mode 100644 index 83c9d86f..00000000 --- a/internal/limiter/limiter_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package limiter - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestRateLimiter(t *testing.T) { - r := NewRateLimiter(5, time.Second) - ticker := time.NewTicker(time.Millisecond * 75) - - // test that we can only get 5 receives from the rate limiter - counter := 0 -outer: - for { - select { - case <-r.C: - counter++ - case <-ticker.C: - break outer - } - } - - assert.Equal(t, 5, counter) - r.Stop() - // verify that the Stop function closes the channel. - _, ok := <-r.C - assert.False(t, ok) -} - -func TestRateLimiterMultipleIterations(t *testing.T) { - r := NewRateLimiter(5, time.Millisecond*50) - ticker := time.NewTicker(time.Millisecond * 250) - - // test that we can get 15 receives from the rate limiter - counter := 0 -outer: - for { - select { - case <-ticker.C: - break outer - case <-r.C: - counter++ - } - } - - assert.True(t, counter > 10) - r.Stop() - // verify that the Stop function closes the channel. - _, ok := <-r.C - assert.False(t, ok) -} diff --git a/internal/models/filter.go b/internal/models/filter.go index 2848ccf0..664a6ff0 100644 --- a/internal/models/filter.go +++ b/internal/models/filter.go @@ -3,6 +3,7 @@ package models import ( "fmt" + "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/filter" ) @@ -93,45 +94,35 @@ func (f *Filter) Compile() error { return nil } -// Apply applies the filter to the given measurement name, fields map, and -// tags map. It will return false if the metric should be "filtered out", and -// true if the metric should "pass". -// It will modify tags & fields in-place if they need to be deleted. -func (f *Filter) Apply( - measurement string, - fields map[string]interface{}, - tags map[string]string, -) bool { +// Select returns true if the metric matches according to the +// namepass/namedrop and tagpass/tagdrop filters. The metric is not modified. +func (f *Filter) Select(metric telegraf.Metric) bool { if !f.isActive { return true } - // check if the measurement name should pass - if !f.shouldNamePass(measurement) { + if !f.shouldNamePass(metric.Name()) { return false } - // check if the tags should pass - if !f.shouldTagsPass(tags) { + if !f.shouldTagsPass(metric.TagList()) { return false } - // filter fields - for fieldkey, _ := range fields { - if !f.shouldFieldPass(fieldkey) { - delete(fields, fieldkey) - } - } - if len(fields) == 0 { - return false - } - - // filter tags - f.filterTags(tags) - return true } +// Modify removes any tags and fields from the metric according to the +// fieldpass/fielddrop and taginclude/tagexclude filters. +func (f *Filter) Modify(metric telegraf.Metric) { + if !f.isActive { + return + } + + f.filterFields(metric) + f.filterTags(metric) +} + // IsActive checking if filter is active func (f *Filter) IsActive() bool { return f.isActive @@ -140,7 +131,6 @@ func (f *Filter) IsActive() bool { // shouldNamePass returns true if the metric should pass, false if should drop // based on the drop/pass filter parameters func (f *Filter) shouldNamePass(key string) bool { - pass := func(f *Filter) bool { if f.namePass.Match(key) { return true @@ -169,44 +159,29 @@ func (f *Filter) shouldNamePass(key string) bool { // shouldFieldPass returns true if the metric should pass, false if should drop // based on the drop/pass filter parameters func (f *Filter) shouldFieldPass(key string) bool { - - pass := func(f *Filter) bool { - if f.fieldPass.Match(key) { - return true - } - return false - } - - drop := func(f *Filter) bool { - if f.fieldDrop.Match(key) { - return false - } - return true - } - if f.fieldPass != nil && f.fieldDrop != nil { - return pass(f) && drop(f) + return f.fieldPass.Match(key) && !f.fieldDrop.Match(key) } else if f.fieldPass != nil { - return pass(f) + return f.fieldPass.Match(key) } else if f.fieldDrop != nil { - return drop(f) + return !f.fieldDrop.Match(key) } - return true } // shouldTagsPass returns true if the metric should pass, false if should drop // based on the tagdrop/tagpass filter parameters -func (f *Filter) shouldTagsPass(tags map[string]string) bool { - +func (f *Filter) shouldTagsPass(tags []*telegraf.Tag) bool { pass := func(f *Filter) bool { for _, pat := range f.TagPass { if pat.filter == nil { continue } - if tagval, ok := tags[pat.Name]; ok { - if pat.filter.Match(tagval) { - return true + for _, tag := range tags { + if tag.Key == pat.Name { + if pat.filter.Match(tag.Value) { + return true + } } } } @@ -218,9 +193,11 @@ func (f *Filter) shouldTagsPass(tags map[string]string) bool { if pat.filter == nil { continue } - if tagval, ok := tags[pat.Name]; ok { - if pat.filter.Match(tagval) { - return false + for _, tag := range tags { + if tag.Key == pat.Name { + if pat.filter.Match(tag.Value) { + return false + } } } } @@ -242,22 +219,42 @@ func (f *Filter) shouldTagsPass(tags map[string]string) bool { return true } -// Apply TagInclude and TagExclude filters. -// modifies the tags map in-place. -func (f *Filter) filterTags(tags map[string]string) { - if f.tagInclude != nil { - for k, _ := range tags { - if !f.tagInclude.Match(k) { - delete(tags, k) - } +// filterFields removes fields according to fieldpass/fielddrop. +func (f *Filter) filterFields(metric telegraf.Metric) { + filterKeys := []string{} + for _, field := range metric.FieldList() { + if !f.shouldFieldPass(field.Key) { + filterKeys = append(filterKeys, field.Key) } } - if f.tagExclude != nil { - for k, _ := range tags { - if f.tagExclude.Match(k) { - delete(tags, k) + for _, key := range filterKeys { + metric.RemoveField(key) + } +} + +// filterTags removes tags according to taginclude/tagexclude. +func (f *Filter) filterTags(metric telegraf.Metric) { + filterKeys := []string{} + if f.tagInclude != nil { + for _, tag := range metric.TagList() { + if !f.tagInclude.Match(tag.Key) { + filterKeys = append(filterKeys, tag.Key) } } } + for _, key := range filterKeys { + metric.RemoveTag(key) + } + + if f.tagExclude != nil { + for _, tag := range metric.TagList() { + if f.tagExclude.Match(tag.Key) { + filterKeys = append(filterKeys, tag.Key) + } + } + } + for _, key := range filterKeys { + metric.RemoveTag(key) + } } diff --git a/internal/models/filter_test.go b/internal/models/filter_test.go index 46f16e83..16a147ca 100644 --- a/internal/models/filter_test.go +++ b/internal/models/filter_test.go @@ -2,17 +2,24 @@ package models import ( "testing" + "time" - "github.com/stretchr/testify/assert" + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/metric" "github.com/stretchr/testify/require" ) func TestFilter_ApplyEmpty(t *testing.T) { f := Filter{} require.NoError(t, f.Compile()) - assert.False(t, f.IsActive()) + require.False(t, f.IsActive()) - assert.True(t, f.Apply("m", map[string]interface{}{"value": int64(1)}, map[string]string{})) + m, err := metric.New("m", + map[string]string{}, + map[string]interface{}{"value": int64(1)}, + time.Now()) + require.NoError(t, err) + require.True(t, f.Select(m)) } func TestFilter_ApplyTagsDontPass(t *testing.T) { @@ -27,11 +34,14 @@ func TestFilter_ApplyTagsDontPass(t *testing.T) { } require.NoError(t, f.Compile()) require.NoError(t, f.Compile()) - assert.True(t, f.IsActive()) + require.True(t, f.IsActive()) - assert.False(t, f.Apply("m", + m, err := metric.New("m", + map[string]string{"cpu": "cpu-total"}, map[string]interface{}{"value": int64(1)}, - map[string]string{"cpu": "cpu-total"})) + time.Now()) + require.NoError(t, err) + require.False(t, f.Select(m)) } func TestFilter_ApplyDeleteFields(t *testing.T) { @@ -40,11 +50,19 @@ func TestFilter_ApplyDeleteFields(t *testing.T) { } require.NoError(t, f.Compile()) require.NoError(t, f.Compile()) - assert.True(t, f.IsActive()) + require.True(t, f.IsActive()) - fields := map[string]interface{}{"value": int64(1), "value2": int64(2)} - assert.True(t, f.Apply("m", fields, nil)) - assert.Equal(t, map[string]interface{}{"value2": int64(2)}, fields) + m, err := metric.New("m", + map[string]string{}, + map[string]interface{}{ + "value": int64(1), + "value2": int64(2), + }, + time.Now()) + require.NoError(t, err) + require.True(t, f.Select(m)) + f.Modify(m) + require.Equal(t, map[string]interface{}{"value2": int64(2)}, m.Fields()) } func TestFilter_ApplyDeleteAllFields(t *testing.T) { @@ -53,10 +71,19 @@ func TestFilter_ApplyDeleteAllFields(t *testing.T) { } require.NoError(t, f.Compile()) require.NoError(t, f.Compile()) - assert.True(t, f.IsActive()) + require.True(t, f.IsActive()) - fields := map[string]interface{}{"value": int64(1), "value2": int64(2)} - assert.False(t, f.Apply("m", fields, nil)) + m, err := metric.New("m", + map[string]string{}, + map[string]interface{}{ + "value": int64(1), + "value2": int64(2), + }, + time.Now()) + require.NoError(t, err) + require.True(t, f.Select(m)) + f.Modify(m) + require.Len(t, m.FieldList(), 0) } func TestFilter_Empty(t *testing.T) { @@ -230,20 +257,20 @@ func TestFilter_TagPass(t *testing.T) { } require.NoError(t, f.Compile()) - passes := []map[string]string{ - {"cpu": "cpu-total"}, - {"cpu": "cpu-0"}, - {"cpu": "cpu-1"}, - {"cpu": "cpu-2"}, - {"mem": "mem_free"}, + passes := [][]*telegraf.Tag{ + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-total"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-0"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-1"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-2"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "mem", Value: "mem_free"}}, } - drops := []map[string]string{ - {"cpu": "cputotal"}, - {"cpu": "cpu0"}, - {"cpu": "cpu1"}, - {"cpu": "cpu2"}, - {"mem": "mem_used"}, + drops := [][]*telegraf.Tag{ + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cputotal"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu0"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu1"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu2"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "mem", Value: "mem_used"}}, } for _, tags := range passes { @@ -274,20 +301,20 @@ func TestFilter_TagDrop(t *testing.T) { } require.NoError(t, f.Compile()) - drops := []map[string]string{ - {"cpu": "cpu-total"}, - {"cpu": "cpu-0"}, - {"cpu": "cpu-1"}, - {"cpu": "cpu-2"}, - {"mem": "mem_free"}, + drops := [][]*telegraf.Tag{ + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-total"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-0"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-1"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu-2"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "mem", Value: "mem_free"}}, } - passes := []map[string]string{ - {"cpu": "cputotal"}, - {"cpu": "cpu0"}, - {"cpu": "cpu1"}, - {"cpu": "cpu2"}, - {"mem": "mem_used"}, + passes := [][]*telegraf.Tag{ + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cputotal"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu0"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu1"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "cpu", Value: "cpu2"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "mem", Value: "mem_used"}}, } for _, tags := range passes { @@ -304,58 +331,70 @@ func TestFilter_TagDrop(t *testing.T) { } func TestFilter_FilterTagsNoMatches(t *testing.T) { - pretags := map[string]string{ - "host": "localhost", - "mytag": "foobar", - } + m, err := metric.New("m", + map[string]string{ + "host": "localhost", + "mytag": "foobar", + }, + map[string]interface{}{"value": int64(1)}, + time.Now()) + require.NoError(t, err) f := Filter{ TagExclude: []string{"nomatch"}, } require.NoError(t, f.Compile()) - f.filterTags(pretags) - assert.Equal(t, map[string]string{ + f.filterTags(m) + require.Equal(t, map[string]string{ "host": "localhost", "mytag": "foobar", - }, pretags) + }, m.Tags()) f = Filter{ TagInclude: []string{"nomatch"}, } require.NoError(t, f.Compile()) - f.filterTags(pretags) - assert.Equal(t, map[string]string{}, pretags) + f.filterTags(m) + require.Equal(t, map[string]string{}, m.Tags()) } func TestFilter_FilterTagsMatches(t *testing.T) { - pretags := map[string]string{ - "host": "localhost", - "mytag": "foobar", - } + m, err := metric.New("m", + map[string]string{ + "host": "localhost", + "mytag": "foobar", + }, + map[string]interface{}{"value": int64(1)}, + time.Now()) + require.NoError(t, err) f := Filter{ TagExclude: []string{"ho*"}, } require.NoError(t, f.Compile()) - f.filterTags(pretags) - assert.Equal(t, map[string]string{ + f.filterTags(m) + require.Equal(t, map[string]string{ "mytag": "foobar", - }, pretags) + }, m.Tags()) - pretags = map[string]string{ - "host": "localhost", - "mytag": "foobar", - } + m, err = metric.New("m", + map[string]string{ + "host": "localhost", + "mytag": "foobar", + }, + map[string]interface{}{"value": int64(1)}, + time.Now()) + require.NoError(t, err) f = Filter{ TagInclude: []string{"my*"}, } require.NoError(t, f.Compile()) - f.filterTags(pretags) - assert.Equal(t, map[string]string{ + f.filterTags(m) + require.Equal(t, map[string]string{ "mytag": "foobar", - }, pretags) + }, m.Tags()) } // TestFilter_FilterNamePassAndDrop used for check case when @@ -374,7 +413,7 @@ func TestFilter_FilterNamePassAndDrop(t *testing.T) { require.NoError(t, f.Compile()) for i, name := range inputData { - assert.Equal(t, f.shouldNamePass(name), expectedResult[i]) + require.Equal(t, f.shouldNamePass(name), expectedResult[i]) } } @@ -394,7 +433,7 @@ func TestFilter_FilterFieldPassAndDrop(t *testing.T) { require.NoError(t, f.Compile()) for i, field := range inputData { - assert.Equal(t, f.shouldFieldPass(field), expectedResult[i]) + require.Equal(t, f.shouldFieldPass(field), expectedResult[i]) } } @@ -402,12 +441,11 @@ func TestFilter_FilterFieldPassAndDrop(t *testing.T) { // both parameters were defined // see: https://github.com/influxdata/telegraf/issues/2860 func TestFilter_FilterTagsPassAndDrop(t *testing.T) { - - inputData := []map[string]string{ - {"tag1": "1", "tag2": "3"}, - {"tag1": "1", "tag2": "2"}, - {"tag1": "2", "tag2": "1"}, - {"tag1": "4", "tag2": "1"}, + inputData := [][]*telegraf.Tag{ + []*telegraf.Tag{&telegraf.Tag{Key: "tag1", Value: "1"}, &telegraf.Tag{Key: "tag2", Value: "3"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "tag1", Value: "1"}, &telegraf.Tag{Key: "tag2", Value: "2"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "tag1", Value: "2"}, &telegraf.Tag{Key: "tag2", Value: "1"}}, + []*telegraf.Tag{&telegraf.Tag{Key: "tag1", Value: "4"}, &telegraf.Tag{Key: "tag2", Value: "1"}}, } expectedResult := []bool{false, true, false, false} @@ -438,7 +476,7 @@ func TestFilter_FilterTagsPassAndDrop(t *testing.T) { require.NoError(t, f.Compile()) for i, tag := range inputData { - assert.Equal(t, f.shouldTagsPass(tag), expectedResult[i]) + require.Equal(t, f.shouldTagsPass(tag), expectedResult[i]) } } diff --git a/internal/models/makemetric.go b/internal/models/makemetric.go index 19d10f58..29ef5f45 100644 --- a/internal/models/makemetric.go +++ b/internal/models/makemetric.go @@ -1,166 +1,42 @@ package models import ( - "log" - "math" - "strings" - "time" - "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/metric" ) -// makemetric is used by both RunningAggregator & RunningInput -// to make metrics. -// nameOverride: override the name of the measurement being made. -// namePrefix: add this prefix to each measurement name. -// nameSuffix: add this suffix to each measurement name. -// pluginTags: these are tags that are specific to this plugin. -// daemonTags: these are daemon-wide global tags, and get applied after pluginTags. -// filter: this is a filter to apply to each metric being made. -// applyFilter: if false, the above filter is not applied to each metric. -// This is used by Aggregators, because aggregators use filters -// on incoming metrics instead of on created metrics. -// TODO refactor this to not have such a huge func signature. +// Makemetric applies new metric plugin and agent measurement and tag +// settings. func makemetric( - measurement string, - fields map[string]interface{}, - tags map[string]string, + metric telegraf.Metric, nameOverride string, namePrefix string, nameSuffix string, - pluginTags map[string]string, - daemonTags map[string]string, - filter Filter, - applyFilter bool, - mType telegraf.ValueType, - t time.Time, + tags map[string]string, + globalTags map[string]string, ) telegraf.Metric { - if len(fields) == 0 || len(measurement) == 0 { - return nil - } - if tags == nil { - tags = make(map[string]string) + if len(nameOverride) != 0 { + metric.SetName(nameOverride) } - // Override measurement name if set - if len(nameOverride) != 0 { - measurement = nameOverride - } - // Apply measurement prefix and suffix if set if len(namePrefix) != 0 { - measurement = namePrefix + measurement + metric.AddPrefix(namePrefix) } if len(nameSuffix) != 0 { - measurement = measurement + nameSuffix - } - - // Apply plugin-wide tags if set - for k, v := range pluginTags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - // Apply daemon-wide tags if set - for k, v := range daemonTags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - - // Apply the metric filter(s) - // for aggregators, the filter does not get applied when the metric is made. - // instead, the filter is applied to metric incoming into the plugin. - // ie, it gets applied in the RunningAggregator.Apply function. - if applyFilter { - if ok := filter.Apply(measurement, fields, tags); !ok { - return nil - } + metric.AddSuffix(nameSuffix) } + // Apply plugin-wide tags for k, v := range tags { - if strings.HasSuffix(k, `\`) { - log.Printf("D! Measurement [%s] tag [%s] "+ - "ends with a backslash, skipping", measurement, k) - delete(tags, k) - continue - } else if strings.HasSuffix(v, `\`) { - log.Printf("D! Measurement [%s] tag [%s] has a value "+ - "ending with a backslash, skipping", measurement, k) - delete(tags, k) - continue + if _, ok := metric.GetTag(k); !ok { + metric.AddTag(k, v) + } + } + // Apply global tags + for k, v := range globalTags { + if _, ok := metric.GetTag(k); !ok { + metric.AddTag(k, v) } } - for k, v := range fields { - if strings.HasSuffix(k, `\`) { - log.Printf("D! Measurement [%s] field [%s] "+ - "ends with a backslash, skipping", measurement, k) - delete(fields, k) - continue - } - // Validate uint64 and float64 fields - // convert all int & uint types to int64 - switch val := v.(type) { - case nil: - // delete nil fields - delete(fields, k) - case uint: - fields[k] = int64(val) - continue - case uint8: - fields[k] = int64(val) - continue - case uint16: - fields[k] = int64(val) - continue - case uint32: - fields[k] = int64(val) - continue - case int: - fields[k] = int64(val) - continue - case int8: - fields[k] = int64(val) - continue - case int16: - fields[k] = int64(val) - continue - case int32: - fields[k] = int64(val) - continue - case uint64: - // InfluxDB does not support writing uint64 - if val < uint64(9223372036854775808) { - fields[k] = int64(val) - } else { - fields[k] = int64(9223372036854775807) - } - continue - case float32: - fields[k] = float64(val) - continue - case float64: - // NaNs are invalid values in influxdb, skip measurement - if math.IsNaN(val) || math.IsInf(val, 0) { - log.Printf("D! Measurement [%s] field [%s] has a NaN or Inf "+ - "field, skipping", - measurement, k) - delete(fields, k) - continue - } - case string: - fields[k] = v - default: - fields[k] = v - } - } - - m, err := metric.New(measurement, tags, fields, t, mType) - if err != nil { - log.Printf("Error adding point [%s]: %s\n", measurement, err.Error()) - return nil - } - - return m + return metric } diff --git a/internal/models/running_aggregator.go b/internal/models/running_aggregator.go index 91e5334e..960fd313 100644 --- a/internal/models/running_aggregator.go +++ b/internal/models/running_aggregator.go @@ -1,10 +1,10 @@ package models import ( + "log" "time" "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/metric" ) type RunningAggregator struct { @@ -28,47 +28,32 @@ func NewRunningAggregator( } } -// AggregatorConfig containing configuration parameters for the running -// aggregator plugin. +// AggregatorConfig is the common config for all aggregators. type AggregatorConfig struct { - Name string + Name string + DropOriginal bool + Period time.Duration + Delay time.Duration - DropOriginal bool NameOverride string MeasurementPrefix string MeasurementSuffix string Tags map[string]string Filter Filter - - Period time.Duration - Delay time.Duration } func (r *RunningAggregator) Name() string { return "aggregators." + r.Config.Name } -func (r *RunningAggregator) MakeMetric( - measurement string, - fields map[string]interface{}, - tags map[string]string, - mType telegraf.ValueType, - t time.Time, -) telegraf.Metric { +func (r *RunningAggregator) MakeMetric(metric telegraf.Metric) telegraf.Metric { m := makemetric( - measurement, - fields, - tags, + metric, r.Config.NameOverride, r.Config.MeasurementPrefix, r.Config.MeasurementSuffix, r.Config.Tags, - nil, - r.Config.Filter, - false, - mType, - t, - ) + nil) if m != nil { m.SetAggregate(true) @@ -77,27 +62,23 @@ func (r *RunningAggregator) MakeMetric( return m } -// Add applies the given metric to the aggregator. -// Before applying to the plugin, it will run any defined filters on the metric. -// Apply returns true if the original metric should be dropped. -func (r *RunningAggregator) Add(in telegraf.Metric) bool { - if r.Config.Filter.IsActive() { - // check if the aggregator should apply this metric - name := in.Name() - fields := in.Fields() - tags := in.Tags() - t := in.Time() - if ok := r.Config.Filter.Apply(name, fields, tags); !ok { - // aggregator should not apply this metric - return false - } - - in, _ = metric.New(name, tags, fields, t) +// Add a metric to the aggregator and return true if the original metric +// should be dropped. +func (r *RunningAggregator) Add(metric telegraf.Metric) bool { + if ok := r.Config.Filter.Select(metric); !ok { + return false } - r.metrics <- in + r.Config.Filter.Modify(metric) + if len(metric.FieldList()) == 0 { + return r.Config.DropOriginal + } + + r.metrics <- metric + return r.Config.DropOriginal } + func (r *RunningAggregator) add(in telegraf.Metric) { r.a.Add(in) } @@ -114,7 +95,6 @@ func (r *RunningAggregator) reset() { // for period ticks to tell it when to push and reset the aggregator. func (r *RunningAggregator) Run( acc telegraf.Accumulator, - now time.Time, shutdown chan struct{}, ) { // The start of the period is truncated to the nearest second. @@ -133,6 +113,7 @@ func (r *RunningAggregator) Run( // 2nd interval: 00:10 - 00:20.5 // etc. // + now := time.Now() r.periodStart = now.Truncate(time.Second) truncation := now.Sub(r.periodStart) r.periodEnd = r.periodStart.Add(r.Config.Period) @@ -153,6 +134,7 @@ func (r *RunningAggregator) Run( m.Time().After(r.periodEnd.Add(truncation).Add(r.Config.Delay)) { // the metric is outside the current aggregation period, so // skip it. + log.Printf("D! aggregator: metric \"%s\" is not in the current timewindow, skipping", m.Name()) continue } r.add(m) diff --git a/internal/models/running_aggregator_test.go b/internal/models/running_aggregator_test.go index cb56dc4e..34d51364 100644 --- a/internal/models/running_aggregator_test.go +++ b/internal/models/running_aggregator_test.go @@ -1,16 +1,17 @@ package models import ( - "fmt" "sync" "sync/atomic" "testing" "time" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/testutil" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestAdd(t *testing.T) { @@ -24,15 +25,17 @@ func TestAdd(t *testing.T) { }) assert.NoError(t, ra.Config.Filter.Compile()) acc := testutil.Accumulator{} - go ra.Run(&acc, time.Now(), make(chan struct{})) + go ra.Run(&acc, make(chan struct{})) - m := ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now().Add(time.Millisecond*150), - ) + telegraf.Untyped) + require.NoError(t, err) + assert.False(t, ra.Add(m)) for { @@ -55,36 +58,39 @@ func TestAddMetricsOutsideCurrentPeriod(t *testing.T) { }) assert.NoError(t, ra.Config.Filter.Compile()) acc := testutil.Accumulator{} - go ra.Run(&acc, time.Now(), make(chan struct{})) + go ra.Run(&acc, make(chan struct{})) - // metric before current period - m := ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now().Add(-time.Hour), - ) + telegraf.Untyped) + require.NoError(t, err) + assert.False(t, ra.Add(m)) // metric after current period - m = ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err = metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now().Add(time.Hour), - ) + telegraf.Untyped) + require.NoError(t, err) assert.False(t, ra.Add(m)) // "now" metric - m = ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err = metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now().Add(time.Millisecond*50), - ) + telegraf.Untyped) + require.NoError(t, err) assert.False(t, ra.Add(m)) for { @@ -113,16 +119,17 @@ func TestAddAndPushOnePeriod(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - ra.Run(&acc, time.Now(), shutdown) + ra.Run(&acc, shutdown) }() - m := ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now().Add(time.Millisecond*100), - ) + telegraf.Untyped) + require.NoError(t, err) assert.False(t, ra.Add(m)) for { @@ -147,89 +154,28 @@ func TestAddDropOriginal(t *testing.T) { }) assert.NoError(t, ra.Config.Filter.Compile()) - m := ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now(), - ) + telegraf.Untyped) + require.NoError(t, err) assert.True(t, ra.Add(m)) // this metric name doesn't match the filter, so Add will return false - m2 := ra.MakeMetric( - "foobar", - map[string]interface{}{"value": int(101)}, + m2, err := metric.New("foobar", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, time.Now(), - ) + telegraf.Untyped) + require.NoError(t, err) assert.False(t, ra.Add(m2)) } -// make an untyped, counter, & gauge metric -func TestMakeMetricA(t *testing.T) { - now := time.Now() - ra := NewRunningAggregator(&TestAggregator{}, &AggregatorConfig{ - Name: "TestRunningAggregator", - }) - assert.Equal(t, "aggregators.TestRunningAggregator", ra.Name()) - - m := ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - map[string]string{}, - telegraf.Untyped, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) - assert.Equal( - t, - m.Type(), - telegraf.Untyped, - ) - - m = ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - map[string]string{}, - telegraf.Counter, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) - assert.Equal( - t, - m.Type(), - telegraf.Counter, - ) - - m = ra.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - map[string]string{}, - telegraf.Gauge, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) - assert.Equal( - t, - m.Type(), - telegraf.Gauge, - ) -} - type TestAggregator struct { sum int64 } diff --git a/internal/models/running_input.go b/internal/models/running_input.go index e9b757bb..fce2437c 100644 --- a/internal/models/running_input.go +++ b/internal/models/running_input.go @@ -5,6 +5,7 @@ import ( "time" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/serializers/influx" "github.com/influxdata/telegraf/selfstat" ) @@ -35,47 +36,47 @@ func NewRunningInput( } } -// InputConfig containing a name, interval, and filter +// InputConfig is the common config for all inputs. type InputConfig struct { - Name string + Name string + Interval time.Duration + NameOverride string MeasurementPrefix string MeasurementSuffix string Tags map[string]string Filter Filter - Interval time.Duration } func (r *RunningInput) Name() string { return "inputs." + r.Config.Name } -// MakeMetric either returns a metric, or returns nil if the metric doesn't -// need to be created (because of filtering, an error, etc.) -func (r *RunningInput) MakeMetric( - measurement string, - fields map[string]interface{}, - tags map[string]string, - mType telegraf.ValueType, - t time.Time, -) telegraf.Metric { +func (r *RunningInput) MakeMetric(metric telegraf.Metric) telegraf.Metric { + if ok := r.Config.Filter.Select(metric); !ok { + return nil + } + + r.Config.Filter.Modify(metric) + if len(metric.FieldList()) == 0 { + return nil + } + m := makemetric( - measurement, - fields, - tags, + metric, r.Config.NameOverride, r.Config.MeasurementPrefix, r.Config.MeasurementSuffix, r.Config.Tags, - r.defaultTags, - r.Config.Filter, - true, - mType, - t, - ) + r.defaultTags) if r.trace && m != nil { - fmt.Print("> " + m.String()) + s := influx.NewSerializer() + s.SetFieldSortOrder(influx.SortFields) + octets, err := s.Serialize(m) + if err == nil { + fmt.Print("> " + string(octets)) + } } r.MetricsGathered.Incr(1) diff --git a/internal/models/running_input_test.go b/internal/models/running_input_test.go index c653090e..b83f75ea 100644 --- a/internal/models/running_input_test.go +++ b/internal/models/running_input_test.go @@ -1,12 +1,11 @@ package models import ( - "fmt" - "math" "testing" "time" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/metric" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -18,13 +17,13 @@ func TestMakeMetricNoFields(t *testing.T) { Name: "TestRunningInput", }) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{}, now, - ) + telegraf.Untyped) + m = ri.MakeMetric(m) + require.NoError(t, err) assert.Nil(t, m) } @@ -35,87 +34,27 @@ func TestMakeMetricNilFields(t *testing.T) { Name: "TestRunningInput", }) - m := ri.MakeMetric( - "RITest", + m, err := metric.New("RITest", + map[string]string{}, map[string]interface{}{ - "value": int(101), + "value": int64(101), "nil": nil, }, + now, + telegraf.Untyped) + require.NoError(t, err) + m = ri.MakeMetric(m) + + expected, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int(101), + }, now, ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) -} + require.NoError(t, err) -// make an untyped, counter, & gauge metric -func TestMakeMetric(t *testing.T) { - now := time.Now() - ri := NewRunningInput(&testInput{}, &InputConfig{ - Name: "TestRunningInput", - }) - - ri.SetTrace(true) - assert.Equal(t, true, ri.Trace()) - assert.Equal(t, "inputs.TestRunningInput", ri.Name()) - - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - map[string]string{}, - telegraf.Untyped, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) - assert.Equal( - t, - m.Type(), - telegraf.Untyped, - ) - - m = ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - map[string]string{}, - telegraf.Counter, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) - assert.Equal( - t, - m.Type(), - telegraf.Counter, - ) - - m = ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - map[string]string{}, - telegraf.Gauge, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) - assert.Equal( - t, - m.Type(), - telegraf.Gauge, - ) + require.Equal(t, expected, m) } func TestMakeMetricWithPluginTags(t *testing.T) { @@ -130,18 +69,27 @@ func TestMakeMetricWithPluginTags(t *testing.T) { ri.SetTrace(true) assert.Equal(t, true, ri.Trace()) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - nil, - telegraf.Untyped, + m, err := metric.New("RITest", + map[string]string{}, + map[string]interface{}{ + "value": int64(101), + }, + now, + telegraf.Untyped) + require.NoError(t, err) + m = ri.MakeMetric(m) + + expected, err := metric.New("RITest", + map[string]string{ + "foo": "bar", + }, + map[string]interface{}{ + "value": 101, + }, now, ) - assert.Equal( - t, - fmt.Sprintf("RITest,foo=bar value=101i %d\n", now.UnixNano()), - m.String(), - ) + require.NoError(t, err) + require.Equal(t, expected, m) } func TestMakeMetricFilteredOut(t *testing.T) { @@ -158,13 +106,15 @@ func TestMakeMetricFilteredOut(t *testing.T) { assert.Equal(t, true, ri.Trace()) assert.NoError(t, ri.Config.Filter.Compile()) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, - nil, - telegraf.Untyped, + m, err := metric.New("RITest", + map[string]string{}, + map[string]interface{}{ + "value": int64(101), + }, now, - ) + telegraf.Untyped) + m = ri.MakeMetric(m) + require.NoError(t, err) assert.Nil(t, m) } @@ -180,94 +130,26 @@ func TestMakeMetricWithDaemonTags(t *testing.T) { ri.SetTrace(true) assert.Equal(t, true, ri.Trace()) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, - now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest,foo=bar value=101i %d\n", now.UnixNano()), - m.String(), - ) -} - -// make an untyped, counter, & gauge metric -func TestMakeMetricInfFields(t *testing.T) { - inf := math.Inf(1) - ninf := math.Inf(-1) - now := time.Now() - ri := NewRunningInput(&testInput{}, &InputConfig{ - Name: "TestRunningInput", - }) - - ri.SetTrace(true) - assert.Equal(t, true, ri.Trace()) - - m := ri.MakeMetric( - "RITest", map[string]interface{}{ - "value": int(101), - "inf": inf, - "ninf": ninf, + "value": int64(101), }, - map[string]string{}, - telegraf.Untyped, now, - ) - assert.Equal( - t, - fmt.Sprintf("RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) -} - -func TestMakeMetricAllFieldTypes(t *testing.T) { - now := time.Now() - ri := NewRunningInput(&testInput{}, &InputConfig{ - Name: "TestRunningInput", - }) - - ri.SetTrace(true) - assert.Equal(t, true, ri.Trace()) - - m := ri.MakeMetric( - "RITest", + telegraf.Untyped) + require.NoError(t, err) + m = ri.MakeMetric(m) + expected, err := metric.New("RITest", + map[string]string{ + "foo": "bar", + }, map[string]interface{}{ - "a": int(10), - "b": int8(10), - "c": int16(10), - "d": int32(10), - "e": uint(10), - "f": uint8(10), - "g": uint16(10), - "h": uint32(10), - "i": uint64(10), - "j": float32(10), - "k": uint64(9223372036854775810), - "l": "foobar", - "m": true, + "value": 101, }, - map[string]string{}, - telegraf.Untyped, now, ) - assert.Contains(t, m.String(), "a=10i") - assert.Contains(t, m.String(), "b=10i") - assert.Contains(t, m.String(), "c=10i") - assert.Contains(t, m.String(), "d=10i") - assert.Contains(t, m.String(), "e=10i") - assert.Contains(t, m.String(), "f=10i") - assert.Contains(t, m.String(), "g=10i") - assert.Contains(t, m.String(), "h=10i") - assert.Contains(t, m.String(), "i=10i") - assert.Contains(t, m.String(), "j=10") - assert.NotContains(t, m.String(), "j=10i") - assert.Contains(t, m.String(), "k=9223372036854775807i") - assert.Contains(t, m.String(), "l=\"foobar\"") - assert.Contains(t, m.String(), "m=true") + require.NoError(t, err) + require.Equal(t, expected, m) } func TestMakeMetricNameOverride(t *testing.T) { @@ -277,18 +159,24 @@ func TestMakeMetricNameOverride(t *testing.T) { NameOverride: "foobar", }) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, + now, + telegraf.Untyped) + require.NoError(t, err) + m = ri.MakeMetric(m) + expected, err := metric.New("foobar", + nil, + map[string]interface{}{ + "value": 101, + }, now, ) - assert.Equal( - t, - fmt.Sprintf("foobar value=101i %d\n", now.UnixNano()), - m.String(), - ) + require.NoError(t, err) + require.Equal(t, expected, m) } func TestMakeMetricNamePrefix(t *testing.T) { @@ -298,18 +186,24 @@ func TestMakeMetricNamePrefix(t *testing.T) { MeasurementPrefix: "foobar_", }) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, + now, + telegraf.Untyped) + require.NoError(t, err) + m = ri.MakeMetric(m) + expected, err := metric.New("foobar_RITest", + nil, + map[string]interface{}{ + "value": 101, + }, now, ) - assert.Equal( - t, - fmt.Sprintf("foobar_RITest value=101i %d\n", now.UnixNano()), - m.String(), - ) + require.NoError(t, err) + require.Equal(t, expected, m) } func TestMakeMetricNameSuffix(t *testing.T) { @@ -319,141 +213,24 @@ func TestMakeMetricNameSuffix(t *testing.T) { MeasurementSuffix: "_foobar", }) - m := ri.MakeMetric( - "RITest", - map[string]interface{}{"value": int(101)}, + m, err := metric.New("RITest", map[string]string{}, - telegraf.Untyped, + map[string]interface{}{ + "value": int64(101), + }, + now, + telegraf.Untyped) + require.NoError(t, err) + m = ri.MakeMetric(m) + expected, err := metric.New("RITest_foobar", + nil, + map[string]interface{}{ + "value": 101, + }, now, ) - assert.Equal( - t, - fmt.Sprintf("RITest_foobar value=101i %d\n", now.UnixNano()), - m.String(), - ) -} - -func TestMakeMetric_TrailingSlash(t *testing.T) { - now := time.Now() - - tests := []struct { - name string - measurement string - fields map[string]interface{} - tags map[string]string - expectedNil bool - expectedMeasurement string - expectedFields map[string]interface{} - expectedTags map[string]string - }{ - { - name: "Measurement cannot have trailing slash", - measurement: `cpu\`, - fields: map[string]interface{}{ - "value": int64(42), - }, - tags: map[string]string{}, - expectedNil: true, - }, - { - name: "Field key with trailing slash dropped", - measurement: `cpu`, - fields: map[string]interface{}{ - "value": int64(42), - `bad\`: `xyzzy`, - }, - tags: map[string]string{}, - expectedMeasurement: `cpu`, - expectedFields: map[string]interface{}{ - "value": int64(42), - }, - expectedTags: map[string]string{}, - }, - { - name: "Field value with trailing slash okay", - measurement: `cpu`, - fields: map[string]interface{}{ - "value": int64(42), - "ok": `xyzzy\`, - }, - tags: map[string]string{}, - expectedMeasurement: `cpu`, - expectedFields: map[string]interface{}{ - "value": int64(42), - "ok": `xyzzy\`, - }, - expectedTags: map[string]string{}, - }, - { - name: "Must have one field after dropped", - measurement: `cpu`, - fields: map[string]interface{}{ - "bad": math.NaN(), - }, - tags: map[string]string{}, - expectedNil: true, - }, - { - name: "Tag key with trailing slash dropped", - measurement: `cpu`, - fields: map[string]interface{}{ - "value": int64(42), - }, - tags: map[string]string{ - `host\`: "localhost", - "a": "x", - }, - expectedMeasurement: `cpu`, - expectedFields: map[string]interface{}{ - "value": int64(42), - }, - expectedTags: map[string]string{ - "a": "x", - }, - }, - { - name: "Tag value with trailing slash dropped", - measurement: `cpu`, - fields: map[string]interface{}{ - "value": int64(42), - }, - tags: map[string]string{ - `host`: `localhost\`, - "a": "x", - }, - expectedMeasurement: `cpu`, - expectedFields: map[string]interface{}{ - "value": int64(42), - }, - expectedTags: map[string]string{ - "a": "x", - }, - }, - } - - ri := NewRunningInput(&testInput{}, &InputConfig{ - Name: "TestRunningInput", - }) - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - m := ri.MakeMetric( - tc.measurement, - tc.fields, - tc.tags, - telegraf.Untyped, - now) - - if tc.expectedNil { - require.Nil(t, m) - } else { - require.NotNil(t, m) - require.Equal(t, tc.expectedMeasurement, m.Name()) - require.Equal(t, tc.expectedFields, m.Fields()) - require.Equal(t, tc.expectedTags, m.Tags()) - } - }) - } + require.NoError(t, err) + require.Equal(t, expected, m) } type testInput struct{} diff --git a/internal/models/running_output.go b/internal/models/running_output.go index 335fb792..0f2c138a 100644 --- a/internal/models/running_output.go +++ b/internal/models/running_output.go @@ -7,7 +7,6 @@ import ( "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/internal/buffer" - "github.com/influxdata/telegraf/metric" "github.com/influxdata/telegraf/selfstat" ) @@ -36,8 +35,16 @@ type RunningOutput struct { metrics *buffer.Buffer failMetrics *buffer.Buffer + // Guards against concurrent calls to Add, Push, Reset + aggMutex sync.Mutex // Guards against concurrent calls to the Output as described in #3009 - sync.Mutex + writeMutex sync.Mutex +} + +// OutputConfig containing name and filter +type OutputConfig struct { + Name string + Filter Filter } func NewRunningOutput( @@ -87,44 +94,51 @@ func NewRunningOutput( map[string]string{"output": name}, ), } - ro.BufferLimit.Incr(int64(ro.MetricBufferLimit)) + ro.BufferLimit.Set(int64(ro.MetricBufferLimit)) return ro } // AddMetric adds a metric to the output. This function can also write cached // points if FlushBufferWhenFull is true. -func (ro *RunningOutput) AddMetric(m telegraf.Metric) { - if m == nil { +func (ro *RunningOutput) AddMetric(metric telegraf.Metric) { + if ok := ro.Config.Filter.Select(metric); !ok { + ro.MetricsFiltered.Incr(1) return } - // Filter any tagexclude/taginclude parameters before adding metric - if ro.Config.Filter.IsActive() { - // In order to filter out tags, we need to create a new metric, since - // metrics are immutable once created. - name := m.Name() - tags := m.Tags() - fields := m.Fields() - t := m.Time() - if ok := ro.Config.Filter.Apply(name, fields, tags); !ok { - ro.MetricsFiltered.Incr(1) - return - } - // error is not possible if creating from another metric, so ignore. - m, _ = metric.New(name, tags, fields, t) + + ro.Config.Filter.Modify(metric) + if len(metric.FieldList()) == 0 { + return } - ro.metrics.Add(m) + if output, ok := ro.Output.(telegraf.AggregatingOutput); ok { + ro.aggMutex.Lock() + output.Add(metric) + ro.aggMutex.Unlock() + return + } + + ro.metrics.Add(metric) if ro.metrics.Len() == ro.MetricBatchSize { batch := ro.metrics.Batch(ro.MetricBatchSize) err := ro.write(batch) if err != nil { ro.failMetrics.Add(batch...) + log.Printf("E! Error writing to output [%s]: %v", ro.Name, err) } } } // Write writes all cached points to this output. func (ro *RunningOutput) Write() error { + if output, ok := ro.Output.(telegraf.AggregatingOutput); ok { + ro.aggMutex.Lock() + metrics := output.Push() + ro.metrics.Add(metrics...) + output.Reset() + ro.aggMutex.Unlock() + } + nFails, nMetrics := ro.failMetrics.Len(), ro.metrics.Len() ro.BufferSize.Set(int64(nFails + nMetrics)) log.Printf("D! Output [%s] buffer fullness: %d / %d metrics. ", @@ -173,8 +187,8 @@ func (ro *RunningOutput) write(metrics []telegraf.Metric) error { if nMetrics == 0 { return nil } - ro.Lock() - defer ro.Unlock() + ro.writeMutex.Lock() + defer ro.writeMutex.Unlock() start := time.Now() err := ro.Output.Write(metrics) elapsed := time.Since(start) @@ -186,9 +200,3 @@ func (ro *RunningOutput) write(metrics []telegraf.Metric) error { } return err } - -// OutputConfig containing name and filter -type OutputConfig struct { - Name string - Filter Filter -} diff --git a/internal/models/running_output_test.go b/internal/models/running_output_test.go index bd39f2f9..c5533421 100644 --- a/internal/models/running_output_test.go +++ b/internal/models/running_output_test.go @@ -75,23 +75,6 @@ func BenchmarkRunningOutputAddFailWrites(b *testing.B) { } } -func TestAddingNilMetric(t *testing.T) { - conf := &OutputConfig{ - Filter: Filter{}, - } - - m := &mockOutput{} - ro := NewRunningOutput("test", m, conf, 1000, 10000) - - ro.AddMetric(nil) - ro.AddMetric(nil) - ro.AddMetric(nil) - - err := ro.Write() - assert.NoError(t, err) - assert.Len(t, m.Metrics(), 0) -} - // Test that NameDrop filters ger properly applied. func TestRunningOutput_DropFilter(t *testing.T) { conf := &OutputConfig{ diff --git a/internal/models/running_processor.go b/internal/models/running_processor.go index 92d3d44d..a210d979 100644 --- a/internal/models/running_processor.go +++ b/internal/models/running_processor.go @@ -34,14 +34,18 @@ func (rp *RunningProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric { ret := []telegraf.Metric{} for _, metric := range in { - if rp.Config.Filter.IsActive() { - // check if the filter should be applied to this metric - if ok := rp.Config.Filter.Apply(metric.Name(), metric.Fields(), metric.Tags()); !ok { - // this means filter should not be applied - ret = append(ret, metric) - continue - } + // In processors when a filter selects a metric it is sent through the + // processor. Otherwise the metric continues downstream unmodified. + if ok := rp.Config.Filter.Select(metric); !ok { + ret = append(ret, metric) + continue } + + rp.Config.Filter.Modify(metric) + if len(metric.FieldList()) == 0 { + continue + } + // This metric should pass through the filter, so call the filter Apply // function and append results to the output slice. ret = append(ret, rp.Processor.Apply(metric)...) diff --git a/internal/models/running_processor_test.go b/internal/models/running_processor_test.go index 8a691a9b..02db4046 100644 --- a/internal/models/running_processor_test.go +++ b/internal/models/running_processor_test.go @@ -1,117 +1,203 @@ package models import ( + "sort" "testing" + "time" "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/testutil" + "github.com/influxdata/telegraf/metric" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -type TestProcessor struct { +// MockProcessor is a Processor with an overrideable Apply implementation. +type MockProcessor struct { + ApplyF func(in ...telegraf.Metric) []telegraf.Metric } -func (f *TestProcessor) SampleConfig() string { return "" } -func (f *TestProcessor) Description() string { return "" } - -// Apply renames: -// "foo" to "fuz" -// "bar" to "baz" -// And it also drops measurements named "dropme" -func (f *TestProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric { - out := make([]telegraf.Metric, 0) - for _, m := range in { - switch m.Name() { - case "foo": - out = append(out, testutil.TestMetric(1, "fuz")) - case "bar": - out = append(out, testutil.TestMetric(1, "baz")) - case "dropme": - // drop the metric! - default: - out = append(out, m) - } - } - return out +func (p *MockProcessor) SampleConfig() string { + return "" } -func NewTestRunningProcessor() *RunningProcessor { - out := &RunningProcessor{ - Name: "test", - Processor: &TestProcessor{}, - Config: &ProcessorConfig{Filter: Filter{}}, - } - return out +func (p *MockProcessor) Description() string { + return "" } -func TestRunningProcessor(t *testing.T) { - inmetrics := []telegraf.Metric{ - testutil.TestMetric(1, "foo"), - testutil.TestMetric(1, "bar"), - testutil.TestMetric(1, "baz"), - } - - expectedNames := []string{ - "fuz", - "baz", - "baz", - } - rfp := NewTestRunningProcessor() - filteredMetrics := rfp.Apply(inmetrics...) - - actualNames := []string{ - filteredMetrics[0].Name(), - filteredMetrics[1].Name(), - filteredMetrics[2].Name(), - } - assert.Equal(t, expectedNames, actualNames) +func (p *MockProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric { + return p.ApplyF(in...) } -func TestRunningProcessor_WithNameDrop(t *testing.T) { - inmetrics := []telegraf.Metric{ - testutil.TestMetric(1, "foo"), - testutil.TestMetric(1, "bar"), - testutil.TestMetric(1, "baz"), +// TagProcessor returns a Processor whose Apply function adds the tag and +// value. +func TagProcessor(key, value string) *MockProcessor { + return &MockProcessor{ + ApplyF: func(in ...telegraf.Metric) []telegraf.Metric { + for _, m := range in { + m.AddTag(key, value) + } + return in + }, } - - expectedNames := []string{ - "foo", - "baz", - "baz", - } - rfp := NewTestRunningProcessor() - - rfp.Config.Filter.NameDrop = []string{"foo"} - assert.NoError(t, rfp.Config.Filter.Compile()) - - filteredMetrics := rfp.Apply(inmetrics...) - - actualNames := []string{ - filteredMetrics[0].Name(), - filteredMetrics[1].Name(), - filteredMetrics[2].Name(), - } - assert.Equal(t, expectedNames, actualNames) } -func TestRunningProcessor_DroppedMetric(t *testing.T) { - inmetrics := []telegraf.Metric{ - testutil.TestMetric(1, "dropme"), - testutil.TestMetric(1, "foo"), - testutil.TestMetric(1, "bar"), +func Metric( + name string, + tags map[string]string, + fields map[string]interface{}, + tm time.Time, + tp ...telegraf.ValueType, +) telegraf.Metric { + m, err := metric.New(name, tags, fields, tm, tp...) + if err != nil { + panic(err) } + return m +} - expectedNames := []string{ - "fuz", - "baz", +func TestRunningProcessor_Apply(t *testing.T) { + type args struct { + Processor telegraf.Processor + Config *ProcessorConfig } - rfp := NewTestRunningProcessor() - filteredMetrics := rfp.Apply(inmetrics...) - actualNames := []string{ - filteredMetrics[0].Name(), - filteredMetrics[1].Name(), + tests := []struct { + name string + args args + input []telegraf.Metric + expected []telegraf.Metric + }{ + { + name: "inactive filter applies metrics", + args: args{ + Processor: TagProcessor("apply", "true"), + Config: &ProcessorConfig{ + Filter: Filter{}, + }, + }, + input: []telegraf.Metric{ + Metric( + "cpu", + map[string]string{}, + map[string]interface{}{ + "value": 42.0, + }, + time.Unix(0, 0), + ), + }, + expected: []telegraf.Metric{ + Metric( + "cpu", + map[string]string{ + "apply": "true", + }, + map[string]interface{}{ + "value": 42.0, + }, + time.Unix(0, 0), + ), + }, + }, + { + name: "filter applies", + args: args{ + Processor: TagProcessor("apply", "true"), + Config: &ProcessorConfig{ + Filter: Filter{ + NamePass: []string{"cpu"}, + }, + }, + }, + input: []telegraf.Metric{ + Metric( + "cpu", + map[string]string{}, + map[string]interface{}{ + "value": 42.0, + }, + time.Unix(0, 0), + ), + }, + expected: []telegraf.Metric{ + Metric( + "cpu", + map[string]string{ + "apply": "true", + }, + map[string]interface{}{ + "value": 42.0, + }, + time.Unix(0, 0), + ), + }, + }, + { + name: "filter doesn't apply", + args: args{ + Processor: TagProcessor("apply", "true"), + Config: &ProcessorConfig{ + Filter: Filter{ + NameDrop: []string{"cpu"}, + }, + }, + }, + input: []telegraf.Metric{ + Metric( + "cpu", + map[string]string{}, + map[string]interface{}{ + "value": 42.0, + }, + time.Unix(0, 0), + ), + }, + expected: []telegraf.Metric{ + Metric( + "cpu", + map[string]string{}, + map[string]interface{}{ + "value": 42.0, + }, + time.Unix(0, 0), + ), + }, + }, } - assert.Equal(t, expectedNames, actualNames) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rp := &RunningProcessor{ + Processor: tt.args.Processor, + Config: tt.args.Config, + } + rp.Config.Filter.Compile() + + actual := rp.Apply(tt.input...) + require.Equal(t, tt.expected, actual) + }) + } +} + +func TestRunningProcessor_Order(t *testing.T) { + rp1 := &RunningProcessor{ + Config: &ProcessorConfig{ + Order: 1, + }, + } + rp2 := &RunningProcessor{ + Config: &ProcessorConfig{ + Order: 2, + }, + } + rp3 := &RunningProcessor{ + Config: &ProcessorConfig{ + Order: 3, + }, + } + + procs := RunningProcessors{rp2, rp3, rp1} + sort.Sort(procs) + require.Equal(t, + RunningProcessors{rp1, rp2, rp3}, + procs) } diff --git a/internal/templating/engine.go b/internal/templating/engine.go new file mode 100644 index 00000000..65d15a42 --- /dev/null +++ b/internal/templating/engine.go @@ -0,0 +1,86 @@ +package templating + +import ( + "sort" + "strings" +) + +const ( + // DefaultSeparator is the default separation character to use when separating template parts. + DefaultSeparator = "." +) + +// Engine uses a Matcher to retrieve the appropriate template and applies the template +// to the input string +type Engine struct { + joiner string + matcher *matcher +} + +// Apply extracts the template fields from the given line and returns the measurement +// name, tags and field name +func (e *Engine) Apply(line string) (string, map[string]string, string, error) { + return e.matcher.match(line).Apply(line, e.joiner) +} + +// NewEngine creates a new templating engine +func NewEngine(joiner string, defaultTemplate *Template, templates []string) (*Engine, error) { + engine := Engine{ + joiner: joiner, + matcher: newMatcher(defaultTemplate), + } + templateSpecs := parseTemplateSpecs(templates) + + for _, templateSpec := range templateSpecs { + if err := engine.matcher.addSpec(templateSpec); err != nil { + return nil, err + } + } + + return &engine, nil +} + +func parseTemplateSpecs(templates []string) templateSpecs { + tmplts := templateSpecs{} + for _, pattern := range templates { + tmplt := templateSpec{ + separator: DefaultSeparator, + } + + // Format is [separator] [filter]