Add container uptime_ns in docker input plugin (#5996)
This commit is contained in:
parent
2aeaed2f27
commit
c52e7d88d7
|
@ -278,6 +278,7 @@ status if configured.
|
||||||
- exitcode (integer)
|
- exitcode (integer)
|
||||||
- started_at (integer)
|
- started_at (integer)
|
||||||
- finished_at (integer)
|
- finished_at (integer)
|
||||||
|
- uptime_ns (integer)
|
||||||
|
|
||||||
- docker_swarm
|
- docker_swarm
|
||||||
- tags:
|
- tags:
|
||||||
|
|
|
@ -73,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"}
|
containerStates = []string{"created", "restarting", "running", "removing", "paused", "exited", "dead"}
|
||||||
|
now = time.Now
|
||||||
)
|
)
|
||||||
|
|
||||||
var sampleConfig = `
|
var sampleConfig = `
|
||||||
|
@ -462,14 +463,21 @@ func (d *Docker) gatherContainer(
|
||||||
"pid": info.State.Pid,
|
"pid": info.State.Pid,
|
||||||
"exitcode": info.State.ExitCode,
|
"exitcode": info.State.ExitCode,
|
||||||
}
|
}
|
||||||
container_time, err := time.Parse(time.RFC3339, info.State.StartedAt)
|
|
||||||
if err == nil && !container_time.IsZero() {
|
finished, err := time.Parse(time.RFC3339, info.State.FinishedAt)
|
||||||
statefields["started_at"] = container_time.UnixNano()
|
if err == nil && !finished.IsZero() {
|
||||||
|
statefields["finished_at"] = finished.UnixNano()
|
||||||
|
} else {
|
||||||
|
// set finished to now for use in uptime
|
||||||
|
finished = now()
|
||||||
}
|
}
|
||||||
container_time, err = time.Parse(time.RFC3339, info.State.FinishedAt)
|
|
||||||
if err == nil && !container_time.IsZero() {
|
started, err := time.Parse(time.RFC3339, info.State.StartedAt)
|
||||||
statefields["finished_at"] = container_time.UnixNano()
|
if err == nil && !started.IsZero() {
|
||||||
|
statefields["started_at"] = started.UnixNano()
|
||||||
|
statefields["uptime_ns"] = finished.Sub(started).Nanoseconds()
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.AddFields("docker_container_status", statefields, tags, time.Now())
|
acc.AddFields("docker_container_status", statefields, tags, time.Now())
|
||||||
|
|
||||||
if info.State.Health != nil {
|
if info.State.Health != nil {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ var baseClient = MockClient{
|
||||||
return containerStats(s), nil
|
return containerStats(s), nil
|
||||||
},
|
},
|
||||||
ContainerInspectF: func(context.Context, string) (types.ContainerJSON, error) {
|
ContainerInspectF: func(context.Context, string) (types.ContainerJSON, error) {
|
||||||
return containerInspect, nil
|
return containerInspect(), nil
|
||||||
},
|
},
|
||||||
ServiceListF: func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) {
|
ServiceListF: func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) {
|
||||||
return ServiceList, nil
|
return ServiceList, nil
|
||||||
|
@ -264,7 +265,7 @@ func TestDocker_WindowsMemoryContainerStats(t *testing.T) {
|
||||||
return containerStatsWindows(), nil
|
return containerStatsWindows(), nil
|
||||||
},
|
},
|
||||||
ContainerInspectF: func(ctx context.Context, containerID string) (types.ContainerJSON, error) {
|
ContainerInspectF: func(ctx context.Context, containerID string) (types.ContainerJSON, error) {
|
||||||
return containerInspect, nil
|
return containerInspect(), nil
|
||||||
},
|
},
|
||||||
ServiceListF: func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) {
|
ServiceListF: func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) {
|
||||||
return ServiceList, nil
|
return ServiceList, nil
|
||||||
|
@ -538,6 +539,135 @@ func TestContainerNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContainerStatus(t *testing.T) {
|
||||||
|
type expectation struct {
|
||||||
|
// tags
|
||||||
|
Status string
|
||||||
|
// fields
|
||||||
|
OOMKilled bool
|
||||||
|
Pid int
|
||||||
|
ExitCode int
|
||||||
|
StartedAt time.Time
|
||||||
|
FinishedAt time.Time
|
||||||
|
UptimeNs int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
now func() time.Time
|
||||||
|
inspect types.ContainerJSON
|
||||||
|
expect expectation
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "finished_at is zero value",
|
||||||
|
now: func() time.Time {
|
||||||
|
return time.Date(2018, 6, 14, 5, 51, 53, 266176036, time.UTC)
|
||||||
|
},
|
||||||
|
inspect: containerInspect(),
|
||||||
|
expect: expectation{
|
||||||
|
Status: "running",
|
||||||
|
OOMKilled: false,
|
||||||
|
Pid: 1234,
|
||||||
|
ExitCode: 0,
|
||||||
|
StartedAt: time.Date(2018, 6, 14, 5, 48, 53, 266176036, time.UTC),
|
||||||
|
UptimeNs: int64(3 * time.Minute),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "finished_at is non-zero value",
|
||||||
|
inspect: func() types.ContainerJSON {
|
||||||
|
i := containerInspect()
|
||||||
|
i.ContainerJSONBase.State.FinishedAt = "2018-06-14T05:53:53.266176036Z"
|
||||||
|
return i
|
||||||
|
}(),
|
||||||
|
expect: expectation{
|
||||||
|
Status: "running",
|
||||||
|
OOMKilled: false,
|
||||||
|
Pid: 1234,
|
||||||
|
ExitCode: 0,
|
||||||
|
StartedAt: time.Date(2018, 6, 14, 5, 48, 53, 266176036, time.UTC),
|
||||||
|
FinishedAt: time.Date(2018, 6, 14, 5, 53, 53, 266176036, time.UTC),
|
||||||
|
UptimeNs: int64(5 * time.Minute),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "started_at is zero value",
|
||||||
|
inspect: func() types.ContainerJSON {
|
||||||
|
i := containerInspect()
|
||||||
|
i.ContainerJSONBase.State.StartedAt = ""
|
||||||
|
i.ContainerJSONBase.State.FinishedAt = "2018-06-14T05:53:53.266176036Z"
|
||||||
|
return i
|
||||||
|
}(),
|
||||||
|
expect: expectation{
|
||||||
|
Status: "running",
|
||||||
|
OOMKilled: false,
|
||||||
|
Pid: 1234,
|
||||||
|
ExitCode: 0,
|
||||||
|
FinishedAt: time.Date(2018, 6, 14, 5, 53, 53, 266176036, time.UTC),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var (
|
||||||
|
acc testutil.Accumulator
|
||||||
|
newClientFunc = func(string, *tls.Config) (Client, error) {
|
||||||
|
client := baseClient
|
||||||
|
client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return containerList[:1], nil
|
||||||
|
}
|
||||||
|
client.ContainerInspectF = func(c context.Context, s string) (types.ContainerJSON, error) {
|
||||||
|
return tt.inspect, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &client, nil
|
||||||
|
}
|
||||||
|
d = Docker{newClient: newClientFunc}
|
||||||
|
)
|
||||||
|
|
||||||
|
// mock time
|
||||||
|
if tt.now != nil {
|
||||||
|
now = tt.now
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
now = time.Now
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := acc.GatherError(d.Gather)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"oomkilled": tt.expect.OOMKilled,
|
||||||
|
"pid": tt.expect.Pid,
|
||||||
|
"exitcode": tt.expect.ExitCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
if started := tt.expect.StartedAt; !started.IsZero() {
|
||||||
|
fields["started_at"] = started.UnixNano()
|
||||||
|
fields["uptime_ns"] = tt.expect.UptimeNs
|
||||||
|
}
|
||||||
|
|
||||||
|
if finished := tt.expect.FinishedAt; !finished.IsZero() {
|
||||||
|
fields["finished_at"] = finished.UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.AssertContainsTaggedFields(t,
|
||||||
|
"docker_container_status",
|
||||||
|
fields,
|
||||||
|
map[string]string{
|
||||||
|
"container_name": "etcd",
|
||||||
|
"container_image": "quay.io/coreos/etcd",
|
||||||
|
"container_version": "v2.2.2",
|
||||||
|
"engine_host": "absol",
|
||||||
|
"label1": "test_value_1",
|
||||||
|
"label2": "test_value_2",
|
||||||
|
"server_version": "17.09.0-ce",
|
||||||
|
"container_status": tt.expect.Status,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDockerGatherInfo(t *testing.T) {
|
func TestDockerGatherInfo(t *testing.T) {
|
||||||
var acc testutil.Accumulator
|
var acc testutil.Accumulator
|
||||||
d := Docker{
|
d := Docker{
|
||||||
|
|
|
@ -492,32 +492,34 @@ func containerStatsWindows() types.ContainerStats {
|
||||||
return stat
|
return stat
|
||||||
}
|
}
|
||||||
|
|
||||||
var containerInspect = types.ContainerJSON{
|
func containerInspect() types.ContainerJSON {
|
||||||
Config: &container.Config{
|
return types.ContainerJSON{
|
||||||
Env: []string{
|
Config: &container.Config{
|
||||||
"ENVVAR1=loremipsum",
|
Env: []string{
|
||||||
"ENVVAR1FOO=loremipsum",
|
"ENVVAR1=loremipsum",
|
||||||
"ENVVAR2=dolorsitamet",
|
"ENVVAR1FOO=loremipsum",
|
||||||
"ENVVAR3==ubuntu:10.04",
|
"ENVVAR2=dolorsitamet",
|
||||||
"ENVVAR4",
|
"ENVVAR3==ubuntu:10.04",
|
||||||
"ENVVAR5=",
|
"ENVVAR4",
|
||||||
"ENVVAR6= ",
|
"ENVVAR5=",
|
||||||
"ENVVAR7=ENVVAR8=ENVVAR9",
|
"ENVVAR6= ",
|
||||||
"PATH=/bin:/sbin",
|
"ENVVAR7=ENVVAR8=ENVVAR9",
|
||||||
},
|
"PATH=/bin:/sbin",
|
||||||
},
|
|
||||||
ContainerJSONBase: &types.ContainerJSONBase{
|
|
||||||
State: &types.ContainerState{
|
|
||||||
Health: &types.Health{
|
|
||||||
FailingStreak: 1,
|
|
||||||
Status: "Unhealthy",
|
|
||||||
},
|
},
|
||||||
Status: "running",
|
|
||||||
OOMKilled: false,
|
|
||||||
Pid: 1234,
|
|
||||||
ExitCode: 0,
|
|
||||||
StartedAt: "2018-06-14T05:48:53.266176036Z",
|
|
||||||
FinishedAt: "0001-01-01T00:00:00Z",
|
|
||||||
},
|
},
|
||||||
},
|
ContainerJSONBase: &types.ContainerJSONBase{
|
||||||
|
State: &types.ContainerState{
|
||||||
|
Health: &types.Health{
|
||||||
|
FailingStreak: 1,
|
||||||
|
Status: "Unhealthy",
|
||||||
|
},
|
||||||
|
Status: "running",
|
||||||
|
OOMKilled: false,
|
||||||
|
Pid: 1234,
|
||||||
|
ExitCode: 0,
|
||||||
|
StartedAt: "2018-06-14T05:48:53.266176036Z",
|
||||||
|
FinishedAt: "0001-01-01T00:00:00Z",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue