From 51fd83f1bebb7c302d0b1d87209f77d8acf93eb9 Mon Sep 17 00:00:00 2001
From: Jan Grewe <jan.grewe@flixbus.com>
Date: Wed, 6 Jun 2018 19:22:55 +0200
Subject: [PATCH] Catch and log API errors, always output 'nexenta_up'

---
 main.go | 57 ++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 25 deletions(-)

diff --git a/main.go b/main.go
index 1812e2a..17abf73 100644
--- a/main.go
+++ b/main.go
@@ -49,6 +49,8 @@ type Exporter struct {
 	mutex  sync.Mutex
 	client *http.Client
 
+	apiReachable float64
+
 	up             *prometheus.Desc
 	scrapeFailures  prometheus.Counter
 	volumeOnline   *prometheus.Desc
@@ -90,10 +92,14 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
 func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
 	e.mutex.Lock() // To protect metrics from concurrent collects.
 	defer e.mutex.Unlock()
+	e.apiReachable = 0
 	err := e.collect(ch)
 	if err != nil {
-		log.Errorf("Collect(): %v", err)
+		log.Errorf("%v", err)
 	}
+
+	ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, e.apiReachable)
+
 	return
 }
 
@@ -101,32 +107,27 @@ func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
 
 	volumes, err := e.getVolumes(ch)
 	if err != nil {
-		log.Errorf("getVolumes(): %v", err)
+		err = fmt.Errorf("getVolumes(): %v", err)
 	}
 
 	if len(volumes) > 0 {
 		for _, volume := range volumes {
-			err := e.getVolumeStatus(ch, volume)
+			err = e.getVolumeStatus(ch, volume)
 			if err != nil {
-				log.Errorf("getVolumeStatus(): %v", err)
+				err = fmt.Errorf("getVolumeStatus(): %v", err)
 			}
 		}
 	}
 
-	if err != nil {
-		ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 0)
-		return fmt.Errorf("Error scraping Nexenta API: %v", err)
-	}
-	ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 1)
-
 	return err
 }
 
 func (e *Exporter) getVolumes(ch chan<- prometheus.Metric) ([]string, error) {
 
 	var reqJson = []byte(`{"object": "volume", "params": [""], "method": "get_names"}`)
+
 	apiResponse, err := e.queryApi(ch, reqJson); if err != nil { return nil, err }
-	apiResult, err := json.Marshal(apiResponse.Result)
+	apiResult, err := json.Marshal(apiResponse.Result); if err != nil { return nil, err }
 
 	var volumes []string
 	err = json.Unmarshal([]byte(apiResult), &volumes)
@@ -138,18 +139,17 @@ func (e *Exporter) getVolumeStatus(ch chan<- prometheus.Metric, volume string) e
 
 	var reqJson = []byte(`{"object": "volume", "params": ["` + volume + `"], "method": "get_status"}`)
 	apiResponse, err := e.queryApi(ch, reqJson); if err != nil { return err }
+	apiResult, err := json.Marshal(apiResponse.Result); if err != nil { return err }
 
-	apiResult, err := json.Marshal(apiResponse.Result)
-
-	var result= new(ResultObject)
-	err = json.Unmarshal(apiResult, &result)
+	var result = new(ResultObject)
+	err = json.Unmarshal(apiResult, &result); if err != nil { return err }
 
 	var volumeOnline float64 = 0
 	if len(result.State) > 0 {
 		if result.State[0] == "ONLINE" { volumeOnline = 1 }
 	}
 
-	ch <- prometheus.MustNewConstMetric(e.volumeOnline, prometheus.GaugeValue, volumeOnline, "data")
+	ch <- prometheus.MustNewConstMetric(e.volumeOnline, prometheus.GaugeValue, volumeOnline, volume)
 
 	return err
 }
@@ -157,31 +157,38 @@ func (e *Exporter) getVolumeStatus(ch chan<- prometheus.Metric, volume string) e
 func (e *Exporter) queryApi(ch chan<- prometheus.Metric, reqJson []byte) (*ApiResponse, error) {
 
 	resp, err := e.client.Post(e.URI, "application/json", bytes.NewBuffer(reqJson))
+	if err != nil {
+		return nil, fmt.Errorf("Error scraping Nexenta API: %v", err)
+	}
+
+	e.apiReachable = 1
 
 	data, err := ioutil.ReadAll(resp.Body)
 	resp.Body.Close()
 	if resp.StatusCode != 200 {
 		if err != nil {
 			data = []byte(err.Error())
-			log.Errorf("Error scraping Nexenta API: %s", err)
-			e.scrapeFailures.Inc()
-			e.scrapeFailures.Collect(ch)
 		}
-		return nil, fmt.Errorf("Status %s (%d)", resp.Status, resp.StatusCode)
+		e.scrapeFailures.Inc()
+		e.scrapeFailures.Collect(ch)
+		return nil, fmt.Errorf("Status %s (%d) %s", resp.Status, resp.StatusCode, data)
 	}
 
 	//log.Infof("response: %s", data)
 
 	var apiResponse = new(ApiResponse)
-	err_json := json.Unmarshal(data, &apiResponse)
-	if err_json != nil {
-		log.Infof("whoops:", err_json)
-	}
+	err = json.Unmarshal(data, &apiResponse); if err != nil { return nil, err }
 
 	if apiResponse.Result == nil {
 		e.scrapeFailures.Inc()
 		e.scrapeFailures.Collect(ch)
-		return nil, fmt.Errorf("Field 'result' in API response is null")
+		return nil, fmt.Errorf("Field 'result' in API response is null, API Error: %v", apiResponse.Error)
+	}
+
+	if apiResponse.Error != nil {
+		e.scrapeFailures.Inc()
+		e.scrapeFailures.Collect(ch)
+		return nil, fmt.Errorf("API Error: %v", apiResponse.Error)
 	}
 
 	return apiResponse, nil
-- 
GitLab