|
|
@@ -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
|
|
|
}
|