From dfba3ff37a33da2c7286801b4a2b7ca8b8731c79 Mon Sep 17 00:00:00 2001
From: Cameron Sparr <cameronsparr@gmail.com>
Date: Wed, 1 Feb 2017 17:14:47 +0000
Subject: [PATCH] fix telegraf swallowing panics in --test mode

this defer function was causing telegraf to call os.Exit(0) instead of
panicking when it was supposed to.

closes #2341
---
 CHANGELOG.md             |   1 +
 cmd/telegraf/telegraf.go | 193 +++++++++++++++++++++------------------
 2 files changed, 105 insertions(+), 89 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f377a98..87748d2b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,7 @@ It is highly recommended that all users migrate to the new riemann output plugin
 - [#2262](https://github.com/influxdata/telegraf/issues/2262): Flush jitter can inhibit metric collection.
 - [#2287](https://github.com/influxdata/telegraf/issues/2287): Kubernetes input: Handle null startTime for stopped pods.
 - [#2356](https://github.com/influxdata/telegraf/issues/2356): cpu input panic when /proc/stat is empty.
+- [#2341](https://github.com/influxdata/telegraf/issues/2341): telegraf swallowing panics in --test mode.
 
 ## v1.2.1 [2017-02-01]
 
diff --git a/cmd/telegraf/telegraf.go b/cmd/telegraf/telegraf.go
index 398617e0..a3631d38 100644
--- a/cmd/telegraf/telegraf.go
+++ b/cmd/telegraf/telegraf.go
@@ -109,94 +109,17 @@ Examples:
 
 var stop chan struct{}
 
-var srvc service.Service
-
-type program struct{}
-
-func reloadLoop(stop chan struct{}, s service.Service) {
-	defer func() {
-		if service.Interactive() {
-			os.Exit(0)
-		}
-		return
-	}()
+func reloadLoop(
+	stop chan struct{},
+	inputFilters []string,
+	outputFilters []string,
+	aggregatorFilters []string,
+	processorFilters []string,
+) {
 	reload := make(chan bool, 1)
 	reload <- true
 	for <-reload {
 		reload <- false
-		flag.Parse()
-		args := flag.Args()
-
-		var inputFilters []string
-		if *fInputFilters != "" {
-			inputFilter := strings.TrimSpace(*fInputFilters)
-			inputFilters = strings.Split(":"+inputFilter+":", ":")
-		}
-		var outputFilters []string
-		if *fOutputFilters != "" {
-			outputFilter := strings.TrimSpace(*fOutputFilters)
-			outputFilters = strings.Split(":"+outputFilter+":", ":")
-		}
-		var aggregatorFilters []string
-		if *fAggregatorFilters != "" {
-			aggregatorFilter := strings.TrimSpace(*fAggregatorFilters)
-			aggregatorFilters = strings.Split(":"+aggregatorFilter+":", ":")
-		}
-		var processorFilters []string
-		if *fProcessorFilters != "" {
-			processorFilter := strings.TrimSpace(*fProcessorFilters)
-			processorFilters = strings.Split(":"+processorFilter+":", ":")
-		}
-
-		if len(args) > 0 {
-			switch args[0] {
-			case "version":
-				fmt.Printf("Telegraf v%s (git: %s %s)\n", version, branch, commit)
-				return
-			case "config":
-				config.PrintSampleConfig(
-					inputFilters,
-					outputFilters,
-					aggregatorFilters,
-					processorFilters,
-				)
-				return
-			}
-		}
-
-		// switch for flags which just do something and exit immediately
-		switch {
-		case *fOutputList:
-			fmt.Println("Available Output Plugins:")
-			for k, _ := range outputs.Outputs {
-				fmt.Printf("  %s\n", k)
-			}
-			return
-		case *fInputList:
-			fmt.Println("Available Input Plugins:")
-			for k, _ := range inputs.Inputs {
-				fmt.Printf("  %s\n", k)
-			}
-			return
-		case *fVersion:
-			fmt.Printf("Telegraf v%s (git: %s %s)\n", version, branch, commit)
-			return
-		case *fSampleConfig:
-			config.PrintSampleConfig(
-				inputFilters,
-				outputFilters,
-				aggregatorFilters,
-				processorFilters,
-			)
-			return
-		case *fUsage != "":
-			if err := config.PrintInputConfig(*fUsage); err != nil {
-				if err2 := config.PrintOutputConfig(*fUsage); err2 != nil {
-					log.Fatalf("E! %s and %s", err, err2)
-				}
-			}
-			return
-		}
 
 		// If no other options are specified, load the config file and run.
 		c := config.NewConfig()
@@ -237,7 +160,7 @@ func reloadLoop(stop chan struct{}, s service.Service) {
 			if err != nil {
 				log.Fatal("E! " + err.Error())
 			}
-			return
+			os.Exit(0)
 		}
 
 		err = ag.Connect()
@@ -290,14 +213,26 @@ func usageExit(rc int) {
 	os.Exit(rc)
 }
 
+type program struct {
+	inputFilters      []string
+	outputFilters     []string
+	aggregatorFilters []string
+	processorFilters  []string
+}
+
 func (p *program) Start(s service.Service) error {
-	srvc = s
 	go p.run()
 	return nil
 }
 func (p *program) run() {
 	stop = make(chan struct{})
-	reloadLoop(stop, srvc)
+	reloadLoop(
+		stop,
+		p.inputFilters,
+		p.outputFilters,
+		p.aggregatorFilters,
+		p.processorFilters,
+	)
 }
 func (p *program) Stop(s service.Service) error {
 	close(stop)
@@ -307,6 +242,74 @@ func (p *program) Stop(s service.Service) error {
 func main() {
 	flag.Usage = func() { usageExit(0) }
 	flag.Parse()
+	args := flag.Args()
+
+	inputFilters, outputFilters := []string{}, []string{}
+	if *fInputFilters != "" {
+		inputFilters = strings.Split(":"+strings.TrimSpace(*fInputFilters)+":", ":")
+	}
+	if *fOutputFilters != "" {
+		outputFilters = strings.Split(":"+strings.TrimSpace(*fOutputFilters)+":", ":")
+	}
+
+	aggregatorFilters, processorFilters := []string{}, []string{}
+	if *fAggregatorFilters != "" {
+		aggregatorFilters = strings.Split(":"+strings.TrimSpace(*fAggregatorFilters)+":", ":")
+	}
+	if *fProcessorFilters != "" {
+		processorFilters = strings.Split(":"+strings.TrimSpace(*fProcessorFilters)+":", ":")
+	}
+
+	if len(args) > 0 {
+		switch args[0] {
+		case "version":
+			fmt.Printf("Telegraf v%s (git: %s %s)\n", version, branch, commit)
+			return
+		case "config":
+			config.PrintSampleConfig(
+				inputFilters,
+				outputFilters,
+				aggregatorFilters,
+				processorFilters,
+			)
+			return
+		}
+	}
+
+	// switch for flags which just do something and exit immediately
+	switch {
+	case *fOutputList:
+		fmt.Println("Available Output Plugins:")
+		for k, _ := range outputs.Outputs {
+			fmt.Printf("  %s\n", k)
+		}
+		return
+	case *fInputList:
+		fmt.Println("Available Input Plugins:")
+		for k, _ := range inputs.Inputs {
+			fmt.Printf("  %s\n", k)
+		}
+		return
+	case *fVersion:
+		fmt.Printf("Telegraf v%s (git: %s %s)\n", version, branch, commit)
+		return
+	case *fSampleConfig:
+		config.PrintSampleConfig(
+			inputFilters,
+			outputFilters,
+			aggregatorFilters,
+			processorFilters,
+		)
+		return
+	case *fUsage != "":
+		err := config.PrintInputConfig(*fUsage)
+		err2 := config.PrintOutputConfig(*fUsage)
+		if err != nil && err2 != nil {
+			log.Fatalf("E! %s and %s", err, err2)
+		}
+		return
+	}
+
 	if runtime.GOOS == "windows" {
 		svcConfig := &service.Config{
 			Name:        "telegraf",
@@ -316,7 +319,12 @@ func main() {
 			Arguments: []string{"-config", "C:\\Program Files\\Telegraf\\telegraf.conf"},
 		}
 
-		prg := &program{}
+		prg := &program{
+			inputFilters:      inputFilters,
+			outputFilters:     outputFilters,
+			aggregatorFilters: aggregatorFilters,
+			processorFilters:  processorFilters,
+		}
 		s, err := service.New(prg, svcConfig)
 		if err != nil {
 			log.Fatal("E! " + err.Error())
@@ -334,6 +342,7 @@ func main() {
 			if err != nil {
 				log.Fatal("E! " + err.Error())
 			}
+			os.Exit(0)
 		} else {
 			err = s.Run()
 			if err != nil {
@@ -342,6 +351,12 @@ func main() {
 		}
 	} else {
 		stop = make(chan struct{})
-		reloadLoop(stop, nil)
+		reloadLoop(
+			stop,
+			inputFilters,
+			outputFilters,
+			aggregatorFilters,
+			processorFilters,
+		)
 	}
 }
-- 
GitLab