mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmui: show query execution duration in the header of query input field
This should simplify the process of query optimization
This commit is contained in:
parent
4fafdda13e
commit
6a98f9df54
13 changed files with 103 additions and 73 deletions
|
@ -30,7 +30,8 @@ See https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries
|
|||
]
|
||||
},
|
||||
"stats":{
|
||||
"seriesFetched": "{%d qs.SeriesFetched %}"
|
||||
"seriesFetched": {%dl qs.SeriesFetched %},
|
||||
"executionTimeMsec": {%dl qs.ExecutionTimeMsec %}
|
||||
}
|
||||
{% code
|
||||
qt.Printf("generate /api/v1/query_range response for series=%d, points=%d", seriesCount, pointsCount)
|
||||
|
|
|
@ -72,85 +72,89 @@ func StreamQueryRangeResponse(qw422016 *qt422016.Writer, isPartial bool, rs []ne
|
|||
//line app/vmselect/prometheus/query_range_response.qtpl:29
|
||||
}
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:29
|
||||
qw422016.N().S(`]},"stats":{"seriesFetched": "`)
|
||||
qw422016.N().S(`]},"stats":{"seriesFetched":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:33
|
||||
qw422016.N().D(qs.SeriesFetched)
|
||||
qw422016.N().DL(qs.SeriesFetched)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:33
|
||||
qw422016.N().S(`"}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:36
|
||||
qw422016.N().S(`,"executionTimeMsec":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:34
|
||||
qw422016.N().DL(qs.ExecutionTimeMsec)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:34
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:37
|
||||
qt.Printf("generate /api/v1/query_range response for series=%d, points=%d", seriesCount, pointsCount)
|
||||
qtDone()
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:39
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:40
|
||||
streamdumpQueryTrace(qw422016, qt)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:39
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:40
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
func WriteQueryRangeResponse(qq422016 qtio422016.Writer, isPartial bool, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
StreamQueryRangeResponse(qw422016, isPartial, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
func QueryRangeResponse(isPartial bool, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) string {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
WriteQueryRangeResponse(qb422016, isPartial, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
qs422016 := string(qb422016.B)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
return qs422016
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:42
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:44
|
||||
func streamqueryRangeLine(qw422016 *qt422016.Writer, r *netstorage.Result) {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:44
|
||||
qw422016.N().S(`{"metric":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:46
|
||||
streammetricNameObject(qw422016, &r.MetricName)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:45
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:46
|
||||
qw422016.N().S(`,"values":`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:46
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:47
|
||||
streamvaluesWithTimestamps(qw422016, r.Values, r.Timestamps)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:46
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:47
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
func writequeryRangeLine(qq422016 qtio422016.Writer, r *netstorage.Result) {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
streamqueryRangeLine(qw422016, r)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
func queryRangeLine(r *netstorage.Result) string {
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
writequeryRangeLine(qb422016, r)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qs422016 := string(qb422016.B)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
return qs422016
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:48
|
||||
//line app/vmselect/prometheus/query_range_response.qtpl:49
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ See https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
|
|||
]
|
||||
},
|
||||
"stats":{
|
||||
"seriesFetched": "{%d qs.SeriesFetched %}"
|
||||
"seriesFetched": {%dl qs.SeriesFetched %},
|
||||
"executionTimeMsec": {%dl qs.ExecutionTimeMsec %}
|
||||
}
|
||||
{% code
|
||||
qt.Printf("generate /api/v1/query response for series=%d", seriesCount)
|
||||
|
|
|
@ -82,44 +82,48 @@ func StreamQueryResponse(qw422016 *qt422016.Writer, isPartial bool, rs []netstor
|
|||
//line app/vmselect/prometheus/query_response.qtpl:31
|
||||
}
|
||||
//line app/vmselect/prometheus/query_response.qtpl:31
|
||||
qw422016.N().S(`]},"stats":{"seriesFetched": "`)
|
||||
qw422016.N().S(`]},"stats":{"seriesFetched":`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:35
|
||||
qw422016.N().D(qs.SeriesFetched)
|
||||
qw422016.N().DL(qs.SeriesFetched)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:35
|
||||
qw422016.N().S(`"}`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:38
|
||||
qw422016.N().S(`,"executionTimeMsec":`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:36
|
||||
qw422016.N().DL(qs.ExecutionTimeMsec)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:36
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:39
|
||||
qt.Printf("generate /api/v1/query response for series=%d", seriesCount)
|
||||
qtDone()
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_response.qtpl:42
|
||||
streamdumpQueryTrace(qw422016, qt)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:41
|
||||
//line app/vmselect/prometheus/query_response.qtpl:42
|
||||
qw422016.N().S(`}`)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
func WriteQueryResponse(qq422016 qtio422016.Writer, isPartial bool, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) {
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
StreamQueryResponse(qw422016, isPartial, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
}
|
||||
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
func QueryResponse(isPartial bool, rs []netstorage.Result, qt *querytracer.Tracer, qtDone func(), qs *promql.QueryStats) string {
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
WriteQueryResponse(qb422016, isPartial, rs, qt, qtDone, qs)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
qs422016 := string(qb422016.B)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
return qs422016
|
||||
//line app/vmselect/prometheus/query_response.qtpl:43
|
||||
//line app/vmselect/prometheus/query_response.qtpl:44
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage"
|
||||
|
@ -144,8 +145,7 @@ type EvalConfig struct {
|
|||
|
||||
// QueryStats contains various stats for the currently executed query.
|
||||
//
|
||||
// The caller must initialize the QueryStats if it needs the stats.
|
||||
// Otherwise the stats isn't collected.
|
||||
// The caller must initialize QueryStats, otherwise it isn't collected.
|
||||
QueryStats *QueryStats
|
||||
|
||||
timestamps []int64
|
||||
|
@ -178,13 +178,24 @@ func copyEvalConfig(src *EvalConfig) *EvalConfig {
|
|||
// QueryStats contains various stats for the query.
|
||||
type QueryStats struct {
|
||||
// SeriesFetched contains the number of series fetched from storage during the query evaluation.
|
||||
SeriesFetched int
|
||||
SeriesFetched int64
|
||||
// ExecutionTimeMsec contains the number of milliseconds the query took to execute.
|
||||
ExecutionTimeMsec int64
|
||||
}
|
||||
|
||||
func (qs *QueryStats) addSeriesFetched(n int) {
|
||||
if qs != nil {
|
||||
qs.SeriesFetched += n
|
||||
if qs == nil {
|
||||
return
|
||||
}
|
||||
atomic.AddInt64(&qs.SeriesFetched, int64(n))
|
||||
}
|
||||
|
||||
func (qs *QueryStats) addExecutionTimeMsec(startTime time.Time) {
|
||||
if qs == nil {
|
||||
return
|
||||
}
|
||||
d := time.Since(startTime).Milliseconds()
|
||||
atomic.AddInt64(&qs.ExecutionTimeMsec, d)
|
||||
}
|
||||
|
||||
func (ec *EvalConfig) updateIsPartialResponse(isPartialResponse bool) {
|
||||
|
|
|
@ -49,7 +49,10 @@ func Exec(qt *querytracer.Tracer, ec *EvalConfig, q string, isFirstPointOnly boo
|
|||
if querystats.Enabled() {
|
||||
startTime := time.Now()
|
||||
ac := ec.AuthToken
|
||||
defer querystats.RegisterQuery(ac.AccountID, ac.ProjectID, q, ec.End-ec.Start, startTime)
|
||||
defer func() {
|
||||
querystats.RegisterQuery(ac.AccountID, ac.ProjectID, q, ec.End-ec.Start, startTime)
|
||||
ec.QueryStats.addExecutionTimeMsec(startTime)
|
||||
}()
|
||||
}
|
||||
|
||||
ec.validate()
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.b863450b.css",
|
||||
"main.js": "./static/js/main.19e7f129.js",
|
||||
"main.js": "./static/js/main.0c55974f.js",
|
||||
"static/js/522.da77e7b3.chunk.js": "./static/js/522.da77e7b3.chunk.js",
|
||||
"static/media/MetricsQL.md": "./static/media/MetricsQL.8644fd7c964802dd34a9.md",
|
||||
"index.html": "./index.html"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.b863450b.css",
|
||||
"static/js/main.19e7f129.js"
|
||||
"static/js/main.0c55974f.js"
|
||||
]
|
||||
}
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=5"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.19e7f129.js"></script><link href="./static/css/main.b863450b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=5"/><meta name="theme-color" content="#000000"/><meta name="description" content="UI for VictoriaMetrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><script src="./dashboards/index.js" type="module"></script><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="./preview.jpg"><meta name="twitter:title" content="UI for VictoriaMetrics"><meta name="twitter:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta name="twitter:site" content="@VictoriaMetrics"><meta property="og:title" content="Metric explorer for VictoriaMetrics"><meta property="og:description" content="Explore and troubleshoot your VictoriaMetrics data"><meta property="og:image" content="./preview.jpg"><meta property="og:type" content="website"><script defer="defer" src="./static/js/main.0c55974f.js"></script><link href="./static/css/main.b863450b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
|
@ -22,7 +22,8 @@ export interface TracingData {
|
|||
}
|
||||
|
||||
export interface QueryStats {
|
||||
seriesFetched?: string;
|
||||
seriesFetched?: number;
|
||||
executionTimeMsec?: number;
|
||||
resultLength?: number;
|
||||
isPartial?: boolean;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
|||
|
||||
const warning = [
|
||||
{
|
||||
show: stats?.seriesFetched === "0" && !stats.resultLength,
|
||||
show: stats?.seriesFetched == 0 && !stats.resultLength,
|
||||
text: seriesFetchedWarning
|
||||
},
|
||||
{
|
||||
|
@ -50,6 +50,10 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
|||
}
|
||||
].filter((w) => w.show).map(w => w.text).join("");
|
||||
|
||||
if (stats) {
|
||||
label = `${label} (${stats.executionTimeMsec || 0}ms)`;
|
||||
}
|
||||
|
||||
const handleSelect = (val: string) => {
|
||||
onChange(val);
|
||||
};
|
||||
|
|
|
@ -62,8 +62,9 @@ The sandbox cluster installation is running under the constant load generated by
|
|||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add support for functions, labels, values in autocomplete. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3006).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): retain specified time interval when executing a query from `Top Queries`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5097).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): improve repeated VMUI page load times by enabling caching of static js and css at web browser side according to [these recommendations](https://developer.chrome.com/docs/lighthouse/performance/uses-long-cache-ttl/).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): show information about lines with bigger values at the top of the legend under the graph in order to simplify graph analysis.
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): sort legend under the graph in descending order of median values. This should simplify graph analysis, since usually the most important lines have bigger values.
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): reduce vertical space usage, so more information is visible on the screen without scrolling.
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): show query execution duration in the header of query input field. This should help optimizing query performance.
|
||||
* FEATURE: support `Strict-Transport-Security`, `Content-Security-Policy` and `X-Frame-Options` HTTP response headers in the all VictoriaMetrics components. The values for headers can be specified via the following command-line flags: `-http.header.hsts`, `-http.header.csp` and `-http.header.frameOptions`.
|
||||
* FEATURE: [vmalert-tool](https://docs.victoriametrics.com/#vmalert-tool): add `unittest` command to run unittest for alerting and recording rules. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4789) for details.
|
||||
* FEATURE: dashboards/vmalert: add new panel `Missed evaluations` for indicating alerting groups that miss their evaluations.
|
||||
|
|
Loading…
Reference in a new issue