Docker: optionally add labels as tags (#2425)
This commit is contained in:
parent
51c99d5b67
commit
35e4390168
|
@ -63,6 +63,7 @@ be deprecated eventually.
|
||||||
- [#2332](https://github.com/influxdata/telegraf/pull/2332): Add Elasticsearch 5.x output
|
- [#2332](https://github.com/influxdata/telegraf/pull/2332): Add Elasticsearch 5.x output
|
||||||
- [#2587](https://github.com/influxdata/telegraf/pull/2587): Add json timestamp units configurability
|
- [#2587](https://github.com/influxdata/telegraf/pull/2587): Add json timestamp units configurability
|
||||||
- [#2597](https://github.com/influxdata/telegraf/issues/2597): Add support for Linux sysctl-fs metrics.
|
- [#2597](https://github.com/influxdata/telegraf/issues/2597): Add support for Linux sysctl-fs metrics.
|
||||||
|
- [#2425](https://github.com/influxdata/telegraf/pull/2425): Support to include/exclude docker container labels as tags
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,12 @@ for the stat structure can be found
|
||||||
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
|
||||||
|
|
||||||
|
## docker labels to include and exclude as tags. Globs accepted.
|
||||||
|
## Note that an empty array for both will include all labels as tags
|
||||||
|
docker_label_include = []
|
||||||
|
docker_label_exclude = []
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Measurements & Fields:
|
### Measurements & Fields:
|
||||||
|
@ -130,30 +136,32 @@ based on the availability of per-cpu stats on your system.
|
||||||
|
|
||||||
|
|
||||||
### Tags:
|
### Tags:
|
||||||
|
#### Docker Engine tags
|
||||||
- docker (memory_total)
|
- docker (memory_total)
|
||||||
- unit=bytes
|
- unit=bytes
|
||||||
|
- engine_host
|
||||||
- docker (pool_blocksize)
|
- docker (pool_blocksize)
|
||||||
- unit=bytes
|
- unit=bytes
|
||||||
|
- engine_host
|
||||||
- docker_data
|
- docker_data
|
||||||
- unit=bytes
|
- unit=bytes
|
||||||
|
- engine_host
|
||||||
- docker_metadata
|
- docker_metadata
|
||||||
- unit=bytes
|
- unit=bytes
|
||||||
|
- engine_host
|
||||||
|
|
||||||
|
#### Docker Container tags
|
||||||
|
- Tags on all containers:
|
||||||
|
- engine_host
|
||||||
|
- container_image
|
||||||
|
- container_name
|
||||||
|
- container_version
|
||||||
- docker_container_mem specific:
|
- docker_container_mem specific:
|
||||||
- container_image
|
|
||||||
- container_name
|
|
||||||
- docker_container_cpu specific:
|
- docker_container_cpu specific:
|
||||||
- container_image
|
|
||||||
- container_name
|
|
||||||
- cpu
|
- cpu
|
||||||
- docker_container_net specific:
|
- docker_container_net specific:
|
||||||
- container_image
|
|
||||||
- container_name
|
|
||||||
- network
|
- network
|
||||||
- docker_container_blkio specific:
|
- docker_container_blkio specific:
|
||||||
- container_image
|
|
||||||
- container_name
|
|
||||||
- device
|
- device
|
||||||
|
|
||||||
### Example Output:
|
### Example Output:
|
||||||
|
|
|
@ -14,12 +14,17 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/filter"
|
||||||
"github.com/influxdata/telegraf/internal"
|
"github.com/influxdata/telegraf/internal"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs"
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DockerLabelFilter struct {
|
||||||
|
labelInclude filter.Filter
|
||||||
|
labelExclude filter.Filter
|
||||||
|
}
|
||||||
|
|
||||||
// Docker object
|
// Docker object
|
||||||
type Docker struct {
|
type Docker struct {
|
||||||
Endpoint string
|
Endpoint string
|
||||||
|
@ -27,11 +32,16 @@ type Docker struct {
|
||||||
Timeout internal.Duration
|
Timeout internal.Duration
|
||||||
PerDevice bool `toml:"perdevice"`
|
PerDevice bool `toml:"perdevice"`
|
||||||
Total bool `toml:"total"`
|
Total bool `toml:"total"`
|
||||||
|
LabelInclude []string `toml:"docker_label_include"`
|
||||||
|
LabelExclude []string `toml:"docker_label_exclude"`
|
||||||
|
|
||||||
|
LabelFilter DockerLabelFilter
|
||||||
|
|
||||||
client *client.Client
|
client *client.Client
|
||||||
engine_host string
|
engine_host string
|
||||||
|
|
||||||
testing bool
|
testing bool
|
||||||
|
labelFiltersCreated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// infoWrapper wraps client.Client.List for testing.
|
// infoWrapper wraps client.Client.List for testing.
|
||||||
|
@ -99,6 +109,10 @@ var sampleConfig = `
|
||||||
## 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
|
||||||
|
|
||||||
|
## docker labels to include and exclude as tags. Globs accepted.
|
||||||
|
## Note that an empty array for both will include all labels as tags
|
||||||
|
docker_label_include = []
|
||||||
|
docker_label_exclude = []
|
||||||
`
|
`
|
||||||
|
|
||||||
// Description returns input description
|
// Description returns input description
|
||||||
|
@ -133,6 +147,14 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
d.client = c
|
d.client = c
|
||||||
}
|
}
|
||||||
|
// Create label filters if not already created
|
||||||
|
if !d.labelFiltersCreated {
|
||||||
|
err := d.createLabelFilters()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.labelFiltersCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
// Get daemon info
|
// Get daemon info
|
||||||
err := d.gatherInfo(acc)
|
err := d.gatherInfo(acc)
|
||||||
|
@ -293,8 +315,12 @@ func (d *Docker) gatherContainer(
|
||||||
|
|
||||||
// Add labels to tags
|
// Add labels to tags
|
||||||
for k, label := range container.Labels {
|
for k, label := range container.Labels {
|
||||||
|
if len(d.LabelInclude) == 0 || d.LabelFilter.labelInclude.Match(k) {
|
||||||
|
if len(d.LabelExclude) == 0 || !d.LabelFilter.labelExclude.Match(k) {
|
||||||
tags[k] = label
|
tags[k] = label
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gatherContainerStats(v, acc, tags, container.ID, d.PerDevice, d.Total)
|
gatherContainerStats(v, acc, tags, container.ID, d.PerDevice, d.Total)
|
||||||
|
|
||||||
|
@ -599,11 +625,32 @@ func parseSize(sizeStr string) (int64, error) {
|
||||||
return int64(size), nil
|
return int64(size), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Docker) createLabelFilters() error {
|
||||||
|
if len(d.LabelInclude) != 0 && d.LabelFilter.labelInclude == nil {
|
||||||
|
var err error
|
||||||
|
d.LabelFilter.labelInclude, err = filter.Compile(d.LabelInclude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.LabelExclude) != 0 && d.LabelFilter.labelExclude == nil {
|
||||||
|
var err error
|
||||||
|
d.LabelFilter.labelExclude, err = filter.Compile(d.LabelExclude)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
inputs.Add("docker", func() telegraf.Input {
|
inputs.Add("docker", func() telegraf.Input {
|
||||||
return &Docker{
|
return &Docker{
|
||||||
PerDevice: true,
|
PerDevice: true,
|
||||||
Timeout: internal.Duration{Duration: time.Second * 5},
|
Timeout: internal.Duration{Duration: time.Second * 5},
|
||||||
|
labelFiltersCreated: false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,6 +244,57 @@ func testStats() *types.StatsJSON {
|
||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gatherLabelsTests = []struct {
|
||||||
|
include []string
|
||||||
|
exclude []string
|
||||||
|
expected []string
|
||||||
|
notexpected []string
|
||||||
|
}{
|
||||||
|
{[]string{}, []string{}, []string{"label1", "label2"}, []string{}},
|
||||||
|
{[]string{"*"}, []string{}, []string{"label1", "label2"}, []string{}},
|
||||||
|
{[]string{"lab*"}, []string{}, []string{"label1", "label2"}, []string{}},
|
||||||
|
{[]string{"label1"}, []string{}, []string{"label1"}, []string{"label2"}},
|
||||||
|
{[]string{"label1*"}, []string{}, []string{"label1"}, []string{"label2"}},
|
||||||
|
{[]string{}, []string{"*"}, []string{}, []string{"label1", "label2"}},
|
||||||
|
{[]string{}, []string{"lab*"}, []string{}, []string{"label1", "label2"}},
|
||||||
|
{[]string{}, []string{"label1"}, []string{"label2"}, []string{"label1"}},
|
||||||
|
{[]string{"*"}, []string{"*"}, []string{}, []string{"label1", "label2"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDockerGatherLabels(t *testing.T) {
|
||||||
|
for _, tt := range gatherLabelsTests {
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
d := Docker{
|
||||||
|
client: nil,
|
||||||
|
testing: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, label := range tt.include {
|
||||||
|
d.LabelInclude = append(d.LabelInclude, label)
|
||||||
|
}
|
||||||
|
for _, label := range tt.exclude {
|
||||||
|
d.LabelExclude = append(d.LabelExclude, label)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for _, label := range tt.expected {
|
||||||
|
if !acc.HasTag("docker_container_cpu", label) {
|
||||||
|
t.Errorf("Didn't get expected label of %s. Test was: Include: %s Exclude %s",
|
||||||
|
label, tt.include, tt.exclude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, label := range tt.notexpected {
|
||||||
|
if acc.HasTag("docker_container_cpu", label) {
|
||||||
|
t.Errorf("Got unexpected label of %s. Test was: Include: %s Exclude %s",
|
||||||
|
label, 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{
|
||||||
|
@ -294,6 +345,8 @@ func TestDockerGatherInfo(t *testing.T) {
|
||||||
"cpu": "cpu3",
|
"cpu": "cpu3",
|
||||||
"container_version": "v2.2.2",
|
"container_version": "v2.2.2",
|
||||||
"engine_host": "absol",
|
"engine_host": "absol",
|
||||||
|
"label1": "test_value_1",
|
||||||
|
"label2": "test_value_2",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
acc.AssertContainsTaggedFields(t,
|
acc.AssertContainsTaggedFields(t,
|
||||||
|
@ -340,6 +393,8 @@ func TestDockerGatherInfo(t *testing.T) {
|
||||||
"container_name": "etcd2",
|
"container_name": "etcd2",
|
||||||
"container_image": "quay.io:4443/coreos/etcd",
|
"container_image": "quay.io:4443/coreos/etcd",
|
||||||
"container_version": "v2.2.2",
|
"container_version": "v2.2.2",
|
||||||
|
"label1": "test_value_1",
|
||||||
|
"label2": "test_value_2",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,10 @@ func (d FakeDockerClient) ContainerList(octx context.Context, options types.Cont
|
||||||
IP: "0.0.0.0",
|
IP: "0.0.0.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"label1": "test_value_1",
|
||||||
|
"label2": "test_value_2",
|
||||||
|
},
|
||||||
SizeRw: 0,
|
SizeRw: 0,
|
||||||
SizeRootFs: 0,
|
SizeRootFs: 0,
|
||||||
}
|
}
|
||||||
|
@ -125,6 +129,10 @@ func (d FakeDockerClient) ContainerList(octx context.Context, options types.Cont
|
||||||
IP: "0.0.0.0",
|
IP: "0.0.0.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"label1": "test_value_1",
|
||||||
|
"label2": "test_value_2",
|
||||||
|
},
|
||||||
SizeRw: 0,
|
SizeRw: 0,
|
||||||
SizeRootFs: 0,
|
SizeRootFs: 0,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue