Add alert-expression console links to notifications.
The ConsoleLinkForExpression() function now escapes console URLs in such a way that works both in emails and in HTML. Change-Id: I917bae0b526cbbac28ccd2a4ec3c5ac03ee4c647
This commit is contained in:
parent
d74c2c54d4
commit
1eb1ceac8c
11
main.go
11
main.go
|
@ -203,14 +203,19 @@ func main() {
|
|||
notifications := make(chan notification.NotificationReqs, *notificationQueueCapacity)
|
||||
|
||||
// Queue depth will need to be exposed
|
||||
ruleManager := rules.NewRuleManager(unwrittenSamples, notifications, conf.EvaluationInterval(), ts)
|
||||
ruleManager := rules.NewRuleManager(&rules.RuleManagerOptions{
|
||||
Results: unwrittenSamples,
|
||||
Notifications: notifications,
|
||||
EvaluationInterval: conf.EvaluationInterval(),
|
||||
Storage: ts,
|
||||
PrometheusUrl: web.MustBuildServerUrl(),
|
||||
})
|
||||
if err := ruleManager.AddRulesFromConfig(conf); err != nil {
|
||||
glog.Fatal("Error loading rule files: ", err)
|
||||
}
|
||||
go ruleManager.Run()
|
||||
|
||||
prometheusUrl := web.MustBuildServerUrl()
|
||||
notificationHandler := notification.NewNotificationHandler(*alertmanagerUrl, prometheusUrl, notifications)
|
||||
notificationHandler := notification.NewNotificationHandler(*alertmanagerUrl, notifications)
|
||||
go notificationHandler.Run()
|
||||
|
||||
flags := map[string]string{}
|
||||
|
|
|
@ -54,6 +54,8 @@ type NotificationReq struct {
|
|||
ActiveSince time.Time
|
||||
// A textual representation of the rule that triggered the alert.
|
||||
RuleString string
|
||||
// Prometheus console link to alert expression.
|
||||
GeneratorUrl string
|
||||
}
|
||||
|
||||
type NotificationReqs []*NotificationReq
|
||||
|
@ -67,8 +69,6 @@ type httpPoster interface {
|
|||
type NotificationHandler struct {
|
||||
// The URL of the alert manager to send notifications to.
|
||||
alertmanagerUrl string
|
||||
// The URL of this Prometheus instance to include in notifications.
|
||||
prometheusUrl string
|
||||
// Buffer of notifications that have not yet been sent.
|
||||
pendingNotifications <-chan NotificationReqs
|
||||
// HTTP client with custom timeout settings.
|
||||
|
@ -76,12 +76,11 @@ type NotificationHandler struct {
|
|||
}
|
||||
|
||||
// Construct a new NotificationHandler.
|
||||
func NewNotificationHandler(alertmanagerUrl string, prometheusUrl string, notificationReqs <-chan NotificationReqs) *NotificationHandler {
|
||||
func NewNotificationHandler(alertmanagerUrl string, notificationReqs <-chan NotificationReqs) *NotificationHandler {
|
||||
return &NotificationHandler{
|
||||
alertmanagerUrl: alertmanagerUrl,
|
||||
pendingNotifications: notificationReqs,
|
||||
httpClient: utility.NewDeadlineClient(*deadline),
|
||||
prometheusUrl: prometheusUrl,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +131,7 @@ func (n *NotificationHandler) sendNotifications(reqs NotificationReqs) error {
|
|||
"Payload": map[string]interface{}{
|
||||
"Value": req.Value,
|
||||
"ActiveSince": req.ActiveSince,
|
||||
"GeneratorUrl": n.prometheusUrl,
|
||||
"GeneratorUrl": req.GeneratorUrl,
|
||||
"AlertingRule": req.RuleString,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -48,7 +48,7 @@ type testNotificationScenario struct {
|
|||
func (s *testNotificationScenario) test(i int, t *testing.T) {
|
||||
notifications := make(chan NotificationReqs)
|
||||
defer close(notifications)
|
||||
h := NewNotificationHandler("alertmanager_url", "prometheus_url", notifications)
|
||||
h := NewNotificationHandler("alertmanager_url", notifications)
|
||||
|
||||
receivedPost := make(chan bool, 1)
|
||||
poster := testHttpPoster{receivedPost: receivedPost}
|
||||
|
@ -63,9 +63,10 @@ func (s *testNotificationScenario) test(i int, t *testing.T) {
|
|||
Labels: clientmodel.LabelSet{
|
||||
clientmodel.LabelName("instance"): clientmodel.LabelValue("testinstance"),
|
||||
},
|
||||
Value: clientmodel.SampleValue(1.0 / 3.0),
|
||||
ActiveSince: time.Time{},
|
||||
RuleString: "Test rule string",
|
||||
Value: clientmodel.SampleValue(1.0 / 3.0),
|
||||
ActiveSince: time.Time{},
|
||||
RuleString: "Test rule string",
|
||||
GeneratorUrl: "prometheus_url",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ package rules
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
clientmodel "github.com/prometheus/client_golang/model"
|
||||
|
||||
|
@ -116,5 +117,13 @@ func NewMatrix(vector ast.Node, intervalStr string) (ast.MatrixNode, error) {
|
|||
}
|
||||
|
||||
func ConsoleLinkForExpression(expr string) string {
|
||||
return html.EscapeString(fmt.Sprintf(`graph#[{"expr":%q,"tab":1}]`, expr))
|
||||
// url.QueryEscape percent-escapes everything except spaces, for which it
|
||||
// uses "+". However, in the non-query part of a URI, only percent-escaped
|
||||
// spaces are legal, so we need to manually replace "+" with "%20" after
|
||||
// query-escaping the string.
|
||||
//
|
||||
// See also:
|
||||
// http://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20.
|
||||
urlData := url.QueryEscape(fmt.Sprintf(`[{"expr":%q,"tab":1}]`, expr))
|
||||
return fmt.Sprintf("/graph#%s", strings.Replace(urlData, "+", "%20", -1))
|
||||
}
|
||||
|
|
|
@ -45,21 +45,37 @@ type ruleManager struct {
|
|||
sync.Mutex
|
||||
rules []Rule
|
||||
|
||||
done chan bool
|
||||
|
||||
interval time.Duration
|
||||
storage *metric.TieredStorage
|
||||
|
||||
results chan<- *extraction.Result
|
||||
notifications chan<- notification.NotificationReqs
|
||||
done chan bool
|
||||
interval time.Duration
|
||||
storage *metric.TieredStorage
|
||||
|
||||
prometheusUrl string
|
||||
}
|
||||
|
||||
func NewRuleManager(results chan<- *extraction.Result, notifications chan<- notification.NotificationReqs, interval time.Duration, storage *metric.TieredStorage) RuleManager {
|
||||
type RuleManagerOptions struct {
|
||||
EvaluationInterval time.Duration
|
||||
Storage *metric.TieredStorage
|
||||
|
||||
Notifications chan<- notification.NotificationReqs
|
||||
Results chan<- *extraction.Result
|
||||
|
||||
PrometheusUrl string
|
||||
}
|
||||
|
||||
func NewRuleManager(o *RuleManagerOptions) RuleManager {
|
||||
manager := &ruleManager{
|
||||
results: results,
|
||||
notifications: notifications,
|
||||
rules: []Rule{},
|
||||
done: make(chan bool),
|
||||
interval: interval,
|
||||
storage: storage,
|
||||
rules: []Rule{},
|
||||
done: make(chan bool),
|
||||
|
||||
interval: o.EvaluationInterval,
|
||||
storage: o.Storage,
|
||||
results: o.Results,
|
||||
notifications: o.Notifications,
|
||||
prometheusUrl: o.PrometheusUrl,
|
||||
}
|
||||
return manager
|
||||
}
|
||||
|
@ -107,9 +123,10 @@ func (m *ruleManager) queueAlertNotifications(rule *AlertingRule) {
|
|||
Labels: aa.Labels.Merge(clientmodel.LabelSet{
|
||||
AlertNameLabel: clientmodel.LabelValue(rule.Name()),
|
||||
}),
|
||||
Value: aa.Value,
|
||||
ActiveSince: aa.ActiveSince,
|
||||
RuleString: rule.String(),
|
||||
Value: aa.Value,
|
||||
ActiveSince: aa.ActiveSince,
|
||||
RuleString: rule.String(),
|
||||
GeneratorUrl: m.prometheusUrl + ConsoleLinkForExpression(rule.vector.String()),
|
||||
})
|
||||
}
|
||||
m.notifications <- notifications
|
||||
|
|
Loading…
Reference in New Issue