From 863cbe512d63b9da0001190eb0c9d39ea0c6b24d Mon Sep 17 00:00:00 2001
From: Cameron Sparr <cameronsparr@gmail.com>
Date: Tue, 5 Apr 2016 10:21:57 -0600
Subject: [PATCH] processes plugin: fix case where there are spaces in cmd name

fixes #968
---
 CHANGELOG.md                            |  7 ++++++
 plugins/inputs/system/processes.go      | 13 ++++++++---
 plugins/inputs/system/processes_test.go | 30 +++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 754701e4..82a224f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.12.1 [unreleased]
+
+### Features
+
+### Bugfixes
+- [#968](https://github.com/influxdata/telegraf/issues/968): Processes plugin gets unknown state when spaces are in (command name)
+
 ## v0.12.0 [2016-04-05]
 
 ### Features
diff --git a/plugins/inputs/system/processes.go b/plugins/inputs/system/processes.go
index aae0e6ba..8c50a4eb 100644
--- a/plugins/inputs/system/processes.go
+++ b/plugins/inputs/system/processes.go
@@ -144,11 +144,18 @@ func (p *Processes) gatherFromProc(fields map[string]interface{}) error {
 			continue
 		}
 
+		// Parse out data after (<cmd name>)
+		i := bytes.LastIndex(data, []byte(")"))
+		if i == -1 {
+			continue
+		}
+		data = data[i+2:]
+
 		stats := bytes.Fields(data)
 		if len(stats) < 3 {
 			return fmt.Errorf("Something is terribly wrong with %s", statFile)
 		}
-		switch stats[2][0] {
+		switch stats[0][0] {
 		case 'R':
 			fields["running"] = fields["running"].(int64) + int64(1)
 		case 'S':
@@ -163,11 +170,11 @@ func (p *Processes) gatherFromProc(fields map[string]interface{}) error {
 			fields["paging"] = fields["paging"].(int64) + int64(1)
 		default:
 			log.Printf("processes: Unknown state [ %s ] in file %s",
-				string(stats[2][0]), statFile)
+				string(stats[0][0]), statFile)
 		}
 		fields["total"] = fields["total"].(int64) + int64(1)
 
-		threads, err := strconv.Atoi(string(stats[19]))
+		threads, err := strconv.Atoi(string(stats[17]))
 		if err != nil {
 			log.Printf("processes: Error parsing thread count: %s", err)
 			continue
diff --git a/plugins/inputs/system/processes_test.go b/plugins/inputs/system/processes_test.go
index de9b6aa5..eef52cd6 100644
--- a/plugins/inputs/system/processes_test.go
+++ b/plugins/inputs/system/processes_test.go
@@ -82,6 +82,28 @@ func TestFromProcFiles(t *testing.T) {
 	acc.AssertContainsTaggedFields(t, "processes", fields, map[string]string{})
 }
 
+func TestFromProcFilesWithSpaceInCmd(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("This test only runs on linux")
+	}
+	tester := tester{}
+	processes := &Processes{
+		readProcFile: tester.testProcFile2,
+		forceProc:    true,
+	}
+
+	var acc testutil.Accumulator
+	err := processes.Gather(&acc)
+	require.NoError(t, err)
+
+	fields := getEmptyFields()
+	fields["sleeping"] = tester.calls
+	fields["total_threads"] = tester.calls * 2
+	fields["total"] = tester.calls
+
+	acc.AssertContainsTaggedFields(t, "processes", fields, map[string]string{})
+}
+
 func testExecPS() ([]byte, error) {
 	return []byte(testPSOut), nil
 }
@@ -96,6 +118,11 @@ func (t *tester) testProcFile(_ string) ([]byte, error) {
 	return []byte(fmt.Sprintf(testProcStat, "S", "2")), nil
 }
 
+func (t *tester) testProcFile2(_ string) ([]byte, error) {
+	t.calls++
+	return []byte(fmt.Sprintf(testProcStat2, "S", "2")), nil
+}
+
 func testExecPSError() ([]byte, error) {
 	return []byte(testPSOut), fmt.Errorf("ERROR!")
 }
@@ -149,3 +176,6 @@ S+
 
 const testProcStat = `10 (rcuob/0) %s 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 20 0 %s 0 11 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 `
+
+const testProcStat2 = `10 (rcuob 0) %s 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 20 0 %s 0 11 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+`
-- 
GitLab