From d217cdc1a62f8db926d787497211426fcfb09d85 Mon Sep 17 00:00:00 2001
From: Bob Shannon <bobmshannon@users.noreply.github.com>
Date: Mon, 26 Jun 2017 18:13:38 -0400
Subject: [PATCH] Add optional usage_active and time_active CPU metrics (#2943)

---
 plugins/inputs/system/CPU_README.md |  4 ++++
 plugins/inputs/system/cpu.go        | 18 ++++++++++++++++++
 plugins/inputs/system/cpu_test.go   |  3 +++
 3 files changed, 25 insertions(+)

diff --git a/plugins/inputs/system/CPU_README.md b/plugins/inputs/system/CPU_README.md
index 01d57855..dfb8561a 100644
--- a/plugins/inputs/system/CPU_README.md
+++ b/plugins/inputs/system/CPU_README.md
@@ -14,6 +14,8 @@
   totalcpu = true
   ## If true, collect raw CPU time metrics.
   collect_cpu_time = false
+  ## If true, compute and report the sum of all non-idle CPU states.
+  report_active = false
 ```
 
 #### Description
@@ -68,6 +70,7 @@ Measurement names:
 - cpu_time_user
 - cpu_time_system
 - cpu_time_idle
+- cpu_time_active (must be explicitly enabled by setting `report_active = true`)
 - cpu_time_nice
 - cpu_time_iowait
 - cpu_time_irq
@@ -86,6 +89,7 @@ Measurement names:
 - cpu_usage_user
 - cpu_usage_system
 - cpu_usage_idle
+- cpu_usage_active (must be explicitly enabled by setting `report_active = true`)
 - cpu_usage_nice
 - cpu_usage_iowait
 - cpu_usage_irq
diff --git a/plugins/inputs/system/cpu.go b/plugins/inputs/system/cpu.go
index e6aa9f22..f60cb20c 100644
--- a/plugins/inputs/system/cpu.go
+++ b/plugins/inputs/system/cpu.go
@@ -16,12 +16,14 @@ type CPUStats struct {
 	PerCPU         bool `toml:"percpu"`
 	TotalCPU       bool `toml:"totalcpu"`
 	CollectCPUTime bool `toml:"collect_cpu_time"`
+	ReportActive   bool `toml:"report_active"`
 }
 
 func NewCPUStats(ps PS) *CPUStats {
 	return &CPUStats{
 		ps:             ps,
 		CollectCPUTime: true,
+		ReportActive:   true,
 	}
 }
 
@@ -36,6 +38,8 @@ var sampleConfig = `
   totalcpu = true
   ## If true, collect raw CPU time metrics.
   collect_cpu_time = false
+  ## If true, compute and report the sum of all non-idle CPU states.
+  report_active = false
 `
 
 func (_ *CPUStats) SampleConfig() string {
@@ -55,6 +59,7 @@ func (s *CPUStats) Gather(acc telegraf.Accumulator) error {
 		}
 
 		total := totalCpuTime(cts)
+		active := activeCpuTime(cts)
 
 		if s.CollectCPUTime {
 			// Add cpu time metrics
@@ -70,6 +75,9 @@ func (s *CPUStats) Gather(acc telegraf.Accumulator) error {
 				"time_guest":      cts.Guest,
 				"time_guest_nice": cts.GuestNice,
 			}
+			if s.ReportActive {
+				fieldsC["time_active"] = activeCpuTime(cts)
+			}
 			acc.AddCounter("cpu", fieldsC, tags, now)
 		}
 
@@ -80,6 +88,7 @@ func (s *CPUStats) Gather(acc telegraf.Accumulator) error {
 		}
 		lastCts := s.lastStats[i]
 		lastTotal := totalCpuTime(lastCts)
+		lastActive := activeCpuTime(lastCts)
 		totalDelta := total - lastTotal
 
 		if totalDelta < 0 {
@@ -90,6 +99,7 @@ func (s *CPUStats) Gather(acc telegraf.Accumulator) error {
 		if totalDelta == 0 {
 			continue
 		}
+
 		fieldsG := map[string]interface{}{
 			"usage_user":       100 * (cts.User - lastCts.User - (cts.Guest - lastCts.Guest)) / totalDelta,
 			"usage_system":     100 * (cts.System - lastCts.System) / totalDelta,
@@ -102,6 +112,9 @@ func (s *CPUStats) Gather(acc telegraf.Accumulator) error {
 			"usage_guest":      100 * (cts.Guest - lastCts.Guest) / totalDelta,
 			"usage_guest_nice": 100 * (cts.GuestNice - lastCts.GuestNice) / totalDelta,
 		}
+		if s.ReportActive {
+			fieldsG["usage_active"] = 100 * (active - lastActive) / totalDelta
+		}
 		acc.AddGauge("cpu", fieldsG, tags, now)
 	}
 
@@ -116,6 +129,11 @@ func totalCpuTime(t cpu.TimesStat) float64 {
 	return total
 }
 
+func activeCpuTime(t cpu.TimesStat) float64 {
+	active := totalCpuTime(t) - t.Idle
+	return active
+}
+
 func init() {
 	inputs.Add("cpu", func() telegraf.Input {
 		return &CPUStats{
diff --git a/plugins/inputs/system/cpu_test.go b/plugins/inputs/system/cpu_test.go
index e071f22c..e9dc7dda 100644
--- a/plugins/inputs/system/cpu_test.go
+++ b/plugins/inputs/system/cpu_test.go
@@ -59,6 +59,7 @@ func TestCPUStats(t *testing.T) {
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 8.8, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_system", 8.2, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 80.1, 0, cputags)
+	assertContainsTaggedFloat(t, &acc, "cpu", "time_active", 19.9, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_nice", 1.3, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 0.8389, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_irq", 0.6, 0, cputags)
@@ -78,6 +79,7 @@ func TestCPUStats(t *testing.T) {
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_user", 24.9, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_system", 10.9, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_idle", 157.9798, 0, cputags)
+	assertContainsTaggedFloat(t, &acc, "cpu", "time_active", 42.0202, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_nice", 3.5, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_iowait", 0.929, 0, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "time_irq", 1.2, 0, cputags)
@@ -89,6 +91,7 @@ func TestCPUStats(t *testing.T) {
 	assertContainsTaggedFloat(t, &acc, "cpu", "usage_user", 7.8, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "usage_system", 2.7, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "usage_idle", 77.8798, 0.0005, cputags)
+	assertContainsTaggedFloat(t, &acc, "cpu", "usage_active", 22.1202, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "usage_nice", 0, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "usage_iowait", 0.0901, 0.0005, cputags)
 	assertContainsTaggedFloat(t, &acc, "cpu", "usage_irq", 0.6, 0.0005, cputags)
-- 
GitLab