mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-05 01:01:09 +01:00
88538df267
* app/vmalert: support multiple notifier urls (#584) User now can set multiple notifier URLs in the same fashion as for other vmutils (e.g. vmagent). The same is correct for TLS setting for every configured URL. Alerts sending is done in sequential way for respecting the specified URLs order. * app/vmalert: add basicAuth support for notifier client (#585) The change adds possibility to set basicAuth creds for notifier client in the same fasion as for remote write/read and datasource.
110 lines
2.8 KiB
Go
110 lines
2.8 KiB
Go
package notifier
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/utils"
|
|
)
|
|
|
|
// Alert the triggered alert
|
|
// TODO: Looks like alert name isn't unique
|
|
type Alert struct {
|
|
GroupID uint64
|
|
Name string
|
|
Labels map[string]string
|
|
Annotations map[string]string
|
|
State AlertState
|
|
|
|
Expr string
|
|
Start time.Time
|
|
End time.Time
|
|
Value float64
|
|
ID uint64
|
|
}
|
|
|
|
// AlertState type indicates the Alert state
|
|
type AlertState int
|
|
|
|
const (
|
|
// StateInactive is the state of an alert that is neither firing nor pending.
|
|
StateInactive AlertState = iota
|
|
// StatePending is the state of an alert that has been active for less than
|
|
// the configured threshold duration.
|
|
StatePending
|
|
// StateFiring is the state of an alert that has been active for longer than
|
|
// the configured threshold duration.
|
|
StateFiring
|
|
)
|
|
|
|
// String stringer for AlertState
|
|
func (as AlertState) String() string {
|
|
switch as {
|
|
case StateFiring:
|
|
return "firing"
|
|
case StatePending:
|
|
return "pending"
|
|
}
|
|
return "inactive"
|
|
}
|
|
|
|
type alertTplData struct {
|
|
Labels map[string]string
|
|
Value float64
|
|
Expr string
|
|
}
|
|
|
|
const tplHeader = `{{ $value := .Value }}{{ $labels := .Labels }}{{ $expr := .Expr }}`
|
|
|
|
// ExecTemplate executes the Alert template for give
|
|
// map of annotations.
|
|
func (a *Alert) ExecTemplate(annotations map[string]string) (map[string]string, error) {
|
|
tplData := alertTplData{Value: a.Value, Labels: a.Labels, Expr: a.Expr}
|
|
return templateAnnotations(annotations, tplHeader, tplData)
|
|
}
|
|
|
|
// ValidateTemplates validate annotations for possible template error, uses empty data for template population
|
|
func ValidateTemplates(annotations map[string]string) error {
|
|
_, err := templateAnnotations(annotations, tplHeader, alertTplData{
|
|
Labels: map[string]string{},
|
|
Value: 0,
|
|
})
|
|
return err
|
|
}
|
|
|
|
func templateAnnotations(annotations map[string]string, header string, data alertTplData) (map[string]string, error) {
|
|
var builder strings.Builder
|
|
var buf bytes.Buffer
|
|
eg := new(utils.ErrGroup)
|
|
r := make(map[string]string, len(annotations))
|
|
for key, text := range annotations {
|
|
r[key] = text
|
|
buf.Reset()
|
|
builder.Reset()
|
|
builder.Grow(len(header) + len(text))
|
|
builder.WriteString(header)
|
|
builder.WriteString(text)
|
|
if err := templateAnnotation(&buf, builder.String(), data); err != nil {
|
|
eg.Add(fmt.Errorf("key %q, template %q: %s", key, text, err))
|
|
continue
|
|
}
|
|
r[key] = buf.String()
|
|
}
|
|
return r, eg.Err()
|
|
}
|
|
|
|
func templateAnnotation(dst io.Writer, text string, data alertTplData) error {
|
|
tpl, err := template.New("").Funcs(tmplFunc).Option("missingkey=zero").Parse(text)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing annotation: %w", err)
|
|
}
|
|
if err = tpl.Execute(dst, data); err != nil {
|
|
return fmt.Errorf("error evaluating annotation template: %w", err)
|
|
}
|
|
return nil
|
|
}
|