| 
									
										
										
										
											2015-01-22 03:07:45 +08:00
										 |  |  | // Copyright 2013 The Prometheus Authors
 | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package rules | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-10-25 12:21:42 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2013-04-26 22:02:52 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-05-13 21:47:04 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 	html_template "html/template" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-25 12:21:42 +08:00
										 |  |  | 	yaml "gopkg.in/yaml.v2" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 	"github.com/go-kit/kit/log" | 
					
						
							|  |  |  | 	"github.com/go-kit/kit/log/level" | 
					
						
							| 
									
										
										
										
											2015-08-20 23:18:46 +08:00
										 |  |  | 	"github.com/prometheus/common/model" | 
					
						
							| 
									
										
										
										
											2013-06-25 20:02:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/pkg/labels" | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/pkg/rulefmt" | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/pkg/timestamp" | 
					
						
							| 
									
										
										
										
											2015-03-31 01:43:19 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/promql" | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/template" | 
					
						
							| 
									
										
										
										
											2015-05-29 19:30:30 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/util/strutil" | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-25 20:02:27 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | 	// AlertMetricName is the metric name for synthetic alert timeseries.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	alertMetricName = "ALERTS" | 
					
						
							| 
									
										
										
										
											2013-06-25 20:02:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | 	// AlertNameLabel is the label name indicating the name of an alert.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	alertNameLabel = "alertname" | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | 	// AlertStateLabel is the label name indicating the state of an alert.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	alertStateLabel = "alertstate" | 
					
						
							| 
									
										
										
										
											2013-06-25 20:02:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // AlertState denotes the state of an active alert.
 | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | type AlertState int | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2016-02-05 12:42:55 +08:00
										 |  |  | 	// StateInactive is the state of an alert that is neither firing nor pending.
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | func (s AlertState) String() string { | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	switch s { | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	case StateInactive: | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 		return "inactive" | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	case StatePending: | 
					
						
							| 
									
										
										
										
											2013-05-16 13:38:31 +08:00
										 |  |  | 		return "pending" | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	case StateFiring: | 
					
						
							| 
									
										
										
										
											2013-05-16 13:38:31 +08:00
										 |  |  | 		return "firing" | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-29 22:23:11 +08:00
										 |  |  | 	panic(fmt.Errorf("unknown alert state: %v", s.String())) | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | // Alert is the user-level representation of a single instance of an alerting rule.
 | 
					
						
							|  |  |  | type Alert struct { | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	State AlertState | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Labels      labels.Labels | 
					
						
							|  |  |  | 	Annotations labels.Labels | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 18:46:10 +08:00
										 |  |  | 	// The value at the last evaluation of the alerting expression.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	Value float64 | 
					
						
							| 
									
										
										
										
											2015-12-17 18:46:10 +08:00
										 |  |  | 	// The interval during which the condition of this alert held true.
 | 
					
						
							|  |  |  | 	// ResolvedAt will be 0 to indicate a still active alert.
 | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 	ActiveAt, ResolvedAt time.Time | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // An AlertingRule generates alerts from its vector expression.
 | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | type AlertingRule struct { | 
					
						
							|  |  |  | 	// The name of the alert.
 | 
					
						
							| 
									
										
										
										
											2013-04-06 00:03:45 +08:00
										 |  |  | 	name string | 
					
						
							|  |  |  | 	// The vector expression from which to generate alerts.
 | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	vector promql.Expr | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	// The duration for which a labelset needs to persist in the expression
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | 	// output vector before an alert transitions from Pending to Firing state.
 | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	holdDuration time.Duration | 
					
						
							|  |  |  | 	// Extra labels to attach to the resulting alert sample vectors.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	labels labels.Labels | 
					
						
							| 
									
										
										
										
											2015-12-12 00:12:34 +08:00
										 |  |  | 	// Non-identifying key/value pairs.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	annotations labels.Labels | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | 	// Time in seconds taken to evaluate rule.
 | 
					
						
							|  |  |  | 	evaluationTimeSeconds float64 | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Protects the below.
 | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	mtx sync.Mutex | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | 	// A map of alerts which are currently active (Pending or Firing), keyed by
 | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	// the fingerprint of the labelset they correspond to.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	active map[uint64]*Alert | 
					
						
							| 
									
										
										
										
											2017-06-16 18:22:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	logger log.Logger | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | // NewAlertingRule constructs a new AlertingRule.
 | 
					
						
							| 
									
										
										
										
											2017-06-16 18:22:44 +08:00
										 |  |  | func NewAlertingRule(name string, vec promql.Expr, hold time.Duration, lbls, anns labels.Labels, logger log.Logger) *AlertingRule { | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	return &AlertingRule{ | 
					
						
							|  |  |  | 		name:         name, | 
					
						
							| 
									
										
										
										
											2015-12-12 00:12:34 +08:00
										 |  |  | 		vector:       vec, | 
					
						
							|  |  |  | 		holdDuration: hold, | 
					
						
							|  |  |  | 		labels:       lbls, | 
					
						
							|  |  |  | 		annotations:  anns, | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		active:       map[uint64]*Alert{}, | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 		logger:       logger, | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // Name returns the name of the alert.
 | 
					
						
							| 
									
										
										
										
											2016-05-19 22:59:53 +08:00
										 |  |  | func (r *AlertingRule) Name() string { | 
					
						
							|  |  |  | 	return r.name | 
					
						
							| 
									
										
										
										
											2013-07-30 23:18:07 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 18:54:37 +08:00
										 |  |  | func (r *AlertingRule) equal(o *AlertingRule) bool { | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	return r.name == o.name && labels.Equal(r.labels, o.labels) | 
					
						
							| 
									
										
										
										
											2016-03-02 18:54:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 00:02:25 +08:00
										 |  |  | func (r *AlertingRule) sample(alert *Alert, ts time.Time) promql.Sample { | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	lb := labels.NewBuilder(r.labels) | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	for _, l := range alert.Labels { | 
					
						
							|  |  |  | 		lb.Set(l.Name, l.Value) | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	lb.Set(labels.MetricName, alertMetricName) | 
					
						
							|  |  |  | 	lb.Set(labels.AlertName, r.name) | 
					
						
							|  |  |  | 	lb.Set(alertStateLabel, alert.State.String()) | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	s := promql.Sample{ | 
					
						
							|  |  |  | 		Metric: lb.Labels(), | 
					
						
							| 
									
										
										
										
											2017-05-20 00:02:25 +08:00
										 |  |  | 		Point:  promql.Point{T: timestamp.FromTime(ts), V: 1}, | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | // setEvaluationTimeSeconds updates evaluationSeconds to the time in seconds it took to evaluate the rule on its last evaluation.
 | 
					
						
							|  |  |  | func (r *AlertingRule) setEvaluationTimeSeconds(seconds float64) { | 
					
						
							|  |  |  | 	r.mtx.Lock() | 
					
						
							|  |  |  | 	defer r.mtx.Unlock() | 
					
						
							|  |  |  | 	r.evaluationTimeSeconds = seconds | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetEvaluationTimeSeconds returns the time in seconds it took to evaluate the alerting rule.
 | 
					
						
							|  |  |  | func (r *AlertingRule) GetEvaluationTimeSeconds() float64 { | 
					
						
							|  |  |  | 	r.mtx.Lock() | 
					
						
							|  |  |  | 	defer r.mtx.Unlock() | 
					
						
							|  |  |  | 	return r.evaluationTimeSeconds | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | // resolvedRetention is the duration for which a resolved alert instance
 | 
					
						
							|  |  |  | // is kept in memory state and consequentally repeatedly sent to the AlertManager.
 | 
					
						
							|  |  |  | const resolvedRetention = 15 * time.Minute | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 00:12:50 +08:00
										 |  |  | // Eval evaluates the rule expression and then creates pending alerts and fires
 | 
					
						
							| 
									
										
										
										
											2015-05-26 02:43:24 +08:00
										 |  |  | // or removes previously pending alerts accordingly.
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:48:37 +08:00
										 |  |  | func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, engine *promql.Engine, externalURL *url.URL) (promql.Vector, error) { | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 	query, err := engine.NewInstantQuery(r.vector.String(), ts) | 
					
						
							| 
									
										
										
										
											2015-03-31 01:43:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 	res, err := query.Exec(ctx).Vector() | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2013-05-16 13:38:31 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	r.mtx.Lock() | 
					
						
							|  |  |  | 	defer r.mtx.Unlock() | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 19:03:19 +08:00
										 |  |  | 	// Create pending alerts for any new vector elements in the alert expression
 | 
					
						
							|  |  |  | 	// or update the expression value for existing elements.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	resultFPs := map[uint64]struct{}{} | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, smpl := range res { | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 		// Provide the alert information to the template.
 | 
					
						
							|  |  |  | 		l := make(map[string]string, len(smpl.Metric)) | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		for _, lbl := range smpl.Metric { | 
					
						
							|  |  |  | 			l[lbl.Name] = lbl.Value | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tmplData := struct { | 
					
						
							|  |  |  | 			Labels map[string]string | 
					
						
							|  |  |  | 			Value  float64 | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			Labels: l, | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 			Value:  smpl.V, | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// 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}}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		expand := func(text string) string { | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 			tmpl := template.NewTemplateExpander( | 
					
						
							| 
									
										
										
										
											2016-09-16 06:58:06 +08:00
										 |  |  | 				ctx, | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 				defs+string(text), | 
					
						
							|  |  |  | 				"__alert_"+r.Name(), | 
					
						
							|  |  |  | 				tmplData, | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 				model.Time(timestamp.FromTime(ts)), | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 				engine, | 
					
						
							| 
									
										
										
										
											2017-05-13 21:47:04 +08:00
										 |  |  | 				externalURL, | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 			) | 
					
						
							|  |  |  | 			result, err := tmpl.Expand() | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				result = fmt.Sprintf("<error expanding template: %s>", err) | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 				level.Warn(r.logger).Log("msg", "Expanding alert template failed", "err", err, "data", tmplData) | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 			return result | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		lb := labels.NewBuilder(smpl.Metric).Del(labels.MetricName) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, l := range r.labels { | 
					
						
							|  |  |  | 			lb.Set(l.Name, expand(l.Value)) | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		lb.Set(labels.AlertName, r.Name()) | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		annotations := make(labels.Labels, 0, len(r.annotations)) | 
					
						
							|  |  |  | 		for _, a := range r.annotations { | 
					
						
							|  |  |  | 			annotations = append(annotations, labels.Label{Name: a.Name, Value: expand(a.Value)}) | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		h := smpl.Metric.Hash() | 
					
						
							|  |  |  | 		resultFPs[h] = struct{}{} | 
					
						
							| 
									
										
										
										
											2013-06-25 20:02:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 22:43:07 +08:00
										 |  |  | 		// Check whether we already have alerting state for the identifying label set.
 | 
					
						
							|  |  |  | 		// Update the last value and annotations if so, create a new alert entry otherwise.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		if alert, ok := r.active[h]; ok && alert.State != StateInactive { | 
					
						
							|  |  |  | 			alert.Value = smpl.V | 
					
						
							| 
									
										
										
										
											2016-11-22 22:43:07 +08:00
										 |  |  | 			alert.Annotations = annotations | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		r.active[h] = &Alert{ | 
					
						
							|  |  |  | 			Labels:      lb.Labels(), | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | 			Annotations: annotations, | 
					
						
							|  |  |  | 			ActiveAt:    ts, | 
					
						
							|  |  |  | 			State:       StatePending, | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 			Value:       smpl.V, | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 	var vec promql.Vector | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	// Check if any pending alerts should be removed or fire now. Write out alert timeseries.
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 	for fp, a := range r.active { | 
					
						
							| 
									
										
										
										
											2015-05-29 03:51:44 +08:00
										 |  |  | 		if _, ok := resultFPs[fp]; !ok { | 
					
						
							| 
									
										
										
										
											2015-12-17 18:46:10 +08:00
										 |  |  | 			// If the alert was previously firing, keep it around for a given
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 			// retention time so it is reported as resolved to the AlertManager.
 | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 			if a.State == StatePending || (!a.ResolvedAt.IsZero() && ts.Sub(a.ResolvedAt) > resolvedRetention) { | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 				delete(r.active, fp) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if a.State != StateInactive { | 
					
						
							|  |  |  | 				a.State = StateInactive | 
					
						
							|  |  |  | 				a.ResolvedAt = ts | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 		if a.State == StatePending && ts.Sub(a.ActiveAt) >= r.holdDuration { | 
					
						
							|  |  |  | 			a.State = StateFiring | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 00:02:25 +08:00
										 |  |  | 		vec = append(vec, r.sample(a, ts)) | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-16 13:38:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	return vec, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 18:46:10 +08:00
										 |  |  | // State returns the maximum state of alert instances for this rule.
 | 
					
						
							|  |  |  | // StateFiring > StatePending > StateInactive
 | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | func (r *AlertingRule) State() AlertState { | 
					
						
							|  |  |  | 	r.mtx.Lock() | 
					
						
							|  |  |  | 	defer r.mtx.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	maxState := StateInactive | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 	for _, a := range r.active { | 
					
						
							|  |  |  | 		if a.State > maxState { | 
					
						
							|  |  |  | 			maxState = a.State | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return maxState | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ActiveAlerts returns a slice of active alerts.
 | 
					
						
							|  |  |  | func (r *AlertingRule) ActiveAlerts() []*Alert { | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 	var res []*Alert | 
					
						
							| 
									
										
										
										
											2015-12-17 18:46:10 +08:00
										 |  |  | 	for _, a := range r.currentAlerts() { | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 		if a.ResolvedAt.IsZero() { | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 			res = append(res, a) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 18:46:10 +08:00
										 |  |  | // currentAlerts returns all instances of alerts for this rule. This may include
 | 
					
						
							|  |  |  | // inactive alerts that were previously firing.
 | 
					
						
							|  |  |  | func (r *AlertingRule) currentAlerts() []*Alert { | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	r.mtx.Lock() | 
					
						
							|  |  |  | 	defer r.mtx.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	alerts := make([]*Alert, 0, len(r.active)) | 
					
						
							| 
									
										
										
										
											2015-12-16 02:46:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, a := range r.active { | 
					
						
							|  |  |  | 		anew := *a | 
					
						
							|  |  |  | 		alerts = append(alerts, &anew) | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return alerts | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-19 22:59:53 +08:00
										 |  |  | func (r *AlertingRule) String() string { | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	ar := rulefmt.Rule{ | 
					
						
							|  |  |  | 		Alert:       r.name, | 
					
						
							|  |  |  | 		Expr:        r.vector.String(), | 
					
						
							|  |  |  | 		For:         model.Duration(r.holdDuration), | 
					
						
							|  |  |  | 		Labels:      r.labels.Map(), | 
					
						
							|  |  |  | 		Annotations: r.annotations.Map(), | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	byt, err := yaml.Marshal(ar) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Sprintf("error marshalling alerting rule: %s", err.Error()) | 
					
						
							| 
									
										
										
										
											2015-12-12 00:12:34 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return string(byt) | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:57 +08:00
										 |  |  | // HTMLSnippet returns an HTML snippet representing this alerting rule. The
 | 
					
						
							|  |  |  | // resulting snippet is expected to be presented in a <pre> element, so that
 | 
					
						
							|  |  |  | // line breaks and other returned whitespace is respected.
 | 
					
						
							| 
									
										
										
										
											2016-07-13 00:11:31 +08:00
										 |  |  | func (r *AlertingRule) HTMLSnippet(pathPrefix string) html_template.HTML { | 
					
						
							| 
									
										
										
										
											2015-08-20 23:18:46 +08:00
										 |  |  | 	alertMetric := model.Metric{ | 
					
						
							|  |  |  | 		model.MetricNameLabel: alertMetricName, | 
					
						
							| 
									
										
										
										
											2016-05-19 22:59:53 +08:00
										 |  |  | 		alertNameLabel:        model.LabelValue(r.name), | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	labels := make(map[string]string, len(r.labels)) | 
					
						
							|  |  |  | 	for _, l := range r.labels { | 
					
						
							|  |  |  | 		labels[l.Name] = html_template.HTMLEscapeString(l.Value) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	annotations := make(map[string]string, len(r.annotations)) | 
					
						
							|  |  |  | 	for _, l := range r.annotations { | 
					
						
							|  |  |  | 		annotations[l.Name] = html_template.HTMLEscapeString(l.Value) | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ar := rulefmt.Rule{ | 
					
						
							| 
									
										
										
										
											2017-10-05 18:16:15 +08:00
										 |  |  | 		Alert:       fmt.Sprintf("<a href=%q>%s</a>", pathPrefix+strutil.TableLinkForExpression(alertMetric.String()), r.name), | 
					
						
							|  |  |  | 		Expr:        fmt.Sprintf("<a href=%q>%s</a>", pathPrefix+strutil.TableLinkForExpression(r.vector.String()), html_template.HTMLEscapeString(r.vector.String())), | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 		For:         model.Duration(r.holdDuration), | 
					
						
							|  |  |  | 		Labels:      labels, | 
					
						
							|  |  |  | 		Annotations: annotations, | 
					
						
							| 
									
										
										
										
											2015-06-23 23:46:57 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	byt, err := yaml.Marshal(ar) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return html_template.HTML(fmt.Sprintf("error marshalling alerting rule: %q", err.Error())) | 
					
						
							| 
									
										
										
										
											2015-12-12 00:12:34 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	return html_template.HTML(byt) | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | } |