Add filters for container state to docker input (#3950)
This commit is contained in:
parent
0d5759daed
commit
005d7823a5
|
@ -31,6 +31,11 @@ to gather stats from the [Engine API](https://docs.docker.com/engine/api/v1.20/)
|
||||||
container_name_include = []
|
container_name_include = []
|
||||||
container_name_exclude = []
|
container_name_exclude = []
|
||||||
|
|
||||||
|
## Container states to include and exclude. Globs accepted.
|
||||||
|
## When empty only containers in the "running" state will be captured.
|
||||||
|
# container_state_include = []
|
||||||
|
# container_state_exclude = []
|
||||||
|
|
||||||
## Timeout for docker list, info, and stats commands
|
## Timeout for docker list, info, and stats commands
|
||||||
timeout = "5s"
|
timeout = "5s"
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/filter"
|
"github.com/influxdata/telegraf/filter"
|
||||||
|
@ -25,7 +26,7 @@ import (
|
||||||
// Docker object
|
// Docker object
|
||||||
type Docker struct {
|
type Docker struct {
|
||||||
Endpoint string
|
Endpoint string
|
||||||
ContainerNames []string
|
ContainerNames []string // deprecated in 1.4; use container_name_include
|
||||||
|
|
||||||
GatherServices bool `toml:"gather_services"`
|
GatherServices bool `toml:"gather_services"`
|
||||||
|
|
||||||
|
@ -39,6 +40,9 @@ type Docker struct {
|
||||||
ContainerInclude []string `toml:"container_name_include"`
|
ContainerInclude []string `toml:"container_name_include"`
|
||||||
ContainerExclude []string `toml:"container_name_exclude"`
|
ContainerExclude []string `toml:"container_name_exclude"`
|
||||||
|
|
||||||
|
ContainerStateInclude []string `toml:"container_state_include"`
|
||||||
|
ContainerStateExclude []string `toml:"container_state_exclude"`
|
||||||
|
|
||||||
SSLCA string `toml:"ssl_ca"`
|
SSLCA string `toml:"ssl_ca"`
|
||||||
SSLCert string `toml:"ssl_cert"`
|
SSLCert string `toml:"ssl_cert"`
|
||||||
SSLKey string `toml:"ssl_key"`
|
SSLKey string `toml:"ssl_key"`
|
||||||
|
@ -53,6 +57,7 @@ type Docker struct {
|
||||||
filtersCreated bool
|
filtersCreated bool
|
||||||
labelFilter filter.Filter
|
labelFilter filter.Filter
|
||||||
containerFilter filter.Filter
|
containerFilter filter.Filter
|
||||||
|
stateFilter filter.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// KB, MB, GB, TB, PB...human friendly
|
// KB, MB, GB, TB, PB...human friendly
|
||||||
|
@ -68,6 +73,7 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`)
|
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`)
|
||||||
|
containerStates = []string{"created", "restarting", "running", "removing", "paused", "exited", "dead"}
|
||||||
)
|
)
|
||||||
|
|
||||||
var sampleConfig = `
|
var sampleConfig = `
|
||||||
|
@ -87,6 +93,11 @@ var sampleConfig = `
|
||||||
container_name_include = []
|
container_name_include = []
|
||||||
container_name_exclude = []
|
container_name_exclude = []
|
||||||
|
|
||||||
|
## Container states to include and exclude. Globs accepted.
|
||||||
|
## When empty only containers in the "running" state will be captured.
|
||||||
|
# container_state_include = []
|
||||||
|
# container_state_exclude = []
|
||||||
|
|
||||||
## Timeout for docker list, info, and stats commands
|
## Timeout for docker list, info, and stats commands
|
||||||
timeout = "5s"
|
timeout = "5s"
|
||||||
|
|
||||||
|
@ -148,6 +159,10 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = d.createContainerStateFilters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
d.filtersCreated = true
|
d.filtersCreated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,8 +179,22 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterArgs := filters.NewArgs()
|
||||||
|
for _, state := range containerStates {
|
||||||
|
if d.stateFilter.Match(state) {
|
||||||
|
filterArgs.Add("status", state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All container states were excluded
|
||||||
|
if filterArgs.Len() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// List containers
|
// List containers
|
||||||
opts := types.ContainerListOptions{}
|
opts := types.ContainerListOptions{
|
||||||
|
Filters: filterArgs,
|
||||||
|
}
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
|
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
containers, err := d.client.ContainerList(ctx, opts)
|
containers, err := d.client.ContainerList(ctx, opts)
|
||||||
|
@ -768,6 +797,18 @@ func (d *Docker) createLabelFilters() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Docker) createContainerStateFilters() error {
|
||||||
|
if len(d.ContainerStateInclude) == 0 && len(d.ContainerStateExclude) == 0 {
|
||||||
|
d.ContainerStateInclude = []string{"running"}
|
||||||
|
}
|
||||||
|
filter, err := filter.NewIncludeExcludeFilter(d.ContainerStateInclude, d.ContainerStateExclude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.stateFilter = filter
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
inputs.Add("docker", func() telegraf.Input {
|
inputs.Add("docker", func() telegraf.Input {
|
||||||
return &Docker{
|
return &Docker{
|
||||||
|
|
|
@ -3,6 +3,7 @@ package docker
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
@ -711,3 +712,85 @@ func TestDockerGatherSwarmInfo(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContainerStateFilter(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
include []string
|
||||||
|
exclude []string
|
||||||
|
expected map[string][]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "default",
|
||||||
|
expected: map[string][]string{
|
||||||
|
"status": []string{"running"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include running",
|
||||||
|
include: []string{"running"},
|
||||||
|
expected: map[string][]string{
|
||||||
|
"status": []string{"running"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include glob",
|
||||||
|
include: []string{"r*"},
|
||||||
|
expected: map[string][]string{
|
||||||
|
"status": []string{"restarting", "running", "removing"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include all",
|
||||||
|
include: []string{"*"},
|
||||||
|
expected: map[string][]string{
|
||||||
|
"status": []string{"created", "restarting", "running", "removing", "paused", "exited", "dead"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exclude all",
|
||||||
|
exclude: []string{"*"},
|
||||||
|
expected: map[string][]string{
|
||||||
|
"status": []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exclude all",
|
||||||
|
include: []string{"*"},
|
||||||
|
exclude: []string{"exited"},
|
||||||
|
expected: map[string][]string{
|
||||||
|
"status": []string{"created", "restarting", "running", "removing", "paused", "dead"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
|
||||||
|
newClientFunc := func(host string, tlsConfig *tls.Config) (Client, error) {
|
||||||
|
client := baseClient
|
||||||
|
client.ContainerListF = func(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
for k, v := range tt.expected {
|
||||||
|
actual := options.Filters.Get(k)
|
||||||
|
sort.Strings(actual)
|
||||||
|
sort.Strings(v)
|
||||||
|
require.Equal(t, v, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
d := Docker{
|
||||||
|
newClient: newClientFunc,
|
||||||
|
ContainerStateInclude: tt.include,
|
||||||
|
ContainerStateExclude: tt.exclude,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue