mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
de35cbf251
* feat: add WithTemplate page * app/vmselect/prometheus: enable json mode for expand with expr API * app/vmselect/prometheus: enable CORS and add content type * feat: add api for expand with templates * fix: remove console from useExpandWithExprs * app/vmselect/prometheus: fix escaping * vmui: integrate WITH template * app/vmctl: check content type instead of form param * fix: add content-type for fetch with-exprs * fix: add a header to the server's response that allows the "Content-Type" header * app/vmctl: added comment and cleanup * app/vmctl: use format query param --------- Co-authored-by: dmitryk-dk <kozlovdmitriyy@gmail.com>
442 lines
15 KiB
Go
442 lines
15 KiB
Go
// Code generated by qtc from "expand-with-exprs.qtpl". DO NOT EDIT.
|
|
// See https://github.com/valyala/quicktemplate for details.
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:1
|
|
package prometheus
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:1
|
|
import (
|
|
"fmt"
|
|
"github.com/VictoriaMetrics/metricsql"
|
|
)
|
|
|
|
// ExpandWithExprsResponse returns a webpage, which expands with templates in q MetricsQL.
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
|
|
import (
|
|
qtio422016 "io"
|
|
|
|
qt422016 "github.com/valyala/quicktemplate"
|
|
)
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
|
|
var (
|
|
_ = qtio422016.Copy
|
|
_ = qt422016.AcquireByteBuffer
|
|
)
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
|
|
func StreamExpandWithExprsResponse(qw422016 *qt422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:9
|
|
qw422016.N().S(`<html><head><title>Expand WITH expressions</title><style>p { font-weight: bold }textarea { margin: 1em }</style></head><body><div><form method="get"><div><p><a href="https://docs.victoriametrics.com/MetricsQL.html">MetricsQL</a> query with optional WITH expressions:</p><textarea name="query" style="height: 15em; width: 90%">`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:26
|
|
qw422016.E().S(q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:26
|
|
qw422016.N().S(`</textarea><br/><input type="submit" value="Expand" /><p><a href="https://docs.victoriametrics.com/MetricsQL.html">MetricsQL</a> query after expanding WITH expressions and applying other optimizations:</p><textarea style="height: 5em; width: 90%" readonly="readonly">`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:32
|
|
streamexpandWithExprs(qw422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:32
|
|
qw422016.N().S(`</textarea></div></form></div><div>`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:37
|
|
streamwithExprsTutorial(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:37
|
|
qw422016.N().S(`</div></body></html>`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
func WriteExpandWithExprsResponse(qq422016 qtio422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
StreamExpandWithExprsResponse(qw422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
qt422016.ReleaseWriter(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
func ExpandWithExprsResponse(q string) string {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
qb422016 := qt422016.AcquireByteBuffer()
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
WriteExpandWithExprsResponse(qb422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
qs422016 := string(qb422016.B)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
qt422016.ReleaseByteBuffer(qb422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
return qs422016
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:41
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:43
|
|
func streamexpandWithExprs(qw422016 *qt422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:44
|
|
if len(q) == 0 {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:45
|
|
return
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:46
|
|
}
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:48
|
|
expr, err := metricsql.Parse(q)
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:49
|
|
if err != nil {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:49
|
|
qw422016.N().S(`Cannot parse query:`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:50
|
|
qw422016.E().V(err)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:51
|
|
} else {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:52
|
|
expr = metricsql.Optimize(expr)
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:53
|
|
qw422016.E().Z(expr.AppendString(nil))
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:54
|
|
}
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
func writeexpandWithExprs(qq422016 qtio422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
streamexpandWithExprs(qw422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
qt422016.ReleaseWriter(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
func expandWithExprs(q string) string {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
qb422016 := qt422016.AcquireByteBuffer()
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
writeexpandWithExprs(qb422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
qs422016 := string(qb422016.B)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
qt422016.ReleaseByteBuffer(qb422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
return qs422016
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:55
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:59
|
|
func streamwithExprsTutorial(qw422016 *qt422016.Writer) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:59
|
|
qw422016.N().S(`
|
|
<h3>Tutorial for WITH expressions in <a href="https://docs.victoriametrics.com/MetricsQL.html">MetricsQL</a></h3>
|
|
|
|
<p>
|
|
Let's look at the following real query from <a href="https://grafana.com/grafana/dashboards/1860-node-exporter-full/">Node Exporter Full</a> dashboard:
|
|
</p>
|
|
|
|
<pre>
|
|
(
|
|
(
|
|
node_memory_MemTotal_bytes{instance=~"$node:$port", job=~"$job"}
|
|
-
|
|
node_memory_MemFree_bytes{instance=~"$node:$port", job=~"$job"}
|
|
)
|
|
/
|
|
node_memory_MemTotal_bytes{instance=~"$node:$port", job=~"$job"}
|
|
)
|
|
*
|
|
100
|
|
</pre>
|
|
|
|
<p>
|
|
It is clear the query calculates the percentage of used memory
|
|
for the given $node, $port and $job. Isn't it? :)
|
|
</p>
|
|
|
|
<p>
|
|
What's wrong with this query? Copy-pasted label filters for distinct timeseries
|
|
which makes it easy to mistype these filters during modification.
|
|
Let's simplify the query with WITH expressions:
|
|
</p>
|
|
|
|
<pre>
|
|
WITH (
|
|
commonFilters = {instance=~"$node:$port",job=~"$job"}
|
|
)
|
|
(
|
|
node_memory_MemTotal_bytes{commonFilters}
|
|
-
|
|
node_memory_MemFree_bytes{commonFilters}
|
|
)
|
|
/
|
|
node_memory_MemTotal_bytes{commonFilters} * 100
|
|
</pre>
|
|
|
|
<p>
|
|
Now label filters are located in a single place instead of three distinct places.
|
|
The query mentions node_memory_MemTotal_bytes metric twice and {commonFilters}
|
|
three times. WITH expressions may improve this:
|
|
</p>
|
|
|
|
<pre>
|
|
WITH (
|
|
my_resource_utilization(free, limit, filters) = (limit{filters} - free{filters}) / limit{filters} * 100
|
|
)
|
|
my_resource_utilization(
|
|
node_memory_MemFree_bytes,
|
|
node_memory_MemTotal_bytes,
|
|
{instance=~"$node:$port",job=~"$job"},
|
|
)
|
|
</pre>
|
|
|
|
<p>
|
|
Now the template function my_resource_utilization() may be used for monitoring arbitrary
|
|
resources - memory, CPU, network, storage, you name it.
|
|
</p>
|
|
|
|
<p>
|
|
Let's take another nice query from <a href="https://grafana.com/grafana/dashboards/1860-node-exporter-full/">Node Exporter Full</a> dashboard:
|
|
</p>
|
|
|
|
<pre>
|
|
(
|
|
(
|
|
(
|
|
count(
|
|
count(node_cpu_seconds_total{instance=~"$node:$port",job=~"$job"}) by (cpu)
|
|
)
|
|
)
|
|
-
|
|
avg(
|
|
sum by (mode) (rate(node_cpu_seconds_total{mode='idle',instance=~"$node:$port",job=~"$job"}[5m]))
|
|
)
|
|
)
|
|
*
|
|
100
|
|
)
|
|
/
|
|
count(
|
|
count(node_cpu_seconds_total{instance=~"$node:$port",job=~"$job"}) by (cpu)
|
|
)
|
|
</pre>
|
|
|
|
<p>
|
|
Do you understand what does this mess do? Is it manageable? :) WITH expressions are happy to help in a few iterations.
|
|
<br/>
|
|
<br/>
|
|
1. Extract common filters used in multiple places into a commonFilters variable:
|
|
</p>
|
|
|
|
<pre>
|
|
WITH (
|
|
commonFilters = {instance=~"$node:$port",job=~"$job"}
|
|
)
|
|
(
|
|
(
|
|
(
|
|
count(
|
|
count(node_cpu_seconds_total{commonFilters}) by (cpu)
|
|
)
|
|
)
|
|
-
|
|
avg(
|
|
sum by (mode) (rate(node_cpu_seconds_total{mode='idle',commonFilters}[5m]))
|
|
)
|
|
)
|
|
*
|
|
100
|
|
)
|
|
/
|
|
count(
|
|
count(node_cpu_seconds_total{commonFilters}) by (cpu)
|
|
)
|
|
</pre>
|
|
|
|
<p>
|
|
2. Extract "count(count(...) by (cpu))" into cpuCount variable:
|
|
</p>
|
|
<pre>
|
|
WITH (
|
|
commonFilters = {instance=~"$node:$port",job=~"$job"},
|
|
cpuCount = count(count(node_cpu_seconds_total{commonFilters}) by (cpu))
|
|
)
|
|
(
|
|
(
|
|
cpuCount
|
|
-
|
|
avg(
|
|
sum by (mode) (rate(node_cpu_seconds_total{mode='idle',commonFilters}[5m]))
|
|
)
|
|
)
|
|
*
|
|
100
|
|
) / cpuCount
|
|
</pre>
|
|
|
|
<p>
|
|
3. Extract rate(...) part into cpuIdle variable, since it is clear now that this part calculates the number of idle CPUs:
|
|
</p>
|
|
<pre>
|
|
WITH (
|
|
commonFilters = {instance=~"$node:$port",job=~"$job"},
|
|
cpuCount = count(count(node_cpu_seconds_total{commonFilters}) by (cpu)),
|
|
cpuIdle = sum(rate(node_cpu_seconds_total{mode='idle',commonFilters}[5m]))
|
|
)
|
|
((cpuCount - cpuIdle) * 100) / cpuCount
|
|
</pre>
|
|
|
|
<p>
|
|
4. Put node_cpu_seconds_total{commonFilters} into its own varialbe with the name cpuSeconds:
|
|
</p>
|
|
<pre>
|
|
WITH (
|
|
cpuSeconds = node_cpu_seconds_total{instance=~"$node:$port",job=~"$job"},
|
|
cpuCount = count(count(cpuSeconds) by (cpu)),
|
|
cpuIdle = sum(rate(cpuSeconds{mode='idle'}[5m]))
|
|
)
|
|
((cpuCount - cpuIdle) * 100) / cpuCount
|
|
</pre>
|
|
|
|
<p>
|
|
Now the query became more clear comparing to the initial query.
|
|
</p>
|
|
|
|
<p>
|
|
WITH expressions may be nested and may be put anywhere. Try expanding the following query:
|
|
</p>
|
|
|
|
<pre>
|
|
WITH (
|
|
f(a, b) = WITH (
|
|
f1(x) = b-x,
|
|
f2(x) = x+x
|
|
) f1(a)*f2(b)
|
|
) f(foo, with(x=bar) x)
|
|
</pre>
|
|
|
|
`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
func writewithExprsTutorial(qq422016 qtio422016.Writer) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
streamwithExprsTutorial(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
qt422016.ReleaseWriter(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
func withExprsTutorial() string {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
qb422016 := qt422016.AcquireByteBuffer()
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
writewithExprsTutorial(qb422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
qs422016 := string(qb422016.B)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
qt422016.ReleaseByteBuffer(qb422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
return qs422016
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:246
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:249
|
|
func StreamExpandWithExprsJSONResponse(qw422016 *qt422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:250
|
|
streamexpandWithExprsJSON(qw422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
func WriteExpandWithExprsJSONResponse(qq422016 qtio422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
StreamExpandWithExprsJSONResponse(qw422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
qt422016.ReleaseWriter(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
func ExpandWithExprsJSONResponse(q string) string {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
qb422016 := qt422016.AcquireByteBuffer()
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
WriteExpandWithExprsJSONResponse(qb422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
qs422016 := string(qb422016.B)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
qt422016.ReleaseByteBuffer(qb422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
return qs422016
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:251
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:253
|
|
func streamexpandWithExprsJSON(qw422016 *qt422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:254
|
|
if len(q) == 0 {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:254
|
|
qw422016.N().S(`{"status": "error","error": "query string cannot be empty"}`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:259
|
|
return
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:260
|
|
}
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:260
|
|
qw422016.N().S(`{`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:263
|
|
expr, err := metricsql.Parse(q)
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:264
|
|
if err != nil {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:264
|
|
qw422016.N().S(`"status": "error","error":`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:266
|
|
qw422016.N().Q(fmt.Sprintf("Cannot parse query: %s", err))
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:267
|
|
} else {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:268
|
|
expr = metricsql.Optimize(expr)
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:268
|
|
qw422016.N().S(`"status": "success","expr":`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:270
|
|
qw422016.N().Q(string(expr.AppendString(nil)))
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:271
|
|
}
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:271
|
|
qw422016.N().S(`}`)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
func writeexpandWithExprsJSON(qq422016 qtio422016.Writer, q string) {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
streamexpandWithExprsJSON(qw422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
qt422016.ReleaseWriter(qw422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
}
|
|
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
func expandWithExprsJSON(q string) string {
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
qb422016 := qt422016.AcquireByteBuffer()
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
writeexpandWithExprsJSON(qb422016, q)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
qs422016 := string(qb422016.B)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
qt422016.ReleaseByteBuffer(qb422016)
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
return qs422016
|
|
//line app/vmselect/prometheus/expand-with-exprs.qtpl:273
|
|
}
|