Add external labels to template expansion

This affects the expansion of templates in alert labels and
annotations and console templates.

Signed-off-by: Sylvain Rabot <sylvain@abstraction.fr>
This commit is contained in:
Sylvain Rabot 2018-12-17 20:16:28 +01:00 committed by Bjoern Rabenstein
parent 1d4c9efe63
commit 335a34486e
7 changed files with 81 additions and 20 deletions

View file

@ -748,6 +748,12 @@ func reloadConfig(filename string, logger log.Logger, rls ...func(*config.Config
return errors.Errorf("one or more errors occurred while applying the new configuration (--config.file=%q)", filename)
}
promql.SetDefaultEvaluationInterval(time.Duration(conf.GlobalConfig.EvaluationInterval))
// Register conf as current config.
config.CurrentConfigMutex.Lock()
config.CurrentConfig = conf
config.CurrentConfigMutex.Unlock()
level.Info(logger).Log("msg", "Completed loading of configuration file", "filename", filename)
return nil
}

View file

@ -20,6 +20,7 @@ import (
"path/filepath"
"regexp"
"strings"
"sync"
"time"
"github.com/pkg/errors"
@ -68,6 +69,10 @@ func LoadFile(filename string) (*Config, error) {
// The defaults applied before parsing the respective config sections.
var (
// CurrentConfig is a pointer to the current configuration.
CurrentConfig *Config
CurrentConfigMutex sync.RWMutex
// DefaultConfig is the default top-level configuration.
DefaultConfig = Config{
GlobalConfig: DefaultGlobalConfig,

View file

@ -43,7 +43,7 @@ The `annotations` clause specifies a set of informational labels that can be use
#### Templating
Label and annotation values can be templated using [console templates](https://prometheus.io/docs/visualization/consoles).
The `$labels` variable holds the label key/value pairs of an alert instance
The `$labels` & `$externalLabels` variables hold the label key/value pairs of an alert instance
and `$value` holds the evaluated value of an alert instance.
# To insert a firing element's label values:

View file

@ -155,7 +155,7 @@ func testTemplateParsing(rl *Rule) (errs []error) {
}
// Trying to parse templates.
tmplData := template.AlertTemplateData(make(map[string]string), 0)
tmplData := template.AlertTemplateData(make(map[string]string), make(map[string]string), 0)
defs := "{{$labels := .Labels}}{{$value := .Value}}"
parseTest := func(text string) error {
tmpl := template.NewTemplateExpander(

View file

@ -28,6 +28,7 @@ import (
"github.com/go-kit/kit/log/level"
"github.com/pkg/errors"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/rulefmt"
@ -79,8 +80,9 @@ func (s AlertState) String() string {
type Alert struct {
State AlertState
Labels labels.Labels
Annotations labels.Labels
Labels labels.Labels
ExternalLabels labels.Labels
Annotations labels.Labels
// The value at the last evaluation of the alerting expression.
Value float64
@ -300,15 +302,27 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc,
var vec promql.Vector
for _, smpl := range res {
// Provide the alert information to the template.
l := make(map[string]string, len(smpl.Metric))
l := make(map[string]string)
for _, lbl := range smpl.Metric {
l[lbl.Name] = lbl.Value
}
tmplData := template.AlertTemplateData(l, smpl.V)
// Add external labels.
el := make(map[string]string)
if config.CurrentConfig != nil {
config.CurrentConfigMutex.RLock()
for eln, elv := range (*config.CurrentConfig).GlobalConfig.ExternalLabels {
el[string(eln)] = string(elv)
}
config.CurrentConfigMutex.RUnlock()
}
tmplData := template.AlertTemplateData(l, el, smpl.V)
// Inject some convenience variables that are easier to remember for users
// who are not used to Go's templating system.
defs := "{{$labels := .Labels}}{{$value := .Value}}"
defs := "{{$labels := .Labels}}"
defs += "{{$externalLabels := .ExternalLabels}}"
defs += "{{$value := .Value}}"
expand := func(text string) string {
tmpl := template.NewTemplateExpander(

View file

@ -28,9 +28,10 @@ import (
text_template "text/template"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/util/strutil"
)
@ -133,6 +134,19 @@ func NewTemplateExpander(
"label": func(label string, s *sample) string {
return s.Labels[label]
},
"externalLabel": func(label string) string {
if config.CurrentConfig == nil {
return ""
}
config.CurrentConfigMutex.RLock()
defer config.CurrentConfigMutex.RUnlock()
for eln, elv := range (*config.CurrentConfig).GlobalConfig.ExternalLabels {
if label == string(eln) {
return string(elv)
}
}
return ""
},
"value": func(s *sample) float64 {
return s.Value
},
@ -261,13 +275,15 @@ func NewTemplateExpander(
}
// AlertTemplateData returns the interface to be used in expanding the template.
func AlertTemplateData(labels map[string]string, value float64) interface{} {
func AlertTemplateData(labels map[string]string, externalLabels map[string]string, value float64) interface{} {
return struct {
Labels map[string]string
Value float64
Labels map[string]string
ExternalLabels map[string]string
Value float64
}{
Labels: labels,
Value: value,
Labels: labels,
ExternalLabels: externalLabels,
Value: value,
}
}

View file

@ -541,19 +541,39 @@ func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
for k, v := range rawParams {
params[k] = v[0]
}
// External labels
el := make(map[string]string)
if config.CurrentConfig != nil {
config.CurrentConfigMutex.RLock()
for eln, elv := range (*config.CurrentConfig).GlobalConfig.ExternalLabels {
el[string(eln)] = string(elv)
}
config.CurrentConfigMutex.RUnlock()
}
// Inject some convenience variables that are easier to remember for users
// who are not used to Go's templating system.
defs := "{{$rawParams := .RawParams }}"
defs += "{{$params := .Params}}"
defs += "{{$path := .Path}}"
defs += "{{$externalLabels := .ExternalLabels}}"
data := struct {
RawParams url.Values
Params map[string]string
Path string
RawParams url.Values
Params map[string]string
Path string
ExternalLabels map[string]string
}{
RawParams: rawParams,
Params: params,
Path: strings.TrimLeft(name, "/"),
RawParams: rawParams,
Params: params,
Path: strings.TrimLeft(name, "/"),
ExternalLabels: el,
}
tmpl := template.NewTemplateExpander(
h.context,
string(text),
defs+string(text),
"__console_"+name,
data,
h.now(),