-
Notifications
You must be signed in to change notification settings - Fork 743
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use go templates to render the builtin promql queries
- Loading branch information
1 parent
c91a128
commit f211e0f
Showing
7 changed files
with
297 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package metrics | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"strconv" | ||
) | ||
|
||
const envoySuccessRateQuery = ` | ||
sum(rate( | ||
envoy_cluster_upstream_rq{kubernetes_namespace="{{ .Namespace }}", | ||
kubernetes_pod_name=~"{{ .Name }}-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)", | ||
envoy_response_code!~"5.*"} | ||
[{{ .Interval }}])) | ||
/ | ||
sum(rate( | ||
envoy_cluster_upstream_rq{kubernetes_namespace="{{ .Namespace }}", | ||
kubernetes_pod_name=~"{{ .Name }}-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)"} | ||
[{{ .Interval }}])) | ||
* 100 | ||
` | ||
|
||
func (c *Observer) GetEnvoySuccessRate(name string, namespace string, metric string, interval string) (float64, error) { | ||
if c.metricsServer == "fake" { | ||
return 100, nil | ||
} | ||
|
||
meta := struct { | ||
Name string | ||
Namespace string | ||
Interval string | ||
}{ | ||
name, | ||
namespace, | ||
interval, | ||
} | ||
|
||
query, err := render(meta, envoySuccessRateQuery) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
var rate *float64 | ||
querySt := url.QueryEscape(query) | ||
result, err := c.queryMetric(querySt) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
for _, v := range result.Data.Result { | ||
metricValue := v.Value[1] | ||
switch metricValue.(type) { | ||
case string: | ||
f, err := strconv.ParseFloat(metricValue.(string), 64) | ||
if err != nil { | ||
return 0, err | ||
} | ||
rate = &f | ||
} | ||
} | ||
if rate == nil { | ||
return 0, fmt.Errorf("no values found for metric %s", metric) | ||
} | ||
return *rate, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package metrics | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func Test_EnvoySuccessRateQueryRender(t *testing.T) { | ||
meta := struct { | ||
Name string | ||
Namespace string | ||
Interval string | ||
}{ | ||
"podinfo", | ||
"default", | ||
"1m", | ||
} | ||
|
||
query, err := render(meta, envoySuccessRateQuery) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := `sum(rate(envoy_cluster_upstream_rq{kubernetes_namespace="default",kubernetes_pod_name=~"podinfo-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)",envoy_response_code!~"5.*"}[1m])) / sum(rate(envoy_cluster_upstream_rq{kubernetes_namespace="default",kubernetes_pod_name=~"podinfo-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)"}[1m])) * 100` | ||
|
||
if query != expected { | ||
t.Errorf("\nGot %s \nWanted %s", query, expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package metrics | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"strconv" | ||
"time" | ||
) | ||
|
||
const istioSuccessRateQuery = ` | ||
sum(rate( | ||
istio_requests_total{reporter="destination", | ||
destination_workload_namespace="{{ .Namespace }}", | ||
destination_workload=~"{{ .Name }}", | ||
response_code!~"5.*"} | ||
[{{ .Interval }}])) | ||
/ | ||
sum(rate( | ||
istio_requests_total{reporter="destination", | ||
destination_workload_namespace="{{ .Namespace }}", | ||
destination_workload=~"{{ .Name }}"} | ||
[{{ .Interval }}])) | ||
* 100 | ||
` | ||
|
||
// GetIstioSuccessRate returns the requests success rate (non 5xx) using istio_requests_total metric | ||
func (c *Observer) GetIstioSuccessRate(name string, namespace string, metric string, interval string) (float64, error) { | ||
if c.metricsServer == "fake" { | ||
return 100, nil | ||
} | ||
|
||
meta := struct { | ||
Name string | ||
Namespace string | ||
Interval string | ||
}{ | ||
name, | ||
namespace, | ||
interval, | ||
} | ||
|
||
query, err := render(meta, istioSuccessRateQuery) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
var rate *float64 | ||
querySt := url.QueryEscape(query) | ||
result, err := c.queryMetric(querySt) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
for _, v := range result.Data.Result { | ||
metricValue := v.Value[1] | ||
switch metricValue.(type) { | ||
case string: | ||
f, err := strconv.ParseFloat(metricValue.(string), 64) | ||
if err != nil { | ||
return 0, err | ||
} | ||
rate = &f | ||
} | ||
} | ||
if rate == nil { | ||
return 0, fmt.Errorf("no values found for metric %s", metric) | ||
} | ||
return *rate, nil | ||
} | ||
|
||
const istioRequestDurationQuery = ` | ||
histogram_quantile(0.99, sum(rate( | ||
istio_request_duration_seconds_bucket{reporter="destination", | ||
destination_workload_namespace="{{ .Namespace }}", | ||
destination_workload=~"{{ .Name }}"} | ||
[{{ .Interval }}])) by (le)) | ||
` | ||
|
||
// GetIstioRequestDuration returns the 99P requests delay using istio_request_duration_seconds_bucket metrics | ||
func (c *Observer) GetIstioRequestDuration(name string, namespace string, metric string, interval string) (time.Duration, error) { | ||
if c.metricsServer == "fake" { | ||
return 1, nil | ||
} | ||
|
||
meta := struct { | ||
Name string | ||
Namespace string | ||
Interval string | ||
}{ | ||
name, | ||
namespace, | ||
interval, | ||
} | ||
|
||
query, err := render(meta, istioRequestDurationQuery) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
var rate *float64 | ||
querySt := url.QueryEscape(query) | ||
result, err := c.queryMetric(querySt) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
for _, v := range result.Data.Result { | ||
metricValue := v.Value[1] | ||
switch metricValue.(type) { | ||
case string: | ||
f, err := strconv.ParseFloat(metricValue.(string), 64) | ||
if err != nil { | ||
return 0, err | ||
} | ||
rate = &f | ||
} | ||
} | ||
if rate == nil { | ||
return 0, fmt.Errorf("no values found for metric %s", metric) | ||
} | ||
ms := time.Duration(int64(*rate*1000)) * time.Millisecond | ||
return ms, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package metrics | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func Test_IstioSuccessRateQueryRender(t *testing.T) { | ||
meta := struct { | ||
Name string | ||
Namespace string | ||
Interval string | ||
}{ | ||
"podinfo", | ||
"default", | ||
"1m", | ||
} | ||
|
||
query, err := render(meta, istioSuccessRateQuery) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := `sum(rate(istio_requests_total{reporter="destination",destination_workload_namespace="default",destination_workload=~"podinfo",response_code!~"5.*"}[1m])) / sum(rate(istio_requests_total{reporter="destination",destination_workload_namespace="default",destination_workload=~"podinfo"}[1m])) * 100` | ||
|
||
if query != expected { | ||
t.Errorf("\nGot %s \nWanted %s", query, expected) | ||
} | ||
} | ||
|
||
func Test_IstioRequestDurationQueryRender(t *testing.T) { | ||
meta := struct { | ||
Name string | ||
Namespace string | ||
Interval string | ||
}{ | ||
"podinfo", | ||
"default", | ||
"1m", | ||
} | ||
|
||
query, err := render(meta, istioRequestDurationQuery) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expected := `histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter="destination",destination_workload_namespace="default",destination_workload=~"podinfo"}[1m])) by (le))` | ||
|
||
if query != expected { | ||
t.Errorf("\nGot %s \nWanted %s", query, expected) | ||
} | ||
} |
Oops, something went wrong.