vmalert: add Source link to alerts UI (#1701)

The source link is controlled by `external.url` and `external.alert.source`
flags, in the same way as for alertmanager notifications.
The source link is added to Alerts list view, and specific Alert view.
This commit is contained in:
Roman Khavronenko 2021-10-13 15:25:11 +03:00 committed by GitHub
parent 3d61a10367
commit 8df3c569c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 164 additions and 128 deletions

View file

@ -415,7 +415,7 @@ func (ar *AlertingRule) AlertsAPI() []*APIAlert {
} }
func (ar *AlertingRule) newAlertAPI(a notifier.Alert) *APIAlert { func (ar *AlertingRule) newAlertAPI(a notifier.Alert) *APIAlert {
return &APIAlert{ aa := &APIAlert{
// encode as strings to avoid rounding // encode as strings to avoid rounding
ID: fmt.Sprintf("%d", a.ID), ID: fmt.Sprintf("%d", a.ID),
GroupID: fmt.Sprintf("%d", a.GroupID), GroupID: fmt.Sprintf("%d", a.GroupID),
@ -429,6 +429,10 @@ func (ar *AlertingRule) newAlertAPI(a notifier.Alert) *APIAlert {
ActiveAt: a.Start, ActiveAt: a.Start,
Value: strconv.FormatFloat(a.Value, 'f', -1, 32), Value: strconv.FormatFloat(a.Value, 'f', -1, 32),
} }
if alertURLGeneratorFn != nil {
aa.SourceLink = alertURLGeneratorFn(a)
}
return aa
} }
const ( const (

View file

@ -59,6 +59,8 @@ eg. 'explore?orgId=1&left=[\"now-1h\",\"now\",\"VictoriaMetrics\",{\"expr\": \"{
dryRun = flag.Bool("dryRun", false, "Whether to check only config files without running vmalert. The rules file are validated. The `-rule` flag must be specified.") dryRun = flag.Bool("dryRun", false, "Whether to check only config files without running vmalert. The rules file are validated. The `-rule` flag must be specified.")
) )
var alertURLGeneratorFn notifier.AlertURLGenerator
func main() { func main() {
// Write flags and help message to stdout, since it is easier to grep or pipe. // Write flags and help message to stdout, since it is easier to grep or pipe.
flag.CommandLine.SetOutput(os.Stdout) flag.CommandLine.SetOutput(os.Stdout)
@ -79,15 +81,22 @@ func main() {
} }
return return
} }
eu, err := getExternalURL(*externalURL, *httpListenAddr, httpserver.IsTLS())
if err != nil {
logger.Fatalf("failed to init `external.url`: %s", err)
}
notifier.InitTemplateFunc(eu)
alertURLGeneratorFn, err = getAlertURLGenerator(eu, *externalAlertSource, *validateTemplates)
if err != nil {
logger.Fatalf("failed to init `external.alert.source`: %s", err)
}
if *replayFrom != "" || *replayTo != "" { if *replayFrom != "" || *replayTo != "" {
rw, err := remotewrite.Init(context.Background()) rw, err := remotewrite.Init(context.Background())
if err != nil { if err != nil {
logger.Fatalf("failed to init remoteWrite: %s", err) logger.Fatalf("failed to init remoteWrite: %s", err)
} }
eu, err := getExternalURL(*externalURL, *httpListenAddr, httpserver.IsTLS())
if err != nil {
logger.Fatalf("failed to init `external.url`: %s", err)
}
notifier.InitTemplateFunc(eu) notifier.InitTemplateFunc(eu)
groupsCfg, err := config.Parse(*rulePath, *validateTemplates, *validateExpressions) groupsCfg, err := config.Parse(*rulePath, *validateTemplates, *validateExpressions)
if err != nil { if err != nil {
@ -148,20 +157,10 @@ func newManager(ctx context.Context) (*manager, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to init datasource: %w", err) return nil, fmt.Errorf("failed to init datasource: %w", err)
} }
eu, err := getExternalURL(*externalURL, *httpListenAddr, httpserver.IsTLS()) nts, err := notifier.Init(alertURLGeneratorFn)
if err != nil {
return nil, fmt.Errorf("failed to init `external.url`: %w", err)
}
notifier.InitTemplateFunc(eu)
aug, err := getAlertURLGenerator(eu, *externalAlertSource, *validateTemplates)
if err != nil {
return nil, fmt.Errorf("failed to init `external.alert.source`: %w", err)
}
nts, err := notifier.Init(aug)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to init notifier: %w", err) return nil, fmt.Errorf("failed to init notifier: %w", err)
} }
manager := &manager{ manager := &manager{
groups: make(map[uint64]*Group), groups: make(map[uint64]*Group),
querierBuilder: q, querierBuilder: q,

View file

@ -155,7 +155,9 @@
sort.Strings(labelKeys) sort.Strings(labelKeys)
%} %}
<br> <br>
<b>alert:</b> {%s defaultAR.Name %} ({%d len(alertsByRule[ruleID]) %})<br> <b>alert:</b> {%s defaultAR.Name %} ({%d len(alertsByRule[ruleID]) %})
| <span><a target="_blank" href="{%s defaultAR.SourceLink %}">Source</a></span>
<br>
<b>expr:</b><code><pre>{%s defaultAR.Expression %}</pre></code> <b>expr:</b><code><pre>{%s defaultAR.Expression %}</pre></code>
<table class="table table-striped table-hover table-sm"> <table class="table table-striped table-hover table-sm">
<thead> <thead>
@ -270,6 +272,16 @@
<a target="_blank" href="/groups#group-{%s alert.GroupID %}">{%s alert.GroupID %}</a> <a target="_blank" href="/groups#group-{%s alert.GroupID %}">{%s alert.GroupID %}</a>
</div> </div>
</div> </div>
</div>
<div class="container border-bottom p-2">
<div class="row">
<div class="col-2">
Source link
</div>
<div class="col">
<a target="_blank" href="{%s alert.SourceLink %}">Link</a>
</div>
</div>
</div> </div>
{%= tpl.Footer() %} {%= tpl.Footer() %}

View file

@ -573,11 +573,17 @@ func StreamListAlerts(qw422016 *qt422016.Writer, groupAlerts []GroupAlerts) {
//line app/vmalert/web.qtpl:158 //line app/vmalert/web.qtpl:158
qw422016.N().D(len(alertsByRule[ruleID])) qw422016.N().D(len(alertsByRule[ruleID]))
//line app/vmalert/web.qtpl:158 //line app/vmalert/web.qtpl:158
qw422016.N().S(`)<br> qw422016.N().S(`)
| <span><a target="_blank" href="`)
//line app/vmalert/web.qtpl:159
qw422016.E().S(defaultAR.SourceLink)
//line app/vmalert/web.qtpl:159
qw422016.N().S(`">Source</a></span>
<br>
<b>expr:</b><code><pre>`) <b>expr:</b><code><pre>`)
//line app/vmalert/web.qtpl:159 //line app/vmalert/web.qtpl:161
qw422016.E().S(defaultAR.Expression) qw422016.E().S(defaultAR.Expression)
//line app/vmalert/web.qtpl:159 //line app/vmalert/web.qtpl:161
qw422016.N().S(`</pre></code> qw422016.N().S(`</pre></code>
<table class="table table-striped table-hover table-sm"> <table class="table table-striped table-hover table-sm">
<thead> <thead>
@ -591,152 +597,152 @@ func StreamListAlerts(qw422016 *qt422016.Writer, groupAlerts []GroupAlerts) {
</thead> </thead>
<tbody> <tbody>
`) `)
//line app/vmalert/web.qtpl:171 //line app/vmalert/web.qtpl:173
for _, ar := range alertsByRule[ruleID] { for _, ar := range alertsByRule[ruleID] {
//line app/vmalert/web.qtpl:171 //line app/vmalert/web.qtpl:173
qw422016.N().S(` qw422016.N().S(`
<tr> <tr>
<td> <td>
`) `)
//line app/vmalert/web.qtpl:174 //line app/vmalert/web.qtpl:176
for _, k := range labelKeys { for _, k := range labelKeys {
//line app/vmalert/web.qtpl:174 //line app/vmalert/web.qtpl:176
qw422016.N().S(` qw422016.N().S(`
<span class="ms-1 badge bg-primary">`) <span class="ms-1 badge bg-primary">`)
//line app/vmalert/web.qtpl:175 //line app/vmalert/web.qtpl:177
qw422016.E().S(k) qw422016.E().S(k)
//line app/vmalert/web.qtpl:175 //line app/vmalert/web.qtpl:177
qw422016.N().S(`=`) qw422016.N().S(`=`)
//line app/vmalert/web.qtpl:175 //line app/vmalert/web.qtpl:177
qw422016.E().S(ar.Labels[k]) qw422016.E().S(ar.Labels[k])
//line app/vmalert/web.qtpl:175 //line app/vmalert/web.qtpl:177
qw422016.N().S(`</span> qw422016.N().S(`</span>
`) `)
//line app/vmalert/web.qtpl:176 //line app/vmalert/web.qtpl:178
} }
//line app/vmalert/web.qtpl:176 //line app/vmalert/web.qtpl:178
qw422016.N().S(` qw422016.N().S(`
</td> </td>
<td><span class="badge `) <td><span class="badge `)
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
if ar.State == "firing" { if ar.State == "firing" {
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
qw422016.N().S(`bg-danger`) qw422016.N().S(`bg-danger`)
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
} else { } else {
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
qw422016.N().S(` bg-warning text-dark`) qw422016.N().S(` bg-warning text-dark`)
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
} }
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
qw422016.E().S(ar.State) qw422016.E().S(ar.State)
//line app/vmalert/web.qtpl:178 //line app/vmalert/web.qtpl:180
qw422016.N().S(`</span></td> qw422016.N().S(`</span></td>
<td>`) <td>`)
//line app/vmalert/web.qtpl:179 //line app/vmalert/web.qtpl:181
qw422016.E().S(ar.ActiveAt.Format("2006-01-02T15:04:05Z07:00")) qw422016.E().S(ar.ActiveAt.Format("2006-01-02T15:04:05Z07:00"))
//line app/vmalert/web.qtpl:179 //line app/vmalert/web.qtpl:181
qw422016.N().S(`</td> qw422016.N().S(`</td>
<td>`) <td>`)
//line app/vmalert/web.qtpl:180 //line app/vmalert/web.qtpl:182
qw422016.E().S(ar.Value) qw422016.E().S(ar.Value)
//line app/vmalert/web.qtpl:180 //line app/vmalert/web.qtpl:182
qw422016.N().S(`</td> qw422016.N().S(`</td>
<td> <td>
<a href="/`) <a href="/`)
//line app/vmalert/web.qtpl:182 //line app/vmalert/web.qtpl:184
qw422016.E().S(g.ID) qw422016.E().S(g.ID)
//line app/vmalert/web.qtpl:182 //line app/vmalert/web.qtpl:184
qw422016.N().S(`/`) qw422016.N().S(`/`)
//line app/vmalert/web.qtpl:182 //line app/vmalert/web.qtpl:184
qw422016.E().S(ar.ID) qw422016.E().S(ar.ID)
//line app/vmalert/web.qtpl:182 //line app/vmalert/web.qtpl:184
qw422016.N().S(`/status">Details</a> qw422016.N().S(`/status">Details</a>
</td> </td>
</tr> </tr>
`) `)
//line app/vmalert/web.qtpl:185 //line app/vmalert/web.qtpl:187
} }
//line app/vmalert/web.qtpl:185 //line app/vmalert/web.qtpl:187
qw422016.N().S(` qw422016.N().S(`
</tbody> </tbody>
</table> </table>
`) `)
//line app/vmalert/web.qtpl:188 //line app/vmalert/web.qtpl:190
} }
//line app/vmalert/web.qtpl:188 //line app/vmalert/web.qtpl:190
qw422016.N().S(` qw422016.N().S(`
</div> </div>
<br> <br>
`) `)
//line app/vmalert/web.qtpl:191 //line app/vmalert/web.qtpl:193
} }
//line app/vmalert/web.qtpl:191 //line app/vmalert/web.qtpl:193
qw422016.N().S(` qw422016.N().S(`
`) `)
//line app/vmalert/web.qtpl:193 //line app/vmalert/web.qtpl:195
} else { } else {
//line app/vmalert/web.qtpl:193 //line app/vmalert/web.qtpl:195
qw422016.N().S(` qw422016.N().S(`
<div> <div>
<p>No items...</p> <p>No items...</p>
</div> </div>
`) `)
//line app/vmalert/web.qtpl:197 //line app/vmalert/web.qtpl:199
} }
//line app/vmalert/web.qtpl:197 //line app/vmalert/web.qtpl:199
qw422016.N().S(` qw422016.N().S(`
`) `)
//line app/vmalert/web.qtpl:199 //line app/vmalert/web.qtpl:201
tpl.StreamFooter(qw422016) tpl.StreamFooter(qw422016)
//line app/vmalert/web.qtpl:199 //line app/vmalert/web.qtpl:201
qw422016.N().S(` qw422016.N().S(`
`) `)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
} }
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
func WriteListAlerts(qq422016 qtio422016.Writer, groupAlerts []GroupAlerts) { func WriteListAlerts(qq422016 qtio422016.Writer, groupAlerts []GroupAlerts) {
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
StreamListAlerts(qw422016, groupAlerts) StreamListAlerts(qw422016, groupAlerts)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
} }
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
func ListAlerts(groupAlerts []GroupAlerts) string { func ListAlerts(groupAlerts []GroupAlerts) string {
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
WriteListAlerts(qb422016, groupAlerts) WriteListAlerts(qb422016, groupAlerts)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
return qs422016 return qs422016
//line app/vmalert/web.qtpl:201 //line app/vmalert/web.qtpl:203
} }
//line app/vmalert/web.qtpl:203 //line app/vmalert/web.qtpl:205
func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) { func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
//line app/vmalert/web.qtpl:203 //line app/vmalert/web.qtpl:205
qw422016.N().S(`
`)
//line app/vmalert/web.qtpl:204
tpl.StreamHeader(qw422016, "", navItems)
//line app/vmalert/web.qtpl:204
qw422016.N().S(` qw422016.N().S(`
`) `)
//line app/vmalert/web.qtpl:206 //line app/vmalert/web.qtpl:206
tpl.StreamHeader(qw422016, "", navItems)
//line app/vmalert/web.qtpl:206
qw422016.N().S(`
`)
//line app/vmalert/web.qtpl:208
var labelKeys []string var labelKeys []string
for k := range alert.Labels { for k := range alert.Labels {
labelKeys = append(labelKeys, k) labelKeys = append(labelKeys, k)
@ -749,28 +755,28 @@ func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
} }
sort.Strings(annotationKeys) sort.Strings(annotationKeys)
//line app/vmalert/web.qtpl:217 //line app/vmalert/web.qtpl:219
qw422016.N().S(` qw422016.N().S(`
<div class="display-6 pb-3 mb-3">`) <div class="display-6 pb-3 mb-3">`)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.E().S(alert.Name) qw422016.E().S(alert.Name)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.N().S(`<span class="ms-2 badge `) qw422016.N().S(`<span class="ms-2 badge `)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
if alert.State == "firing" { if alert.State == "firing" {
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.N().S(`bg-danger`) qw422016.N().S(`bg-danger`)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
} else { } else {
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.N().S(` bg-warning text-dark`) qw422016.N().S(` bg-warning text-dark`)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
} }
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.E().S(alert.State) qw422016.E().S(alert.State)
//line app/vmalert/web.qtpl:218 //line app/vmalert/web.qtpl:220
qw422016.N().S(`</span></div> qw422016.N().S(`</span></div>
<div class="container border-bottom p-2"> <div class="container border-bottom p-2">
<div class="row"> <div class="row">
@ -779,9 +785,9 @@ func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
</div> </div>
<div class="col"> <div class="col">
`) `)
//line app/vmalert/web.qtpl:225 //line app/vmalert/web.qtpl:227
qw422016.E().S(alert.ActiveAt.Format("2006-01-02T15:04:05Z07:00")) qw422016.E().S(alert.ActiveAt.Format("2006-01-02T15:04:05Z07:00"))
//line app/vmalert/web.qtpl:225 //line app/vmalert/web.qtpl:227
qw422016.N().S(` qw422016.N().S(`
</div> </div>
</div> </div>
@ -793,9 +799,9 @@ func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
</div> </div>
<div class="col"> <div class="col">
<code><pre>`) <code><pre>`)
//line app/vmalert/web.qtpl:235 //line app/vmalert/web.qtpl:237
qw422016.E().S(alert.Expression) qw422016.E().S(alert.Expression)
//line app/vmalert/web.qtpl:235 //line app/vmalert/web.qtpl:237
qw422016.N().S(`</pre></code> qw422016.N().S(`</pre></code>
</div> </div>
</div> </div>
@ -807,23 +813,23 @@ func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
</div> </div>
<div class="col"> <div class="col">
`) `)
//line app/vmalert/web.qtpl:245 //line app/vmalert/web.qtpl:247
for _, k := range labelKeys { for _, k := range labelKeys {
//line app/vmalert/web.qtpl:245 //line app/vmalert/web.qtpl:247
qw422016.N().S(` qw422016.N().S(`
<span class="m-1 badge bg-primary">`) <span class="m-1 badge bg-primary">`)
//line app/vmalert/web.qtpl:246 //line app/vmalert/web.qtpl:248
qw422016.E().S(k) qw422016.E().S(k)
//line app/vmalert/web.qtpl:246 //line app/vmalert/web.qtpl:248
qw422016.N().S(`=`) qw422016.N().S(`=`)
//line app/vmalert/web.qtpl:246 //line app/vmalert/web.qtpl:248
qw422016.E().S(alert.Labels[k]) qw422016.E().S(alert.Labels[k])
//line app/vmalert/web.qtpl:246 //line app/vmalert/web.qtpl:248
qw422016.N().S(`</span> qw422016.N().S(`</span>
`) `)
//line app/vmalert/web.qtpl:247 //line app/vmalert/web.qtpl:249
} }
//line app/vmalert/web.qtpl:247 //line app/vmalert/web.qtpl:249
qw422016.N().S(` qw422016.N().S(`
</div> </div>
</div> </div>
@ -835,24 +841,24 @@ func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
</div> </div>
<div class="col"> <div class="col">
`) `)
//line app/vmalert/web.qtpl:257 //line app/vmalert/web.qtpl:259
for _, k := range annotationKeys { for _, k := range annotationKeys {
//line app/vmalert/web.qtpl:257 //line app/vmalert/web.qtpl:259
qw422016.N().S(` qw422016.N().S(`
<b>`) <b>`)
//line app/vmalert/web.qtpl:258 //line app/vmalert/web.qtpl:260
qw422016.E().S(k) qw422016.E().S(k)
//line app/vmalert/web.qtpl:258 //line app/vmalert/web.qtpl:260
qw422016.N().S(`:</b><br> qw422016.N().S(`:</b><br>
<p>`) <p>`)
//line app/vmalert/web.qtpl:259 //line app/vmalert/web.qtpl:261
qw422016.E().S(alert.Annotations[k]) qw422016.E().S(alert.Annotations[k])
//line app/vmalert/web.qtpl:259 //line app/vmalert/web.qtpl:261
qw422016.N().S(`</p> qw422016.N().S(`</p>
`) `)
//line app/vmalert/web.qtpl:260 //line app/vmalert/web.qtpl:262
} }
//line app/vmalert/web.qtpl:260 //line app/vmalert/web.qtpl:262
qw422016.N().S(` qw422016.N().S(`
</div> </div>
</div> </div>
@ -864,49 +870,63 @@ func StreamAlert(qw422016 *qt422016.Writer, alert *APIAlert) {
</div> </div>
<div class="col"> <div class="col">
<a target="_blank" href="/groups#group-`) <a target="_blank" href="/groups#group-`)
//line app/vmalert/web.qtpl:270 //line app/vmalert/web.qtpl:272
qw422016.E().S(alert.GroupID) qw422016.E().S(alert.GroupID)
//line app/vmalert/web.qtpl:270 //line app/vmalert/web.qtpl:272
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line app/vmalert/web.qtpl:270 //line app/vmalert/web.qtpl:272
qw422016.E().S(alert.GroupID) qw422016.E().S(alert.GroupID)
//line app/vmalert/web.qtpl:270 //line app/vmalert/web.qtpl:272
qw422016.N().S(`</a> qw422016.N().S(`</a>
</div> </div>
</div> </div>
</div>
<div class="container border-bottom p-2">
<div class="row">
<div class="col-2">
Source link
</div>
<div class="col">
<a target="_blank" href="`)
//line app/vmalert/web.qtpl:282
qw422016.E().S(alert.SourceLink)
//line app/vmalert/web.qtpl:282
qw422016.N().S(`">Link</a>
</div>
</div>
</div> </div>
`) `)
//line app/vmalert/web.qtpl:274 //line app/vmalert/web.qtpl:286
tpl.StreamFooter(qw422016) tpl.StreamFooter(qw422016)
//line app/vmalert/web.qtpl:274 //line app/vmalert/web.qtpl:286
qw422016.N().S(` qw422016.N().S(`
`) `)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
} }
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
func WriteAlert(qq422016 qtio422016.Writer, alert *APIAlert) { func WriteAlert(qq422016 qtio422016.Writer, alert *APIAlert) {
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
StreamAlert(qw422016, alert) StreamAlert(qw422016, alert)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
} }
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
func Alert(alert *APIAlert) string { func Alert(alert *APIAlert) string {
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
WriteAlert(qb422016, alert) WriteAlert(qb422016, alert)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
return qs422016 return qs422016
//line app/vmalert/web.qtpl:276 //line app/vmalert/web.qtpl:288
} }

View file

@ -17,6 +17,7 @@ type APIAlert struct {
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"` Annotations map[string]string `json:"annotations"`
ActiveAt time.Time `json:"activeAt"` ActiveAt time.Time `json:"activeAt"`
SourceLink string `json:"source"`
} }
// APIGroup represents Group for WEB view // APIGroup represents Group for WEB view