Merge branch 'master' into bench/6124

This commit is contained in:
greg linton
2019-10-08 08:37:49 -06:00
170 changed files with 3092 additions and 1176 deletions
+48 -52
View File
@@ -4,20 +4,17 @@ defaults:
working_directory: '/go/src/github.com/influxdata/telegraf'
environment:
GOFLAGS: -p=8
go-1_10: &go-1_10
docker:
- image: 'quay.io/influxdb/telegraf-ci:1.10.8'
go-1_11: &go-1_11
docker:
- image: 'quay.io/influxdb/telegraf-ci:1.11.13'
go-1_12: &go-1_12
docker:
- image: 'quay.io/influxdb/telegraf-ci:1.12.9'
- image: 'quay.io/influxdb/telegraf-ci:1.12.10'
go-1_13: &go-1_13
docker:
- image: 'quay.io/influxdb/telegraf-ci:1.13.1'
version: 2
jobs:
deps:
<<: [ *defaults, *go-1_12 ]
<<: [ *defaults, *go-1_13 ]
steps:
- checkout
- restore_cache:
@@ -34,28 +31,13 @@ jobs:
paths:
- '*'
test-go-1.10:
<<: [ *defaults, *go-1_10 ]
steps:
- attach_workspace:
at: '/go/src'
# disabled due to gofmt differences (1.10 vs 1.11).
#- run: 'make check'
- run: 'make test'
test-go-1.11:
<<: [ *defaults, *go-1_11 ]
steps:
- attach_workspace:
at: '/go/src'
- run: 'make check'
- run: 'make test'
test-go-1.12:
<<: [ *defaults, *go-1_12 ]
steps:
- attach_workspace:
at: '/go/src'
- run: 'GOARCH=386 make check'
- run: 'GOARCH=386 make test'
- run: 'make check'
- run: 'make test'
test-go-1.12-386:
<<: [ *defaults, *go-1_12 ]
steps:
@@ -63,9 +45,23 @@ jobs:
at: '/go/src'
- run: 'GOARCH=386 make check'
- run: 'GOARCH=386 make test'
test-go-1.13:
<<: [ *defaults, *go-1_13 ]
steps:
- attach_workspace:
at: '/go/src'
- run: 'make check'
- run: 'make test'
test-go-1.13-386:
<<: [ *defaults, *go-1_13 ]
steps:
- attach_workspace:
at: '/go/src'
- run: 'GOARCH=386 make check'
- run: 'GOARCH=386 make test'
package:
<<: [ *defaults, *go-1_12 ]
<<: [ *defaults, *go-1_13 ]
steps:
- attach_workspace:
at: '/go/src'
@@ -74,7 +70,7 @@ jobs:
path: './build'
destination: 'build'
release:
<<: [ *defaults, *go-1_12 ]
<<: [ *defaults, *go-1_13 ]
steps:
- attach_workspace:
at: '/go/src'
@@ -83,7 +79,7 @@ jobs:
path: './build'
destination: 'build'
nightly:
<<: [ *defaults, *go-1_12 ]
<<: [ *defaults, *go-1_13 ]
steps:
- attach_workspace:
at: '/go/src'
@@ -100,18 +96,6 @@ workflows:
filters:
tags:
only: /.*/
- 'test-go-1.10':
requires:
- 'deps'
filters:
tags:
only: /.*/
- 'test-go-1.11':
requires:
- 'deps'
filters:
tags:
only: /.*/
- 'test-go-1.12':
requires:
- 'deps'
@@ -124,18 +108,30 @@ workflows:
filters:
tags:
only: /.*/
- 'test-go-1.13':
requires:
- 'deps'
filters:
tags:
only: /.*/
- 'test-go-1.13-386':
requires:
- 'deps'
filters:
tags:
only: /.*/
- 'package':
requires:
- 'test-go-1.10'
- 'test-go-1.11'
- 'test-go-1.12'
- 'test-go-1.12-386'
- 'test-go-1.13'
- 'test-go-1.13-386'
- 'release':
requires:
- 'test-go-1.10'
- 'test-go-1.11'
- 'test-go-1.12'
- 'test-go-1.12-386'
- 'test-go-1.13'
- 'test-go-1.13-386'
filters:
tags:
only: /.*/
@@ -144,24 +140,24 @@ workflows:
nightly:
jobs:
- 'deps'
- 'test-go-1.10':
requires:
- 'deps'
- 'test-go-1.11':
requires:
- 'deps'
- 'test-go-1.12':
requires:
- 'deps'
- 'test-go-1.12-386':
requires:
- 'deps'
- 'test-go-1.13':
requires:
- 'deps'
- 'test-go-1.13-386':
requires:
- 'deps'
- 'nightly':
requires:
- 'test-go-1.10'
- 'test-go-1.11'
- 'test-go-1.12'
- 'test-go-1.12-386'
- 'test-go-1.13'
- 'test-go-1.13-386'
triggers:
- schedule:
cron: "0 7 * * *"
+16
View File
@@ -0,0 +1,16 @@
on:
pull_request:
types: [opened]
jobs:
cla-checker:
runs-on: ubuntu-latest
name: "Check CLA"
steps:
- name: "Lookup PR Author"
uses: influxdata/clasee@v1
with:
spreadsheet: "1jnRZYSw83oa6hcEBb1lxK6nNvXrWnOzPT8Bz9iR4Q8s"
range: "Form Responses!E:E"
env:
CLASEE_SECRET: ${{ secrets.CLASEE_SECRET }}
+29 -1
View File
@@ -1,8 +1,17 @@
## v1.13 [unreleased]
#### Release Notes
- Official packages are built with Go 1.13.1.
#### New Inputs
- [azure_storage_queue](/plugins/inputs/azure_storage_queue/README.md) - Contributed by @mjiderhamn
- [suricata](/plugins/inputs/suricata/README.md) - Contributed by @satta
#### New Aggregators
- [merge](/plugins/aggregators/merge/README.md) - Contributed by @influxdata
#### Features
@@ -10,14 +19,33 @@
- [#6361](https://github.com/influxdata/telegraf/pull/6361): Add ability to read query from file to postgresql_extensible input.
- [#5921](https://github.com/influxdata/telegraf/pull/5921): Add replication metrics to the redis input.
- [#6177](https://github.com/influxdata/telegraf/pull/6177): Support NX-OS telemetry extensions in cisco_telemetry_mdt.
- [#6415](https://github.com/influxdata/telegraf/pull/6415): Allow graphite parser to create Inf and NaN values.
- [#6434](https://github.com/influxdata/telegraf/pull/6434): Use prefix base detection for ints in grok parser.
- [#6465](https://github.com/influxdata/telegraf/pull/6465): Add more performance counter metrics to sqlserver input.
- [#6476](https://github.com/influxdata/telegraf/pull/6476): Add millisecond unix time support to grok parser.
- [#6473](https://github.com/influxdata/telegraf/pull/6473): Add container id as optional source tag to docker and docker_log input.
## v1.12.2 [unreleased]
## v1.12.3 [2019-10-07]
#### Bugfixes
- [#6445](https://github.com/influxdata/telegraf/issues/6445): Use batch serialization format in exec output.
- [#6455](https://github.com/influxdata/telegraf/issues/6455): Build official packages with Go 1.12.10.
- [#6464](https://github.com/influxdata/telegraf/pull/6464): Use case insensitive serial numer match in smart input.
- [#6469](https://github.com/influxdata/telegraf/pull/6469): Add auth header only when env var is set.
- [#6468](https://github.com/influxdata/telegraf/pull/6468): Fix running multiple mysql and sqlserver plugin instances.
- [#6471](https://github.com/influxdata/telegraf/issues/6471): Fix database routing on retry with exclude_database_tag.
- [#6488](https://github.com/influxdata/telegraf/issues/6488): Fix logging panic in exec input with nagios data format.
## v1.12.2 [2019-09-24]
#### Bugfixes
- [#6386](https://github.com/influxdata/telegraf/issues/6386): Fix detection of layout timestamps in csv and json parser.
- [#6394](https://github.com/influxdata/telegraf/issues/6394): Fix parsing of BATTDATE in apcupsd input.
- [#6398](https://github.com/influxdata/telegraf/issues/6398): Keep boolean values listed in json_string_fields.
- [#6393](https://github.com/influxdata/telegraf/issues/6393): Disable Go plugin support in official builds.
- [#6391](https://github.com/influxdata/telegraf/issues/6391): Fix path handling issues in cisco_telemetry_gnmi.
## v1.12.1 [2019-09-10]
+7 -12
View File
@@ -129,17 +129,12 @@ plugin-%:
@echo "Starting dev environment for $${$(@)} input plugin..."
@docker-compose -f plugins/inputs/$${$(@)}/dev/docker-compose.yml up
.PHONY: ci-1.13
ci-1.13:
docker build -t quay.io/influxdb/telegraf-ci:1.13.1 - < scripts/ci-1.13.docker
docker push quay.io/influxdb/telegraf-ci:1.13.1
.PHONY: ci-1.12
ci-1.12:
docker build -t quay.io/influxdb/telegraf-ci:1.12.9 - < scripts/ci-1.12.docker
docker push quay.io/influxdb/telegraf-ci:1.12.9
.PHONY: ci-1.11
ci-1.11:
docker build -t quay.io/influxdb/telegraf-ci:1.11.13 - < scripts/ci-1.11.docker
docker push quay.io/influxdb/telegraf-ci:1.11.13
.PHONY: ci-1.10
ci-1.10:
docker build -t quay.io/influxdb/telegraf-ci:1.10.8 - < scripts/ci-1.10.docker
docker push quay.io/influxdb/telegraf-ci:1.10.8
docker build -t quay.io/influxdb/telegraf-ci:1.12.10 - < scripts/ci-1.12.docker
docker push quay.io/influxdb/telegraf-ci:1.12.10
+4 -2
View File
@@ -40,9 +40,9 @@ Ansible role: https://github.com/rossmcdonald/telegraf
### From Source:
Telegraf requires golang version 1.10 or newer, the Makefile requires GNU make.
Telegraf requires golang version 1.12 or newer, the Makefile requires GNU make.
1. [Install Go](https://golang.org/doc/install) >=1.10 (1.12 recommended)
1. [Install Go](https://golang.org/doc/install) >=1.12 (1.13 recommended)
2. [Install dep](https://golang.github.io/dep/docs/installation.html) ==v0.5.0
3. Download Telegraf source:
```
@@ -276,6 +276,7 @@ For documentation on the latest development code see the [documentation index][d
* [sql server](./plugins/inputs/sqlserver) (microsoft)
* [stackdriver](./plugins/inputs/stackdriver)
* [statsd](./plugins/inputs/statsd)
* [suricata](./plugins/inputs/suricata)
* [swap](./plugins/inputs/swap)
* [syslog](./plugins/inputs/syslog)
* [sysstat](./plugins/inputs/sysstat)
@@ -353,6 +354,7 @@ For documentation on the latest development code see the [documentation index][d
* [basicstats](./plugins/aggregators/basicstats)
* [final](./plugins/aggregators/final)
* [histogram](./plugins/aggregators/histogram)
* [merge](./plugins/aggregators/merge)
* [minmax](./plugins/aggregators/minmax)
* [valuecounter](./plugins/aggregators/valuecounter)
+2 -2
View File
@@ -13,11 +13,11 @@ platform: x64
install:
- IF NOT EXIST "C:\Cache" mkdir C:\Cache
- IF NOT EXIST "C:\Cache\go1.12.9.msi" curl -o "C:\Cache\go1.12.9.msi" https://storage.googleapis.com/golang/go1.12.9.windows-amd64.msi
- IF NOT EXIST "C:\Cache\go1.13.1.msi" curl -o "C:\Cache\go1.13.1.msi" https://storage.googleapis.com/golang/go1.13.1.windows-amd64.msi
- 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.12.9.msi" /quiet
- msiexec.exe /i "C:\Cache\go1.13.1.msi" /quiet
- 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
+2 -34
View File
@@ -10,9 +10,6 @@ import (
_ "net/http/pprof" // Comment this line to disable pprof endpoint.
"os"
"os/signal"
"path"
"path/filepath"
"plugin"
"runtime"
"strings"
"syscall"
@@ -21,6 +18,7 @@ import (
"github.com/influxdata/telegraf/agent"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/config"
"github.com/influxdata/telegraf/internal/goplugin"
"github.com/influxdata/telegraf/logger"
_ "github.com/influxdata/telegraf/plugins/aggregators/all"
"github.com/influxdata/telegraf/plugins/inputs"
@@ -116,36 +114,6 @@ func reloadLoop(
}
}
// loadExternalPlugins loads external plugins from shared libraries (.so, .dll, etc.)
// in the specified directory.
func loadExternalPlugins(rootDir string) error {
return filepath.Walk(rootDir, func(pth string, info os.FileInfo, err error) error {
// Stop if there was an error.
if err != nil {
return err
}
// Ignore directories.
if info.IsDir() {
return nil
}
// Ignore files that aren't shared libraries.
ext := strings.ToLower(path.Ext(pth))
if ext != ".so" && ext != ".dll" {
return nil
}
// Load plugin.
_, err = plugin.Open(pth)
if err != nil {
return fmt.Errorf("error loading %s: %s", pth, err)
}
return nil
})
}
func runAgent(ctx context.Context,
inputFilters []string,
outputFilters []string,
@@ -317,7 +285,7 @@ func main() {
// Load external plugins, if requested.
if *fPlugins != "" {
log.Printf("I! Loading external plugins from: %s", *fPlugins)
if err := loadExternalPlugins(*fPlugins); err != nil {
if err := goplugin.LoadExternalPlugins(*fPlugins); err != nil {
log.Fatal("E! " + err.Error())
}
}
+1
View File
@@ -188,6 +188,7 @@ driven operation.
Parameters that can be used with any input plugin:
- **alias**: Name an instance of a plugin.
- **interval**: How often to gather this metric. Normal plugins use a single
global interval, but if one particular input should be run less or more
often, you can configure that here.
+4 -3
View File
@@ -841,13 +841,14 @@ func loadConfig(config string) ([]byte, error) {
}
func fetchConfig(u *url.URL) ([]byte, error) {
v := os.Getenv("INFLUX_TOKEN")
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Token "+v)
if v, exists := os.LookupEnv("INFLUX_TOKEN"); exists {
req.Header.Add("Authorization", "Token "+v)
}
req.Header.Add("Accept", "application/toml")
resp, err := http.DefaultClient.Do(req)
if err != nil {
+5
View File
@@ -158,6 +158,11 @@ func TestConfig_LoadDirectory(t *testing.T) {
MeasurementSuffix: "_myothercollector",
}
eConfig.Tags = make(map[string]string)
exec := c.Inputs[1].Input.(*exec.Exec)
require.NotNil(t, exec.Log)
exec.Log = nil
assert.Equal(t, ex, c.Inputs[1].Input,
"Merged Testdata did not produce a correct exec struct.")
assert.Equal(t, eConfig, c.Inputs[1].Config,
+9
View File
@@ -0,0 +1,9 @@
// +build !goplugin
package goplugin
import "errors"
func LoadExternalPlugins(rootDir string) error {
return errors.New("go plugin support is not enabled")
}
+42
View File
@@ -0,0 +1,42 @@
// +build goplugin
package goplugin
import (
"fmt"
"os"
"path"
"path/filepath"
"plugin"
"strings"
)
// loadExternalPlugins loads external plugins from shared libraries (.so, .dll, etc.)
// in the specified directory.
func LoadExternalPlugins(rootDir string) error {
return filepath.Walk(rootDir, func(pth string, info os.FileInfo, err error) error {
// Stop if there was an error.
if err != nil {
return err
}
// Ignore directories.
if info.IsDir() {
return nil
}
// Ignore files that aren't shared libraries.
ext := strings.ToLower(path.Ext(pth))
if ext != ".so" && ext != ".dll" {
return nil
}
// Load plugin.
_, err = plugin.Open(pth)
if err != nil {
return fmt.Errorf("error loading %s: %s", pth, err)
}
return nil
})
}
+1 -1
View File
@@ -144,7 +144,7 @@ func (r *RunningAggregator) Add(m telegraf.Metric) bool {
defer r.Unlock()
if m.Time().Before(r.periodStart.Add(-r.Config.Grace)) || m.Time().After(r.periodEnd.Add(r.Config.Delay)) {
r.log.Debugf("metric is outside aggregation window; discarding. %s: m: %s e: %s g: %s",
r.log.Debugf("Metric is outside aggregation window; discarding. %s: m: %s e: %s g: %s",
m.Time(), r.periodStart, r.periodEnd, r.Config.Grace)
r.MetricsDropped.Incr(1)
return r.Config.DropOriginal
+1
View File
@@ -4,6 +4,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/aggregators/basicstats"
_ "github.com/influxdata/telegraf/plugins/aggregators/final"
_ "github.com/influxdata/telegraf/plugins/aggregators/histogram"
_ "github.com/influxdata/telegraf/plugins/aggregators/merge"
_ "github.com/influxdata/telegraf/plugins/aggregators/minmax"
_ "github.com/influxdata/telegraf/plugins/aggregators/valuecounter"
)
+1
View File
@@ -10,6 +10,7 @@ emitting the aggregate every `period` seconds.
[[aggregators.basicstats]]
## 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
+50 -60
View File
@@ -1,7 +1,6 @@
package basicstats
import (
"log"
"math"
"github.com/influxdata/telegraf"
@@ -10,6 +9,7 @@ import (
type BasicStats struct {
Stats []string `toml:"stats"`
Log telegraf.Logger
cache map[uint64]aggregate
statsConfig *configuredStats
@@ -28,9 +28,9 @@ type configuredStats struct {
}
func NewBasicStats() *BasicStats {
mm := &BasicStats{}
mm.Reset()
return mm
return &BasicStats{
cache: make(map[uint64]aggregate),
}
}
type aggregate struct {
@@ -53,6 +53,7 @@ type basicstats struct {
var sampleConfig = `
## 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
@@ -61,17 +62,17 @@ var sampleConfig = `
# stats = ["count", "min", "max", "mean", "stdev", "s2", "sum"]
`
func (m *BasicStats) SampleConfig() string {
func (*BasicStats) SampleConfig() string {
return sampleConfig
}
func (m *BasicStats) Description() string {
func (*BasicStats) Description() string {
return "Keep the aggregate basicstats of each metric passing through."
}
func (m *BasicStats) Add(in telegraf.Metric) {
func (b *BasicStats) Add(in telegraf.Metric) {
id := in.HashID()
if _, ok := m.cache[id]; !ok {
if _, ok := b.cache[id]; !ok {
// hit an uncached metric, create caches for first time:
a := aggregate{
name: in.Name(),
@@ -92,13 +93,13 @@ func (m *BasicStats) Add(in telegraf.Metric) {
}
}
}
m.cache[id] = a
b.cache[id] = a
} else {
for _, field := range in.FieldList() {
if fv, ok := convert(field.Value); ok {
if _, ok := m.cache[id].fields[field.Key]; !ok {
if _, ok := b.cache[id].fields[field.Key]; !ok {
// hit an uncached field of a cached metric
m.cache[id].fields[field.Key] = basicstats{
b.cache[id].fields[field.Key] = basicstats{
count: 1,
min: fv,
max: fv,
@@ -111,7 +112,7 @@ func (m *BasicStats) Add(in telegraf.Metric) {
continue
}
tmp := m.cache[id].fields[field.Key]
tmp := b.cache[id].fields[field.Key]
//https://en.m.wikipedia.org/wiki/Algorithms_for_calculating_variance
//variable initialization
x := fv
@@ -138,32 +139,30 @@ func (m *BasicStats) Add(in telegraf.Metric) {
//diff compute
tmp.diff = fv - tmp.LAST
//store final data
m.cache[id].fields[field.Key] = tmp
b.cache[id].fields[field.Key] = tmp
}
}
}
}
func (m *BasicStats) Push(acc telegraf.Accumulator) {
config := getConfiguredStats(m)
for _, aggregate := range m.cache {
func (b *BasicStats) Push(acc telegraf.Accumulator) {
for _, aggregate := range b.cache {
fields := map[string]interface{}{}
for k, v := range aggregate.fields {
if config.count {
if b.statsConfig.count {
fields[k+"_count"] = v.count
}
if config.min {
if b.statsConfig.min {
fields[k+"_min"] = v.min
}
if config.max {
if b.statsConfig.max {
fields[k+"_max"] = v.max
}
if config.mean {
if b.statsConfig.mean {
fields[k+"_mean"] = v.mean
}
if config.sum {
if b.statsConfig.sum {
fields[k+"_sum"] = v.sum
}
@@ -171,16 +170,16 @@ func (m *BasicStats) Push(acc telegraf.Accumulator) {
if v.count > 1 {
variance := v.M2 / (v.count - 1)
if config.variance {
if b.statsConfig.variance {
fields[k+"_s2"] = variance
}
if config.stdev {
if b.statsConfig.stdev {
fields[k+"_stdev"] = math.Sqrt(variance)
}
if config.diff {
if b.statsConfig.diff {
fields[k+"_diff"] = v.diff
}
if config.non_negative_diff && v.diff >= 0 {
if b.statsConfig.non_negative_diff && v.diff >= 0 {
fields[k+"_non_negative_diff"] = v.diff
}
@@ -194,14 +193,12 @@ func (m *BasicStats) Push(acc telegraf.Accumulator) {
}
}
func parseStats(names []string) *configuredStats {
// member function for logging.
func (b *BasicStats) parseStats() *configuredStats {
parsed := &configuredStats{}
for _, name := range names {
for _, name := range b.Stats {
switch name {
case "count":
parsed.count = true
case "min":
@@ -222,45 +219,32 @@ func parseStats(names []string) *configuredStats {
parsed.non_negative_diff = true
default:
log.Printf("W! Unrecognized basic stat '%s', ignoring", name)
b.Log.Warnf("Unrecognized basic stat %q, ignoring", name)
}
}
return parsed
}
func defaultStats() *configuredStats {
defaults := &configuredStats{}
defaults.count = true
defaults.min = true
defaults.max = true
defaults.mean = true
defaults.variance = true
defaults.stdev = true
defaults.sum = false
defaults.non_negative_diff = false
return defaults
}
func getConfiguredStats(m *BasicStats) *configuredStats {
if m.statsConfig == nil {
if m.Stats == nil {
m.statsConfig = defaultStats()
} else {
m.statsConfig = parseStats(m.Stats)
func (b *BasicStats) getConfiguredStats() {
if b.Stats == nil {
b.statsConfig = &configuredStats{
count: true,
min: true,
max: true,
mean: true,
variance: true,
stdev: true,
sum: false,
non_negative_diff: false,
}
} else {
b.statsConfig = b.parseStats()
}
return m.statsConfig
}
func (m *BasicStats) Reset() {
m.cache = make(map[uint64]aggregate)
func (b *BasicStats) Reset() {
b.cache = make(map[uint64]aggregate)
}
func convert(in interface{}) (float64, bool) {
@@ -276,6 +260,12 @@ func convert(in interface{}) (float64, bool) {
}
}
func (b *BasicStats) Init() error {
b.getConfiguredStats()
return nil
}
func init() {
aggregators.Add("basicstats", func() telegraf.Aggregator {
return NewBasicStats()
@@ -39,6 +39,8 @@ var m2, _ = metric.New("m1",
func BenchmarkApply(b *testing.B) {
minmax := NewBasicStats()
minmax.Log = testutil.Logger{}
minmax.getConfiguredStats()
for n := 0; n < b.N; n++ {
minmax.Add(m1)
@@ -50,6 +52,8 @@ func BenchmarkApply(b *testing.B) {
func TestBasicStatsWithPeriod(t *testing.T) {
acc := testutil.Accumulator{}
minmax := NewBasicStats()
minmax.Log = testutil.Logger{}
minmax.getConfiguredStats()
minmax.Add(m1)
minmax.Add(m2)
@@ -106,6 +110,8 @@ func TestBasicStatsWithPeriod(t *testing.T) {
func TestBasicStatsDifferentPeriods(t *testing.T) {
acc := testutil.Accumulator{}
minmax := NewBasicStats()
minmax.Log = testutil.Logger{}
minmax.getConfiguredStats()
minmax.Add(m1)
minmax.Push(&acc)
@@ -181,6 +187,8 @@ func TestBasicStatsWithOnlyCount(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"count"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -208,6 +216,8 @@ func TestBasicStatsWithOnlyMin(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"min"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -235,6 +245,8 @@ func TestBasicStatsWithOnlyMax(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"max"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -262,6 +274,8 @@ func TestBasicStatsWithOnlyMean(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"mean"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -289,6 +303,8 @@ func TestBasicStatsWithOnlySum(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"sum"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -347,6 +363,8 @@ func TestBasicStatsWithOnlySumFloatingPointErrata(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"sum"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(sum1)
aggregator.Add(sum2)
@@ -368,6 +386,8 @@ func TestBasicStatsWithOnlyVariance(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"s2"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -393,6 +413,8 @@ func TestBasicStatsWithOnlyStandardDeviation(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"stdev"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -418,6 +440,8 @@ func TestBasicStatsWithMinAndMax(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"min", "max"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -452,6 +476,8 @@ func TestBasicStatsWithDiff(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"diff"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -477,6 +503,8 @@ func TestBasicStatsWithNonNegativeDiff(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"non_negative_diff"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -500,7 +528,9 @@ func TestBasicStatsWithNonNegativeDiff(t *testing.T) {
func TestBasicStatsWithAllStats(t *testing.T) {
acc := testutil.Accumulator{}
minmax := NewBasicStats()
minmax.Log = testutil.Logger{}
minmax.Stats = []string{"count", "min", "max", "mean", "stdev", "s2", "sum"}
minmax.getConfiguredStats()
minmax.Add(m1)
minmax.Add(m2)
@@ -564,6 +594,8 @@ func TestBasicStatsWithNoStats(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -579,6 +611,8 @@ func TestBasicStatsWithUnknownStat(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Stats = []string{"crazy"}
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
@@ -596,6 +630,8 @@ func TestBasicStatsWithUnknownStat(t *testing.T) {
func TestBasicStatsWithDefaultStats(t *testing.T) {
aggregator := NewBasicStats()
aggregator.Log = testutil.Logger{}
aggregator.getConfiguredStats()
aggregator.Add(m1)
aggregator.Add(m2)
+23
View File
@@ -0,0 +1,23 @@
# Merge Aggregator
Merge metrics together into a metric with multiple fields into the most memory
and network transfer efficient form.
Use this plugin when fields are split over multiple metrics, with the same
measurement, tag set and timestamp. By merging into a single metric they can
be handled more efficiently by the output.
### Configuration
```toml
[[aggregators.merge]]
# no configuration
```
### Example
```diff
- cpu,host=localhost usage_time=42 1567562620000000000
- cpu,host=localhost idle_time=42 1567562620000000000
+ cpu,host=localhost idle_time=42,usage_time=42 1567562620000000000
```
+62
View File
@@ -0,0 +1,62 @@
package seriesgrouper
import (
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/plugins/aggregators"
)
const (
description = "Merge metrics into multifield metrics by series key"
sampleConfig = ""
)
type Merge struct {
grouper *metric.SeriesGrouper
log telegraf.Logger
}
func (a *Merge) Init() error {
a.grouper = metric.NewSeriesGrouper()
return nil
}
func (a *Merge) Description() string {
return description
}
func (a *Merge) SampleConfig() string {
return sampleConfig
}
func (a *Merge) Add(m telegraf.Metric) {
tags := m.Tags()
for _, field := range m.FieldList() {
err := a.grouper.Add(m.Name(), tags, m.Time(), field.Key, field.Value)
if err != nil {
a.log.Errorf("Error adding metric: %v", err)
}
}
}
func (a *Merge) Push(acc telegraf.Accumulator) {
// Always use nanosecond precision to avoid rounding metrics that were
// produced at a precision higher than the agent default.
acc.SetPrecision(time.Nanosecond)
for _, m := range a.grouper.Metrics() {
acc.AddMetric(m)
}
}
func (a *Merge) Reset() {
a.grouper = metric.NewSeriesGrouper()
}
func init() {
aggregators.Add("merge", func() telegraf.Aggregator {
return &Merge{}
})
}
+186
View File
@@ -0,0 +1,186 @@
package seriesgrouper
import (
"testing"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/require"
)
func TestSimple(t *testing.T) {
plugin := &Merge{}
err := plugin.Init()
require.NoError(t, err)
plugin.Add(
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_idle": 42,
},
time.Unix(0, 0),
),
)
require.NoError(t, err)
plugin.Add(
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_guest": 42,
},
time.Unix(0, 0),
),
)
require.NoError(t, err)
var acc testutil.Accumulator
plugin.Push(&acc)
expected := []telegraf.Metric{
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_idle": 42,
"time_guest": 42,
},
time.Unix(0, 0),
),
}
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())
}
func TestNanosecondPrecision(t *testing.T) {
plugin := &Merge{}
err := plugin.Init()
require.NoError(t, err)
plugin.Add(
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_idle": 42,
},
time.Unix(0, 1),
),
)
require.NoError(t, err)
plugin.Add(
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_guest": 42,
},
time.Unix(0, 1),
),
)
require.NoError(t, err)
var acc testutil.Accumulator
acc.SetPrecision(time.Second)
plugin.Push(&acc)
expected := []telegraf.Metric{
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_idle": 42,
"time_guest": 42,
},
time.Unix(0, 1),
),
}
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())
}
func TestReset(t *testing.T) {
plugin := &Merge{}
err := plugin.Init()
require.NoError(t, err)
plugin.Add(
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_idle": 42,
},
time.Unix(0, 0),
),
)
require.NoError(t, err)
var acc testutil.Accumulator
plugin.Push(&acc)
plugin.Reset()
plugin.Add(
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_guest": 42,
},
time.Unix(0, 0),
),
)
require.NoError(t, err)
plugin.Push(&acc)
expected := []telegraf.Metric{
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_idle": 42,
},
time.Unix(0, 0),
),
testutil.MustMetric(
"cpu",
map[string]string{
"cpu": "cpu0",
},
map[string]interface{}{
"time_guest": 42,
},
time.Unix(0, 0),
),
}
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())
}
+1
View File
@@ -140,6 +140,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/sqlserver"
_ "github.com/influxdata/telegraf/plugins/inputs/stackdriver"
_ "github.com/influxdata/telegraf/plugins/inputs/statsd"
_ "github.com/influxdata/telegraf/plugins/inputs/suricata"
_ "github.com/influxdata/telegraf/plugins/inputs/swap"
_ "github.com/influxdata/telegraf/plugins/inputs/syslog"
_ "github.com/influxdata/telegraf/plugins/inputs/sysstat"
+13 -16
View File
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"log"
"math/rand"
"strings"
"sync"
@@ -55,6 +54,7 @@ type AMQPConsumer struct {
tls.ClientConfig
ContentEncoding string `toml:"content_encoding"`
Log telegraf.Logger
deliveries map[telegraf.TrackingID]amqp.Delivery
@@ -241,11 +241,11 @@ func (a *AMQPConsumer) Start(acc telegraf.Accumulator) error {
break
}
log.Printf("I! [inputs.amqp_consumer] connection closed: %s; trying to reconnect", err)
a.Log.Infof("Connection closed: %s; trying to reconnect", err)
for {
msgs, err := a.connect(amqpConf)
if err != nil {
log.Printf("E! AMQP connection failed: %s", err)
a.Log.Errorf("AMQP connection failed: %s", err)
time.Sleep(10 * time.Second)
continue
}
@@ -272,14 +272,14 @@ func (a *AMQPConsumer) connect(amqpConf *amqp.Config) (<-chan amqp.Delivery, err
p := rand.Perm(len(brokers))
for _, n := range p {
broker := brokers[n]
log.Printf("D! [inputs.amqp_consumer] connecting to %q", broker)
a.Log.Debugf("Connecting to %q", broker)
conn, err := amqp.DialConfig(broker, *amqpConf)
if err == nil {
a.conn = conn
log.Printf("D! [inputs.amqp_consumer] connected to %q", broker)
a.Log.Debugf("Connected to %q", broker)
break
}
log.Printf("D! [inputs.amqp_consumer] error connecting to %q", broker)
a.Log.Debugf("Error connecting to %q", broker)
}
if a.conn == nil {
@@ -288,7 +288,7 @@ func (a *AMQPConsumer) connect(amqpConf *amqp.Config) (<-chan amqp.Delivery, err
ch, err := a.conn.Channel()
if err != nil {
return nil, fmt.Errorf("Failed to open a channel: %s", err)
return nil, fmt.Errorf("Failed to open a channel: %s", err.Error())
}
if a.Exchange != "" {
@@ -395,7 +395,7 @@ func declareExchange(
)
}
if err != nil {
return fmt.Errorf("error declaring exchange: %v", err)
return fmt.Errorf("Error declaring exchange: %v", err)
}
return nil
}
@@ -437,7 +437,7 @@ func declareQueue(
)
}
if err != nil {
return nil, fmt.Errorf("error declaring queue: %v", err)
return nil, fmt.Errorf("Error declaring queue: %v", err)
}
return &queue, nil
}
@@ -486,8 +486,7 @@ func (a *AMQPConsumer) onMessage(acc telegraf.TrackingAccumulator, d amqp.Delive
// this message.
rejErr := d.Ack(false)
if rejErr != nil {
log.Printf("E! [inputs.amqp_consumer] Unable to reject message: %d: %v",
d.DeliveryTag, rejErr)
a.Log.Errorf("Unable to reject message: %d: %v", d.DeliveryTag, rejErr)
a.conn.Close()
}
}
@@ -519,15 +518,13 @@ func (a *AMQPConsumer) onDelivery(track telegraf.DeliveryInfo) bool {
if track.Delivered() {
err := delivery.Ack(false)
if err != nil {
log.Printf("E! [inputs.amqp_consumer] Unable to ack written delivery: %d: %v",
delivery.DeliveryTag, err)
a.Log.Errorf("Unable to ack written delivery: %d: %v", delivery.DeliveryTag, err)
a.conn.Close()
}
} else {
err := delivery.Reject(false)
if err != nil {
log.Printf("E! [inputs.amqp_consumer] Unable to reject failed delivery: %d: %v",
delivery.DeliveryTag, err)
a.Log.Errorf("Unable to reject failed delivery: %d: %v", delivery.DeliveryTag, err)
a.conn.Close()
}
}
@@ -541,7 +538,7 @@ func (a *AMQPConsumer) Stop() {
a.wg.Wait()
err := a.conn.Close()
if err != nil && err != amqp.ErrClosed {
log.Printf("E! [inputs.amqp_consumer] Error closing AMQP connection: %s", err)
a.Log.Errorf("Error closing AMQP connection: %s", err)
return
}
}
@@ -1,9 +1,8 @@
package activemq
package azure_storage_queue
import (
"context"
"errors"
"log"
"net/url"
"strings"
"time"
@@ -17,6 +16,7 @@ type AzureStorageQueue struct {
StorageAccountName string `toml:"account_name"`
StorageAccountKey string `toml:"account_key"`
PeekOldestMessageAge bool `toml:"peek_oldest_message_age"`
Log telegraf.Logger
serviceURL *azqueue.ServiceURL
}
@@ -92,7 +92,7 @@ func (a *AzureStorageQueue) Gather(acc telegraf.Accumulator) error {
ctx := context.TODO()
for marker := (azqueue.Marker{}); marker.NotDone(); {
log.Printf("D! [inputs.azure_storage_queue] Listing queues of storage account '%s'", a.StorageAccountName)
a.Log.Debugf("Listing queues of storage account '%s'", a.StorageAccountName)
queuesSegment, err := serviceURL.ListQueuesSegment(ctx, marker,
azqueue.ListQueuesSegmentOptions{
Detail: azqueue.ListQueuesSegmentDetails{Metadata: false},
@@ -103,11 +103,11 @@ func (a *AzureStorageQueue) Gather(acc telegraf.Accumulator) error {
marker = queuesSegment.NextMarker
for _, queueItem := range queuesSegment.QueueItems {
log.Printf("D! [inputs.azure_storage_queue] Processing queue '%s' of storage account '%s'", queueItem.Name, a.StorageAccountName)
a.Log.Debugf("Processing queue '%s' of storage account '%s'", queueItem.Name, a.StorageAccountName)
queueURL := serviceURL.NewQueueURL(queueItem.Name)
properties, err := queueURL.GetProperties(ctx)
if err != nil {
log.Printf("E! [inputs.azure_storage_queue] Error getting properties for queue %s: %s", queueItem.Name, err.Error())
a.Log.Errorf("Error getting properties for queue %s: %s", queueItem.Name, err.Error())
continue
}
var peekedMessage *azqueue.PeekedMessage
@@ -115,7 +115,7 @@ func (a *AzureStorageQueue) Gather(acc telegraf.Accumulator) error {
messagesURL := queueURL.NewMessagesURL()
messagesResponse, err := messagesURL.Peek(ctx, 1)
if err != nil {
log.Printf("E! [inputs.azure_storage_queue] Error peeking queue %s: %s", queueItem.Name, err.Error())
a.Log.Errorf("Error peeking queue %s: %s", queueItem.Name, err.Error())
} else if messagesResponse.NumMessages() > 0 {
peekedMessage = messagesResponse.Message(0)
}
+3 -3
View File
@@ -101,12 +101,12 @@ func (c *Ceph) gatherAdminSocketStats(acc telegraf.Accumulator) error {
for _, s := range sockets {
dump, err := perfDump(c.CephBinary, s)
if err != nil {
acc.AddError(fmt.Errorf("E! error reading from socket '%s': %v", s.socket, err))
acc.AddError(fmt.Errorf("error reading from socket '%s': %v", s.socket, err))
continue
}
data, err := parseDump(dump)
if err != nil {
acc.AddError(fmt.Errorf("E! error parsing dump from socket '%s': %v", s.socket, err))
acc.AddError(fmt.Errorf("error parsing dump from socket '%s': %v", s.socket, err))
continue
}
for tag, metrics := range data {
@@ -287,7 +287,7 @@ func flatten(data interface{}) []*metric {
}
}
default:
log.Printf("I! Ignoring unexpected type '%T' for value %v", val, val)
log.Printf("I! [inputs.ceph] ignoring unexpected type '%T' for value %v", val, val)
}
return metrics
@@ -7,8 +7,8 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"path"
"strings"
"sync"
"time"
@@ -54,6 +54,8 @@ type CiscoTelemetryGNMI struct {
acc telegraf.Accumulator
cancel context.CancelFunc
wg sync.WaitGroup
Log telegraf.Logger
}
// Subscription for a GNMI client
@@ -101,21 +103,27 @@ func (c *CiscoTelemetryGNMI) Start(acc telegraf.Accumulator) error {
// Invert explicit alias list and prefill subscription names
c.aliases = make(map[string]string, len(c.Subscriptions)+len(c.Aliases))
for _, subscription := range c.Subscriptions {
var gnmiLongPath, gnmiShortPath *gnmi.Path
// Build the subscription path without keys
gnmiPath, err := parsePath(subscription.Origin, subscription.Path, "")
if err != nil {
if gnmiLongPath, err = parsePath(subscription.Origin, subscription.Path, ""); err != nil {
return err
}
if gnmiShortPath, err = parsePath("", subscription.Path, ""); err != nil {
return err
}
path, _ := c.handlePath(gnmiPath, nil, "")
longPath, _ := c.handlePath(gnmiLongPath, nil, "")
shortPath, _ := c.handlePath(gnmiShortPath, nil, "")
name := subscription.Name
// If the user didn't provide a measurement name, use last path element
if len(name) == 0 {
name = path[strings.LastIndexByte(path, '/')+1:]
name = path.Base(shortPath)
}
if len(name) > 0 {
c.aliases[path] = name
c.aliases[longPath] = name
c.aliases[shortPath] = name
}
}
for alias, path := range c.Aliases {
@@ -211,8 +219,8 @@ func (c *CiscoTelemetryGNMI) subscribeGNMI(ctx context.Context, address string,
return fmt.Errorf("failed to send subscription request: %v", err)
}
log.Printf("D! [inputs.cisco_telemetry_gnmi]: Connection to GNMI device %s established", address)
defer log.Printf("D! [inputs.cisco_telemetry_gnmi]: Connection to GNMI device %s closed", address)
c.Log.Debugf("Connection to GNMI device %s established", address)
defer c.Log.Debugf("Connection to GNMI device %s closed", address)
for ctx.Err() == nil {
var reply *gnmi.SubscribeResponse
if reply, err = subscribeClient.Recv(); err != nil {
@@ -267,7 +275,7 @@ func (c *CiscoTelemetryGNMI) handleSubscribeResponse(address string, reply *gnmi
if alias, ok := c.aliases[aliasPath]; ok {
name = alias
} else {
log.Printf("D! [inputs.cisco_telemetry_gnmi]: No measurement alias for GNMI path: %s", name)
c.Log.Debugf("No measurement alias for GNMI path: %s", name)
}
}
@@ -295,6 +303,12 @@ func (c *CiscoTelemetryGNMI) handleTelemetryField(update *gnmi.Update, tags map[
var value interface{}
var jsondata []byte
// Make sure a value is actually set
if update.Val == nil || update.Val.Value == nil {
c.Log.Infof("Discarded empty or legacy type value with path: %q", path)
return aliasPath, nil
}
switch val := update.Val.Value.(type) {
case *gnmi.TypedValue_AsciiVal:
value = val.AsciiVal
@@ -346,8 +360,10 @@ func (c *CiscoTelemetryGNMI) handlePath(path *gnmi.Path, tags map[string]string,
// Parse generic keys from prefix
for _, elem := range path.Elem {
builder.WriteRune('/')
builder.WriteString(elem.Name)
if len(elem.Name) > 0 {
builder.WriteRune('/')
builder.WriteString(elem.Name)
}
name := builder.String()
if _, exists := c.aliases[name]; exists {
@@ -104,8 +104,10 @@ func TestGNMIError(t *testing.T) {
acc := &testutil.Accumulator{}
gnmi.RegisterGNMIServer(server, &mockGNMIServer{t: t, scenario: 0, server: server, acc: acc})
c := &CiscoTelemetryGNMI{Addresses: []string{listener.Addr().String()},
Username: "theuser", Password: "thepassword", Encoding: "proto",
c := &CiscoTelemetryGNMI{
Log: testutil.Logger{},
Addresses: []string{listener.Addr().String()},
Username: "theuser", Password: "thepassword", Encoding: "proto",
Redial: internal.Duration{Duration: 1 * time.Second}}
require.NoError(t, c.Start(acc))
@@ -174,8 +176,10 @@ func TestGNMIMultiple(t *testing.T) {
acc := &testutil.Accumulator{}
gnmi.RegisterGNMIServer(server, &mockGNMIServer{t: t, scenario: 1, server: server, acc: acc})
c := &CiscoTelemetryGNMI{Addresses: []string{listener.Addr().String()},
Username: "theuser", Password: "thepassword", Encoding: "proto",
c := &CiscoTelemetryGNMI{
Log: testutil.Logger{},
Addresses: []string{listener.Addr().String()},
Username: "theuser", Password: "thepassword", Encoding: "proto",
Redial: internal.Duration{Duration: 1 * time.Second},
Subscriptions: []Subscription{{Name: "alias", Origin: "type", Path: "/model", SubscriptionMode: "sample"}},
}
@@ -215,8 +219,10 @@ func TestGNMIMultipleRedial(t *testing.T) {
acc := &testutil.Accumulator{}
gnmi.RegisterGNMIServer(server, &mockGNMIServer{t: t, scenario: 2, server: server, acc: acc})
c := &CiscoTelemetryGNMI{Addresses: []string{listener.Addr().String()},
Username: "theuser", Password: "thepassword", Encoding: "proto",
c := &CiscoTelemetryGNMI{
Log: testutil.Logger{},
Addresses: []string{listener.Addr().String()},
Username: "theuser", Password: "thepassword", Encoding: "proto",
Redial: internal.Duration{Duration: 10 * time.Millisecond},
Subscriptions: []Subscription{{Name: "alias", Origin: "type", Path: "/model", SubscriptionMode: "sample"}},
}
@@ -5,7 +5,6 @@ import (
"encoding/binary"
"fmt"
"io"
"log"
"net"
"path"
"strconv"
@@ -43,6 +42,8 @@ type CiscoTelemetryMDT struct {
Aliases map[string]string `toml:"aliases"`
EmbeddedTags []string `toml:"embedded_tags"`
Log telegraf.Logger
// GRPC TLS settings
internaltls.ServerConfig
@@ -146,11 +147,11 @@ func (c *CiscoTelemetryMDT) acceptTCPClients() {
// Individual client connection routine
c.wg.Add(1)
go func() {
log.Printf("D! [inputs.cisco_telemetry_mdt]: Accepted Cisco MDT TCP dialout connection from %s", conn.RemoteAddr())
c.Log.Debugf("Accepted Cisco MDT TCP dialout connection from %s", conn.RemoteAddr())
if err := c.handleTCPClient(conn); err != nil {
c.acc.AddError(err)
}
log.Printf("D! [inputs.cisco_telemetry_mdt]: Closed Cisco MDT TCP dialout connection from %s", conn.RemoteAddr())
c.Log.Debugf("Closed Cisco MDT TCP dialout connection from %s", conn.RemoteAddr())
mutex.Lock()
delete(clients, conn)
@@ -165,7 +166,7 @@ func (c *CiscoTelemetryMDT) acceptTCPClients() {
mutex.Lock()
for client := range clients {
if err := client.Close(); err != nil {
log.Printf("E! [inputs.cisco_telemetry_mdt]: Failed to close TCP dialout client: %v", err)
c.Log.Errorf("Failed to close TCP dialout client: %v", err)
}
}
mutex.Unlock()
@@ -218,7 +219,7 @@ func (c *CiscoTelemetryMDT) handleTCPClient(conn net.Conn) error {
func (c *CiscoTelemetryMDT) MdtDialout(stream dialout.GRPCMdtDialout_MdtDialoutServer) error {
peer, peerOK := peer.FromContext(stream.Context())
if peerOK {
log.Printf("D! [inputs.cisco_telemetry_mdt]: Accepted Cisco MDT GRPC dialout connection from %s", peer.Addr)
c.Log.Debugf("Accepted Cisco MDT GRPC dialout connection from %s", peer.Addr)
}
var chunkBuffer bytes.Buffer
@@ -252,7 +253,7 @@ func (c *CiscoTelemetryMDT) MdtDialout(stream dialout.GRPCMdtDialout_MdtDialoutS
}
if peerOK {
log.Printf("D! [inputs.cisco_telemetry_mdt]: Closed Cisco MDT GRPC dialout connection from %s", peer.Addr)
c.Log.Debugf("Closed Cisco MDT GRPC dialout connection from %s", peer.Addr)
}
return nil
@@ -291,7 +292,7 @@ func (c *CiscoTelemetryMDT) handleTelemetry(data []byte) {
}
if keys == nil || content == nil {
log.Printf("I! [inputs.cisco_telemetry_mdt]: Message from %s missing keys or content", msg.GetNodeIdStr())
c.Log.Infof("Message from %s missing keys or content", msg.GetNodeIdStr())
continue
}
@@ -412,7 +413,7 @@ func (c *CiscoTelemetryMDT) parseContentField(grouper *metric.SeriesGrouper, fie
} else {
c.mutex.Lock()
if _, haveWarned := c.warned[path]; !haveWarned {
log.Printf("D! [inputs.cisco_telemetry_mdt]: No measurement alias for encoding path: %s", path)
c.Log.Debugf("No measurement alias for encoding path: %s", path)
c.warned[path] = struct{}{}
}
c.mutex.Unlock()
@@ -18,7 +18,7 @@ import (
)
func TestHandleTelemetryTwoSimple(t *testing.T) {
c := &CiscoTelemetryMDT{Transport: "dummy", Aliases: map[string]string{"alias": "type:model/some/path"}}
c := &CiscoTelemetryMDT{Log: testutil.Logger{}, Transport: "dummy", Aliases: map[string]string{"alias": "type:model/some/path"}}
acc := &testutil.Accumulator{}
c.Start(acc)
@@ -93,7 +93,7 @@ func TestHandleTelemetryTwoSimple(t *testing.T) {
}
func TestHandleTelemetrySingleNested(t *testing.T) {
c := &CiscoTelemetryMDT{Transport: "dummy", Aliases: map[string]string{"nested": "type:model/nested/path"}}
c := &CiscoTelemetryMDT{Log: testutil.Logger{}, Transport: "dummy", Aliases: map[string]string{"nested": "type:model/nested/path"}}
acc := &testutil.Accumulator{}
c.Start(acc)
@@ -385,7 +385,7 @@ func TestHandleNXDME(t *testing.T) {
}
func TestTCPDialoutOverflow(t *testing.T) {
c := &CiscoTelemetryMDT{Transport: "tcp", ServiceAddress: "127.0.0.1:57000"}
c := &CiscoTelemetryMDT{Log: testutil.Logger{}, Transport: "tcp", ServiceAddress: "127.0.0.1:57000"}
acc := &testutil.Accumulator{}
assert.Nil(t, c.Start(acc))
@@ -441,7 +441,7 @@ func mockTelemetryMessage() *telemetry.Telemetry {
}
func TestTCPDialoutMultiple(t *testing.T) {
c := &CiscoTelemetryMDT{Transport: "tcp", ServiceAddress: "127.0.0.1:57000", Aliases: map[string]string{
c := &CiscoTelemetryMDT{Log: testutil.Logger{}, Transport: "tcp", ServiceAddress: "127.0.0.1:57000", Aliases: map[string]string{
"some": "type:model/some/path", "parallel": "type:model/parallel/path", "other": "type:model/other/path"}}
acc := &testutil.Accumulator{}
assert.Nil(t, c.Start(acc))
@@ -500,7 +500,7 @@ func TestTCPDialoutMultiple(t *testing.T) {
}
func TestGRPCDialoutError(t *testing.T) {
c := &CiscoTelemetryMDT{Transport: "grpc", ServiceAddress: "127.0.0.1:57001"}
c := &CiscoTelemetryMDT{Log: testutil.Logger{}, Transport: "grpc", ServiceAddress: "127.0.0.1:57001"}
acc := &testutil.Accumulator{}
assert.Nil(t, c.Start(acc))
@@ -519,7 +519,7 @@ func TestGRPCDialoutError(t *testing.T) {
}
func TestGRPCDialoutMultiple(t *testing.T) {
c := &CiscoTelemetryMDT{Transport: "grpc", ServiceAddress: "127.0.0.1:57001", Aliases: map[string]string{
c := &CiscoTelemetryMDT{Log: testutil.Logger{}, Transport: "grpc", ServiceAddress: "127.0.0.1:57001", Aliases: map[string]string{
"some": "type:model/some/path", "parallel": "type:model/parallel/path", "other": "type:model/other/path"}}
acc := &testutil.Accumulator{}
assert.Nil(t, c.Start(acc))
+9 -7
View File
@@ -5,16 +5,16 @@ import (
"fmt"
"sync"
"cloud.google.com/go/pubsub"
"encoding/base64"
"time"
"cloud.google.com/go/pubsub"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/parsers"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
"log"
"time"
)
type empty struct{}
@@ -43,6 +43,8 @@ type PubSub struct {
Base64Data bool `toml:"base64_data"`
Log telegraf.Logger
sub subscription
stubSub func() subscription
@@ -134,14 +136,14 @@ func (ps *PubSub) receiveWithRetry(parentCtx context.Context) {
err := ps.startReceiver(parentCtx)
for err != nil && parentCtx.Err() == nil {
log.Printf("E! [inputs.cloud_pubsub] Receiver for subscription %s exited with error: %v", ps.sub.ID(), err)
ps.Log.Errorf("Receiver for subscription %s exited with error: %v", ps.sub.ID(), err)
delay := defaultRetryDelaySeconds
if ps.RetryReceiveDelaySeconds > 0 {
delay = ps.RetryReceiveDelaySeconds
}
log.Printf("I! [inputs.cloud_pubsub] Waiting %d seconds before attempting to restart receiver...", delay)
ps.Log.Infof("Waiting %d seconds before attempting to restart receiver...", delay)
time.Sleep(time.Duration(delay) * time.Second)
err = ps.startReceiver(parentCtx)
@@ -149,7 +151,7 @@ func (ps *PubSub) receiveWithRetry(parentCtx context.Context) {
}
func (ps *PubSub) startReceiver(parentCtx context.Context) error {
log.Printf("I! [inputs.cloud_pubsub] Starting receiver for subscription %s...", ps.sub.ID())
ps.Log.Infof("Starting receiver for subscription %s...", ps.sub.ID())
cctx, ccancel := context.WithCancel(parentCtx)
err := ps.sub.Receive(cctx, func(ctx context.Context, msg message) {
if err := ps.onMessage(ctx, msg); err != nil {
@@ -159,7 +161,7 @@ func (ps *PubSub) startReceiver(parentCtx context.Context) error {
if err != nil {
ps.acc.AddError(fmt.Errorf("receiver for subscription %s exited: %v", ps.sub.ID(), err))
} else {
log.Printf("I! [inputs.cloud_pubsub] subscription pull ended (no error, most likely stopped)")
ps.Log.Info("Subscription pull ended (no error, most likely stopped)")
}
ccancel()
return err
+7 -1
View File
@@ -3,10 +3,11 @@ package cloud_pubsub
import (
"encoding/base64"
"errors"
"testing"
"github.com/influxdata/telegraf/plugins/parsers"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/assert"
"testing"
)
const (
@@ -26,6 +27,7 @@ func TestRunParse(t *testing.T) {
sub.receiver = testMessagesReceive(sub)
ps := &PubSub{
Log: testutil.Logger{},
parser: testParser,
stubSub: func() subscription { return sub },
Project: "projectIDontMatterForTests",
@@ -69,6 +71,7 @@ func TestRunBase64(t *testing.T) {
sub.receiver = testMessagesReceive(sub)
ps := &PubSub{
Log: testutil.Logger{},
parser: testParser,
stubSub: func() subscription { return sub },
Project: "projectIDontMatterForTests",
@@ -112,6 +115,7 @@ func TestRunInvalidMessages(t *testing.T) {
sub.receiver = testMessagesReceive(sub)
ps := &PubSub{
Log: testutil.Logger{},
parser: testParser,
stubSub: func() subscription { return sub },
Project: "projectIDontMatterForTests",
@@ -158,6 +162,7 @@ func TestRunOverlongMessages(t *testing.T) {
sub.receiver = testMessagesReceive(sub)
ps := &PubSub{
Log: testutil.Logger{},
parser: testParser,
stubSub: func() subscription { return sub },
Project: "projectIDontMatterForTests",
@@ -205,6 +210,7 @@ func TestRunErrorInSubscriber(t *testing.T) {
sub.receiver = testMessagesError(sub, errors.New("a fake error"))
ps := &PubSub{
Log: testutil.Logger{},
parser: testParser,
stubSub: func() subscription { return sub },
Project: "projectIDontMatterForTests",
@@ -6,7 +6,6 @@ import (
"encoding/base64"
"encoding/json"
"io/ioutil"
"log"
"net"
"net/http"
"sync"
@@ -33,6 +32,7 @@ type PubSubPush struct {
WriteTimeout internal.Duration
MaxBodySize internal.Size
AddMeta bool
Log telegraf.Logger
MaxUndeliveredMessages int `toml:"max_undelivered_messages"`
@@ -227,21 +227,21 @@ func (p *PubSubPush) serveWrite(res http.ResponseWriter, req *http.Request) {
var payload Payload
if err = json.Unmarshal(bytes, &payload); err != nil {
log.Printf("E! [inputs.cloud_pubsub_push] Error decoding payload %s", err.Error())
p.Log.Errorf("Error decoding payload %s", err.Error())
res.WriteHeader(http.StatusBadRequest)
return
}
sDec, err := base64.StdEncoding.DecodeString(payload.Msg.Data)
if err != nil {
log.Printf("E! [inputs.cloud_pubsub_push] Base64-Decode Failed %s", err.Error())
p.Log.Errorf("Base64-decode failed %s", err.Error())
res.WriteHeader(http.StatusBadRequest)
return
}
metrics, err := p.Parse(sDec)
if err != nil {
log.Println("D! [inputs.cloud_pubsub_push] " + err.Error())
p.Log.Debug(err.Error())
res.WriteHeader(http.StatusBadRequest)
return
}
@@ -295,7 +295,7 @@ func (p *PubSubPush) receiveDelivered() {
ch <- true
} else {
ch <- false
log.Println("D! [inputs.cloud_pubsub_push] Metric group failed to process")
p.Log.Debug("Metric group failed to process")
}
}
}
@@ -18,6 +18,7 @@ import (
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/models"
"github.com/influxdata/telegraf/plugins/parsers"
"github.com/influxdata/telegraf/testutil"
)
func TestServeHTTP(t *testing.T) {
@@ -118,6 +119,7 @@ func TestServeHTTP(t *testing.T) {
rr := httptest.NewRecorder()
pubPush := &PubSubPush{
Log: testutil.Logger{},
Path: "/",
MaxBodySize: internal.Size{
Size: test.maxsize,
+50 -82
View File
@@ -1,12 +1,9 @@
# Telegraf plugin: CPU
# CPU Input Plugin
#### Plugin arguments:
- **totalcpu** boolean: If true, include `cpu-total` data
- **percpu** boolean: If true, include data on a per-cpu basis `cpu0, cpu1, etc.`
The `cpu` plugin gather metrics on the system CPUs.
##### Configuration:
```
#### Configuration
```toml
[[inputs.cpu]]
## Whether to report per-cpu stats or not
percpu = true
@@ -18,82 +15,53 @@
report_active = false
```
#### Description
### Metrics
The CPU plugin collects standard CPU metrics as defined in `man proc`. All
architectures do not support all of these metrics.
On Linux, consult `man proc` for details on the meanings of these values.
- cpu
- tags:
- cpu (CPU ID or `cpu-total`)
- fields:
- time_user (float)
- time_system (float)
- time_idle (float)
- time_active (float)
- time_nice (float)
- time_iowait (float)
- time_irq (float)
- time_softirq (float)
- time_steal (float)
- time_guest (float)
- time_guest_nice (float)
- usage_user (float, percent)
- usage_system (float, percent)
- usage_idle (float, percent)
- usage_active (float)
- usage_nice (float, percent)
- usage_iowait (float, percent)
- usage_irq (float, percent)
- usage_softirq (float, percent)
- usage_steal (float, percent)
- usage_guest (float, percent)
- usage_guest_nice (float, percent)
### Troubleshooting
On Linux systems the `/proc/stat` file is used to gather CPU times.
Percentages are based on the last 2 samples.
### Example Output
```
cpu 3357 0 4313 1362393
The amount of time, measured in units of USER_HZ (1/100ths of a second on
most architectures, use sysconf(_SC_CLK_TCK) to obtain the right value),
that the system spent in various states:
user (1) Time spent in user mode.
nice (2) Time spent in user mode with low priority (nice).
system (3) Time spent in system mode.
idle (4) Time spent in the idle task. This value should be USER_HZ times
the second entry in the /proc/uptime pseudo-file.
iowait (since Linux 2.5.41)
(5) Time waiting for I/O to complete.
irq (since Linux 2.6.0-test4)
(6) Time servicing interrupts.
softirq (since Linux 2.6.0-test4)
(7) Time servicing softirqs.
steal (since Linux 2.6.11)
(8) Stolen time, which is the time spent in other operating systems
when running in a virtualized environment
guest (since Linux 2.6.24)
(9) Time spent running a virtual CPU for guest operating systems
under the control of the Linux kernel.
guest_nice (since Linux 2.6.33)
(10) Time spent running a niced guest (virtual CPU for guest operating systems under the control of the Linux kernel).
cpu,cpu=cpu0,host=loaner time_active=202224.15999999992,time_guest=30250.35,time_guest_nice=0,time_idle=1527035.04,time_iowait=1352,time_irq=0,time_nice=169.28,time_softirq=6281.4,time_steal=0,time_system=40097.14,time_user=154324.34 1568760922000000000
cpu,cpu=cpu0,host=loaner usage_active=31.249999981810106,usage_guest=2.083333333080696,usage_guest_nice=0,usage_idle=68.7500000181899,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=0,usage_steal=0,usage_system=4.166666666161392,usage_user=25.000000002273737 1568760922000000000
cpu,cpu=cpu1,host=loaner time_active=201890.02000000002,time_guest=30508.41,time_guest_nice=0,time_idle=264641.18,time_iowait=210.44,time_irq=0,time_nice=181.75,time_softirq=4537.88,time_steal=0,time_system=39480.7,time_user=157479.25 1568760922000000000
cpu,cpu=cpu1,host=loaner usage_active=12.500000010610771,usage_guest=2.0833333328280585,usage_guest_nice=0,usage_idle=87.49999998938922,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=2.0833333332070145,usage_steal=0,usage_system=4.166666665656117,usage_user=4.166666666414029 1568760922000000000
cpu,cpu=cpu2,host=loaner time_active=201382.78999999998,time_guest=30325.8,time_guest_nice=0,time_idle=264686.63,time_iowait=202.77,time_irq=0,time_nice=162.81,time_softirq=3378.34,time_steal=0,time_system=39270.59,time_user=158368.28 1568760922000000000
cpu,cpu=cpu2,host=loaner usage_active=15.999999993480742,usage_guest=1.9999999999126885,usage_guest_nice=0,usage_idle=84.00000000651926,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=2.0000000002764864,usage_steal=0,usage_system=3.999999999825377,usage_user=7.999999998923158 1568760922000000000
cpu,cpu=cpu3,host=loaner time_active=198953.51000000007,time_guest=30344.43,time_guest_nice=0,time_idle=265504.09,time_iowait=187.64,time_irq=0,time_nice=197.47,time_softirq=2301.47,time_steal=0,time_system=39313.73,time_user=156953.2 1568760922000000000
cpu,cpu=cpu3,host=loaner usage_active=10.41666667424579,usage_guest=0,usage_guest_nice=0,usage_idle=89.58333332575421,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=0,usage_steal=0,usage_system=4.166666666666667,usage_user=6.249999998484175 1568760922000000000
cpu,cpu=cpu-total,host=loaner time_active=804450.5299999998,time_guest=121429,time_guest_nice=0,time_idle=2321866.96,time_iowait=1952.86,time_irq=0,time_nice=711.32,time_softirq=16499.1,time_steal=0,time_system=158162.17,time_user=627125.08 1568760922000000000
cpu,cpu=cpu-total,host=loaner usage_active=17.616580305880305,usage_guest=1.036269430422946,usage_guest_nice=0,usage_idle=82.3834196941197,usage_iowait=0,usage_irq=0,usage_nice=0,usage_softirq=1.0362694300459534,usage_steal=0,usage_system=4.145077721691784,usage_user=11.398963731636465 1568760922000000000
```
# Measurements:
### CPU Time measurements:
Meta:
- units: CPU Time
- tags: `cpu=<cpuN> or <cpu-total>`
Measurement names:
- cpu_time_user
- cpu_time_system
- cpu_time_idle
- cpu_time_active (must be explicitly enabled by setting `report_active = true`)
- cpu_time_nice
- cpu_time_iowait
- cpu_time_irq
- cpu_time_softirq
- cpu_time_steal
- cpu_time_guest
- cpu_time_guest_nice
### CPU Usage Percent Measurements:
Meta:
- units: percent (out of 100)
- tags: `cpu=<cpuN> or <cpu-total>`
Measurement names:
- cpu_usage_user
- cpu_usage_system
- cpu_usage_idle
- cpu_usage_active (must be explicitly enabled by setting `report_active = true`)
- cpu_usage_nice
- cpu_usage_iowait
- cpu_usage_irq
- cpu_usage_softirq
- cpu_usage_steal
- cpu_usage_guest
- cpu_usage_guest_nice
+6 -5
View File
@@ -2,7 +2,6 @@ package diskio
import (
"fmt"
"log"
"regexp"
"strings"
@@ -24,6 +23,8 @@ type DiskIO struct {
NameTemplates []string
SkipSerialNumber bool
Log telegraf.Logger
infoCache map[string]diskInfoCache
deviceFilter filter.Filter
initialized bool
@@ -75,7 +76,7 @@ func (s *DiskIO) init() error {
if hasMeta(device) {
filter, err := filter.Compile(s.Devices)
if err != nil {
return fmt.Errorf("error compiling device pattern: %v", err)
return fmt.Errorf("error compiling device pattern: %s", err.Error())
}
s.deviceFilter = filter
}
@@ -99,7 +100,7 @@ func (s *DiskIO) Gather(acc telegraf.Accumulator) error {
diskio, err := s.ps.DiskIO(devices)
if err != nil {
return fmt.Errorf("error getting disk io info: %s", err)
return fmt.Errorf("error getting disk io info: %s", err.Error())
}
for _, io := range diskio {
@@ -166,7 +167,7 @@ func (s *DiskIO) diskName(devName string) (string, []string) {
}
if err != nil {
log.Printf("W! Error gathering disk info: %s", err)
s.Log.Warnf("Error gathering disk info: %s", err)
return devName, devLinks
}
@@ -199,7 +200,7 @@ func (s *DiskIO) diskTags(devName string) map[string]string {
di, err := s.diskInfo(devName)
if err != nil {
log.Printf("W! Error gathering disk info: %s", err)
s.Log.Warnf("Error gathering disk info: %s", err)
return nil
}
+1
View File
@@ -103,6 +103,7 @@ func TestDiskIO(t *testing.T) {
var acc testutil.Accumulator
diskio := &DiskIO{
Log: testutil.Logger{},
ps: &mps,
Devices: tt.devices,
}
+14
View File
@@ -26,6 +26,9 @@ to gather stats from the [Engine API](https://docs.docker.com/engine/api/v1.24/)
## Deprecated (1.4.0), use container_name_include
container_names = []
## Set the source tag for the metrics to the container ID hostname, eg first 12 chars
source_tag = false
## Containers to include and exclude. Collect all if empty. Globs accepted.
container_name_include = []
container_name_exclude = []
@@ -93,6 +96,17 @@ volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
#### source tag
Selecting the containers measurements can be tricky if you have many containers with the same name.
To alleviate this issue you can set the below value to `true`
```toml
source_tag = true
```
This will cause all measurements to have the `source` tag be set to the first 12 characters of the container id. The first 12 characters is the common hostname for containers that have no explicit hostname set, as defined by docker.
#### Kubernetes Labels
Kubernetes may add many labels to your containers, if they are not needed you
+21 -2
View File
@@ -6,7 +6,6 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"regexp"
"strconv"
@@ -45,6 +44,10 @@ type Docker struct {
ContainerStateInclude []string `toml:"container_state_include"`
ContainerStateExclude []string `toml:"container_state_exclude"`
IncludeSourceTag bool `toml:"source_tag"`
Log telegraf.Logger
tlsint.ClientConfig
newEnvClient func() (Client, error)
@@ -89,6 +92,9 @@ var sampleConfig = `
## Only collect metrics for these containers, collect all if empty
container_names = []
## Set the source tag for the metrics to the container ID hostname, eg first 12 chars
source_tag = false
## Containers to include and exclude. Globs accepted.
## Note that an empty array for both will include all containers
container_name_include = []
@@ -107,8 +113,10 @@ var sampleConfig = `
## Whether to report for each container per-device blkio (8:0, 8:1...) and
## network (eth0, eth1, ...) stats or not
perdevice = true
## Whether to report for each container total blkio and network stats or not
total = false
## Which environment variables should we use as a tag
##tag_env = ["JAVA_HOME", "HEAP_SIZE"]
@@ -274,7 +282,7 @@ func (d *Docker) gatherSwarmInfo(acc telegraf.Accumulator) error {
fields["tasks_running"] = running[service.ID]
fields["tasks_desired"] = tasksNoShutdown[service.ID]
} else {
log.Printf("E! Unknow Replicas Mode")
d.Log.Error("Unknown replica mode")
}
// Add metrics
acc.AddFields("docker_swarm",
@@ -409,6 +417,13 @@ func (d *Docker) gatherInfo(acc telegraf.Accumulator) error {
return nil
}
func hostnameFromID(id string) string {
if len(id) > 12 {
return id[0:12]
}
return id
}
func (d *Docker) gatherContainer(
container types.Container,
acc telegraf.Accumulator,
@@ -440,6 +455,10 @@ func (d *Docker) gatherContainer(
"container_version": imageVersion,
}
if d.IncludeSourceTag {
tags["source"] = hostnameFromID(container.ID)
}
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
defer cancel()
+47 -1
View File
@@ -252,6 +252,7 @@ func TestDocker_WindowsMemoryContainerStats(t *testing.T) {
var acc testutil.Accumulator
d := Docker{
Log: testutil.Logger{},
newClient: func(string, *tls.Config) (Client, error) {
return &MockClient{
InfoF: func(ctx context.Context) (types.Info, error) {
@@ -390,6 +391,7 @@ func TestContainerLabels(t *testing.T) {
}
d := Docker{
Log: testutil.Logger{},
newClient: newClientFunc,
LabelInclude: tt.include,
LabelExclude: tt.exclude,
@@ -511,6 +513,7 @@ func TestContainerNames(t *testing.T) {
}
d := Docker{
Log: testutil.Logger{},
newClient: newClientFunc,
ContainerInclude: tt.include,
ContainerExclude: tt.exclude,
@@ -625,7 +628,11 @@ func TestContainerStatus(t *testing.T) {
return &client, nil
}
d = Docker{newClient: newClientFunc}
d = Docker{
Log: testutil.Logger{},
newClient: newClientFunc,
IncludeSourceTag: true,
}
)
// mock time
@@ -667,6 +674,7 @@ func TestContainerStatus(t *testing.T) {
"label2": "test_value_2",
"server_version": "17.09.0-ce",
"container_status": tt.expect.Status,
"source": "e2173b9478a6",
})
})
}
@@ -675,6 +683,7 @@ func TestContainerStatus(t *testing.T) {
func TestDockerGatherInfo(t *testing.T) {
var acc testutil.Accumulator
d := Docker{
Log: testutil.Logger{},
newClient: newClient,
TagEnvironment: []string{"ENVVAR1", "ENVVAR2", "ENVVAR3", "ENVVAR5",
"ENVVAR6", "ENVVAR7", "ENVVAR8", "ENVVAR9"},
@@ -824,6 +833,7 @@ func TestDockerGatherInfo(t *testing.T) {
func TestDockerGatherSwarmInfo(t *testing.T) {
var acc testutil.Accumulator
d := Docker{
Log: testutil.Logger{},
newClient: newClient,
}
@@ -931,6 +941,7 @@ func TestContainerStateFilter(t *testing.T) {
}
d := Docker{
Log: testutil.Logger{},
newClient: newClientFunc,
ContainerStateInclude: tt.include,
ContainerStateExclude: tt.exclude,
@@ -992,6 +1003,7 @@ func TestContainerName(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := Docker{
Log: testutil.Logger{},
newClient: tt.clientFunc,
}
var acc testutil.Accumulator
@@ -1007,3 +1019,37 @@ func TestContainerName(t *testing.T) {
})
}
}
func TestHostnameFromID(t *testing.T) {
tests := []struct {
name string
id string
expect string
}{
{
name: "Real ID",
id: "565e3a55f5843cfdd4aa5659a1a75e4e78d47f73c3c483f782fe4a26fc8caa07",
expect: "565e3a55f584",
},
{
name: "Short ID",
id: "shortid123",
expect: "shortid123",
},
{
name: "No ID",
id: "",
expect: "shortid123",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
output := hostnameFromID(test.id)
if test.expect != output {
t.Logf("Container ID for hostname is wrong. Want: %s, Got: %s", output, test.expect)
}
})
}
}
+15
View File
@@ -43,6 +43,9 @@ The docker plugin uses the [Official Docker Client][] to gather logs from the
# docker_label_include = []
# docker_label_exclude = []
## Set the source tag for the metrics to the container ID hostname, eg first 12 chars
source_tag = false
## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
@@ -58,6 +61,17 @@ When using the `"ENV"` endpoint, the connection is configured using the
[env]: https://godoc.org/github.com/moby/moby/client#NewEnvClient
### source tag
Selecting the containers can be tricky if you have many containers with the same name.
To alleviate this issue you can set the below value to `true`
```toml
source_tag = true
```
This will cause all data points to have the `source` tag be set to the first 12 characters of the container id. The first 12 characters is the common hostname for containers that have no explicit hostname set, as defined by docker.
### Metrics
- docker_log
@@ -66,6 +80,7 @@ When using the `"ENV"` endpoint, the connection is configured using the
- container_version
- container_name
- stream (stdout, stderr, or tty)
- source
- fields:
- container_id
- message
+15
View File
@@ -49,6 +49,9 @@ var sampleConfig = `
# docker_label_include = []
# docker_label_exclude = []
## Set the source tag for the metrics to the container ID hostname, eg first 12 chars
source_tag = false
## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
@@ -82,6 +85,7 @@ type DockerLogs struct {
ContainerExclude []string `toml:"container_name_exclude"`
ContainerStateInclude []string `toml:"container_state_include"`
ContainerStateExclude []string `toml:"container_state_exclude"`
IncludeSourceTag bool `toml:"source_tag"`
tlsint.ClientConfig
@@ -258,6 +262,10 @@ func (d *DockerLogs) tailContainerLogs(
"container_version": imageVersion,
}
if d.IncludeSourceTag {
tags["source"] = hostnameFromID(container.ID)
}
// Add matching container labels as tags
for k, label := range container.Labels {
if d.labelFilter.Match(k) {
@@ -435,3 +443,10 @@ func init() {
}
})
}
func hostnameFromID(id string) string {
if len(id) > 12 {
return id[0:12]
}
return id
}
+6 -3
View File
@@ -98,6 +98,7 @@ func Test(t *testing.T) {
"container_image": "influxdata/telegraf",
"container_version": "1.11.0",
"stream": "tty",
"source": "deadbeef",
},
map[string]interface{}{
"container_id": "deadbeef",
@@ -141,6 +142,7 @@ func Test(t *testing.T) {
"container_image": "influxdata/telegraf",
"container_version": "1.11.0",
"stream": "stdout",
"source": "deadbeef",
},
map[string]interface{}{
"container_id": "deadbeef",
@@ -155,9 +157,10 @@ func Test(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
var acc testutil.Accumulator
plugin := &DockerLogs{
Timeout: internal.Duration{Duration: time.Second * 5},
newClient: func(string, *tls.Config) (Client, error) { return tt.client, nil },
containerList: make(map[string]context.CancelFunc),
Timeout: internal.Duration{Duration: time.Second * 5},
newClient: func(string, *tls.Config) (Client, error) { return tt.client, nil },
containerList: make(map[string]context.CancelFunc),
IncludeSourceTag: true,
}
err := plugin.Init()
+2
View File
@@ -17,8 +17,10 @@ the [upgrading steps][upgrading].
##
## If no servers are specified, then localhost is used as the host.
servers = ["localhost:24242"]
## Type is one of "user", "domain", "ip", or "global"
type = "global"
## Wildcard matches like "*.com". An empty string "" is same as "*"
## If type = "ip" filters should be <IP/network>
filters = [""]
+4 -3
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
// "log"
"net"
"strconv"
"strings"
@@ -32,8 +31,10 @@ var sampleConfig = `
##
## If no servers are specified, then localhost is used as the host.
servers = ["localhost:24242"]
## Type is one of "user", "domain", "ip", or "global"
type = "global"
## Wildcard matches like "*.com". An empty string "" is same as "*"
## If type = "ip" filters should be <IP/network>
filters = [""]
@@ -82,12 +83,12 @@ func (d *Dovecot) Gather(acc telegraf.Accumulator) error {
func (d *Dovecot) gatherServer(addr string, acc telegraf.Accumulator, qtype string, filter string) error {
_, _, err := net.SplitHostPort(addr)
if err != nil {
return fmt.Errorf("Error: %s on url %s\n", err, addr)
return fmt.Errorf("%q on url %s", err.Error(), addr)
}
c, err := net.DialTimeout("tcp", addr, defaultTimeout)
if err != nil {
return fmt.Errorf("Unable to connect to dovecot server '%s': %s", addr, err)
return fmt.Errorf("enable to connect to dovecot server '%s': %s", addr, err)
}
defer c.Close()
+3 -4
View File
@@ -10,13 +10,12 @@ import (
"sync"
"time"
"github.com/kballard/go-shellquote"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/parsers"
"github.com/influxdata/telegraf/plugins/parsers/nagios"
"github.com/kballard/go-shellquote"
)
const sampleConfig = `
@@ -50,7 +49,7 @@ type Exec struct {
parser parsers.Parser
runner Runner
log telegraf.Logger
Log telegraf.Logger `toml:"-"`
}
func NewExec() *Exec {
@@ -161,7 +160,7 @@ func (e *Exec) ProcessCommand(command string, acc telegraf.Accumulator, wg *sync
if isNagios {
metrics, err = nagios.TryAddState(runErr, metrics)
if err != nil {
e.log.Errorf("failed to add nagios state: %s", err)
e.Log.Errorf("Failed to add nagios state: %s", err)
}
}
+3 -3
View File
@@ -96,7 +96,7 @@ func TestExec(t *testing.T) {
MetricName: "exec",
})
e := &Exec{
log: testutil.Logger{},
Log: testutil.Logger{},
runner: newRunnerMock([]byte(validJson), nil, nil),
Commands: []string{"testcommand arg1"},
parser: parser,
@@ -126,7 +126,7 @@ func TestExecMalformed(t *testing.T) {
MetricName: "exec",
})
e := &Exec{
log: testutil.Logger{},
Log: testutil.Logger{},
runner: newRunnerMock([]byte(malformedJson), nil, nil),
Commands: []string{"badcommand arg1"},
parser: parser,
@@ -143,7 +143,7 @@ func TestCommandError(t *testing.T) {
MetricName: "exec",
})
e := &Exec{
log: testutil.Logger{},
Log: testutil.Logger{},
runner: newRunnerMock(nil, nil, fmt.Errorf("exit status code 1")),
Commands: []string{"badcommand"},
parser: parser,
+2 -2
View File
@@ -1,7 +1,6 @@
package filecount
import (
"log"
"os"
"path/filepath"
"time"
@@ -59,6 +58,7 @@ type FileCount struct {
fileFilters []fileFilterFunc
globPaths []globpath.GlobPath
Fs fileSystem
Log telegraf.Logger
}
func (_ *FileCount) Description() string {
@@ -210,7 +210,7 @@ func (fc *FileCount) count(acc telegraf.Accumulator, basedir string, glob globpa
Unsorted: true,
ErrorCallback: func(osPathname string, err error) godirwalk.ErrorAction {
if os.IsPermission(errors.Cause(err)) {
log.Println("D! [inputs.filecount]", err)
fc.Log.Debug(err)
return godirwalk.SkipNode
}
return godirwalk.Halt
@@ -152,6 +152,7 @@ func TestDirectoryWithTrailingSlash(t *testing.T) {
func getNoFilterFileCount() FileCount {
return FileCount{
Log: testutil.Logger{},
Directories: []string{getTestdataDir()},
Name: "*",
Recursive: true,
+1
View File
@@ -11,6 +11,7 @@ The filestat plugin gathers metrics about file existence, size, and other stats.
## These accept standard unix glob matching rules, but with the addition of
## ** as a "super asterisk". See https://github.com/gobwas/glob.
files = ["/etc/telegraf/telegraf.conf", "/var/log/**.log"]
## If true, read the entire file and calculate an md5 checksum.
md5 = false
```
+6 -4
View File
@@ -4,7 +4,6 @@ import (
"crypto/md5"
"fmt"
"io"
"log"
"os"
"github.com/influxdata/telegraf"
@@ -23,6 +22,7 @@ const sampleConfig = `
## See https://github.com/gobwas/glob for more examples
##
files = ["/var/log/**.log"]
## If true, read the entire file and calculate an md5 checksum.
md5 = false
`
@@ -31,6 +31,8 @@ type FileStat struct {
Md5 bool
Files []string
Log telegraf.Logger
// maps full file paths to globmatch obj
globs map[string]*globpath.GlobPath
}
@@ -41,11 +43,11 @@ func NewFileStat() *FileStat {
}
}
func (_ *FileStat) Description() string {
func (*FileStat) Description() string {
return "Read stats about given file(s)"
}
func (_ *FileStat) SampleConfig() string { return sampleConfig }
func (*FileStat) SampleConfig() string { return sampleConfig }
func (f *FileStat) Gather(acc telegraf.Accumulator) error {
var err error
@@ -86,7 +88,7 @@ func (f *FileStat) Gather(acc telegraf.Accumulator) error {
}
if fileInfo == nil {
log.Printf("E! Unable to get info for file [%s], possible permissions issue",
f.Log.Errorf("Unable to get info for file %q, possible permissions issue",
fileName)
} else {
fields["size_bytes"] = fileInfo.Size()
+6
View File
@@ -14,6 +14,7 @@ import (
func TestGatherNoMd5(t *testing.T) {
dir := getTestdataDir()
fs := NewFileStat()
fs.Log = testutil.Logger{}
fs.Files = []string{
dir + "log1.log",
dir + "log2.log",
@@ -44,6 +45,7 @@ func TestGatherNoMd5(t *testing.T) {
func TestGatherExplicitFiles(t *testing.T) {
dir := getTestdataDir()
fs := NewFileStat()
fs.Log = testutil.Logger{}
fs.Md5 = true
fs.Files = []string{
dir + "log1.log",
@@ -77,6 +79,7 @@ func TestGatherExplicitFiles(t *testing.T) {
func TestGatherGlob(t *testing.T) {
dir := getTestdataDir()
fs := NewFileStat()
fs.Log = testutil.Logger{}
fs.Md5 = true
fs.Files = []string{
dir + "*.log",
@@ -103,6 +106,7 @@ func TestGatherGlob(t *testing.T) {
func TestGatherSuperAsterisk(t *testing.T) {
dir := getTestdataDir()
fs := NewFileStat()
fs.Log = testutil.Logger{}
fs.Md5 = true
fs.Files = []string{
dir + "**",
@@ -136,6 +140,7 @@ func TestGatherSuperAsterisk(t *testing.T) {
func TestModificationTime(t *testing.T) {
dir := getTestdataDir()
fs := NewFileStat()
fs.Log = testutil.Logger{}
fs.Files = []string{
dir + "log1.log",
}
@@ -153,6 +158,7 @@ func TestModificationTime(t *testing.T) {
func TestNoModificationTime(t *testing.T) {
fs := NewFileStat()
fs.Log = testutil.Logger{}
fs.Files = []string{
"/non/existant/file",
}
@@ -5,7 +5,6 @@ import (
"crypto/subtle"
"crypto/tls"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
@@ -48,6 +47,7 @@ type HTTPListenerV2 struct {
tlsint.ServerConfig
TimeFunc
Log telegraf.Logger
wg sync.WaitGroup
@@ -162,7 +162,7 @@ func (h *HTTPListenerV2) Start(acc telegraf.Accumulator) error {
server.Serve(h.listener)
}()
log.Printf("I! [inputs.http_listener_v2] Listening on %s", listener.Addr().String())
h.Log.Infof("Listening on %s", listener.Addr().String())
return nil
}
@@ -219,7 +219,7 @@ func (h *HTTPListenerV2) serveWrite(res http.ResponseWriter, req *http.Request)
metrics, err := h.Parse(bytes)
if err != nil {
log.Printf("D! [inputs.http_listener_v2] Parse error: %v", err)
h.Log.Debugf("Parse error: %s", err.Error())
badRequest(res)
return
}
@@ -239,7 +239,7 @@ func (h *HTTPListenerV2) collectBody(res http.ResponseWriter, req *http.Request)
var err error
body, err = gzip.NewReader(req.Body)
if err != nil {
log.Println("D! " + err.Error())
h.Log.Debug(err.Error())
badRequest(res)
return nil, false
}
@@ -261,7 +261,7 @@ func (h *HTTPListenerV2) collectQuery(res http.ResponseWriter, req *http.Request
query, err := url.QueryUnescape(rawQuery)
if err != nil {
log.Printf("D! [inputs.http_listener_v2] Error parsing query: %v", err)
h.Log.Debugf("Error parsing query: %s", err.Error())
badRequest(res)
return nil, false
}
@@ -46,6 +46,7 @@ func newTestHTTPListenerV2() *HTTPListenerV2 {
parser, _ := parsers.NewInfluxParser()
listener := &HTTPListenerV2{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
Path: "/write",
Methods: []string{"POST"},
@@ -68,6 +69,7 @@ func newTestHTTPSListenerV2() *HTTPListenerV2 {
parser, _ := parsers.NewInfluxParser()
listener := &HTTPListenerV2{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
Path: "/write",
Methods: []string{"POST"},
@@ -231,6 +233,7 @@ func TestWriteHTTPExactMaxBodySize(t *testing.T) {
parser, _ := parsers.NewInfluxParser()
listener := &HTTPListenerV2{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
Path: "/write",
Methods: []string{"POST"},
@@ -253,6 +256,7 @@ func TestWriteHTTPVerySmallMaxBody(t *testing.T) {
parser, _ := parsers.NewInfluxParser()
listener := &HTTPListenerV2{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
Path: "/write",
Methods: []string{"POST"},
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
@@ -34,6 +33,8 @@ type HTTPResponse struct {
Interface string
tls.ClientConfig
Log telegraf.Logger
compiledStringMatch *regexp.Regexp
client *http.Client
}
@@ -242,7 +243,7 @@ func (h *HTTPResponse) httpGather(u string) (map[string]interface{}, map[string]
// HTTP error codes do not generate errors in the net/http library
if err != nil {
// Log error
log.Printf("D! Network error while polling %s: %s", u, err.Error())
h.Log.Debugf("Network error while polling %s: %s", u, err.Error())
// Get error details
netErr := setError(err, fields, tags)
@@ -271,7 +272,7 @@ func (h *HTTPResponse) httpGather(u string) (map[string]interface{}, map[string]
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("D! Failed to read body of HTTP Response : %s", err)
h.Log.Debugf("Failed to read body of HTTP Response : %s", err.Error())
setResult("body_read_error", fields, tags)
fields["content_length"] = len(bodyBytes)
if h.ResponseStringMatch != "" {
@@ -322,7 +323,7 @@ func (h *HTTPResponse) Gather(acc telegraf.Accumulator) error {
if h.Address == "" {
h.URLs = []string{"http://localhost"}
} else {
log.Printf("W! [inputs.http_response] 'address' deprecated in telegraf 1.12, please use 'urls'")
h.Log.Warn("'address' deprecated in telegraf 1.12, please use 'urls'")
h.URLs = []string{h.Address}
}
}
@@ -150,6 +150,7 @@ func TestHeaders(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL,
Method: "GET",
ResponseTimeout: internal.Duration{Duration: time.Second * 2},
@@ -185,6 +186,7 @@ func TestFields(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/good",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -246,6 +248,7 @@ func TestInterface(t *testing.T) {
require.NoError(t, err)
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/good",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -284,6 +287,7 @@ func TestRedirects(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/redirect",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -314,6 +318,7 @@ func TestRedirects(t *testing.T) {
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)
h = &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/badredirect",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -350,6 +355,7 @@ func TestMethod(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/mustbepostmethod",
Body: "{ 'test': 'data'}",
Method: "POST",
@@ -380,6 +386,7 @@ func TestMethod(t *testing.T) {
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)
h = &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/mustbepostmethod",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -411,6 +418,7 @@ func TestMethod(t *testing.T) {
//check that lowercase methods work correctly
h = &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/mustbepostmethod",
Body: "{ 'test': 'data'}",
Method: "head",
@@ -447,6 +455,7 @@ func TestBody(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/musthaveabody",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -477,6 +486,7 @@ func TestBody(t *testing.T) {
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)
h = &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/musthaveabody",
Method: "GET",
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
@@ -510,6 +520,7 @@ func TestStringMatch(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/good",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -547,6 +558,7 @@ func TestStringMatchJson(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/jsonresponse",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -584,6 +596,7 @@ func TestStringMatchFail(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/good",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -626,6 +639,7 @@ func TestTimeout(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/twosecondnap",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -659,6 +673,7 @@ func TestBadRegex(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
Address: ts.URL + "/good",
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -682,6 +697,7 @@ func TestBadRegex(t *testing.T) {
func TestNetworkErrors(t *testing.T) {
// DNS error
h := &HTTPResponse{
Log: testutil.Logger{},
Address: "https://nonexistent.nonexistent", // Any non-resolvable URL works here
Body: "",
Method: "GET",
@@ -708,6 +724,7 @@ func TestNetworkErrors(t *testing.T) {
// Connecton failed
h = &HTTPResponse{
Log: testutil.Logger{},
Address: "https:/nonexistent.nonexistent", // Any non-routable IP works here
Body: "",
Method: "GET",
@@ -739,6 +756,7 @@ func TestContentLength(t *testing.T) {
defer ts.Close()
h := &HTTPResponse{
Log: testutil.Logger{},
URLs: []string{ts.URL + "/good"},
Body: "{ 'test': 'data'}",
Method: "GET",
@@ -769,6 +787,7 @@ func TestContentLength(t *testing.T) {
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)
h = &HTTPResponse{
Log: testutil.Logger{},
URLs: []string{ts.URL + "/musthaveabody"},
Body: "{ 'test': 'data'}",
Method: "GET",
+2 -2
View File
@@ -11,10 +11,10 @@ services and hosts. You can read Icinga2's documentation for their remote API
```toml
# Description
[[inputs.icinga2]]
## Required Icinga2 server address (default: "https://localhost:5665")
## Required Icinga2 server address
# server = "https://localhost:5665"
## Required Icinga2 object type ("services" or "hosts, default "services")
## Required Icinga2 object type ("services" or "hosts")
# object_type = "services"
## Credentials for basic HTTP authentication
+22 -18
View File
@@ -3,7 +3,6 @@ package icinga2
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"time"
@@ -22,6 +21,8 @@ type Icinga2 struct {
ResponseTimeout internal.Duration
tls.ClientConfig
Log telegraf.Logger
client *http.Client
}
@@ -49,10 +50,10 @@ var levels = []string{"ok", "warning", "critical", "unknown"}
type ObjectType string
var sampleConfig = `
## Required Icinga2 server address (default: "https://localhost:5665")
## Required Icinga2 server address
# server = "https://localhost:5665"
## Required Icinga2 object type ("services" or "hosts, default "services")
## Required Icinga2 object type ("services" or "hosts")
# object_type = "services"
## Credentials for basic HTTP authentication
@@ -80,25 +81,27 @@ func (i *Icinga2) SampleConfig() string {
func (i *Icinga2) GatherStatus(acc telegraf.Accumulator, checks []Object) {
for _, check := range checks {
fields := make(map[string]interface{})
tags := make(map[string]string)
url, err := url.Parse(i.Server)
if err != nil {
log.Fatal(err)
i.Log.Error(err.Error())
continue
}
state := int64(check.Attrs.State)
fields["name"] = check.Attrs.Name
fields["state_code"] = state
fields := map[string]interface{}{
"name": check.Attrs.Name,
"state_code": state,
}
tags["display_name"] = check.Attrs.DisplayName
tags["check_command"] = check.Attrs.CheckCommand
tags["state"] = levels[state]
tags["source"] = url.Hostname()
tags["scheme"] = url.Scheme
tags["port"] = url.Port()
tags := map[string]string{
"display_name": check.Attrs.DisplayName,
"check_command": check.Attrs.CheckCommand,
"state": levels[state],
"source": url.Hostname(),
"scheme": url.Scheme,
"port": url.Port(),
}
acc.AddFields(fmt.Sprintf("icinga2_%s", i.ObjectType), fields, tags)
}
@@ -165,8 +168,9 @@ func (i *Icinga2) Gather(acc telegraf.Accumulator) error {
func init() {
inputs.Add("icinga2", func() telegraf.Input {
return &Icinga2{
Server: "https://localhost:5665",
ObjectType: "services",
Server: "https://localhost:5665",
ObjectType: "services",
ResponseTimeout: internal.Duration{Duration: time.Second * 5},
}
})
}
+2
View File
@@ -32,6 +32,7 @@ func TestGatherServicesStatus(t *testing.T) {
json.Unmarshal([]byte(s), &checks)
icinga2 := new(Icinga2)
icinga2.Log = testutil.Logger{}
icinga2.ObjectType = "services"
icinga2.Server = "https://localhost:5665"
@@ -86,6 +87,7 @@ func TestGatherHostsStatus(t *testing.T) {
var acc testutil.Accumulator
icinga2 := new(Icinga2)
icinga2.Log = testutil.Logger{}
icinga2.ObjectType = "hosts"
icinga2.Server = "https://localhost:5665"
@@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
"sync"
@@ -75,6 +74,8 @@ type HTTPListener struct {
BuffersCreated selfstat.Stat
AuthFailures selfstat.Stat
Log telegraf.Logger
longLines selfstat.Stat
}
@@ -202,7 +203,7 @@ func (h *HTTPListener) Start(acc telegraf.Accumulator) error {
server.Serve(h.listener)
}()
log.Printf("I! Started HTTP listener service on %s\n", h.ServiceAddress)
h.Log.Infof("Started HTTP listener service on %s", h.ServiceAddress)
return nil
}
@@ -215,7 +216,7 @@ func (h *HTTPListener) Stop() {
h.listener.Close()
h.wg.Wait()
log.Println("I! Stopped HTTP listener service on ", h.ServiceAddress)
h.Log.Infof("Stopped HTTP listener service on %s", h.ServiceAddress)
}
func (h *HTTPListener) ServeHTTP(res http.ResponseWriter, req *http.Request) {
@@ -274,7 +275,7 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
var err error
body, err = gzip.NewReader(req.Body)
if err != nil {
log.Println("D! " + err.Error())
h.Log.Debug(err.Error())
badRequest(res, err.Error())
return
}
@@ -290,7 +291,7 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
for {
n, err := io.ReadFull(body, buf[bufStart:])
if err != nil && err != io.ErrUnexpectedEOF && err != io.EOF {
log.Println("D! " + err.Error())
h.Log.Debug(err.Error())
// problem reading the request body
badRequest(res, err.Error())
return
@@ -327,7 +328,7 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
// finished reading the request body
err = h.parse(buf[:n+bufStart], now, precision, db)
if err != nil {
log.Println("D! "+err.Error(), bufStart+n)
h.Log.Debugf("%s: %s", err.Error(), bufStart+n)
return400 = true
}
if return400 {
@@ -349,7 +350,7 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
if i == -1 {
h.longLines.Incr(1)
// drop any line longer than the max buffer size
log.Printf("D! http_listener received a single line longer than the maximum of %d bytes",
h.Log.Debugf("Http_listener received a single line longer than the maximum of %d bytes",
len(buf))
hangingBytes = true
return400 = true
@@ -357,7 +358,7 @@ func (h *HTTPListener) serveWrite(res http.ResponseWriter, req *http.Request) {
continue
}
if err := h.parse(buf[:i+1], now, precision, db); err != nil {
log.Println("D! " + err.Error())
h.Log.Debug(err.Error())
return400 = true
}
// rotate the bit remaining after the last newline to the front of the buffer
@@ -53,6 +53,7 @@ func init() {
func newTestHTTPListener() *HTTPListener {
listener := &HTTPListener{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
TimeFunc: time.Now,
}
@@ -68,6 +69,7 @@ func newTestHTTPAuthListener() *HTTPListener {
func newTestHTTPSListener() *HTTPListener {
listener := &HTTPListener{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
ServerConfig: *pki.TLSServerConfig(),
TimeFunc: time.Now,
@@ -321,6 +323,7 @@ func TestWriteHTTPNoNewline(t *testing.T) {
func TestWriteHTTPMaxLineSizeIncrease(t *testing.T) {
listener := &HTTPListener{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
MaxLineSize: internal.Size{Size: 128 * 1000},
TimeFunc: time.Now,
@@ -369,6 +372,7 @@ func BenchmarkWriteHTTPMaxLineSizeIncrease(b *testing.B) {
func TestWriteHTTPVerySmallMaxBody(t *testing.T) {
listener := &HTTPListener{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
MaxBodySize: internal.Size{Size: 4096},
TimeFunc: time.Now,
@@ -386,6 +390,7 @@ func TestWriteHTTPVerySmallMaxBody(t *testing.T) {
func TestWriteHTTPVerySmallMaxLineSize(t *testing.T) {
listener := &HTTPListener{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
MaxLineSize: internal.Size{Size: 70},
TimeFunc: time.Now,
@@ -413,6 +418,7 @@ func TestWriteHTTPVerySmallMaxLineSize(t *testing.T) {
func TestWriteHTTPLargeLinesSkipped(t *testing.T) {
listener := &HTTPListener{
Log: testutil.Logger{},
ServiceAddress: "localhost:0",
MaxLineSize: internal.Size{Size: 100},
TimeFunc: time.Now,
+2 -2
View File
@@ -5,7 +5,6 @@ package ipvs
import (
"errors"
"fmt"
"log"
"math/bits"
"strconv"
"syscall"
@@ -18,6 +17,7 @@ import (
// IPVS holds the state for this input plugin
type IPVS struct {
handle *ipvs.Handle
Log telegraf.Logger
}
// Description returns a description string
@@ -61,7 +61,7 @@ func (i *IPVS) Gather(acc telegraf.Accumulator) error {
destinations, err := i.handle.GetDestinations(s)
if err != nil {
log.Println("E! Failed to list destinations for a virtual server")
i.Log.Errorf("Failed to list destinations for a virtual server: %s", err.Error())
continue // move on to the next virtual server
}
+3 -2
View File
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"log"
"net/http"
"strconv"
"strings"
@@ -29,6 +28,8 @@ type Jenkins struct {
tls.ClientConfig
client *client
Log telegraf.Logger
MaxConnections int `toml:"max_connections"`
MaxBuildAge internal.Duration `toml:"max_build_age"`
MaxSubJobDepth int `toml:"max_subjob_depth"`
@@ -304,7 +305,7 @@ func (j *Jenkins) getJobDetail(jr jobRequest, acc telegraf.Accumulator) error {
}
if build.Building {
log.Printf("D! Ignore running build on %s, build %v", jr.name, number)
j.Log.Debugf("Ignore running build on %s, build %v", jr.name, number)
return nil
}
+6
View File
@@ -206,6 +206,7 @@ func TestGatherNodeData(t *testing.T) {
ts := httptest.NewServer(test.input)
defer ts.Close()
j := &Jenkins{
Log: testutil.Logger{},
URL: ts.URL,
ResponseTimeout: internal.Duration{Duration: time.Microsecond},
NodeExclude: []string{"ignore-1", "ignore-2"},
@@ -258,6 +259,7 @@ func TestInitialize(t *testing.T) {
{
name: "bad jenkins config",
input: &Jenkins{
Log: testutil.Logger{},
URL: "http://a bad url",
ResponseTimeout: internal.Duration{Duration: time.Microsecond},
},
@@ -266,6 +268,7 @@ func TestInitialize(t *testing.T) {
{
name: "has filter",
input: &Jenkins{
Log: testutil.Logger{},
URL: ts.URL,
ResponseTimeout: internal.Duration{Duration: time.Microsecond},
JobExclude: []string{"job1", "job2"},
@@ -275,10 +278,12 @@ func TestInitialize(t *testing.T) {
{
name: "default config",
input: &Jenkins{
Log: testutil.Logger{},
URL: ts.URL,
ResponseTimeout: internal.Duration{Duration: time.Microsecond},
},
output: &Jenkins{
Log: testutil.Logger{},
MaxConnections: 5,
MaxSubJobPerLayer: 10,
},
@@ -570,6 +575,7 @@ func TestGatherJobs(t *testing.T) {
ts := httptest.NewServer(test.input)
defer ts.Close()
j := &Jenkins{
Log: testutil.Logger{},
URL: ts.URL,
MaxBuildAge: internal.Duration{Duration: time.Hour},
ResponseTimeout: internal.Duration{Duration: time.Microsecond},
@@ -2,7 +2,6 @@ package jti_openconfig_telemetry
import (
"fmt"
"log"
"net"
"regexp"
"strings"
@@ -34,6 +33,8 @@ type OpenConfigTelemetry struct {
EnableTLS bool `toml:"enable_tls"`
internaltls.ClientConfig
Log telegraf.Logger
sensorsConfig []sensorConfig
grpcClientConns []*grpc.ClientConn
wg *sync.WaitGroup
@@ -243,7 +244,7 @@ func (m *OpenConfigTelemetry) splitSensorConfig() int {
}
if len(spathSplit) == 0 {
log.Printf("E! No sensors are specified")
m.Log.Error("No sensors are specified")
continue
}
@@ -257,7 +258,7 @@ func (m *OpenConfigTelemetry) splitSensorConfig() int {
}
if len(spathSplit) == 0 {
log.Printf("E! No valid sensors are specified")
m.Log.Error("No valid sensors are specified")
continue
}
@@ -294,13 +295,13 @@ func (m *OpenConfigTelemetry) collectData(ctx context.Context,
rpcStatus, _ := status.FromError(err)
// If service is currently unavailable and may come back later, retry
if rpcStatus.Code() != codes.Unavailable {
acc.AddError(fmt.Errorf("E! Could not subscribe to %s: %v", grpcServer,
acc.AddError(fmt.Errorf("could not subscribe to %s: %v", grpcServer,
err))
return
} else {
// Retry with delay. If delay is not provided, use default
if m.RetryDelay.Duration > 0 {
log.Printf("D! Retrying %s with timeout %v", grpcServer,
m.Log.Debugf("Retrying %s with timeout %v", grpcServer,
m.RetryDelay.Duration)
time.Sleep(m.RetryDelay.Duration)
continue
@@ -314,11 +315,11 @@ func (m *OpenConfigTelemetry) collectData(ctx context.Context,
if err != nil {
// If we encounter error in the stream, break so we can retry
// the connection
acc.AddError(fmt.Errorf("E! Failed to read from %s: %v", err, grpcServer))
acc.AddError(fmt.Errorf("failed to read from %s: %s", grpcServer, err))
break
}
log.Printf("D! Received from %s: %v", grpcServer, r)
m.Log.Debugf("Received from %s: %v", grpcServer, r)
// Create a point and add to batch
tags := make(map[string]string)
@@ -329,7 +330,7 @@ func (m *OpenConfigTelemetry) collectData(ctx context.Context,
dgroups := m.extractData(r, grpcServer)
// Print final data collection
log.Printf("D! Available collection for %s is: %v", grpcServer, dgroups)
m.Log.Debugf("Available collection for %s is: %v", grpcServer, dgroups)
tnow := time.Now()
// Iterate through data groups and add them
@@ -349,10 +350,9 @@ func (m *OpenConfigTelemetry) collectData(ctx context.Context,
}
func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
// Build sensors config
if m.splitSensorConfig() == 0 {
return fmt.Errorf("E! No valid sensor configuration available")
return fmt.Errorf("no valid sensor configuration available")
}
// Parse TLS config
@@ -376,15 +376,15 @@ func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
// Extract device address and port
grpcServer, grpcPort, err := net.SplitHostPort(server)
if err != nil {
log.Printf("E! Invalid server address: %v", err)
m.Log.Errorf("Invalid server address: %s", err.Error())
continue
}
grpcClientConn, err = grpc.Dial(server, opts...)
if err != nil {
log.Printf("E! Failed to connect to %s: %v", server, err)
m.Log.Errorf("Failed to connect to %s: %s", server, err.Error())
} else {
log.Printf("D! Opened a new gRPC session to %s on port %s", grpcServer, grpcPort)
m.Log.Debugf("Opened a new gRPC session to %s on port %s", grpcServer, grpcPort)
}
// Add to the list of client connections
@@ -396,13 +396,13 @@ func (m *OpenConfigTelemetry) Start(acc telegraf.Accumulator) error {
&authentication.LoginRequest{UserName: m.Username,
Password: m.Password, ClientId: m.ClientID})
if loginErr != nil {
log.Printf("E! Could not initiate login check for %s: %v", server, loginErr)
m.Log.Errorf("Could not initiate login check for %s: %v", server, loginErr)
continue
}
// Check if the user is authenticated. Bail if auth error
if !loginReply.Result {
log.Printf("E! Failed to authenticate the user for %s", server)
m.Log.Errorf("Failed to authenticate the user for %s", server)
continue
}
}
@@ -17,6 +17,7 @@ import (
)
var cfg = &OpenConfigTelemetry{
Log: testutil.Logger{},
Servers: []string{"127.0.0.1:50051"},
SampleFrequency: internal.Duration{Duration: time.Second * 2},
}
@@ -13,12 +13,16 @@ from the same topic in parallel.
[[inputs.kafka_consumer]]
## topic(s) to consume
topics = ["telegraf"]
## an array of Zookeeper connection strings
zookeeper_peers = ["localhost:2181"]
## Zookeeper Chroot
zookeeper_chroot = ""
## the name of the consumer group
consumer_group = "telegraf_metrics_consumers"
## Offset (must be either "oldest" or "newest")
offset = "oldest"
@@ -2,7 +2,6 @@ package kafka_consumer_legacy
import (
"fmt"
"log"
"strings"
"sync"
@@ -30,6 +29,8 @@ type Kafka struct {
Offset string
parser parsers.Parser
Log telegraf.Logger
sync.Mutex
// channel for all incoming kafka messages
@@ -49,12 +50,16 @@ type Kafka struct {
var sampleConfig = `
## topic(s) to consume
topics = ["telegraf"]
## an array of Zookeeper connection strings
zookeeper_peers = ["localhost:2181"]
## Zookeeper Chroot
zookeeper_chroot = ""
## the name of the consumer group
consumer_group = "telegraf_metrics_consumers"
## Offset (must be either "oldest" or "newest")
offset = "oldest"
@@ -96,7 +101,7 @@ func (k *Kafka) Start(acc telegraf.Accumulator) error {
case "newest":
config.Offsets.Initial = sarama.OffsetNewest
default:
log.Printf("I! WARNING: Kafka consumer invalid offset '%s', using 'oldest'\n",
k.Log.Infof("WARNING: Kafka consumer invalid offset '%s', using 'oldest'\n",
k.Offset)
config.Offsets.Initial = sarama.OffsetOldest
}
@@ -121,7 +126,7 @@ func (k *Kafka) Start(acc telegraf.Accumulator) error {
// Start the kafka message reader
go k.receiver()
log.Printf("I! Started the kafka consumer service, peers: %v, topics: %v\n",
k.Log.Infof("Started the kafka consumer service, peers: %v, topics: %v\n",
k.ZookeeperPeers, k.Topics)
return nil
}
@@ -37,6 +37,7 @@ func TestReadsMetricsFromKafka(t *testing.T) {
// Start the Kafka Consumer
k := &Kafka{
Log: testutil.Logger{},
ConsumerGroup: "telegraf_test_consumers",
Topics: []string{testTopic},
ZookeeperPeers: zkPeers,
@@ -21,6 +21,7 @@ const (
func newTestKafka() (*Kafka, chan *sarama.ConsumerMessage) {
in := make(chan *sarama.ConsumerMessage, 1000)
k := Kafka{
Log: testutil.Logger{},
ConsumerGroup: "test",
Topics: []string{"telegraf"},
ZookeeperPeers: []string{"localhost:2181"},
@@ -3,7 +3,6 @@ package kinesis_consumer
import (
"context"
"fmt"
"log"
"math/big"
"strings"
"sync"
@@ -40,6 +39,8 @@ type (
DynamoDB *DynamoDB `toml:"checkpoint_dynamodb"`
MaxUndeliveredMessages int `toml:"max_undelivered_messages"`
Log telegraf.Logger
cons *consumer.Consumer
parser parsers.Parser
cancel context.CancelFunc
@@ -220,7 +221,7 @@ func (k *KinesisConsumer) connect(ac telegraf.Accumulator) error {
})
if err != nil {
k.cancel()
log.Printf("E! [inputs.kinesis_consumer] Scan encounterred an error - %s", err.Error())
k.Log.Errorf("Scan encounterred an error: %s", err.Error())
k.cons = nil
}
}()
@@ -285,7 +286,7 @@ func (k *KinesisConsumer) onDelivery(ctx context.Context) {
k.lastSeqNum = strToBint(sequenceNum)
k.checkpoint.Set(chk.streamName, chk.shardID, sequenceNum)
} else {
log.Println("D! [inputs.kinesis_consumer] Metric group failed to process")
k.Log.Debug("Metric group failed to process")
}
}
}
-1
View File
@@ -280,4 +280,3 @@ kubernetes_statefulset,namespace=default,statefulset_name=etcd replicas_updated=
[series cardinality]: https://docs.influxdata.com/influxdb/latest/query_language/spec/#show-cardinality
[influx-docs]: https://docs.influxdata.com/influxdb/latest/
[k8s-telegraf]: https://www.influxdata.com/blog/monitoring-kubernetes-architecture/
[tick-charts]: https://github.com/influxdata/tick-charts
+4 -4
View File
@@ -114,11 +114,11 @@ var availableCollectors = map[string]func(ctx context.Context, acc telegraf.Accu
"endpoints": collectEndpoints,
"ingress": collectIngress,
"nodes": collectNodes,
"persistentvolumes": collectPersistentVolumes,
"persistentvolumeclaims": collectPersistentVolumeClaims,
"pods": collectPods,
"services": collectServices,
"statefulsets": collectStatefulSets,
"persistentvolumes": collectPersistentVolumes,
"persistentvolumeclaims": collectPersistentVolumeClaims,
}
func (ki *KubernetesInventory) initClient() (*client, error) {
@@ -144,12 +144,12 @@ func atoi(s string) int64 {
func convertQuantity(s string, m float64) int64 {
q, err := resource.ParseQuantity(s)
if err != nil {
log.Printf("E! Failed to parse quantity - %v", err)
log.Printf("D! [inputs.kube_inventory] failed to parse quantity: %s", err.Error())
return 0
}
f, err := strconv.ParseFloat(fmt.Sprint(q.AsDec()), 64)
if err != nil {
log.Printf("E! Failed to parse float - %v", err)
log.Printf("D! [inputs.kube_inventory] failed to parse float: %s", err.Error())
return 0
}
if m < 1 {
+10 -2
View File
@@ -48,7 +48,12 @@ avoid cardinality issues:
### DaemonSet
For recommendations on running Telegraf as a DaemonSet see [Monitoring Kubernetes
Architecture][k8s-telegraf] or view the [Helm charts][tick-charts].
Architecture][k8s-telegraf] or view the Helm charts:
- [Telegraf][]
- [InfluxDB][]
- [Chronograf][]
- [Kapacitor][]
### Metrics
@@ -136,4 +141,7 @@ kubernetes_system_container
[series cardinality]: https://docs.influxdata.com/influxdb/latest/query_language/spec/#show-cardinality
[influx-docs]: https://docs.influxdata.com/influxdb/latest/
[k8s-telegraf]: https://www.influxdata.com/blog/monitoring-kubernetes-architecture/
[tick-charts]: https://github.com/influxdata/tick-charts
[Telegraf]: https://github.com/helm/charts/tree/master/stable/telegraf
[InfluxDB]: https://github.com/helm/charts/tree/master/stable/influxdb
[Chronograf]: https://github.com/helm/charts/tree/master/stable/chronograf
[Kapacitor]: https://github.com/helm/charts/tree/master/stable/kapacitor
+1
View File
@@ -105,6 +105,7 @@ Patterns that convert all captures to tags will result in points that can't be w
- ts-rfc3339nano ("2006-01-02T15:04:05.999999999Z07:00")
- ts-httpd ("02/Jan/2006:15:04:05 -0700")
- ts-epoch (seconds since unix epoch, may contain decimal)
- ts-epochmilli (milliseconds since unix epoch, may contain decimal)
- ts-epochnano (nanoseconds since unix epoch)
- ts-syslog ("Jan 02 15:04:05", parsed time is set to the current year)
- ts-"CUSTOM"
+10 -10
View File
@@ -4,7 +4,6 @@ package logparser
import (
"fmt"
"log"
"strings"
"sync"
@@ -14,7 +13,6 @@ import (
"github.com/influxdata/telegraf/internal/globpath"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/parsers"
// Parsers
)
const (
@@ -48,6 +46,8 @@ type LogParserPlugin struct {
FromBeginning bool
WatchMethod string
Log telegraf.Logger
tailers map[string]*tail.Tail
offsets map[string]int64
lines chan logEntry
@@ -207,7 +207,7 @@ func (l *LogParserPlugin) tailNewfiles(fromBeginning bool) error {
for _, filepath := range l.Files {
g, err := globpath.Compile(filepath)
if err != nil {
log.Printf("E! [inputs.logparser] Error Glob %s failed to compile, %s", filepath, err)
l.Log.Errorf("Glob %q failed to compile: %s", filepath, err)
continue
}
files := g.Match()
@@ -221,7 +221,7 @@ func (l *LogParserPlugin) tailNewfiles(fromBeginning bool) error {
var seek *tail.SeekInfo
if !fromBeginning {
if offset, ok := l.offsets[file]; ok {
log.Printf("D! [inputs.tail] using offset %d for file: %v", offset, file)
l.Log.Debugf("Using offset %d for file: %v", offset, file)
seek = &tail.SeekInfo{
Whence: 0,
Offset: offset,
@@ -248,7 +248,7 @@ func (l *LogParserPlugin) tailNewfiles(fromBeginning bool) error {
continue
}
log.Printf("D! [inputs.logparser] tail added for file: %v", file)
l.Log.Debugf("Tail added for file: %v", file)
// create a goroutine for each "tailer"
l.wg.Add(1)
@@ -269,7 +269,7 @@ func (l *LogParserPlugin) receiver(tailer *tail.Tail) {
for line = range tailer.Lines {
if line.Err != nil {
log.Printf("E! [inputs.logparser] Error tailing file %s, Error: %s",
l.Log.Errorf("Error tailing file %s, Error: %s",
tailer.Filename, line.Err)
continue
}
@@ -315,7 +315,7 @@ func (l *LogParserPlugin) parser() {
l.acc.AddFields(m.Name(), m.Fields(), tags, m.Time())
}
} else {
log.Println("E! [inputs.logparser] Error parsing log line: " + err.Error())
l.Log.Errorf("Error parsing log line: %s", err.Error())
}
}
@@ -332,7 +332,7 @@ func (l *LogParserPlugin) Stop() {
offset, err := t.Tell()
if err == nil {
l.offsets[t.Filename] = offset
log.Printf("D! [inputs.logparser] recording offset %d for file: %v", offset, t.Filename)
l.Log.Debugf("Recording offset %d for file: %v", offset, t.Filename)
} else {
l.acc.AddError(fmt.Errorf("error recording offset for file %s", t.Filename))
}
@@ -340,10 +340,10 @@ func (l *LogParserPlugin) Stop() {
err := t.Stop()
//message for a stopped tailer
log.Printf("D! [inputs.logparser] tail dropped for file: %v", t.Filename)
l.Log.Debugf("Tail dropped for file: %v", t.Filename)
if err != nil {
log.Printf("E! [inputs.logparser] Error stopping tail on file %s", t.Filename)
l.Log.Errorf("Error stopping tail on file %s", t.Filename)
}
}
close(l.done)
+40 -1
View File
@@ -14,6 +14,7 @@ import (
func TestStartNoParsers(t *testing.T) {
logparser := &LogParserPlugin{
Log: testutil.Logger{},
FromBeginning: true,
Files: []string{"testdata/*.log"},
}
@@ -26,6 +27,7 @@ func TestGrokParseLogFilesNonExistPattern(t *testing.T) {
thisdir := getCurrentDir()
logparser := &LogParserPlugin{
Log: testutil.Logger{},
FromBeginning: true,
Files: []string{thisdir + "testdata/*.log"},
GrokConfig: GrokConfig{
@@ -43,9 +45,10 @@ func TestGrokParseLogFiles(t *testing.T) {
thisdir := getCurrentDir()
logparser := &LogParserPlugin{
Log: testutil.Logger{},
GrokConfig: GrokConfig{
MeasurementName: "logparser_grok",
Patterns: []string{"%{TEST_LOG_A}", "%{TEST_LOG_B}"},
Patterns: []string{"%{TEST_LOG_A}", "%{TEST_LOG_B}", "%{TEST_LOG_C}"},
CustomPatternFiles: []string{thisdir + "testdata/test-patterns"},
},
FromBeginning: true,
@@ -89,6 +92,7 @@ func TestGrokParseLogFilesAppearLater(t *testing.T) {
thisdir := getCurrentDir()
logparser := &LogParserPlugin{
Log: testutil.Logger{},
FromBeginning: true,
Files: []string{emptydir + "/*.log"},
GrokConfig: GrokConfig{
@@ -128,6 +132,7 @@ func TestGrokParseLogFilesOneBad(t *testing.T) {
thisdir := getCurrentDir()
logparser := &LogParserPlugin{
Log: testutil.Logger{},
FromBeginning: true,
Files: []string{thisdir + "testdata/test_a.log"},
GrokConfig: GrokConfig{
@@ -157,6 +162,40 @@ func TestGrokParseLogFilesOneBad(t *testing.T) {
})
}
func TestGrokParseLogFiles_TimestampInEpochMilli(t *testing.T) {
thisdir := getCurrentDir()
logparser := &LogParserPlugin{
Log: testutil.Logger{},
GrokConfig: GrokConfig{
MeasurementName: "logparser_grok",
Patterns: []string{"%{TEST_LOG_C}"},
CustomPatternFiles: []string{thisdir + "testdata/test-patterns"},
},
FromBeginning: true,
Files: []string{thisdir + "testdata/test_c.log"},
}
acc := testutil.Accumulator{}
acc.SetDebug(true)
assert.NoError(t, logparser.Start(&acc))
acc.Wait(1)
logparser.Stop()
acc.AssertContainsTaggedFields(t, "logparser_grok",
map[string]interface{}{
"clientip": "192.168.1.1",
"myfloat": float64(1.25),
"response_time": int64(5432),
"myint": int64(101),
},
map[string]string{
"response_code": "200",
"path": thisdir + "testdata/test_c.log",
})
}
func getCurrentDir() string {
_, filename, _, _ := runtime.Caller(1)
return strings.Replace(filename, "logparser_test.go", "", 1)
+4
View File
@@ -12,3 +12,7 @@ TEST_LOG_B \[%{TEST_TIMESTAMP:timestamp:ts-"02/01/2006--15:04:05"}\] %{NUMBER:my
TEST_TIMESTAMP %{MONTHDAY}/%{MONTHNUM}/%{YEAR}--%{TIME}
TEST_LOG_BAD \[%{TEST_TIMESTAMP:timestamp:ts-"02/01/2006--15:04:05"}\] %{NUMBER:myfloat:float} %{WORD:mystring:int} %{WORD:dropme:drop} %{WORD:nomodifier}
# Test C log line:
# 1568723594631 1.25 200 192.168.1.1 5.432µs 101
TEST_LOG_C %{POSINT:timestamp:ts-epochmilli} %{NUMBER:myfloat:float} %{RESPONSE_CODE} %{IPORHOST:clientip} %{RESPONSE_TIME} %{NUMBER:myint:int}
+1
View File
@@ -0,0 +1 @@
1568723594631 1.25 200 192.168.1.1 5.432µs 101
+2 -2
View File
@@ -134,7 +134,7 @@ func runChimp(api *ChimpAPI, params ReportsParams) ([]byte, error) {
req.URL.RawQuery = params.String()
req.Header.Set("User-Agent", "Telegraf-MailChimp-Plugin")
if api.Debug {
log.Printf("D! Request URL: %s", req.URL.String())
log.Printf("D! [inputs.mailchimp] request URL: %s", req.URL.String())
}
resp, err := client.Do(req)
@@ -148,7 +148,7 @@ func runChimp(api *ChimpAPI, params ReportsParams) ([]byte, error) {
return nil, err
}
if api.Debug {
log.Printf("D! Response Body:%s", string(body))
log.Printf("D! [inputs.mailchimp] response Body: %q", string(body))
}
if err = chimpErrorCheck(body); err != nil {
+4
View File
@@ -10,8 +10,10 @@ For more information, please check the [Mesos Observability Metrics](http://meso
[[inputs.mesos]]
## Timeout, in ms.
timeout = 100
## A list of Mesos masters.
masters = ["http://localhost:5050"]
## Master metrics groups to be collected, by default, all enabled.
master_collections = [
"resources",
@@ -26,8 +28,10 @@ For more information, please check the [Mesos Observability Metrics](http://meso
"registrar",
"allocator",
]
## A list of Mesos slaves, default is []
# slaves = []
## Slave metrics groups to be collected, by default, all enabled.
# slave_collections = [
# "resources",
+9 -15
View File
@@ -32,9 +32,10 @@ type Mesos struct {
MasterCols []string `toml:"master_collections"`
Slaves []string
SlaveCols []string `toml:"slave_collections"`
//SlaveTasks bool
tls.ClientConfig
Log telegraf.Logger
initialized bool
client *http.Client
masterURLs []*url.URL
@@ -49,8 +50,10 @@ var allMetrics = map[Role][]string{
var sampleConfig = `
## Timeout, in ms.
timeout = 100
## A list of Mesos masters.
masters = ["http://localhost:5050"]
## Master metrics groups to be collected, by default, all enabled.
master_collections = [
"resources",
@@ -65,8 +68,10 @@ var sampleConfig = `
"registrar",
"allocator",
]
## A list of Mesos slaves, default is []
# slaves = []
## Slave metrics groups to be collected, by default, all enabled.
# slave_collections = [
# "resources",
@@ -110,7 +115,7 @@ func parseURL(s string, role Role) (*url.URL, error) {
}
s = "http://" + host + ":" + port
log.Printf("W! [inputs.mesos] Using %q as connection URL; please update your configuration to use an URL", s)
log.Printf("W! [inputs.mesos] using %q as connection URL; please update your configuration to use an URL", s)
}
return url.Parse(s)
@@ -126,7 +131,7 @@ func (m *Mesos) initialize() error {
}
if m.Timeout == 0 {
log.Println("I! [inputs.mesos] Missing timeout value, setting default value (100ms)")
m.Log.Info("Missing timeout value, setting default value (100ms)")
m.Timeout = 100
}
@@ -191,17 +196,6 @@ func (m *Mesos) Gather(acc telegraf.Accumulator) error {
wg.Done()
return
}(slave)
// if !m.SlaveTasks {
// continue
// }
// wg.Add(1)
// go func(c string) {
// acc.AddError(m.gatherSlaveTaskMetrics(slave, acc))
// wg.Done()
// return
// }(v)
}
wg.Wait()
@@ -487,7 +481,7 @@ func getMetrics(role Role, group string) []string {
ret, ok := m[group]
if !ok {
log.Printf("I! [mesos] Unknown %s metrics group: %s\n", role, group)
log.Printf("I! [inputs.mesos] unknown role %q metrics group: %s", role, group)
return []string{}
}
+4
View File
@@ -349,6 +349,7 @@ func TestMesosMaster(t *testing.T) {
var acc testutil.Accumulator
m := Mesos{
Log: testutil.Logger{},
Masters: []string{masterTestServer.Listener.Addr().String()},
Timeout: 10,
}
@@ -364,6 +365,7 @@ func TestMesosMaster(t *testing.T) {
func TestMasterFilter(t *testing.T) {
m := Mesos{
Log: testutil.Logger{},
MasterCols: []string{
"resources", "master", "registrar", "allocator",
},
@@ -416,6 +418,7 @@ func TestMesosSlave(t *testing.T) {
var acc testutil.Accumulator
m := Mesos{
Log: testutil.Logger{},
Masters: []string{},
Slaves: []string{slaveTestServer.Listener.Addr().String()},
// SlaveTasks: true,
@@ -433,6 +436,7 @@ func TestMesosSlave(t *testing.T) {
func TestSlaveFilter(t *testing.T) {
m := Mesos{
Log: testutil.Logger{},
SlaveCols: []string{
"resources", "agent", "tasks",
},
+9 -8
View File
@@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"net"
"net/url"
"strings"
@@ -25,6 +24,8 @@ type MongoDB struct {
GatherColStats bool
ColStatsDbs []string
tlsint.ClientConfig
Log telegraf.Logger
}
type Ssl struct {
@@ -82,24 +83,24 @@ func (m *MongoDB) Gather(acc telegraf.Accumulator) error {
// Preserve backwards compatibility for hostnames without a
// scheme, broken in go 1.8. Remove in Telegraf 2.0
serv = "mongodb://" + serv
log.Printf("W! [inputs.mongodb] Using %q as connection URL; please update your configuration to use an URL", serv)
m.Log.Warnf("Using %q as connection URL; please update your configuration to use an URL", serv)
m.Servers[i] = serv
}
u, err := url.Parse(serv)
if err != nil {
acc.AddError(fmt.Errorf("Unable to parse address %q: %s", serv, err))
m.Log.Errorf("Unable to parse address %q: %s", serv, err.Error())
continue
}
if u.Host == "" {
acc.AddError(fmt.Errorf("Unable to parse address %q", serv))
m.Log.Errorf("Unable to parse address %q", serv)
continue
}
wg.Add(1)
go func(srv *Server) {
defer wg.Done()
acc.AddError(m.gatherServer(srv, acc))
m.Log.Error(m.gatherServer(srv, acc))
}(m.getMongoServer(u))
}
@@ -110,6 +111,7 @@ func (m *MongoDB) Gather(acc telegraf.Accumulator) error {
func (m *MongoDB) getMongoServer(url *url.URL) *Server {
if _, ok := m.mongos[url.Host]; !ok {
m.mongos[url.Host] = &Server{
Log: m.Log,
Url: url,
}
}
@@ -126,8 +128,7 @@ func (m *MongoDB) gatherServer(server *Server, acc telegraf.Accumulator) error {
}
dialInfo, err := mgo.ParseURL(dialAddrs[0])
if err != nil {
return fmt.Errorf("Unable to parse URL (%s), %s\n",
dialAddrs[0], err.Error())
return fmt.Errorf("unable to parse URL %q: %s", dialAddrs[0], err.Error())
}
dialInfo.Direct = true
dialInfo.Timeout = 5 * time.Second
@@ -169,7 +170,7 @@ func (m *MongoDB) gatherServer(server *Server, acc telegraf.Accumulator) error {
sess, err := mgo.DialWithInfo(dialInfo)
if err != nil {
return fmt.Errorf("Unable to connect to MongoDB, %s\n", err.Error())
return fmt.Errorf("unable to connect to MongoDB: %s", err.Error())
}
server.Session = sess
}
+23 -22
View File
@@ -1,7 +1,7 @@
package mongodb
import (
"log"
"fmt"
"net/url"
"strings"
"time"
@@ -15,6 +15,8 @@ type Server struct {
Url *url.URL
Session *mgo.Session
lastResult *MongoStatus
Log telegraf.Logger
}
func (s *Server) getDefaultTags() map[string]string {
@@ -31,11 +33,11 @@ func IsAuthorization(err error) bool {
return strings.Contains(err.Error(), "not authorized")
}
func authLogLevel(err error) string {
func (s *Server) authLog(err error) {
if IsAuthorization(err) {
return "D!"
s.Log.Debug(err.Error())
} else {
return "E!"
s.Log.Error(err.Error())
}
}
@@ -158,30 +160,30 @@ func (s *Server) gatherCollectionStats(colStatsDbs []string) (*ColStats, error)
}
results := &ColStats{}
for _, db_name := range names {
if stringInSlice(db_name, colStatsDbs) || len(colStatsDbs) == 0 {
for _, dbName := range names {
if stringInSlice(dbName, colStatsDbs) || len(colStatsDbs) == 0 {
var colls []string
colls, err = s.Session.DB(db_name).CollectionNames()
colls, err = s.Session.DB(dbName).CollectionNames()
if err != nil {
log.Printf("E! [inputs.mongodb] Error getting collection names: %v", err)
s.Log.Errorf("Error getting collection names: %s", err.Error())
continue
}
for _, col_name := range colls {
col_stat_line := &ColStatsData{}
err = s.Session.DB(db_name).Run(bson.D{
for _, colName := range colls {
colStatLine := &ColStatsData{}
err = s.Session.DB(dbName).Run(bson.D{
{
Name: "collStats",
Value: col_name,
Value: colName,
},
}, col_stat_line)
}, colStatLine)
if err != nil {
log.Printf("%s [inputs.mongodb] Error getting col stats from %q: %v", authLogLevel(err), col_name, err)
s.authLog(fmt.Errorf("error getting col stats from %q: %v", colName, err))
continue
}
collection := &Collection{
Name: col_name,
DbName: db_name,
ColStatsData: col_stat_line,
Name: colName,
DbName: dbName,
ColStatsData: colStatLine,
}
results.Collections = append(results.Collections, *collection)
}
@@ -203,7 +205,7 @@ func (s *Server) gatherData(acc telegraf.Accumulator, gatherDbStats bool, gather
// member of a replica set.
replSetStatus, err := s.gatherReplSetStatus()
if err != nil {
log.Printf("D! [inputs.mongodb] Unable to gather replica set status: %v", err)
s.Log.Debugf("Unable to gather replica set status: %s", err.Error())
}
// Gather the oplog if we are a member of a replica set. Non-replica set
@@ -218,13 +220,12 @@ func (s *Server) gatherData(acc telegraf.Accumulator, gatherDbStats bool, gather
clusterStatus, err := s.gatherClusterStatus()
if err != nil {
log.Printf("D! [inputs.mongodb] Unable to gather cluster status: %v", err)
s.Log.Debugf("Unable to gather cluster status: %s", err.Error())
}
shardStats, err := s.gatherShardConnPoolStats()
if err != nil {
log.Printf("%s [inputs.mongodb] Unable to gather shard connection pool stats: %v",
authLogLevel(err), err)
s.authLog(fmt.Errorf("unable to gather shard connection pool stats: %s", err.Error()))
}
var collectionStats *ColStats
@@ -246,7 +247,7 @@ func (s *Server) gatherData(acc telegraf.Accumulator, gatherDbStats bool, gather
for _, name := range names {
db, err := s.gatherDBStats(name)
if err != nil {
log.Printf("D! [inputs.mongodb] Error getting db stats from %q: %v", name, err)
s.Log.Debugf("Error getting db stats from %q: %s", name, err.Error())
}
dbStats.Dbs = append(dbStats.Dbs, *db)
}
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"log"
"strings"
"time"
@@ -61,6 +60,8 @@ type MQTTConsumer struct {
ClientID string `toml:"client_id"`
tls.ClientConfig
Log telegraf.Logger
clientFactory ClientFactory
client Client
opts *mqtt.ClientOptions
@@ -212,7 +213,7 @@ func (m *MQTTConsumer) connect() error {
return err
}
log.Printf("I! [inputs.mqtt_consumer] Connected %v", m.Servers)
m.Log.Infof("Connected %v", m.Servers)
m.state = Connected
m.sem = make(semaphore, m.MaxUndeliveredMessages)
m.messages = make(map[telegraf.TrackingID]bool)
@@ -223,7 +224,7 @@ func (m *MQTTConsumer) connect() error {
SessionPresent() bool
}
if t, ok := token.(sessionPresent); ok && t.SessionPresent() {
log.Printf("D! [inputs.mqtt_consumer] Session found %v", m.Servers)
m.Log.Debugf("Session found %v", m.Servers)
return nil
}
@@ -244,7 +245,7 @@ func (m *MQTTConsumer) connect() error {
func (m *MQTTConsumer) onConnectionLost(c mqtt.Client, err error) {
m.acc.AddError(fmt.Errorf("connection lost: %v", err))
log.Printf("D! [inputs.mqtt_consumer] Disconnected %v", m.Servers)
m.Log.Debugf("Disconnected %v", m.Servers)
m.state = Disconnected
return
}
@@ -292,9 +293,9 @@ func (m *MQTTConsumer) onMessage(acc telegraf.TrackingAccumulator, msg mqtt.Mess
func (m *MQTTConsumer) Stop() {
if m.state == Connected {
log.Printf("D! [inputs.mqtt_consumer] Disconnecting %v", m.Servers)
m.Log.Debugf("Disconnecting %v", m.Servers)
m.client.Disconnect(200)
log.Printf("D! [inputs.mqtt_consumer] Disconnected %v", m.Servers)
m.Log.Debugf("Disconnected %v", m.Servers)
m.state = Disconnected
}
m.cancel()
@@ -303,7 +304,7 @@ func (m *MQTTConsumer) Stop() {
func (m *MQTTConsumer) Gather(acc telegraf.Accumulator) error {
if m.state == Disconnected {
m.state = Connecting
log.Printf("D! [inputs.mqtt_consumer] Connecting %v", m.Servers)
m.Log.Debugf("Connecting %v", m.Servers)
m.connect()
}
@@ -346,7 +347,7 @@ func (m *MQTTConsumer) createOpts() (*mqtt.ClientOptions, error) {
for _, server := range m.Servers {
// Preserve support for host:port style servers; deprecated in Telegraf 1.4.4
if !strings.Contains(server, "://") {
log.Printf("W! [inputs.mqtt_consumer] Server %q should be updated to use `scheme://host:port` format", server)
m.Log.Warnf("Server %q should be updated to use `scheme://host:port` format", server)
if tlsCfg == nil {
server = "tcp://" + server
} else {
@@ -102,6 +102,7 @@ func TestLifecycleSanity(t *testing.T) {
},
}
})
plugin.Log = testutil.Logger{}
plugin.Servers = []string{"tcp://127.0.0.1"}
parser := &FakeParser{}
@@ -124,10 +125,12 @@ func TestRandomClientID(t *testing.T) {
var err error
m1 := New(nil)
m1.Log = testutil.Logger{}
err = m1.Init()
require.NoError(t, err)
m2 := New(nil)
m2.Log = testutil.Logger{}
err = m2.Init()
require.NoError(t, err)
@@ -137,6 +140,7 @@ func TestRandomClientID(t *testing.T) {
// PersistentSession requires ClientID
func TestPersistentClientIDFail(t *testing.T) {
plugin := New(nil)
plugin.Log = testutil.Logger{}
plugin.PersistentSession = true
err := plugin.Init()
@@ -255,6 +259,7 @@ func TestTopicTag(t *testing.T) {
plugin := New(func(o *mqtt.ClientOptions) Client {
return client
})
plugin.Log = testutil.Logger{}
plugin.Topics = []string{"telegraf"}
plugin.TopicTag = tt.topicTag()
@@ -295,6 +300,7 @@ func TestAddRouteCalledForEachTopic(t *testing.T) {
plugin := New(func(o *mqtt.ClientOptions) Client {
return client
})
plugin.Log = testutil.Logger{}
plugin.Topics = []string{"a", "b"}
err := plugin.Init()
@@ -325,6 +331,7 @@ func TestSubscribeCalledIfNoSession(t *testing.T) {
plugin := New(func(o *mqtt.ClientOptions) Client {
return client
})
plugin.Log = testutil.Logger{}
plugin.Topics = []string{"b"}
err := plugin.Init()
@@ -355,6 +362,7 @@ func TestSubscribeNotCalledIfSession(t *testing.T) {
plugin := New(func(o *mqtt.ClientOptions) Client {
return client
})
plugin.Log = testutil.Logger{}
plugin.Topics = []string{"b"}
err := plugin.Init()
+12 -13
View File
@@ -39,9 +39,12 @@ type Mysql struct {
IntervalSlow string `toml:"interval_slow"`
MetricVersion int `toml:"metric_version"`
tls.ClientConfig
lastT time.Time
initDone bool
scanIntervalSlow uint32
}
var sampleConfig = `
const sampleConfig = `
## specify servers via a url matching:
## [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify|custom]]
## see https://github.com/go-sql-driver/mysql#dsn-data-source-name
@@ -123,7 +126,7 @@ var sampleConfig = `
# insecure_skip_verify = false
`
var defaultTimeout = time.Second * time.Duration(5)
const defaultTimeout = time.Second * time.Duration(5)
func (m *Mysql) SampleConfig() string {
return sampleConfig
@@ -133,21 +136,16 @@ func (m *Mysql) Description() string {
return "Read metrics from one or many mysql servers"
}
var (
localhost = ""
lastT time.Time
initDone = false
scanIntervalSlow uint32
)
const localhost = ""
func (m *Mysql) InitMysql() {
if len(m.IntervalSlow) > 0 {
interval, err := time.ParseDuration(m.IntervalSlow)
if err == nil && interval.Seconds() >= 1.0 {
scanIntervalSlow = uint32(interval.Seconds())
m.scanIntervalSlow = uint32(interval.Seconds())
}
}
initDone = true
m.initDone = true
}
func (m *Mysql) Gather(acc telegraf.Accumulator) error {
@@ -156,7 +154,7 @@ func (m *Mysql) Gather(acc telegraf.Accumulator) error {
return m.gatherServer(localhost, acc)
}
// Initialise additional query intervals
if !initDone {
if !m.initDone {
m.InitMysql()
}
@@ -184,6 +182,7 @@ func (m *Mysql) Gather(acc telegraf.Accumulator) error {
return nil
}
// These are const but can't be declared as such because golang doesn't allow const maps
var (
// status counter
generalThreadStates = map[string]uint32{
@@ -426,12 +425,12 @@ func (m *Mysql) gatherServer(serv string, acc telegraf.Accumulator) error {
// Global Variables may be gathered less often
if len(m.IntervalSlow) > 0 {
if uint32(time.Since(lastT).Seconds()) >= scanIntervalSlow {
if uint32(time.Since(m.lastT).Seconds()) >= m.scanIntervalSlow {
err = m.gatherGlobalVariables(db, serv, acc)
if err != nil {
return err
}
lastT = time.Now()
m.lastT = time.Now()
}
}
+48
View File
@@ -26,6 +26,54 @@ func TestMysqlDefaultsToLocal(t *testing.T) {
assert.True(t, acc.HasMeasurement("mysql"))
}
func TestMysqlMultipleInstances(t *testing.T) {
// Invoke Gather() from two separate configurations and
// confirm they don't interfere with each other
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}
testServer := "root@tcp(127.0.0.1:3306)/?tls=false"
m := &Mysql{
Servers: []string{testServer},
IntervalSlow: "30s",
}
var acc, acc2 testutil.Accumulator
err := m.Gather(&acc)
require.NoError(t, err)
assert.True(t, acc.HasMeasurement("mysql"))
// acc should have global variables
assert.True(t, acc.HasMeasurement("mysql_variables"))
m2 := &Mysql{
Servers: []string{testServer},
}
err = m2.Gather(&acc2)
require.NoError(t, err)
assert.True(t, acc2.HasMeasurement("mysql"))
// acc2 should not have global variables
assert.False(t, acc2.HasMeasurement("mysql_variables"))
}
func TestMysqlMultipleInits(t *testing.T) {
m := &Mysql{
IntervalSlow: "30s",
}
m2 := &Mysql{}
m.InitMysql()
assert.True(t, m.initDone)
assert.False(t, m2.initDone)
assert.Equal(t, m.scanIntervalSlow, uint32(30))
assert.Equal(t, m2.scanIntervalSlow, uint32(0))
m2.InitMysql()
assert.True(t, m.initDone)
assert.True(t, m2.initDone)
assert.Equal(t, m.scanIntervalSlow, uint32(30))
assert.Equal(t, m2.scanIntervalSlow, uint32(0))
}
func TestMysqlGetDSNTag(t *testing.T) {
tests := []struct {
input string
+2
View File
@@ -12,8 +12,10 @@ instances of telegraf can read from a NATS cluster in parallel.
[[inputs.nats_consumer]]
## urls of NATS servers
servers = ["nats://localhost:4222"]
## subject(s) to consume
subjects = ["telegraf"]
## name a queue group
queue_group = "telegraf_consumers"
@@ -3,7 +3,6 @@ package natsconsumer
import (
"context"
"fmt"
"log"
"sync"
"github.com/influxdata/telegraf"
@@ -40,6 +39,8 @@ type natsConsumer struct {
Password string `toml:"password"`
tls.ClientConfig
Log telegraf.Logger
// Client pending limits:
PendingMessageLimit int `toml:"pending_message_limit"`
PendingBytesLimit int `toml:"pending_bytes_limit"`
@@ -68,6 +69,7 @@ var sampleConfig = `
## subject(s) to consume
subjects = ["telegraf"]
## name a queue group
queue_group = "telegraf_consumers"
@@ -198,7 +200,7 @@ func (n *natsConsumer) Start(acc telegraf.Accumulator) error {
go n.receiver(ctx)
}()
log.Printf("I! Started the NATS consumer service, nats: %v, subjects: %v, queue: %v\n",
n.Log.Infof("Started the NATS consumer service, nats: %v, subjects: %v, queue: %v",
n.conn.ConnectedUrl(), n.Subjects, n.QueueGroup)
return nil
@@ -216,21 +218,21 @@ func (n *natsConsumer) receiver(ctx context.Context) {
case <-n.acc.Delivered():
<-sem
case err := <-n.errs:
n.acc.AddError(err)
n.Log.Error(err)
case sem <- empty{}:
select {
case <-ctx.Done():
return
case err := <-n.errs:
<-sem
n.acc.AddError(err)
n.Log.Error(err)
case <-n.acc.Delivered():
<-sem
<-sem
case msg := <-n.in:
metrics, err := n.parser.Parse(msg.Data)
if err != nil {
n.acc.AddError(fmt.Errorf("subject: %s, error: %s", msg.Subject, err.Error()))
n.Log.Errorf("Subject: %s, error: %s", msg.Subject, err.Error())
<-sem
continue
}
@@ -244,8 +246,8 @@ func (n *natsConsumer) receiver(ctx context.Context) {
func (n *natsConsumer) clean() {
for _, sub := range n.subs {
if err := sub.Unsubscribe(); err != nil {
n.acc.AddError(fmt.Errorf("Error unsubscribing from subject %s in queue %s: %s\n",
sub.Subject, sub.Queue, err.Error()))
n.Log.Errorf("Error unsubscribing from subject %s in queue %s: %s",
sub.Subject, sub.Queue, err.Error())
}
}
+2
View File
@@ -10,8 +10,10 @@ of the supported [input data formats][].
[[inputs.nsq_consumer]]
## Server option still works but is deprecated, we just prepend it to the nsqd array.
# server = "localhost:4150"
## An array representing the NSQD TCP HTTP Endpoints
nsqd = ["localhost:4150"]
## An array representing the NSQLookupd HTTP Endpoints
nsqlookupd = ["localhost:4161"]
topic = "telegraf"
+9 -4
View File
@@ -2,7 +2,6 @@ package nsq_consumer
import (
"context"
"log"
"sync"
"github.com/influxdata/telegraf"
@@ -18,10 +17,12 @@ const (
type empty struct{}
type semaphore chan empty
type logger struct{}
type logger struct {
log telegraf.Logger
}
func (l *logger) Output(calldepth int, s string) error {
log.Println("D! [inputs.nsq_consumer] " + s)
l.log.Debug(s)
return nil
}
@@ -39,6 +40,8 @@ type NSQConsumer struct {
parser parsers.Parser
consumer *nsq.Consumer
Log telegraf.Logger
mu sync.Mutex
messages map[telegraf.TrackingID]*nsq.Message
wg sync.WaitGroup
@@ -48,8 +51,10 @@ type NSQConsumer struct {
var sampleConfig = `
## Server option still works but is deprecated, we just prepend it to the nsqd array.
# server = "localhost:4150"
## An array representing the NSQD TCP HTTP Endpoints
nsqd = ["localhost:4150"]
## An array representing the NSQLookupd HTTP Endpoints
nsqlookupd = ["localhost:4161"]
topic = "telegraf"
@@ -98,7 +103,7 @@ func (n *NSQConsumer) Start(ac telegraf.Accumulator) error {
n.cancel = cancel
n.connect()
n.consumer.SetLogger(&logger{}, nsq.LogLevelInfo)
n.consumer.SetLogger(&logger{log: n.Log}, nsq.LogLevelInfo)
n.consumer.AddHandler(nsq.HandlerFunc(func(message *nsq.Message) error {
metrics, err := n.parser.Parse(message.Body)
if err != nil {
@@ -36,6 +36,7 @@ func TestReadsMetricsFromNSQ(t *testing.T) {
newMockNSQD(script, addr.String())
consumer := &NSQConsumer{
Log: testutil.Logger{},
Server: "127.0.0.1:4155",
Topic: "telegraf",
Channel: "consume",
+109 -60
View File
@@ -2,92 +2,142 @@
Sends a ping message by executing the system ping command and reports the results.
This plugin has two main methods of operation: `exec` and `native`. The
recommended method is `native`, which has greater system compatibility and
performance. However, for backwards compatibility the `exec` method is the
default.
When using `method = "exec"`, the systems ping utility is executed to send the
ping packets.
Most ping command implementations are supported, one notable exception being
that there is currently no support for GNU Inetutils ping. You may instead
use the iputils-ping implementation:
that there is currently no support for GNU Inetutils ping. You may instead use
the iputils-ping implementation:
```
apt-get install iputils-ping
```
When using `method = "native"` a ping is sent and the results are reported in pure go, eliminating the need to execute the system `ping` command. Not using the system binary allows the use of this plugin on non-english systems.
There is currently no support for TTL on windows with `"native"`; track progress at https://github.com/golang/go/issues/7175 and https://github.com/golang/go/issues/7174
When using `method = "native"` a ping is sent and the results are reported in
native Go by the Telegraf process, eliminating the need to execute the system
`ping` command.
### Configuration:
```toml
[[inputs.ping]]
## List of urls to ping
## Hosts to send ping packets to.
urls = ["example.org"]
## Number of pings to send per collection (ping -c <COUNT>)
# count = 1
## Interval, in s, at which to ping. 0 == default (ping -i <PING_INTERVAL>)
## Not available in Windows.
# ping_interval = 1.0
## Per-ping timeout, in s. 0 == no timeout (ping -W <TIMEOUT>)
# timeout = 1.0
## Total-ping deadline, in s. 0 == no deadline (ping -w <DEADLINE>)
# deadline = 10
## Interface or source address to send ping from (ping -I <INTERFACE/SRC_ADDR>)
## on Darwin and Freebsd only source address possible: (ping -S <SRC_ADDR>)
# interface = ""
## How to ping. "native" doesn't have external dependencies, while "exec" depends on 'ping'.
## Method used for sending pings, can be either "exec" or "native". When set
## to "exec" the systems ping command will be executed. When set to "native"
## the plugin will send pings directly.
##
## While the default is "exec" for backwards compatibility, new deployments
## are encouraged to use the "native" method for improved compatibility and
## performance.
# method = "exec"
## Specify the ping executable binary, default is "ping"
## Number of ping packets to send per interval. Corresponds to the "-c"
## option of the ping command.
# count = 1
## Time to wait between sending ping packets in seconds. Operates like the
## "-i" option of the ping command.
# ping_interval = 1.0
## If set, the time to wait for a ping response in seconds. Operates like
## the "-W" option of the ping command.
# timeout = 1.0
## If set, the total ping deadline, in seconds. Operates like the -w option
## of the ping command.
# deadline = 10
## Interface or source address to send ping from. Operates like the -I or -S
## option of the ping command.
# interface = ""
## Specify the ping executable binary.
# binary = "ping"
## Arguments for ping command. When arguments is not empty, system binary will be used and
## other options (ping_interval, timeout, etc) will be ignored
## Arguments for ping command. When arguments is not empty, the command from
## the binary option will be used and other options (ping_interval, timeout,
## etc) will be ignored.
# arguments = ["-c", "3"]
## Use only ipv6 addresses when resolving hostnames.
## Use only IPv6 addresses when resolving a hostname.
# ipv6 = false
```
#### File Limit
Since this plugin runs the ping command, it may need to open several files per
host. With a large host list you may receive a `too many open files` error.
Since this plugin runs the ping command, it may need to open multiple files per
host. The number of files used is lessened with the `native` option but still
many files are used. With a large host list you may receive a `too many open
files` error.
To increase this limit on platforms using systemd it must be done in the
service file.
To increase this limit on platforms using systemd the recommended method is to
use the "drop-in directory", usually located at
`/etc/systemd/system/telegraf.service.d`.
Find the service unit file:
```
$ systemctl show telegraf.service -p FragmentPath
FragmentPath=/lib/systemd/system/telegraf.service
You can create or edit a drop-in file in the correct location using:
```sh
$ systemctl edit telegraf
```
Set the file number limit:
```
Increase the number of open files:
```ini
[Service]
LimitNOFILE=4096
LimitNOFILE=8192
```
#### Permission Caveat (non Windows)
It is preferred that this plugin listen on privileged ICMP sockets. To do so, telegraf can either be run as the root user or the root user can add the capability to access raw sockets to telegraf by running the following commant:
```
setcap cap_net_raw=eip /path/to/telegraf
Restart Telegraf:
```sh
$ systemctl edit telegraf
```
Another option (doesn't work as well or in all circumstances) is to listen on unprivileged raw sockets (non-Windows only). The system group of the user running telegraf must be allowed to create ICMP Echo sockets. [See man pages icmp(7) for `ping_group_range`](http://man7.org/linux/man-pages/man7/icmp.7.html). On Linux hosts, run the following to give a group the proper permissions:
#### Linux Permissions
When using `method = "native"`, Telegraf will attempt to use privileged raw
ICMP sockets. On most systems, doing so requires `CAP_NET_RAW` capabilities.
With systemd:
```sh
$ systemctl edit telegraf
```
sudo sysctl -w net.ipv4.ping_group_range="GROUP_ID_LOW GROUP_ID_HIGH"
```ini
[Service]
CapabilityBoundingSet=CAP_NET_RAW
AmbientCapabilities=CAP_NET_RAW
```
```sh
$ systemctl restart telegraf
```
Without systemd:
```sh
$ setcap cap_net_raw=eip /usr/bin/telegraf
```
### Metrics:
Reference [`man 7 capabilities`][man 7 capabilities] for more information about
setting capabilities.
[man 7 capabilities]: http://man7.org/linux/man-pages/man7/capabilities.7.html
When Telegraf cannot listen on a privileged ICMP socket it will attempt to use
ICMP echo sockets. If you wish to use this method you must ensure Telegraf's
group, usually `telegraf`, is allowed to use ICMP echo sockets:
```sh
$ sysctl -w net.ipv4.ping_group_range="GROUP_ID_LOW GROUP_ID_HIGH"
```
Reference [`man 7 icmp`][man 7 icmp] for more information about ICMP echo
sockets and the `ping_group_range` setting.
[man 7 icmp]: http://man7.org/linux/man-pages/man7/icmp.7.html
### Metrics
- ping
- tags:
@@ -102,24 +152,23 @@ sudo sysctl -w net.ipv4.ping_group_range="GROUP_ID_LOW GROUP_ID_HIGH"
- maximum_response_ms (integer)
- standard_deviation_ms (integer, Available on Windows only with native ping)
- errors (float, Windows only)
- reply_received (integer, Windows only*)
- percent_reply_loss (float, Windows only*)
- reply_received (integer, Windows with method = "exec" only)
- percent_reply_loss (float, Windows with method = "exec" only)
- result_code (int, success = 0, no such host = 1, ping error = 2)
##### reply_received vs packets_received
On Windows systems, "Destination net unreachable" reply will increment `packets_received` but not `reply_received`*
On Windows systems with `method = "exec"`, the "Destination net unreachable" reply will increment `packets_received` but not `reply_received`*.
### Example Output:
##### ttl
**Windows:**
```
ping,url=example.org result_code=0i,average_response_ms=7i,maximum_response_ms=9i,minimum_response_ms=7i,packets_received=4i,packets_transmitted=4i,percent_packet_loss=0,percent_reply_loss=0,reply_received=4i 1469879119000000000
```
There is currently no support for TTL on windows with `"native"`; track
progress at https://github.com/golang/go/issues/7175 and
https://github.com/golang/go/issues/7174
### Example Output
**Linux:**
```
ping,url=example.org average_response_ms=23.066,ttl=63,maximum_response_ms=24.64,minimum_response_ms=22.451,packets_received=5i,packets_transmitted=5i,percent_packet_loss=0,result_code=0i,standard_deviation_ms=0.809 1535747258000000000
```
*not when `method = "native"` is used
+34 -23
View File
@@ -11,7 +11,6 @@ import (
"time"
"github.com/glinton/ping"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
@@ -68,35 +67,47 @@ func (*Ping) Description() string {
}
const sampleConfig = `
## List of urls to ping
## Hosts to send ping packets to.
urls = ["example.org"]
## Number of pings to send per collection (ping -c <COUNT>)
# count = 1
## Interval, in s, at which to ping. 0 == default (ping -i <PING_INTERVAL>)
# ping_interval = 1.0
## Per-ping timeout, in s. 0 == no timeout (ping -W <TIMEOUT>)
# timeout = 1.0
## Total-ping deadline, in s. 0 == no deadline (ping -w <DEADLINE>)
# deadline = 10
## Interface or source address to send ping from (ping -I[-S] <INTERFACE/SRC_ADDR>)
# interface = ""
## How to ping. "native" doesn't have external dependencies, while "exec" depends on 'ping'.
## Method used for sending pings, can be either "exec" or "native". When set
## to "exec" the systems ping command will be executed. When set to "native"
## the plugin will send pings directly.
##
## While the default is "exec" for backwards compatibility, new deployments
## are encouraged to use the "native" method for improved compatibility and
## performance.
# method = "exec"
## Specify the ping executable binary, default is "ping"
# binary = "ping"
## Number of ping packets to send per interval. Corresponds to the "-c"
## option of the ping command.
# count = 1
## Arguments for ping command. When arguments is not empty, system binary will be used and
## other options (ping_interval, timeout, etc) will be ignored.
## Time to wait between sending ping packets in seconds. Operates like the
## "-i" option of the ping command.
# ping_interval = 1.0
## If set, the time to wait for a ping response in seconds. Operates like
## the "-W" option of the ping command.
# timeout = 1.0
## If set, the total ping deadline, in seconds. Operates like the -w option
## of the ping command.
# deadline = 10
## Interface or source address to send ping from. Operates like the -I or -S
## option of the ping command.
# interface = ""
## Specify the ping executable binary.
# binary = "ping"
## Arguments for ping command. When arguments is not empty, the command from
## the binary option will be used and other options (ping_interval, timeout,
## etc) will be ignored.
# arguments = ["-c", "3"]
## Use only ipv6 addresses when resolving hostnames.
## Use only IPv6 addresses when resolving a hostname.
# ipv6 = false
`
@@ -4,11 +4,9 @@ import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
// register in driver.
_ "github.com/jackc/pgx/stdlib"
"github.com/influxdata/telegraf"
@@ -23,6 +21,8 @@ type Postgresql struct {
AdditionalTags []string
Query query
Debug bool
Log telegraf.Logger
}
type query []struct {
@@ -186,7 +186,7 @@ func (p *Postgresql) Gather(acc telegraf.Accumulator) error {
if p.Query[i].Version <= db_version {
rows, err := p.DB.Query(sql_query)
if err != nil {
acc.AddError(err)
p.Log.Error(err.Error())
continue
}
@@ -194,7 +194,7 @@ func (p *Postgresql) Gather(acc telegraf.Accumulator) error {
// grab the column information from the result
if columns, err = rows.Columns(); err != nil {
acc.AddError(err)
p.Log.Error(err.Error())
continue
}
@@ -209,7 +209,7 @@ func (p *Postgresql) Gather(acc telegraf.Accumulator) error {
for rows.Next() {
err = p.accRow(meas_name, rows, acc, columns)
if err != nil {
acc.AddError(err)
p.Log.Error(err.Error())
break
}
}
@@ -272,7 +272,7 @@ func (p *Postgresql) accRow(meas_name string, row scanner, acc telegraf.Accumula
fields := make(map[string]interface{})
COLUMN:
for col, val := range columnMap {
log.Printf("D! postgresql_extensible: column: %s = %T: %v\n", col, *val, *val)
p.Log.Debugf("Column: %s = %T: %v\n", col, *val, *val)
_, ignore := ignoredColumns[col]
if ignore || *val == nil {
continue
@@ -290,7 +290,7 @@ COLUMN:
case int64, int32, int:
tags[col] = fmt.Sprintf("%d", v)
default:
log.Println("failed to add additional tag", col)
p.Log.Debugf("Failed to add %q as additional tag", col)
}
continue COLUMN
}
@@ -13,6 +13,7 @@ import (
func queryRunner(t *testing.T, q query) *testutil.Accumulator {
p := &Postgresql{
Log: testutil.Logger{},
Service: postgresql.Service{
Address: fmt.Sprintf(
"host=%s user=postgres sslmode=disable",
@@ -232,6 +233,7 @@ func TestPostgresqlIgnoresUnwantedColumns(t *testing.T) {
}
p := &Postgresql{
Log: testutil.Logger{},
Service: postgresql.Service{
Address: fmt.Sprintf(
"host=%s user=postgres sslmode=disable",
@@ -251,7 +253,10 @@ func TestPostgresqlIgnoresUnwantedColumns(t *testing.T) {
}
func TestAccRow(t *testing.T) {
p := Postgresql{}
p := Postgresql{
Log: testutil.Logger{},
}
var acc testutil.Accumulator
columns := []string{"datname", "cat"}
+2 -2
View File
@@ -110,8 +110,8 @@ func parseResponse(metrics string) map[string]interface{} {
i, err := strconv.ParseInt(m[1], 10, 64)
if err != nil {
log.Printf("E! powerdns: Error parsing integer for metric [%s]: %s",
metric, err)
log.Printf("E! [inputs.powerdns] error parsing integer for metric %q: %s",
metric, err.Error())
continue
}
values[m[0]] = i
@@ -139,8 +139,8 @@ func parseResponse(metrics string) map[string]interface{} {
i, err := strconv.ParseInt(m[1], 10, 64)
if err != nil {
log.Printf("E! [inputs.powerdns_recursor] Error parsing integer for metric [%s] %v",
metric, err)
log.Printf("E! [inputs.powerdns_recursor] error parsing integer for metric %q: %s",
metric, err.Error())
continue
}
values[m[0]] = i
+5 -6
View File
@@ -6,7 +6,6 @@ import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
@@ -23,6 +22,8 @@ type Processes struct {
execPS func() ([]byte, error)
readProcFile func(filename string) ([]byte, error)
Log telegraf.Logger
forcePS bool
forceProc bool
}
@@ -124,8 +125,7 @@ func (p *Processes) gatherFromPS(fields map[string]interface{}) error {
case '?':
fields["unknown"] = fields["unknown"].(int64) + int64(1)
default:
log.Printf("I! processes: Unknown state [ %s ] from ps",
string(status[0]))
p.Log.Infof("Unknown state %q from ps", string(status[0]))
}
fields["total"] = fields["total"].(int64) + int64(1)
}
@@ -184,14 +184,13 @@ func (p *Processes) gatherFromProc(fields map[string]interface{}) error {
}
fields["parked"] = int64(1)
default:
log.Printf("I! processes: Unknown state [ %s ] in file %s",
string(stats[0][0]), filename)
p.Log.Infof("Unknown state %q in file %q", string(stats[0][0]), filename)
}
fields["total"] = fields["total"].(int64) + int64(1)
threads, err := strconv.Atoi(string(stats[17]))
if err != nil {
log.Printf("I! processes: Error parsing thread count: %s", err)
p.Log.Infof("Error parsing thread count: %s", err.Error())
continue
}
fields["total_threads"] = fields["total_threads"].(int64) + int64(threads)
@@ -16,6 +16,7 @@ import (
func TestProcesses(t *testing.T) {
processes := &Processes{
Log: testutil.Logger{},
execPS: execPS,
readProcFile: readProcFile,
}
@@ -35,6 +36,7 @@ func TestProcesses(t *testing.T) {
func TestFromPS(t *testing.T) {
processes := &Processes{
Log: testutil.Logger{},
execPS: testExecPS,
forcePS: true,
}
@@ -56,6 +58,7 @@ func TestFromPS(t *testing.T) {
func TestFromPSError(t *testing.T) {
processes := &Processes{
Log: testutil.Logger{},
execPS: testExecPSError,
forcePS: true,
}
@@ -71,6 +74,7 @@ func TestFromProcFiles(t *testing.T) {
}
tester := tester{}
processes := &Processes{
Log: testutil.Logger{},
readProcFile: tester.testProcFile,
forceProc: true,
}
@@ -93,6 +97,7 @@ func TestFromProcFilesWithSpaceInCmd(t *testing.T) {
}
tester := tester{}
processes := &Processes{
Log: testutil.Logger{},
readProcFile: tester.testProcFile2,
forceProc: true,
}
@@ -120,6 +125,7 @@ func TestParkedProcess(t *testing.T) {
procstat := `88 (watchdog/13) P 2 0 0 0 -1 69238848 0 0 0 0 0 0 0 0 20 0 1 0 20 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 1 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
`
plugin := &Processes{
Log: testutil.Logger{},
readProcFile: func(string) ([]byte, error) {
return []byte(procstat), nil
},

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