| 
									
										
										
										
											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-24 17:51:40 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 	"html/template" | 
					
						
							| 
									
										
										
										
											2017-05-13 21:47:04 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	yaml "gopkg.in/yaml.v2" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2015-03-31 01:43:19 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/promql" | 
					
						
							| 
									
										
										
										
											2015-05-29 19:30:30 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/util/strutil" | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A RecordingRule records its vector expression into new timeseries.
 | 
					
						
							|  |  |  | type RecordingRule struct { | 
					
						
							| 
									
										
										
										
											2018-08-07 06:33:45 +08:00
										 |  |  | 	name   string | 
					
						
							|  |  |  | 	vector promql.Expr | 
					
						
							|  |  |  | 	labels labels.Labels | 
					
						
							|  |  |  | 	// Protects the below.
 | 
					
						
							|  |  |  | 	mtx sync.Mutex | 
					
						
							|  |  |  | 	// The health of the recording rule.
 | 
					
						
							|  |  |  | 	health RuleHealth | 
					
						
							|  |  |  | 	// The last error seen by the recording rule.
 | 
					
						
							|  |  |  | 	lastError          error | 
					
						
							| 
									
										
										
										
											2018-07-18 11:54:33 +08:00
										 |  |  | 	evaluationDuration time.Duration | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | // NewRecordingRule returns a new recording rule.
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | func NewRecordingRule(name string, vector promql.Expr, lset labels.Labels) *RecordingRule { | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	return &RecordingRule{ | 
					
						
							|  |  |  | 		name:   name, | 
					
						
							|  |  |  | 		vector: vector, | 
					
						
							| 
									
										
										
										
											2018-08-07 06:33:45 +08:00
										 |  |  | 		health: HealthUnknown, | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		labels: lset, | 
					
						
							| 
									
										
										
										
											2015-05-26 03:16:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // Name returns the rule name.
 | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | func (rule *RecordingRule) Name() string { | 
					
						
							| 
									
										
										
										
											2015-12-15 00:40:40 +08:00
										 |  |  | 	return rule.name | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-27 15:15:17 +08:00
										 |  |  | // Query returns the rule query expression.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) Query() promql.Expr { | 
					
						
							|  |  |  | 	return rule.vector | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Labels returns the rule labels.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) Labels() labels.Labels { | 
					
						
							|  |  |  | 	return rule.labels | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 00:12:50 +08:00
										 |  |  | // Eval evaluates the rule and then overrides the metric names and labels accordingly.
 | 
					
						
							| 
									
										
										
										
											2017-11-23 20:04:54 +08:00
										 |  |  | func (rule *RecordingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, _ *url.URL) (promql.Vector, error) { | 
					
						
							|  |  |  | 	vector, err := query(ctx, rule.vector.String(), ts) | 
					
						
							| 
									
										
										
										
											2015-03-31 01:43:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-07 06:33:45 +08:00
										 |  |  | 		rule.SetHealth(HealthBad) | 
					
						
							|  |  |  | 		rule.SetLastError(err) | 
					
						
							| 
									
										
										
										
											2015-03-31 01:43:19 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	// Override the metric name and labels.
 | 
					
						
							| 
									
										
										
										
											2016-12-30 00:31:14 +08:00
										 |  |  | 	for i := range vector { | 
					
						
							|  |  |  | 		sample := &vector[i] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		lb := labels.NewBuilder(sample.Metric) | 
					
						
							| 
									
										
										
										
											2015-08-25 00:04:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 		lb.Set(labels.MetricName, rule.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, l := range rule.labels { | 
					
						
							|  |  |  | 			if l.Value == "" { | 
					
						
							|  |  |  | 				lb.Del(l.Name) | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 				lb.Set(l.Name, l.Value) | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-25 07:37:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		sample.Metric = lb.Labels() | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-07 06:33:45 +08:00
										 |  |  | 	rule.SetHealth(HealthGood) | 
					
						
							|  |  |  | 	rule.SetLastError(err) | 
					
						
							| 
									
										
										
										
											2013-05-16 13:38:31 +08:00
										 |  |  | 	return vector, nil | 
					
						
							| 
									
										
										
										
											2013-04-24 17:51:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | func (rule *RecordingRule) String() string { | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	r := rulefmt.Rule{ | 
					
						
							|  |  |  | 		Record: rule.name, | 
					
						
							|  |  |  | 		Expr:   rule.vector.String(), | 
					
						
							|  |  |  | 		Labels: rule.labels.Map(), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	byt, err := yaml.Marshal(r) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return fmt.Sprintf("error marshalling recording rule: %q", err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return string(byt) | 
					
						
							| 
									
										
										
										
											2013-06-06 21:12:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 11:54:33 +08:00
										 |  |  | // SetEvaluationDuration updates evaluationDuration to the time in seconds it took to evaluate the rule on its last evaluation.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) SetEvaluationDuration(dur time.Duration) { | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | 	rule.mtx.Lock() | 
					
						
							|  |  |  | 	defer rule.mtx.Unlock() | 
					
						
							| 
									
										
										
										
											2018-07-18 11:54:33 +08:00
										 |  |  | 	rule.evaluationDuration = dur | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-07 06:33:45 +08:00
										 |  |  | // SetLastError sets the current error seen by the recording rule.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) SetLastError(err error) { | 
					
						
							|  |  |  | 	rule.mtx.Lock() | 
					
						
							|  |  |  | 	defer rule.mtx.Unlock() | 
					
						
							|  |  |  | 	rule.lastError = err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LastError returns the last error seen by the recording rule.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) LastError() error { | 
					
						
							|  |  |  | 	rule.mtx.Lock() | 
					
						
							|  |  |  | 	defer rule.mtx.Unlock() | 
					
						
							|  |  |  | 	return rule.lastError | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetHealth sets the current health of the recording rule.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) SetHealth(health RuleHealth) { | 
					
						
							|  |  |  | 	rule.mtx.Lock() | 
					
						
							|  |  |  | 	defer rule.mtx.Unlock() | 
					
						
							|  |  |  | 	rule.health = health | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Health returns the current health of the recording rule.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) Health() RuleHealth { | 
					
						
							|  |  |  | 	rule.mtx.Lock() | 
					
						
							|  |  |  | 	defer rule.mtx.Unlock() | 
					
						
							|  |  |  | 	return rule.health | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 11:54:33 +08:00
										 |  |  | // GetEvaluationDuration returns the time in seconds it took to evaluate the recording rule.
 | 
					
						
							|  |  |  | func (rule *RecordingRule) GetEvaluationDuration() time.Duration { | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | 	rule.mtx.Lock() | 
					
						
							|  |  |  | 	defer rule.mtx.Unlock() | 
					
						
							| 
									
										
										
										
											2018-07-18 11:54:33 +08:00
										 |  |  | 	return rule.evaluationDuration | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-10 23:16:49 +08:00
										 |  |  | // HTMLSnippet returns an HTML snippet representing this rule.
 | 
					
						
							| 
									
										
										
										
											2017-11-17 23:18:34 +08:00
										 |  |  | func (rule *RecordingRule) HTMLSnippet(pathPrefix string) template.HTML { | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | 	ruleExpr := rule.vector.String() | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	labels := make(map[string]string, len(rule.labels)) | 
					
						
							|  |  |  | 	for _, l := range rule.labels { | 
					
						
							|  |  |  | 		labels[l.Name] = template.HTMLEscapeString(l.Value) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r := rulefmt.Rule{ | 
					
						
							| 
									
										
										
										
											2017-10-05 18:16:15 +08:00
										 |  |  | 		Record: fmt.Sprintf(`<a href="%s">%s</a>`, pathPrefix+strutil.TableLinkForExpression(rule.name), rule.name), | 
					
						
							|  |  |  | 		Expr:   fmt.Sprintf(`<a href="%s">%s</a>`, pathPrefix+strutil.TableLinkForExpression(ruleExpr), template.HTMLEscapeString(ruleExpr)), | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 		Labels: labels, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	byt, err := yaml.Marshal(r) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-05 20:01:51 +08:00
										 |  |  | 		return template.HTML(fmt.Sprintf("error marshalling recording rule: %q", template.HTMLEscapeString(err.Error()))) | 
					
						
							| 
									
										
										
										
											2017-07-08 17:38:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return template.HTML(byt) | 
					
						
							| 
									
										
										
										
											2013-06-13 22:10:05 +08:00
										 |  |  | } |