Add wildcard support for container inclusion/exclusion (#2793)
This commit is contained in:
parent
d5c7fa206c
commit
d7d64a76fe
|
@ -20,14 +20,22 @@ for the stat structure can be found
|
||||||
## To use TCP, set endpoint = "tcp://[ip]:[port]"
|
## To use TCP, set endpoint = "tcp://[ip]:[port]"
|
||||||
## To use environment variables (ie, docker-machine), set endpoint = "ENV"
|
## To use environment variables (ie, docker-machine), set endpoint = "ENV"
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
## Only collect metrics for these containers, collect all if empty
|
|
||||||
|
## Only collect metrics for these containers. Values will be appended to container_name_include.
|
||||||
|
## Deprecated (1.4.0), use container_name_include
|
||||||
container_names = []
|
container_names = []
|
||||||
|
|
||||||
|
## Containers to include and exclude. Collect all if empty. Globs accepted.
|
||||||
|
container_name_include = []
|
||||||
|
container_name_exclude = []
|
||||||
|
|
||||||
## Timeout for docker list, info, and stats commands
|
## Timeout for docker list, info, and stats commands
|
||||||
timeout = "5s"
|
timeout = "5s"
|
||||||
|
|
||||||
## Whether to report for each container per-device blkio (8:0, 8:1...) and
|
## Whether to report for each container per-device blkio (8:0, 8:1...) and
|
||||||
## network (eth0, eth1, ...) stats or not
|
## network (eth0, eth1, ...) stats or not
|
||||||
perdevice = true
|
perdevice = true
|
||||||
|
|
||||||
## Whether to report for each container total blkio and network stats or not
|
## Whether to report for each container total blkio and network stats or not
|
||||||
total = false
|
total = false
|
||||||
|
|
||||||
|
|
|
@ -24,24 +24,33 @@ type DockerLabelFilter struct {
|
||||||
labelExclude filter.Filter
|
labelExclude filter.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DockerContainerFilter struct {
|
||||||
|
containerInclude filter.Filter
|
||||||
|
containerExclude filter.Filter
|
||||||
|
}
|
||||||
|
|
||||||
// Docker object
|
// Docker object
|
||||||
type Docker struct {
|
type Docker struct {
|
||||||
Endpoint string
|
Endpoint string
|
||||||
ContainerNames []string
|
ContainerNames []string
|
||||||
|
|
||||||
Timeout internal.Duration
|
Timeout internal.Duration
|
||||||
PerDevice bool `toml:"perdevice"`
|
PerDevice bool `toml:"perdevice"`
|
||||||
Total bool `toml:"total"`
|
Total bool `toml:"total"`
|
||||||
TagEnvironment []string `toml:"tag_env"`
|
TagEnvironment []string `toml:"tag_env"`
|
||||||
LabelInclude []string `toml:"docker_label_include"`
|
LabelInclude []string `toml:"docker_label_include"`
|
||||||
LabelExclude []string `toml:"docker_label_exclude"`
|
LabelExclude []string `toml:"docker_label_exclude"`
|
||||||
|
|
||||||
LabelFilter DockerLabelFilter
|
LabelFilter DockerLabelFilter
|
||||||
|
|
||||||
|
ContainerInclude []string `toml:"container_name_include"`
|
||||||
|
ContainerExclude []string `toml:"container_name_exclude"`
|
||||||
|
ContainerFilter DockerContainerFilter
|
||||||
|
|
||||||
client *client.Client
|
client *client.Client
|
||||||
engine_host string
|
engine_host string
|
||||||
|
|
||||||
testing bool
|
testing bool
|
||||||
labelFiltersCreated bool
|
filtersCreated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// infoWrapper wraps client.Client.List for testing.
|
// infoWrapper wraps client.Client.List for testing.
|
||||||
|
@ -110,8 +119,15 @@ var sampleConfig = `
|
||||||
## To use TCP, set endpoint = "tcp://[ip]:[port]"
|
## To use TCP, set endpoint = "tcp://[ip]:[port]"
|
||||||
## To use environment variables (ie, docker-machine), set endpoint = "ENV"
|
## To use environment variables (ie, docker-machine), set endpoint = "ENV"
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
|
|
||||||
## Only collect metrics for these containers, collect all if empty
|
## Only collect metrics for these containers, collect all if empty
|
||||||
container_names = []
|
container_names = []
|
||||||
|
|
||||||
|
## Containers to include and exclude. Globs accepted.
|
||||||
|
## Note that an empty array for both will include all containers
|
||||||
|
container_name_include = []
|
||||||
|
container_name_exclude = []
|
||||||
|
|
||||||
## Timeout for docker list, info, and stats commands
|
## Timeout for docker list, info, and stats commands
|
||||||
timeout = "5s"
|
timeout = "5s"
|
||||||
|
|
||||||
|
@ -161,13 +177,18 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
d.client = c
|
d.client = c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create label filters if not already created
|
// Create label filters if not already created
|
||||||
if !d.labelFiltersCreated {
|
if !d.filtersCreated {
|
||||||
err := d.createLabelFilters()
|
err := d.createLabelFilters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.labelFiltersCreated = true
|
err = d.createContainerFilters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.filtersCreated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get daemon info
|
// Get daemon info
|
||||||
|
@ -306,11 +327,14 @@ func (d *Docker) gatherContainer(
|
||||||
"container_image": imageName,
|
"container_image": imageName,
|
||||||
"container_version": imageVersion,
|
"container_version": imageVersion,
|
||||||
}
|
}
|
||||||
if len(d.ContainerNames) > 0 {
|
|
||||||
if !sliceContains(cname, d.ContainerNames) {
|
if len(d.ContainerInclude) > 0 || len(d.ContainerExclude) > 0 {
|
||||||
|
if len(d.ContainerInclude) == 0 || !d.ContainerFilter.containerInclude.Match(cname) {
|
||||||
|
if len(d.ContainerExclude) == 0 || d.ContainerFilter.containerExclude.Match(cname) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
|
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -656,8 +680,32 @@ func parseSize(sizeStr string) (int64, error) {
|
||||||
return int64(size), nil
|
return int64(size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Docker) createContainerFilters() error {
|
||||||
|
if len(d.ContainerNames) > 0 {
|
||||||
|
d.ContainerInclude = append(d.ContainerInclude, d.ContainerNames...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.ContainerInclude) != 0 {
|
||||||
|
var err error
|
||||||
|
d.ContainerFilter.containerInclude, err = filter.Compile(d.ContainerInclude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.ContainerExclude) != 0 {
|
||||||
|
var err error
|
||||||
|
d.ContainerFilter.containerExclude, err = filter.Compile(d.ContainerExclude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Docker) createLabelFilters() error {
|
func (d *Docker) createLabelFilters() error {
|
||||||
if len(d.LabelInclude) != 0 && d.LabelFilter.labelInclude == nil {
|
if len(d.LabelInclude) != 0 {
|
||||||
var err error
|
var err error
|
||||||
d.LabelFilter.labelInclude, err = filter.Compile(d.LabelInclude)
|
d.LabelFilter.labelInclude, err = filter.Compile(d.LabelInclude)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -665,7 +713,7 @@ func (d *Docker) createLabelFilters() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(d.LabelExclude) != 0 && d.LabelFilter.labelExclude == nil {
|
if len(d.LabelExclude) != 0 {
|
||||||
var err error
|
var err error
|
||||||
d.LabelFilter.labelExclude, err = filter.Compile(d.LabelExclude)
|
d.LabelFilter.labelExclude, err = filter.Compile(d.LabelExclude)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -681,7 +729,7 @@ func init() {
|
||||||
return &Docker{
|
return &Docker{
|
||||||
PerDevice: true,
|
PerDevice: true,
|
||||||
Timeout: internal.Duration{Duration: time.Second * 5},
|
Timeout: internal.Duration{Duration: time.Second * 5},
|
||||||
labelFiltersCreated: false,
|
filtersCreated: false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ func TestDockerGatherContainerStats(t *testing.T) {
|
||||||
"container_name": "redis",
|
"container_name": "redis",
|
||||||
"container_image": "redis/image",
|
"container_image": "redis/image",
|
||||||
}
|
}
|
||||||
|
|
||||||
gatherContainerStats(stats, &acc, tags, "123456789", true, true)
|
gatherContainerStats(stats, &acc, tags, "123456789", true, true)
|
||||||
|
|
||||||
// test docker_container_net measurement
|
// test docker_container_net measurement
|
||||||
|
@ -295,6 +296,73 @@ func TestDockerGatherLabels(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gatherContainerNames = []struct {
|
||||||
|
include []string
|
||||||
|
exclude []string
|
||||||
|
expected []string
|
||||||
|
notexpected []string
|
||||||
|
}{
|
||||||
|
{[]string{}, []string{}, []string{"etcd", "etcd2"}, []string{}},
|
||||||
|
{[]string{"*"}, []string{}, []string{"etcd", "etcd2"}, []string{}},
|
||||||
|
{[]string{"etc*"}, []string{}, []string{"etcd", "etcd2"}, []string{}},
|
||||||
|
{[]string{"etcd"}, []string{}, []string{"etcd"}, []string{"etcd2"}},
|
||||||
|
{[]string{"etcd2*"}, []string{}, []string{"etcd2"}, []string{"etcd"}},
|
||||||
|
{[]string{}, []string{"etc*"}, []string{}, []string{"etcd", "etcd2"}},
|
||||||
|
{[]string{}, []string{"etcd"}, []string{"etcd2"}, []string{"etcd"}},
|
||||||
|
{[]string{"*"}, []string{"*"}, []string{"etcd", "etcd2"}, []string{}},
|
||||||
|
{[]string{}, []string{"*"}, []string{""}, []string{"etcd", "etcd2"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerNames(t *testing.T) {
|
||||||
|
for _, tt := range gatherContainerNames {
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
|
||||||
|
d := Docker{
|
||||||
|
client: nil,
|
||||||
|
testing: true,
|
||||||
|
ContainerInclude: tt.include,
|
||||||
|
ContainerExclude: tt.exclude,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for _, metric := range acc.Metrics {
|
||||||
|
if metric.Measurement == "docker_container_cpu" {
|
||||||
|
if val, ok := metric.Tags["container_name"]; ok {
|
||||||
|
var found bool = false
|
||||||
|
for _, cname := range tt.expected {
|
||||||
|
if val == cname {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("Got unexpected container of %s. Test was -> Include: %s, Exclude: %s", val, tt.include, tt.exclude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, metric := range acc.Metrics {
|
||||||
|
if metric.Measurement == "docker_container_cpu" {
|
||||||
|
if val, ok := metric.Tags["container_name"]; ok {
|
||||||
|
var found bool = false
|
||||||
|
for _, cname := range tt.notexpected {
|
||||||
|
if val == cname {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
t.Errorf("Got unexpected container of %s. Test was -> Include: %s, Exclude: %s", val, tt.include, tt.exclude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDockerGatherInfo(t *testing.T) {
|
func TestDockerGatherInfo(t *testing.T) {
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
d := Docker{
|
d := Docker{
|
||||||
|
|
Loading…
Reference in New Issue