Skip to content

Commit

Permalink
Add container id as optional source tag to docker and docker_log input (
Browse files Browse the repository at this point in the history
  • Loading branch information
morfien101 authored and danielnelson committed Oct 8, 2019
1 parent e7cf831 commit a5294fd
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 5 deletions.
14 changes: 14 additions & 0 deletions plugins/inputs/docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions plugins/inputs/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ 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
Expand Down Expand Up @@ -90,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 = []
Expand Down Expand Up @@ -412,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,
Expand Down Expand Up @@ -443,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()

Expand Down
40 changes: 38 additions & 2 deletions plugins/inputs/docker/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,9 @@ func TestContainerStatus(t *testing.T) {
return &client, nil
}
d = Docker{
Log: testutil.Logger{},
newClient: newClientFunc,
Log: testutil.Logger{},
newClient: newClientFunc,
IncludeSourceTag: true,
}
)

Expand Down Expand Up @@ -673,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",
})
})
}
Expand Down Expand Up @@ -1017,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 changes: 15 additions & 0 deletions plugins/inputs/docker_log/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -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
Expand Down
15 changes: 15 additions & 0 deletions plugins/inputs/docker_log/docker_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -435,3 +443,10 @@ func init() {
}
})
}

func hostnameFromID(id string) string {
if len(id) > 12 {
return id[0:12]
}
return id
}
9 changes: 6 additions & 3 deletions plugins/inputs/docker_log/docker_log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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()
Expand Down

0 comments on commit a5294fd

Please sign in to comment.