From 7c20522a30cff17e5bd88b3e838a66e440a5e859 Mon Sep 17 00:00:00 2001 From: Mike Tonks Date: Tue, 9 Feb 2016 15:20:56 +0000 Subject: [PATCH 1/2] Add calculated cpu and memory percentages to docker input (via config option) --- plugins/inputs/docker/README.md | 8 ++ plugins/inputs/docker/docker.go | 32 ++++++- plugins/inputs/docker/docker_test.go | 132 +++++++++++++++++---------- 3 files changed, 123 insertions(+), 49 deletions(-) diff --git a/plugins/inputs/docker/README.md b/plugins/inputs/docker/README.md index fa662ca80..9aea54c07 100644 --- a/plugins/inputs/docker/README.md +++ b/plugins/inputs/docker/README.md @@ -22,8 +22,16 @@ for the stat structure can be found endpoint = "unix:///var/run/docker.sock" # Only collect metrics for these containers, collect all if empty container_names = [] + calculate_percentages = false ``` +### Calculate Percentages + +Optionally percentages can be calculated for cpu and memory usage. This uses +the same calculation as the 'docker stats' command line tool. Set this option +to 'true' to enable this feature. + + ### Measurements & Fields: Every effort was made to preserve the names based on the JSON response from the diff --git a/plugins/inputs/docker/docker.go b/plugins/inputs/docker/docker.go index 6814c190a..8c927f954 100644 --- a/plugins/inputs/docker/docker.go +++ b/plugins/inputs/docker/docker.go @@ -14,8 +14,9 @@ import ( ) type Docker struct { - Endpoint string - ContainerNames []string + Endpoint string + ContainerNames []string + CalculatePercentages bool client *docker.Client } @@ -27,6 +28,8 @@ var sampleConfig = ` endpoint = "unix:///var/run/docker.sock" # Only collect metrics for these containers, collect all if empty container_names = [] + # Add calculated percentages for mem and cpu, as per 'docker stats' command + calculate_percentages = false ` func (d *Docker) Description() string { @@ -67,6 +70,7 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error { var wg sync.WaitGroup wg.Add(len(containers)) for _, container := range containers { + go func(c docker.APIContainers) { defer wg.Done() err := d.gatherContainer(c, acc) @@ -131,7 +135,7 @@ func (d *Docker) gatherContainer( tags[k] = v } - gatherContainerStats(stat, acc, tags) + gatherContainerStats(stat, acc, tags, d.CalculatePercentages) return nil } @@ -140,6 +144,7 @@ func gatherContainerStats( stat *docker.Stats, acc telegraf.Accumulator, tags map[string]string, + calculate_percentages bool, ) { now := stat.Read @@ -178,6 +183,9 @@ func gatherContainerStats( "inactive_file": stat.MemoryStats.Stats.InactiveFile, "total_pgpgin": stat.MemoryStats.Stats.TotalPgpgin, } + if calculate_percentages { + memfields["usage_percent"] = float64(stat.MemoryStats.Usage) / float64(stat.MemoryStats.Limit) * 100.0 + } acc.AddFields("docker_mem", memfields, tags, now) cpufields := map[string]interface{}{ @@ -189,6 +197,9 @@ func gatherContainerStats( "throttling_throttled_periods": stat.CPUStats.ThrottlingData.ThrottledPeriods, "throttling_throttled_time": stat.CPUStats.ThrottlingData.ThrottledTime, } + if calculate_percentages { + cpufields["usage_percent"] = calculateCPUPercent(stat) + } cputags := copyTags(tags) cputags["cpu"] = "cpu-total" acc.AddFields("docker_cpu", cpufields, cputags, now) @@ -219,6 +230,21 @@ func gatherContainerStats( gatherBlockIOMetrics(stat, acc, tags, now) } +func calculateCPUPercent(stat *docker.Stats) float64 { + var ( + cpuPercent = 0.0 + // calculate the change for the cpu usage of the container in between readings + cpuDelta = float64(stat.CPUStats.CPUUsage.TotalUsage) - float64(stat.PreCPUStats.CPUUsage.TotalUsage) + // calculate the change for the entire system between readings + systemDelta = float64(stat.CPUStats.SystemCPUUsage) - float64(stat.PreCPUStats.SystemCPUUsage) + ) + + if systemDelta > 0.0 && cpuDelta > 0.0 { + cpuPercent = (cpuDelta / systemDelta) * float64(len(stat.CPUStats.CPUUsage.PercpuUsage)) * 100.0 + } + return cpuPercent +} + func gatherBlockIOMetrics( stat *docker.Stats, acc telegraf.Accumulator, diff --git a/plugins/inputs/docker/docker_test.go b/plugins/inputs/docker/docker_test.go index 9b85d1029..3e27ea59b 100644 --- a/plugins/inputs/docker/docker_test.go +++ b/plugins/inputs/docker/docker_test.go @@ -18,7 +18,7 @@ func TestDockerGatherContainerStats(t *testing.T) { "cont_name": "redis", "cont_image": "redis/image", } - gatherContainerStats(stats, &acc, tags) + gatherContainerStats(stats, &acc, tags, false) // test docker_net measurement netfields := map[string]interface{}{ @@ -45,55 +45,13 @@ func TestDockerGatherContainerStats(t *testing.T) { acc.AssertContainsTaggedFields(t, "docker_blkio", blkiofields, blkiotags) // test docker_mem measurement - memfields := map[string]interface{}{ - "max_usage": uint64(1001), - "usage": uint64(1111), - "fail_count": uint64(1), - "limit": uint64(20), - "total_pgmafault": uint64(0), - "cache": uint64(0), - "mapped_file": uint64(0), - "total_inactive_file": uint64(0), - "pgpgout": uint64(0), - "rss": uint64(0), - "total_mapped_file": uint64(0), - "writeback": uint64(0), - "unevictable": uint64(0), - "pgpgin": uint64(0), - "total_unevictable": uint64(0), - "pgmajfault": uint64(0), - "total_rss": uint64(44), - "total_rss_huge": uint64(444), - "total_writeback": uint64(55), - "total_inactive_anon": uint64(0), - "rss_huge": uint64(0), - "hierarchical_memory_limit": uint64(0), - "total_pgfault": uint64(0), - "total_active_file": uint64(0), - "active_anon": uint64(0), - "total_active_anon": uint64(0), - "total_pgpgout": uint64(0), - "total_cache": uint64(0), - "inactive_anon": uint64(0), - "active_file": uint64(1), - "pgfault": uint64(2), - "inactive_file": uint64(3), - "total_pgpgin": uint64(4), - } + memfields := sample_mem_fields() acc.AssertContainsTaggedFields(t, "docker_mem", memfields, tags) // test docker_cpu measurement cputags := copyTags(tags) cputags["cpu"] = "cpu-total" - cpufields := map[string]interface{}{ - "usage_total": uint64(500), - "usage_in_usermode": uint64(100), - "usage_in_kernelmode": uint64(200), - "usage_system": uint64(100), - "throttling_periods": uint64(1), - "throttling_throttled_periods": uint64(0), - "throttling_throttled_time": uint64(0), - } + cpufields := sample_cpu_fields() acc.AssertContainsTaggedFields(t, "docker_cpu", cpufields, cputags) cputags["cpu"] = "cpu0" @@ -109,6 +67,30 @@ func TestDockerGatherContainerStats(t *testing.T) { acc.AssertContainsTaggedFields(t, "docker_cpu", cpu1fields, cputags) } +func TestDockerGatherContainerPercentages(t *testing.T) { + var acc testutil.Accumulator + stats := testStats() + + tags := map[string]string{ + "cont_id": "foobarbaz", + "cont_name": "redis", + "cont_image": "redis/image", + } + gatherContainerStats(stats, &acc, tags, true) + + // test docker_mem measurement + memfields := sample_mem_fields() + memfields["usage_percent"] = 55.55 + acc.AssertContainsTaggedFields(t, "docker_mem", memfields, tags) + + // test docker_cpu measurement + cputags := copyTags(tags) + cputags["cpu"] = "cpu-total" + cpufields := sample_cpu_fields() + cpufields["usage_percent"] = 400.0 + acc.AssertContainsTaggedFields(t, "docker_cpu", cpufields, cputags) +} + func testStats() *docker.Stats { stats := &docker.Stats{ Read: time.Now(), @@ -122,6 +104,9 @@ func testStats() *docker.Stats { stats.CPUStats.SystemCPUUsage = 100 stats.CPUStats.ThrottlingData.Periods = 1 + stats.PreCPUStats.CPUUsage.TotalUsage = 400 + stats.PreCPUStats.SystemCPUUsage = 50 + stats.MemoryStats.Stats.TotalPgmafault = 0 stats.MemoryStats.Stats.Cache = 0 stats.MemoryStats.Stats.MappedFile = 0 @@ -155,7 +140,7 @@ func testStats() *docker.Stats { stats.MemoryStats.MaxUsage = 1001 stats.MemoryStats.Usage = 1111 stats.MemoryStats.Failcnt = 1 - stats.MemoryStats.Limit = 20 + stats.MemoryStats.Limit = 2000 stats.Networks["eth0"] = docker.NetworkStats{ RxDropped: 1, @@ -188,3 +173,58 @@ func testStats() *docker.Stats { return stats } + +func sample_mem_fields() map[string]interface{} { + + memfields := map[string]interface{}{ + "max_usage": uint64(1001), + "usage": uint64(1111), + "fail_count": uint64(1), + "limit": uint64(2000), + "total_pgmafault": uint64(0), + "cache": uint64(0), + "mapped_file": uint64(0), + "total_inactive_file": uint64(0), + "pgpgout": uint64(0), + "rss": uint64(0), + "total_mapped_file": uint64(0), + "writeback": uint64(0), + "unevictable": uint64(0), + "pgpgin": uint64(0), + "total_unevictable": uint64(0), + "pgmajfault": uint64(0), + "total_rss": uint64(44), + "total_rss_huge": uint64(444), + "total_writeback": uint64(55), + "total_inactive_anon": uint64(0), + "rss_huge": uint64(0), + "hierarchical_memory_limit": uint64(0), + "total_pgfault": uint64(0), + "total_active_file": uint64(0), + "active_anon": uint64(0), + "total_active_anon": uint64(0), + "total_pgpgout": uint64(0), + "total_cache": uint64(0), + "inactive_anon": uint64(0), + "active_file": uint64(1), + "pgfault": uint64(2), + "inactive_file": uint64(3), + "total_pgpgin": uint64(4), + } + + return memfields +} + +func sample_cpu_fields() map[string]interface{} { + + cpufields := map[string]interface{}{ + "usage_total": uint64(500), + "usage_in_usermode": uint64(100), + "usage_in_kernelmode": uint64(200), + "usage_system": uint64(100), + "throttling_periods": uint64(1), + "throttling_throttled_periods": uint64(0), + "throttling_throttled_time": uint64(0), + } + return cpufields +} From 7587dc350e158fbb8f7550ad873d0acea6633457 Mon Sep 17 00:00:00 2001 From: Mike Tonks Date: Thu, 11 Feb 2016 10:49:48 +0000 Subject: [PATCH 2/2] Remove config option, percent option always activated. Fix review issues --- plugins/inputs/docker/README.md | 8 -- plugins/inputs/docker/docker.go | 37 ++++---- plugins/inputs/docker/docker_test.go | 130 ++++++++++----------------- 3 files changed, 65 insertions(+), 110 deletions(-) diff --git a/plugins/inputs/docker/README.md b/plugins/inputs/docker/README.md index 9aea54c07..fa662ca80 100644 --- a/plugins/inputs/docker/README.md +++ b/plugins/inputs/docker/README.md @@ -22,16 +22,8 @@ for the stat structure can be found endpoint = "unix:///var/run/docker.sock" # Only collect metrics for these containers, collect all if empty container_names = [] - calculate_percentages = false ``` -### Calculate Percentages - -Optionally percentages can be calculated for cpu and memory usage. This uses -the same calculation as the 'docker stats' command line tool. Set this option -to 'true' to enable this feature. - - ### Measurements & Fields: Every effort was made to preserve the names based on the JSON response from the diff --git a/plugins/inputs/docker/docker.go b/plugins/inputs/docker/docker.go index 8c927f954..cdb1dff31 100644 --- a/plugins/inputs/docker/docker.go +++ b/plugins/inputs/docker/docker.go @@ -14,9 +14,8 @@ import ( ) type Docker struct { - Endpoint string - ContainerNames []string - CalculatePercentages bool + Endpoint string + ContainerNames []string client *docker.Client } @@ -28,8 +27,6 @@ var sampleConfig = ` endpoint = "unix:///var/run/docker.sock" # Only collect metrics for these containers, collect all if empty container_names = [] - # Add calculated percentages for mem and cpu, as per 'docker stats' command - calculate_percentages = false ` func (d *Docker) Description() string { @@ -135,7 +132,7 @@ func (d *Docker) gatherContainer( tags[k] = v } - gatherContainerStats(stat, acc, tags, d.CalculatePercentages) + gatherContainerStats(stat, acc, tags) return nil } @@ -144,7 +141,6 @@ func gatherContainerStats( stat *docker.Stats, acc telegraf.Accumulator, tags map[string]string, - calculate_percentages bool, ) { now := stat.Read @@ -182,9 +178,7 @@ func gatherContainerStats( "pgfault": stat.MemoryStats.Stats.Pgfault, "inactive_file": stat.MemoryStats.Stats.InactiveFile, "total_pgpgin": stat.MemoryStats.Stats.TotalPgpgin, - } - if calculate_percentages { - memfields["usage_percent"] = float64(stat.MemoryStats.Usage) / float64(stat.MemoryStats.Limit) * 100.0 + "usage_percent": calculateMemPercent(stat), } acc.AddFields("docker_mem", memfields, tags, now) @@ -196,9 +190,7 @@ func gatherContainerStats( "throttling_periods": stat.CPUStats.ThrottlingData.Periods, "throttling_throttled_periods": stat.CPUStats.ThrottlingData.ThrottledPeriods, "throttling_throttled_time": stat.CPUStats.ThrottlingData.ThrottledTime, - } - if calculate_percentages { - cpufields["usage_percent"] = calculateCPUPercent(stat) + "usage_percent": calculateCPUPercent(stat), } cputags := copyTags(tags) cputags["cpu"] = "cpu-total" @@ -230,14 +222,19 @@ func gatherContainerStats( gatherBlockIOMetrics(stat, acc, tags, now) } +func calculateMemPercent(stat *docker.Stats) float64 { + var memPercent = 0.0 + if stat.MemoryStats.Limit > 0 { + memPercent = float64(stat.MemoryStats.Usage) / float64(stat.MemoryStats.Limit) * 100.0 + } + return memPercent +} + func calculateCPUPercent(stat *docker.Stats) float64 { - var ( - cpuPercent = 0.0 - // calculate the change for the cpu usage of the container in between readings - cpuDelta = float64(stat.CPUStats.CPUUsage.TotalUsage) - float64(stat.PreCPUStats.CPUUsage.TotalUsage) - // calculate the change for the entire system between readings - systemDelta = float64(stat.CPUStats.SystemCPUUsage) - float64(stat.PreCPUStats.SystemCPUUsage) - ) + var cpuPercent = 0.0 + // calculate the change for the cpu and system usage of the container in between readings + cpuDelta := float64(stat.CPUStats.CPUUsage.TotalUsage) - float64(stat.PreCPUStats.CPUUsage.TotalUsage) + systemDelta := float64(stat.CPUStats.SystemCPUUsage) - float64(stat.PreCPUStats.SystemCPUUsage) if systemDelta > 0.0 && cpuDelta > 0.0 { cpuPercent = (cpuDelta / systemDelta) * float64(len(stat.CPUStats.CPUUsage.PercpuUsage)) * 100.0 diff --git a/plugins/inputs/docker/docker_test.go b/plugins/inputs/docker/docker_test.go index 3e27ea59b..aebe8102e 100644 --- a/plugins/inputs/docker/docker_test.go +++ b/plugins/inputs/docker/docker_test.go @@ -18,7 +18,7 @@ func TestDockerGatherContainerStats(t *testing.T) { "cont_name": "redis", "cont_image": "redis/image", } - gatherContainerStats(stats, &acc, tags, false) + gatherContainerStats(stats, &acc, tags) // test docker_net measurement netfields := map[string]interface{}{ @@ -45,13 +45,58 @@ func TestDockerGatherContainerStats(t *testing.T) { acc.AssertContainsTaggedFields(t, "docker_blkio", blkiofields, blkiotags) // test docker_mem measurement - memfields := sample_mem_fields() + memfields := map[string]interface{}{ + "max_usage": uint64(1001), + "usage": uint64(1111), + "fail_count": uint64(1), + "limit": uint64(2000), + "total_pgmafault": uint64(0), + "cache": uint64(0), + "mapped_file": uint64(0), + "total_inactive_file": uint64(0), + "pgpgout": uint64(0), + "rss": uint64(0), + "total_mapped_file": uint64(0), + "writeback": uint64(0), + "unevictable": uint64(0), + "pgpgin": uint64(0), + "total_unevictable": uint64(0), + "pgmajfault": uint64(0), + "total_rss": uint64(44), + "total_rss_huge": uint64(444), + "total_writeback": uint64(55), + "total_inactive_anon": uint64(0), + "rss_huge": uint64(0), + "hierarchical_memory_limit": uint64(0), + "total_pgfault": uint64(0), + "total_active_file": uint64(0), + "active_anon": uint64(0), + "total_active_anon": uint64(0), + "total_pgpgout": uint64(0), + "total_cache": uint64(0), + "inactive_anon": uint64(0), + "active_file": uint64(1), + "pgfault": uint64(2), + "inactive_file": uint64(3), + "total_pgpgin": uint64(4), + "usage_percent": float64(55.55), + } + acc.AssertContainsTaggedFields(t, "docker_mem", memfields, tags) // test docker_cpu measurement cputags := copyTags(tags) cputags["cpu"] = "cpu-total" - cpufields := sample_cpu_fields() + cpufields := map[string]interface{}{ + "usage_total": uint64(500), + "usage_in_usermode": uint64(100), + "usage_in_kernelmode": uint64(200), + "usage_system": uint64(100), + "throttling_periods": uint64(1), + "throttling_throttled_periods": uint64(0), + "throttling_throttled_time": uint64(0), + "usage_percent": float64(400.0), + } acc.AssertContainsTaggedFields(t, "docker_cpu", cpufields, cputags) cputags["cpu"] = "cpu0" @@ -67,30 +112,6 @@ func TestDockerGatherContainerStats(t *testing.T) { acc.AssertContainsTaggedFields(t, "docker_cpu", cpu1fields, cputags) } -func TestDockerGatherContainerPercentages(t *testing.T) { - var acc testutil.Accumulator - stats := testStats() - - tags := map[string]string{ - "cont_id": "foobarbaz", - "cont_name": "redis", - "cont_image": "redis/image", - } - gatherContainerStats(stats, &acc, tags, true) - - // test docker_mem measurement - memfields := sample_mem_fields() - memfields["usage_percent"] = 55.55 - acc.AssertContainsTaggedFields(t, "docker_mem", memfields, tags) - - // test docker_cpu measurement - cputags := copyTags(tags) - cputags["cpu"] = "cpu-total" - cpufields := sample_cpu_fields() - cpufields["usage_percent"] = 400.0 - acc.AssertContainsTaggedFields(t, "docker_cpu", cpufields, cputags) -} - func testStats() *docker.Stats { stats := &docker.Stats{ Read: time.Now(), @@ -173,58 +194,3 @@ func testStats() *docker.Stats { return stats } - -func sample_mem_fields() map[string]interface{} { - - memfields := map[string]interface{}{ - "max_usage": uint64(1001), - "usage": uint64(1111), - "fail_count": uint64(1), - "limit": uint64(2000), - "total_pgmafault": uint64(0), - "cache": uint64(0), - "mapped_file": uint64(0), - "total_inactive_file": uint64(0), - "pgpgout": uint64(0), - "rss": uint64(0), - "total_mapped_file": uint64(0), - "writeback": uint64(0), - "unevictable": uint64(0), - "pgpgin": uint64(0), - "total_unevictable": uint64(0), - "pgmajfault": uint64(0), - "total_rss": uint64(44), - "total_rss_huge": uint64(444), - "total_writeback": uint64(55), - "total_inactive_anon": uint64(0), - "rss_huge": uint64(0), - "hierarchical_memory_limit": uint64(0), - "total_pgfault": uint64(0), - "total_active_file": uint64(0), - "active_anon": uint64(0), - "total_active_anon": uint64(0), - "total_pgpgout": uint64(0), - "total_cache": uint64(0), - "inactive_anon": uint64(0), - "active_file": uint64(1), - "pgfault": uint64(2), - "inactive_file": uint64(3), - "total_pgpgin": uint64(4), - } - - return memfields -} - -func sample_cpu_fields() map[string]interface{} { - - cpufields := map[string]interface{}{ - "usage_total": uint64(500), - "usage_in_usermode": uint64(100), - "usage_in_kernelmode": uint64(200), - "usage_system": uint64(100), - "throttling_periods": uint64(1), - "throttling_throttled_periods": uint64(0), - "throttling_throttled_time": uint64(0), - } - return cpufields -}