2021-09-07 21:39:22 +02:00
|
|
|
{% package main %}
|
|
|
|
|
|
|
|
{% import (
|
|
|
|
"time"
|
|
|
|
"sort"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/tpl"
|
|
|
|
) %}
|
|
|
|
|
|
|
|
|
2021-09-21 13:41:01 +02:00
|
|
|
{% func Welcome() %}
|
2021-09-07 21:39:22 +02:00
|
|
|
{%= tpl.Header("vmalert", navItems) %}
|
|
|
|
<p>
|
|
|
|
API:<br>
|
2021-09-21 13:41:01 +02:00
|
|
|
{% for _, p := range apiLinks %}
|
2021-09-07 21:39:22 +02:00
|
|
|
{%code
|
|
|
|
p, doc := p[0], p[1]
|
|
|
|
%}
|
|
|
|
<a href="{%s p %}">{%s p %}</a> - {%s doc %}<br/>
|
|
|
|
{% endfor %}
|
|
|
|
</p>
|
|
|
|
{%= tpl.Footer() %}
|
|
|
|
{% endfunc %}
|
|
|
|
|
|
|
|
{% func ListGroups(groups []APIGroup) %}
|
|
|
|
{%= tpl.Header("Groups", navItems) %}
|
|
|
|
{% if len(groups) > 0 %}
|
|
|
|
{%code
|
|
|
|
rOk := make(map[string]int)
|
|
|
|
rNotOk := make(map[string]int)
|
|
|
|
for _, g := range groups {
|
|
|
|
for _, r := range g.AlertingRules{
|
|
|
|
if r.LastError != "" {
|
|
|
|
rNotOk[g.Name]++
|
|
|
|
} else {
|
|
|
|
rOk[g.Name]++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, r := range g.RecordingRules{
|
|
|
|
if r.LastError != "" {
|
|
|
|
rNotOk[g.Name]++
|
|
|
|
} else {
|
|
|
|
rOk[g.Name]++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
<a class="btn btn-primary" role="button" onclick="collapseAll()">Collapse All</a>
|
|
|
|
<a class="btn btn-primary" role="button" onclick="expandAll()">Expand All</a>
|
|
|
|
{% for _, g := range groups %}
|
|
|
|
<div class="group-heading{% if rNotOk[g.Name] > 0 %} alert-danger{% endif %}" data-bs-target="rules-{%s g.ID %}">
|
|
|
|
<span class="anchor" id="group-{%s g.ID %}"></span>
|
|
|
|
<a href="#group-{%s g.ID %}">{%s g.Name %}{% if g.Type != "prometheus" %} ({%s g.Type %}){% endif %} (every {%s g.Interval %})</a>
|
|
|
|
{% if rNotOk[g.Name] > 0 %}<span class="badge bg-danger" title="Number of rules withs status Error">{%d rNotOk[g.Name] %}</span> {% endif %}
|
|
|
|
<span class="badge bg-success" title="Number of rules withs status Ok">{%d rOk[g.Name] %}</span>
|
|
|
|
<p class="fs-6 fw-lighter">{%s g.File %}</p>
|
2021-09-13 13:11:38 +02:00
|
|
|
{% if len(g.ExtraFilterLabels) > 0 %}
|
|
|
|
<div class="fs-6 fw-lighter">Extra filter labels
|
|
|
|
{% for k, v := range g.ExtraFilterLabels %}
|
|
|
|
<span class="float-left badge bg-primary">{%s k %}={%s v %}</span>
|
|
|
|
{% endfor %}
|
|
|
|
</div>
|
|
|
|
{% endif %}
|
2021-09-07 21:39:22 +02:00
|
|
|
</div>
|
|
|
|
<div class="collapse" id="rules-{%s g.ID %}">
|
|
|
|
<table class="table table-striped table-hover table-sm">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th scope="col">Rule</th>
|
|
|
|
<th scope="col" title="Shows if rule's execution ended with error">Error</th>
|
|
|
|
<th scope="col" title="How many samples were produced by the rule">Samples</th>
|
|
|
|
<th scope="col" title="How many seconds ago rule was executed">Updated</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{% for _, ar := range g.AlertingRules %}
|
|
|
|
<tr{% if ar.LastError != "" %} class="alert-danger"{% endif %}>
|
|
|
|
<td>
|
|
|
|
<b>alert:</b> {%s ar.Name %} (for: {%v ar.For %})<br>
|
|
|
|
<code><pre>{%s ar.Expression %}</pre></code><br>
|
|
|
|
{% if len(ar.Labels) > 0 %} <b>Labels:</b>{% endif %}
|
|
|
|
{% for k, v := range ar.Labels %}
|
|
|
|
<span class="ms-1 badge bg-primary">{%s k %}={%s v %}</span>
|
|
|
|
{% endfor %}
|
|
|
|
</td>
|
|
|
|
<td><div class="error-cell">{%s ar.LastError %}</div></td>
|
|
|
|
<td>{%d ar.LastSamples %}</td>
|
|
|
|
<td>{%f.3 time.Since(ar.LastExec).Seconds() %}s ago</td>
|
|
|
|
</tr>
|
|
|
|
{% endfor %}
|
|
|
|
{% for _, rr := range g.RecordingRules %}
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
|
|
<b>record:</b> {%s rr.Name %}<br>
|
|
|
|
<code><pre>{%s rr.Expression %}</pre></code>
|
|
|
|
{% if len(rr.Labels) > 0 %} <b>Labels:</b>{% endif %}
|
|
|
|
{% for k, v := range rr.Labels %}
|
|
|
|
<span class="ms-1 badge bg-primary">{%s k %}={%s v %}</span>
|
|
|
|
{% endfor %}
|
|
|
|
</td>
|
|
|
|
<td><div class="error-cell">{%s rr.LastError %}</div></td>
|
|
|
|
<td>{%d rr.LastSamples %}</td>
|
|
|
|
<td>{%f.3 time.Since(rr.LastExec).Seconds() %}s ago</td>
|
|
|
|
</tr>
|
|
|
|
{% endfor %}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
{% else %}
|
|
|
|
<div>
|
|
|
|
<p>No items...</p>
|
|
|
|
</div>
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
{%= tpl.Footer() %}
|
|
|
|
|
|
|
|
{% endfunc %}
|
|
|
|
|
|
|
|
|
|
|
|
{% func ListAlerts(groupAlerts []GroupAlerts) %}
|
|
|
|
{%= tpl.Header("Alerts", navItems) %}
|
|
|
|
{% if len(groupAlerts) > 0 %}
|
|
|
|
<a class="btn btn-primary" role="button" onclick="collapseAll()">Collapse All</a>
|
|
|
|
<a class="btn btn-primary" role="button" onclick="expandAll()">Expand All</a>
|
|
|
|
{% for _, ga := range groupAlerts %}
|
|
|
|
{%code g := ga.Group %}
|
|
|
|
<div class="group-heading alert-danger" data-bs-target="rules-{%s g.ID %}">
|
|
|
|
<span class="anchor" id="group-{%s g.ID %}"></span>
|
|
|
|
<a href="#group-{%s g.ID %}">{%s g.Name %}{% if g.Type != "prometheus" %} ({%s g.Type %}){% endif %}</a>
|
|
|
|
<span class="badge bg-danger" title="Number of active alerts">{%d len(ga.Alerts) %}</span>
|
|
|
|
<br>
|
|
|
|
<p class="fs-6 fw-lighter">{%s g.File %}</p>
|
|
|
|
</div>
|
|
|
|
{%code
|
|
|
|
var keys []string
|
|
|
|
alertsByRule := make(map[string][]*APIAlert)
|
|
|
|
for _, alert := range ga.Alerts {
|
|
|
|
if len(alertsByRule[alert.RuleID]) < 1 {
|
|
|
|
keys = append(keys, alert.RuleID)
|
|
|
|
}
|
|
|
|
alertsByRule[alert.RuleID] = append(alertsByRule[alert.RuleID], alert)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
%}
|
|
|
|
<div class="collapse" id="rules-{%s g.ID %}">
|
|
|
|
{% for _, ruleID := range keys %}
|
|
|
|
{%code
|
|
|
|
defaultAR := alertsByRule[ruleID][0]
|
|
|
|
var labelKeys []string
|
|
|
|
for k := range defaultAR.Labels {
|
|
|
|
labelKeys = append(labelKeys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
%}
|
|
|
|
<br>
|
|
|
|
<b>alert:</b> {%s defaultAR.Name %} ({%d len(alertsByRule[ruleID]) %})<br>
|
|
|
|
<b>expr:</b><code><pre>{%s defaultAR.Expression %}</pre></code>
|
|
|
|
<table class="table table-striped table-hover table-sm">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th scope="col">Labels</th>
|
|
|
|
<th scope="col">State</th>
|
|
|
|
<th scope="col">Active at</th>
|
|
|
|
<th scope="col">Value</th>
|
|
|
|
<th scope="col">Link</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{% for _, ar := range alertsByRule[ruleID] %}
|
|
|
|
<tr>
|
|
|
|
<td>
|
|
|
|
{% for _, k := range labelKeys %}
|
|
|
|
<span class="ms-1 badge bg-primary">{%s k %}={%s ar.Labels[k] %}</span>
|
|
|
|
{% endfor %}
|
|
|
|
</td>
|
|
|
|
<td><span class="badge {% if ar.State=="firing" %}bg-danger{% else %} bg-warning text-dark{% endif %}">{%s ar.State %}</span></td>
|
|
|
|
<td>{%s ar.ActiveAt.Format("2006-01-02T15:04:05Z07:00") %}</td>
|
|
|
|
<td>{%s ar.Value %}</td>
|
|
|
|
<td>
|
|
|
|
<a href="/{%s g.ID %}/{%s ar.ID %}/status">Details</a>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
{% endfor %}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
{% endfor %}
|
|
|
|
</div>
|
|
|
|
<br>
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
{% else %}
|
|
|
|
<div>
|
|
|
|
<p>No items...</p>
|
|
|
|
</div>
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
{%= tpl.Footer() %}
|
|
|
|
|
|
|
|
{% endfunc %}
|
|
|
|
|
|
|
|
{% func Alert(alert *APIAlert) %}
|
|
|
|
{%= tpl.Header("", navItems) %}
|
|
|
|
{%code
|
|
|
|
var labelKeys []string
|
|
|
|
for k := range alert.Labels {
|
|
|
|
labelKeys = append(labelKeys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
|
|
|
|
var annotationKeys []string
|
|
|
|
for k := range alert.Annotations {
|
|
|
|
annotationKeys = append(annotationKeys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(annotationKeys)
|
|
|
|
%}
|
|
|
|
<div class="display-6 pb-3 mb-3">{%s alert.Name %}<span class="ms-2 badge {% if alert.State=="firing" %}bg-danger{% else %} bg-warning text-dark{% endif %}">{%s alert.State %}</span></div>
|
|
|
|
<div class="container border-bottom p-2">
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-2">
|
|
|
|
Active at
|
|
|
|
</div>
|
|
|
|
<div class="col">
|
|
|
|
{%s alert.ActiveAt.Format("2006-01-02T15:04:05Z07:00") %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="container border-bottom p-2">
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-2">
|
|
|
|
Expr
|
|
|
|
</div>
|
|
|
|
<div class="col">
|
|
|
|
<code><pre>{%s alert.Expression %}</pre></code>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="container border-bottom p-2">
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-2">
|
|
|
|
Labels
|
|
|
|
</div>
|
|
|
|
<div class="col">
|
|
|
|
{% for _, k := range labelKeys %}
|
|
|
|
<span class="m-1 badge bg-primary">{%s k %}={%s alert.Labels[k] %}</span>
|
|
|
|
{% endfor %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="container border-bottom p-2">
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-2">
|
|
|
|
Annotations
|
|
|
|
</div>
|
|
|
|
<div class="col">
|
|
|
|
{% for _, k := range annotationKeys %}
|
|
|
|
<b>{%s k %}:</b><br>
|
|
|
|
<p>{%s alert.Annotations[k] %}</p>
|
|
|
|
{% endfor %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="container border-bottom p-2">
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-2">
|
|
|
|
Group
|
|
|
|
</div>
|
|
|
|
<div class="col">
|
|
|
|
<a target="_blank" href="/groups#group-{%s alert.GroupID %}">{%s alert.GroupID %}</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{%= tpl.Footer() %}
|
|
|
|
|
|
|
|
{% endfunc %}
|