forked from chop-dbhi/prometheus-sql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathset.go
More file actions
121 lines (104 loc) · 2.92 KB
/
set.go
File metadata and controls
121 lines (104 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"encoding/json"
"errors"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"strconv"
"strings"
)
type QueryResult struct {
Query *Query
Result map[string]prometheus.Gauge // Internally we represent each facet with a JSON-encoded string for simplicity
}
// NewSetMetrics initializes a new metrics collector.
func NewQueryResult(q *Query) *QueryResult {
r := &QueryResult{
Query: q,
Result: make(map[string]prometheus.Gauge),
}
return r
}
func (r *QueryResult) registerMetric(facets map[string]interface{}) string {
labels := prometheus.Labels{}
jsonData, _ := json.Marshal(facets)
resultKey := string(jsonData)
for k, v := range facets {
labels[k] = strings.ToLower(fmt.Sprintf("%v", v))
}
if _, ok := r.Result[resultKey]; ok { // A metric with this name is already registered
return resultKey
}
fmt.Println("Registering metric", r.Query.Name, "with facets", resultKey)
r.Result[resultKey] = prometheus.NewGauge(prometheus.GaugeOpts{
Name: fmt.Sprintf("query_result_%s", r.Query.Name),
Help: "Result of an SQL query",
ConstLabels: labels,
})
prometheus.MustRegister(r.Result[resultKey])
return resultKey
}
type record map[string]interface{}
type records []record
func setValueForResult(r prometheus.Gauge, v interface{}) error {
switch t := v.(type) {
case string:
f, err := strconv.ParseFloat(t, 64)
if err != nil {
return err
}
r.Set(f)
case int:
r.Set(float64(t))
case float64:
r.Set(t)
default:
return fmt.Errorf("Unhandled type %s", t)
}
return nil
}
func (r *QueryResult) SetMetrics(recs records) (map[string]bool, error) {
// Queries that return only one record should only have one column
if len(recs) > 1 && len(recs[0]) == 1 {
return nil, errors.New("There is more than one row in the query result - with a single column")
}
facetsWithResult := make(map[string]bool, 0)
for _, row := range recs {
facet := make(map[string]interface{})
var (
dataVal interface{}
dataFound bool
)
if len(row) > 1 && r.Query.DataField == "" {
return nil, errors.New("Data field not specified for multi-column query")
}
for k, v := range row {
if len(row) > 1 && strings.ToLower(k) != r.Query.DataField { // facet field, add to facets
facet[strings.ToLower(fmt.Sprintf("%v", k))] = v
} else { // this is the actual gauge data
dataVal = v
dataFound = true
}
}
if !dataFound {
return nil, errors.New("Data field not found in result set")
}
key := r.registerMetric(facet)
err := setValueForResult(r.Result[key], dataVal)
if err != nil {
return nil, err
}
facetsWithResult[key] = true
}
return facetsWithResult, nil
}
func (r *QueryResult) RemoveMissingMetrics(facetsWithResult map[string]bool) {
for key, m := range r.Result {
if _, ok := facetsWithResult[key]; ok {
continue
}
fmt.Println("Unregistering metric", r.Query.Name, "with facets", key)
prometheus.Unregister(m)
delete(r.Result, key)
}
}