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) return errors.Errorf("one or more errors occurred while applying the new configuration (--config.file=%q)", filename)
} }
promql.SetDefaultEvaluationInterval(time.Duration(conf.GlobalConfig.EvaluationInterval)) 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) level.Info(logger).Log("msg", "Completed loading of configuration file", "filename", filename)
return nil return nil
} }

View file

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

View file

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

View file

@ -155,7 +155,7 @@ func testTemplateParsing(rl *Rule) (errs []error) {
} }
// Trying to parse templates. // 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}}" defs := "{{$labels := .Labels}}{{$value := .Value}}"
parseTest := func(text string) error { parseTest := func(text string) error {
tmpl := template.NewTemplateExpander( tmpl := template.NewTemplateExpander(

View file

@ -28,6 +28,7 @@ import (
"github.com/go-kit/kit/log/level" "github.com/go-kit/kit/log/level"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/rulefmt" "github.com/prometheus/prometheus/pkg/rulefmt"
@ -79,8 +80,9 @@ func (s AlertState) String() string {
type Alert struct { type Alert struct {
State AlertState State AlertState
Labels labels.Labels Labels labels.Labels
Annotations labels.Labels ExternalLabels labels.Labels
Annotations labels.Labels
// The value at the last evaluation of the alerting expression. // The value at the last evaluation of the alerting expression.
Value float64 Value float64
@ -300,15 +302,27 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc,
var vec promql.Vector var vec promql.Vector
for _, smpl := range res { for _, smpl := range res {
// Provide the alert information to the template. // 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 { for _, lbl := range smpl.Metric {
l[lbl.Name] = lbl.Value 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 // Inject some convenience variables that are easier to remember for users
// who are not used to Go's templating system. // 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 { expand := func(text string) string {
tmpl := template.NewTemplateExpander( tmpl := template.NewTemplateExpander(

View file

@ -28,9 +28,10 @@ import (
text_template "text/template" text_template "text/template"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/promql" "github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/util/strutil" "github.com/prometheus/prometheus/util/strutil"
) )
@ -133,6 +134,19 @@ func NewTemplateExpander(
"label": func(label string, s *sample) string { "label": func(label string, s *sample) string {
return s.Labels[label] 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 { "value": func(s *sample) float64 {
return s.Value return s.Value
}, },
@ -261,13 +275,15 @@ func NewTemplateExpander(
} }
// AlertTemplateData returns the interface to be used in expanding the template. // 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 { return struct {
Labels map[string]string Labels map[string]string
Value float64 ExternalLabels map[string]string
Value float64
}{ }{
Labels: labels, Labels: labels,
Value: value, 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 { for k, v := range rawParams {
params[k] = v[0] 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 { data := struct {
RawParams url.Values RawParams url.Values
Params map[string]string Params map[string]string
Path string Path string
ExternalLabels map[string]string
}{ }{
RawParams: rawParams, RawParams: rawParams,
Params: params, Params: params,
Path: strings.TrimLeft(name, "/"), Path: strings.TrimLeft(name, "/"),
ExternalLabels: el,
} }
tmpl := template.NewTemplateExpander( tmpl := template.NewTemplateExpander(
h.context, h.context,
string(text), defs+string(text),
"__console_"+name, "__console_"+name,
data, data,
h.now(), h.now(),