Просмотр исходного кода

Prom error propagation of query

Niko Kovacevic 5 лет назад
Родитель
Сommit
1ad113c3bb
3 измененных файлов с 72 добавлено и 40 удалено
  1. 3 3
      pkg/costmodel/promparsers.go
  2. 5 6
      pkg/prom/query.go
  3. 64 31
      pkg/prom/result.go

+ 3 - 3
pkg/costmodel/promparsers.go

@@ -392,10 +392,10 @@ func getCost(qrs []*prom.QueryResult) (map[string][]*util.Vector, error) {
 // normalization data is empty: time window may be invalid or kube-state-metrics or node-exporter may not be running
 func getNormalization(qrs []*prom.QueryResult) (float64, error) {
 	if len(qrs) == 0 {
-		return 0.0, prom.NoDataErr
+		return 0.0, prom.NoDataErr("getNormalization")
 	}
 	if len(qrs[0].Values) == 0 {
-		return 0.0, prom.NoDataErr
+		return 0.0, prom.NoDataErr("getNormalization")
 	}
 	return qrs[0].Values[0].Value, nil
 }
@@ -404,7 +404,7 @@ func getNormalization(qrs []*prom.QueryResult) (float64, error) {
 // normalization data is empty: time window may be invalid or kube-state-metrics or node-exporter may not be running
 func getNormalizations(qrs []*prom.QueryResult) ([]*util.Vector, error) {
 	if len(qrs) == 0 {
-		return nil, prom.NoDataErr
+		return nil, prom.NoDataErr("getNormalizations")
 	}
 
 	return qrs[0].Values, nil

+ 5 - 6
pkg/prom/query.go

@@ -13,7 +13,6 @@ import (
 	"github.com/kubecost/cost-model/pkg/log"
 	"github.com/kubecost/cost-model/pkg/util"
 	prometheus "github.com/prometheus/client_golang/api"
-	"k8s.io/klog"
 )
 
 const (
@@ -152,20 +151,20 @@ func (ctx *Context) query(query string) (interface{}, error) {
 
 	resp, body, warnings, err := ctx.Client.Do(context.Background(), req)
 	for _, w := range warnings {
-		klog.V(3).Infof("Warning '%s' fetching query '%s'", w, query)
+		log.Warningf("fetching query '%s': %s", query, w)
 	}
 	if err != nil {
 		if resp == nil {
-			return nil, fmt.Errorf("Error %s fetching query %s", err.Error(), query)
+			return nil, fmt.Errorf("query error: '%s' fetching query '%s'", err.Error(), query)
 		}
 
-		return nil, fmt.Errorf("%d Error %s fetching query %s", resp.StatusCode, err.Error(), query)
+		return nil, fmt.Errorf("query error %d: '%s' fetching query '%s'", resp.StatusCode, err.Error(), query)
 	}
 
 	var toReturn interface{}
 	err = json.Unmarshal(body, &toReturn)
 	if err != nil {
-		return nil, fmt.Errorf("Error %s fetching query %s", err.Error(), query)
+		return nil, fmt.Errorf("query error: '%s' fetching query '%s'", err.Error(), query)
 	}
 
 	return toReturn, nil
@@ -243,7 +242,7 @@ func (ctx *Context) queryRange(query string, start, end time.Time, step time.Dur
 
 	resp, body, warnings, err := ctx.Client.Do(context.Background(), req)
 	for _, w := range warnings {
-		klog.V(3).Infof("Warning '%s' fetching query '%s'", w, query)
+		log.Warningf("fetching query '%s': %s", query, w)
 	}
 	if err != nil {
 		if resp == nil {

+ 64 - 31
pkg/prom/result.go

@@ -1,7 +1,6 @@
 package prom
 
 import (
-	"errors"
 	"fmt"
 	"math"
 	"strconv"
@@ -15,22 +14,56 @@ var (
 	// Static Warnings for data point parsing
 	InfWarning warning = newWarning("Found Inf value parsing vector data point for metric")
 	NaNWarning warning = newWarning("Found NaN value parsing vector data point for metric")
-
-	// Static Errors for query result parsing
-	DataFieldFormatErr         error = errors.New("Data field improperly formatted in prometheus repsonse")
-	DataPointFormatErr         error = errors.New("Improperly formatted datapoint from Prometheus")
-	MetricFieldDoesNotExistErr error = errors.New("Metric field does not exist in data result vector")
-	MetricFieldFormatErr       error = errors.New("Metric field is improperly formatted")
-	NoDataErr                  error = errors.New("No data")
-	PromUnexpectedResponseErr  error = errors.New("Unexpected response from Prometheus")
-	QueryResultNilErr          error = NewCommError("nil queryResult")
-	ResultFieldDoesNotExistErr error = errors.New("Result field not does not exist in prometheus response")
-	ResultFieldFormatErr       error = errors.New("Result field improperly formatted in prometheus response")
-	ResultFormatErr            error = errors.New("Result is improperly formatted")
-	ValueFieldDoesNotExistErr  error = errors.New("Value field does not exist in data result vector")
-	ValueFieldFormatErr        error = errors.New("Values field is improperly formatted")
 )
 
+func DataFieldFormatErr(query string) error {
+	return fmt.Errorf("Data field improperly formatted in prometheus repsonse fetching query '%s'", query)
+}
+
+func DataPointFormatErr(query string) error {
+	return fmt.Errorf("Improperly formatted datapoint from Prometheus fetching query '%s'", query)
+}
+
+func MetricFieldDoesNotExistErr(query string) error {
+	return fmt.Errorf("Metric field does not exist in data result vector fetching query '%s'", query)
+}
+
+func MetricFieldFormatErr(query string) error {
+	return fmt.Errorf("Metric field is improperly formatted fetching query '%s'", query)
+}
+
+func NoDataErr(query string) error {
+	return fmt.Errorf("No data fetching query '%s'", query)
+}
+
+func PromUnexpectedResponseErr(query string) error {
+	return fmt.Errorf("Unexpected response from Prometheus fetching query '%s'", query)
+}
+
+func QueryResultNilErr(query string) error {
+	return NewCommError(fmt.Sprintf("nil queryResult fetching query '%s'", query))
+}
+
+func ResultFieldDoesNotExistErr(query string) error {
+	return fmt.Errorf("Result field not does not exist in prometheus response fetching query '%s'", query)
+}
+
+func ResultFieldFormatErr(query string) error {
+	return fmt.Errorf("Result field improperly formatted in prometheus response fetching query '%s'", query)
+}
+
+func ResultFormatErr(query string) error {
+	return fmt.Errorf("Result is improperly formatted fetching query '%s'", query)
+}
+
+func ValueFieldDoesNotExistErr(query string) error {
+	return fmt.Errorf("Value field does not exist in data result vector fetching query '%s'", query)
+}
+
+func ValueFieldFormatErr(query string) error {
+	return fmt.Errorf("Values field is improperly formatted fetching query '%s'", query)
+}
+
 // QueryResultsChan is a channel of query results
 type QueryResultsChan chan *QueryResults
 
@@ -67,13 +100,13 @@ func NewQueryResults(query string, queryResult interface{}) *QueryResults {
 	qrs := &QueryResults{Query: query}
 
 	if queryResult == nil {
-		qrs.Error = QueryResultNilErr
+		qrs.Error = QueryResultNilErr(query)
 		return qrs
 	}
 
 	data, ok := queryResult.(map[string]interface{})["data"]
 	if !ok {
-		e, err := wrapPrometheusError(queryResult)
+		e, err := wrapPrometheusError(query, queryResult)
 		if err != nil {
 			qrs.Error = err
 			return qrs
@@ -85,17 +118,17 @@ func NewQueryResults(query string, queryResult interface{}) *QueryResults {
 	// Deep Check for proper formatting
 	d, ok := data.(map[string]interface{})
 	if !ok {
-		qrs.Error = DataFieldFormatErr
+		qrs.Error = DataFieldFormatErr(query)
 		return qrs
 	}
 	resultData, ok := d["result"]
 	if !ok {
-		qrs.Error = ResultFieldDoesNotExistErr
+		qrs.Error = ResultFieldDoesNotExistErr(query)
 		return qrs
 	}
 	resultsData, ok := resultData.([]interface{})
 	if !ok {
-		qrs.Error = ResultFieldFormatErr
+		qrs.Error = ResultFieldFormatErr(query)
 		return qrs
 	}
 
@@ -106,18 +139,18 @@ func NewQueryResults(query string, queryResult interface{}) *QueryResults {
 	for _, val := range resultsData {
 		resultInterface, ok := val.(map[string]interface{})
 		if !ok {
-			qrs.Error = ResultFormatErr
+			qrs.Error = ResultFormatErr(query)
 			return qrs
 		}
 
 		metricInterface, ok := resultInterface["metric"]
 		if !ok {
-			qrs.Error = MetricFieldDoesNotExistErr
+			qrs.Error = MetricFieldDoesNotExistErr(query)
 			return qrs
 		}
 		metricMap, ok := metricInterface.(map[string]interface{})
 		if !ok {
-			qrs.Error = MetricFieldFormatErr
+			qrs.Error = MetricFieldFormatErr(query)
 			return qrs
 		}
 
@@ -132,12 +165,12 @@ func NewQueryResults(query string, queryResult interface{}) *QueryResults {
 		if !isRange {
 			dataPoint, ok := resultInterface["value"]
 			if !ok {
-				qrs.Error = ValueFieldDoesNotExistErr
+				qrs.Error = ValueFieldDoesNotExistErr(query)
 				return qrs
 			}
 
 			// Append new data point, log warnings
-			v, warn, err := parseDataPoint(dataPoint)
+			v, warn, err := parseDataPoint(query, dataPoint)
 			if err != nil {
 				qrs.Error = err
 				return qrs
@@ -156,7 +189,7 @@ func NewQueryResults(query string, queryResult interface{}) *QueryResults {
 
 			// Append new data points, log warnings
 			for _, value := range values {
-				v, warn, err := parseDataPoint(value)
+				v, warn, err := parseDataPoint(query, value)
 				if err != nil {
 					qrs.Error = err
 					return qrs
@@ -222,12 +255,12 @@ func (qr *QueryResult) GetLabels() map[string]string {
 
 // parseDataPoint parses a data point from raw prometheus query results and returns
 // a new Vector instance containing the parsed data along with any warnings or errors.
-func parseDataPoint(dataPoint interface{}) (*util.Vector, warning, error) {
+func parseDataPoint(query string, dataPoint interface{}) (*util.Vector, warning, error) {
 	var w warning = nil
 
 	value, ok := dataPoint.([]interface{})
 	if !ok || len(value) != 2 {
-		return nil, w, DataPointFormatErr
+		return nil, w, DataPointFormatErr(query)
 	}
 
 	strVal := value[1].(string)
@@ -260,11 +293,11 @@ func labelsForMetric(metricMap map[string]interface{}) string {
 	return fmt.Sprintf("{%s}", strings.Join(pairs, ", "))
 }
 
-func wrapPrometheusError(qr interface{}) (string, error) {
+func wrapPrometheusError(query string, qr interface{}) (string, error) {
 	e, ok := qr.(map[string]interface{})["error"]
 	if !ok {
-		return "", PromUnexpectedResponseErr
+		return "", PromUnexpectedResponseErr(query)
 	}
 	eStr, ok := e.(string)
-	return eStr, nil
+	return fmt.Sprintf("'%s' parsing query '%s'", eStr, query), nil
 }