-
Notifications
You must be signed in to change notification settings - Fork 6
/
metrics.go
137 lines (129 loc) · 4.8 KB
/
metrics.go
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package handlers
import (
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
"github.com/kiali/kiali/log"
"github.com/kiali/kiali/models"
"github.com/kiali/kiali/prometheus"
"github.com/kiali/kiali/util"
)
func extractIstioMetricsQueryParams(r *http.Request, q *prometheus.IstioMetricsQuery, namespaceInfo *models.Namespace) error {
q.FillDefaults()
queryParams := r.URL.Query()
if filters, ok := queryParams["filters[]"]; ok && len(filters) > 0 {
q.Filters = filters
}
dir := queryParams.Get("direction")
if dir != "" {
if dir != "inbound" && dir != "outbound" {
return errors.New("bad request, query parameter 'direction' must be either 'inbound' or 'outbound'")
}
q.Direction = dir
}
requestProtocol := queryParams.Get("requestProtocol")
if requestProtocol != "" {
q.RequestProtocol = requestProtocol
}
reporter := queryParams.Get("reporter")
if reporter != "" {
if reporter != "source" && reporter != "destination" {
return errors.New("bad request, query parameter 'reporter' must be either 'source' or 'destination'")
}
q.Reporter = reporter
}
return extractBaseMetricsQueryParams(queryParams, &q.BaseMetricsQuery, namespaceInfo)
}
func extractBaseMetricsQueryParams(queryParams url.Values, q *prometheus.BaseMetricsQuery, namespaceInfo *models.Namespace) error {
if rateIntervals, ok := queryParams["rateInterval"]; ok && len(rateIntervals) > 0 {
// Only first is taken into consideration
q.RateInterval = rateIntervals[0]
}
if rateFuncs, ok := queryParams["rateFunc"]; ok && len(rateFuncs) > 0 {
// Only first is taken into consideration
if rateFuncs[0] != "rate" && rateFuncs[0] != "irate" {
// Bad request
return errors.New("bad request, query parameter 'rateFunc' must be either 'rate' or 'irate'")
}
q.RateFunc = rateFuncs[0]
}
if queryTimes, ok := queryParams["queryTime"]; ok && len(queryTimes) > 0 {
if num, err := strconv.ParseInt(queryTimes[0], 10, 64); err == nil {
q.End = time.Unix(num, 0)
} else {
// Bad request
return errors.New("bad request, cannot parse query parameter 'queryTime'")
}
}
if durations, ok := queryParams["duration"]; ok && len(durations) > 0 {
if num, err := strconv.ParseInt(durations[0], 10, 64); err == nil {
duration := time.Duration(num) * time.Second
q.Start = q.End.Add(-duration)
} else {
// Bad request
return errors.New("bad request, cannot parse query parameter 'duration'")
}
}
if steps, ok := queryParams["step"]; ok && len(steps) > 0 {
if num, err := strconv.Atoi(steps[0]); err == nil {
q.Step = time.Duration(num) * time.Second
} else {
// Bad request
return errors.New("bad request, cannot parse query parameter 'step'")
}
}
if quantiles, ok := queryParams["quantiles[]"]; ok && len(quantiles) > 0 {
for _, quantile := range quantiles {
f, err := strconv.ParseFloat(quantile, 64)
if err != nil {
// Non parseable quantile
return errors.New("bad request, cannot parse query parameter 'quantiles', float expected")
}
if f < 0 || f > 1 {
return errors.New("bad request, invalid quantile(s): should be between 0 and 1")
}
}
q.Quantiles = quantiles
}
if avgFlags, ok := queryParams["avg"]; ok && len(avgFlags) > 0 {
if avgFlag, err := strconv.ParseBool(avgFlags[0]); err == nil {
q.Avg = avgFlag
} else {
// Bad request
return errors.New("bad request, cannot parse query parameter 'avg'")
}
}
if lbls, ok := queryParams["byLabels[]"]; ok && len(lbls) > 0 {
q.ByLabels = lbls
}
// If needed, adjust interval -- Make sure query won't fetch data before the namespace creation
intervalStartTime, err := util.GetStartTimeForRateInterval(q.End, q.RateInterval)
if err != nil {
return err
}
if intervalStartTime.Before(namespaceInfo.CreationTimestamp) {
q.RateInterval = fmt.Sprintf("%ds", int(q.End.Sub(namespaceInfo.CreationTimestamp).Seconds()))
intervalStartTime = namespaceInfo.CreationTimestamp
log.Debugf("[extractMetricsQueryParams] Interval set to: %v", q.RateInterval)
}
// If needed, adjust query start time (bound to namespace creation time)
intervalDuration := q.End.Sub(intervalStartTime)
allowedStart := namespaceInfo.CreationTimestamp.Add(intervalDuration)
if q.Start.Before(allowedStart) {
log.Debugf("[extractMetricsQueryParams] Requested query start time [%v] set to allowed time [%v]", q.Start, allowedStart)
q.Start = allowedStart
if q.Start.After(q.End) {
// This means that the query range does not fall in the range
// of life of the namespace. So, there are no metrics to query.
log.Debugf("[extractMetricsQueryParams] Query end time = %v; not querying metrics.", q.End)
return errors.New("after checks, query start time is after end time")
}
}
// Adjust start & end times to be a multiple of step
stepInSecs := int64(q.Step.Seconds())
q.Start = time.Unix((q.Start.Unix()/stepInSecs)*stepInSecs, 0)
return nil
}