// 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/">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/">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:57 func StreamExpandWithExprsJSONResponse(qw422016 *qt422016.Writer, q string) { //line app/vmselect/prometheus/expand-with-exprs.qtpl:58 if len(q) == 0 { //line app/vmselect/prometheus/expand-with-exprs.qtpl:58 qw422016.N().S(`{"status": "error","error": "query string cannot be empty"}`) //line app/vmselect/prometheus/expand-with-exprs.qtpl:63 return //line app/vmselect/prometheus/expand-with-exprs.qtpl:64 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:64 qw422016.N().S(`{`) //line app/vmselect/prometheus/expand-with-exprs.qtpl:67 expr, err := metricsql.Parse(q) //line app/vmselect/prometheus/expand-with-exprs.qtpl:68 if err != nil { //line app/vmselect/prometheus/expand-with-exprs.qtpl:68 qw422016.N().S(`"status": "error","error":`) //line app/vmselect/prometheus/expand-with-exprs.qtpl:70 qw422016.N().Q(fmt.Sprintf("Cannot parse query: %s", err)) //line app/vmselect/prometheus/expand-with-exprs.qtpl:71 } else { //line app/vmselect/prometheus/expand-with-exprs.qtpl:72 expr = metricsql.Optimize(expr) //line app/vmselect/prometheus/expand-with-exprs.qtpl:72 qw422016.N().S(`"status": "success","expr":`) //line app/vmselect/prometheus/expand-with-exprs.qtpl:74 qw422016.N().QZ(expr.AppendString(nil)) //line app/vmselect/prometheus/expand-with-exprs.qtpl:75 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:75 qw422016.N().S(`}`) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 func WriteExpandWithExprsJSONResponse(qq422016 qtio422016.Writer, q string) { //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 qw422016 := qt422016.AcquireWriter(qq422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 StreamExpandWithExprsJSONResponse(qw422016, q) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 qt422016.ReleaseWriter(qw422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 func ExpandWithExprsJSONResponse(q string) string { //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 qb422016 := qt422016.AcquireByteBuffer() //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 WriteExpandWithExprsJSONResponse(qb422016, q) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 qs422016 := string(qb422016.B) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 qt422016.ReleaseByteBuffer(qb422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 return qs422016 //line app/vmselect/prometheus/expand-with-exprs.qtpl:77 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:81 func streamwithExprsTutorial(qw422016 *qt422016.Writer) { //line app/vmselect/prometheus/expand-with-exprs.qtpl:81 qw422016.N().S(` <h3>Tutorial for WITH expressions in <a href="https://docs.victoriametrics.com/metricsql/">MetricsQL</a></h3> <p> Let's look at the following real query from <a href="https://grafana.com/grafana/dashboards/1860">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</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:268 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 func writewithExprsTutorial(qq422016 qtio422016.Writer) { //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 qw422016 := qt422016.AcquireWriter(qq422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 streamwithExprsTutorial(qw422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 qt422016.ReleaseWriter(qw422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 } //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 func withExprsTutorial() string { //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 qb422016 := qt422016.AcquireByteBuffer() //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 writewithExprsTutorial(qb422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 qs422016 := string(qb422016.B) //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 qt422016.ReleaseByteBuffer(qb422016) //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 return qs422016 //line app/vmselect/prometheus/expand-with-exprs.qtpl:268 }