diff --git a/plugins/inputs/docker/docker.go b/plugins/inputs/docker/docker.go index c98f1f845..f5633f099 100644 --- a/plugins/inputs/docker/docker.go +++ b/plugins/inputs/docker/docker.go @@ -416,7 +416,9 @@ func (d *Docker) gatherContainer( daemonOSType := r.OSType // use common (printed at `docker ps`) name for container - tags["container_name"] = strings.TrimPrefix(v.Name, "/") + if v.Name != "" { + tags["container_name"] = strings.TrimPrefix(v.Name, "/") + } // Add labels to tags for k, label := range container.Labels { @@ -442,6 +444,7 @@ func (d *Docker) gatherContainer( } } } + if info.State != nil { tags["container_status"] = info.State.Status statefields := map[string]interface{}{ @@ -458,14 +461,14 @@ func (d *Docker) gatherContainer( statefields["finished_at"] = container_time.UnixNano() } acc.AddFields("docker_container_status", statefields, tags, time.Now()) - } - if info.State.Health != nil { - healthfields := map[string]interface{}{ - "health_status": info.State.Health.Status, - "failing_streak": info.ContainerJSONBase.State.Health.FailingStreak, + if info.State.Health != nil { + healthfields := map[string]interface{}{ + "health_status": info.State.Health.Status, + "failing_streak": info.ContainerJSONBase.State.Health.FailingStreak, + } + acc.AddFields("docker_container_health", healthfields, tags, time.Now()) } - acc.AddFields("docker_container_health", healthfields, tags, time.Now()) } parseContainerStats(v, acc, tags, container.ID, d.PerDevice, d.Total, daemonOSType) diff --git a/plugins/inputs/docker/docker_test.go b/plugins/inputs/docker/docker_test.go index b97c34b6b..968dbf725 100644 --- a/plugins/inputs/docker/docker_test.go +++ b/plugins/inputs/docker/docker_test.go @@ -3,7 +3,9 @@ package docker import ( "context" "crypto/tls" + "io/ioutil" "sort" + "strings" "testing" "github.com/influxdata/telegraf/testutil" @@ -747,3 +749,69 @@ func TestContainerStateFilter(t *testing.T) { }) } } + +func TestContainerName(t *testing.T) { + tests := []struct { + name string + clientFunc func(host string, tlsConfig *tls.Config) (Client, error) + expected string + }{ + { + name: "container stats name is preferred", + clientFunc: func(host string, tlsConfig *tls.Config) (Client, error) { + client := baseClient + client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) { + var containers []types.Container + containers = append(containers, types.Container{ + Names: []string{"/logspout/foo"}, + }) + return containers, nil + } + client.ContainerStatsF = func(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) { + return types.ContainerStats{ + Body: ioutil.NopCloser(strings.NewReader(`{"name": "logspout"}`)), + }, nil + } + return &client, nil + }, + expected: "logspout", + }, + { + name: "container stats without name uses container list name", + clientFunc: func(host string, tlsConfig *tls.Config) (Client, error) { + client := baseClient + client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) { + var containers []types.Container + containers = append(containers, types.Container{ + Names: []string{"/logspout"}, + }) + return containers, nil + } + client.ContainerStatsF = func(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) { + return types.ContainerStats{ + Body: ioutil.NopCloser(strings.NewReader(`{}`)), + }, nil + } + return &client, nil + }, + expected: "logspout", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := Docker{ + newClient: tt.clientFunc, + } + var acc testutil.Accumulator + err := d.Gather(&acc) + require.NoError(t, err) + + for _, metric := range acc.Metrics { + // This tag is set on all container measurements + if metric.Measurement == "docker_container_mem" { + require.Equal(t, tt.expected, metric.Tags["container_name"]) + } + } + }) + } +}