| 
									
										
										
										
											2013-02-07 18:49:04 +08:00
										 |  |  | // Copyright 2013 Prometheus Team
 | 
					
						
							|  |  |  | // 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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | package rules | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2013-01-28 01:49:45 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/model" | 
					
						
							|  |  |  | 	"github.com/prometheus/prometheus/rules/ast" | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	"regexp" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func rulesError(error string, v ...interface{}) error { | 
					
						
							|  |  |  | 	return errors.New(fmt.Sprintf(error, v...)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO move to common place, currently duplicated in config/
 | 
					
						
							|  |  |  | func stringToDuration(durationStr string) (time.Duration, error) { | 
					
						
							| 
									
										
										
										
											2013-01-18 06:44:54 +08:00
										 |  |  | 	durationRE := regexp.MustCompile("^([0-9]+)([ywdhms]+)$") | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	matches := durationRE.FindStringSubmatch(durationStr) | 
					
						
							|  |  |  | 	if len(matches) != 3 { | 
					
						
							|  |  |  | 		return 0, rulesError("Not a valid duration string: '%v'", durationStr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	value, _ := strconv.Atoi(matches[1]) | 
					
						
							|  |  |  | 	unit := matches[2] | 
					
						
							|  |  |  | 	switch unit { | 
					
						
							|  |  |  | 	case "y": | 
					
						
							|  |  |  | 		value *= 60 * 60 * 24 * 365 | 
					
						
							| 
									
										
										
										
											2013-01-18 06:44:54 +08:00
										 |  |  | 	case "w": | 
					
						
							|  |  |  | 		value *= 60 * 60 * 24 | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	case "d": | 
					
						
							|  |  |  | 		value *= 60 * 60 * 24 | 
					
						
							|  |  |  | 	case "h": | 
					
						
							|  |  |  | 		value *= 60 * 60 | 
					
						
							|  |  |  | 	case "m": | 
					
						
							|  |  |  | 		value *= 60 | 
					
						
							|  |  |  | 	case "s": | 
					
						
							|  |  |  | 		value *= 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return time.Duration(value) * time.Second, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func CreateRule(name string, labels model.LabelSet, root ast.Node, permanent bool) (*Rule, error) { | 
					
						
							|  |  |  | 	if root.Type() != ast.VECTOR { | 
					
						
							|  |  |  | 		return nil, rulesError("Rule %v does not evaluate to vector type", name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NewRule(name, labels, root.(ast.VectorNode), permanent), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewFunctionCall(name string, args []ast.Node) (ast.Node, error) { | 
					
						
							|  |  |  | 	function, err := ast.GetFunction(name) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, rulesError("Unknown function \"%v\"", name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	functionCall, err := ast.NewFunctionCall(function, args) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, rulesError(err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return functionCall, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewVectorAggregation(aggrTypeStr string, vector ast.Node, groupBy []model.LabelName) (*ast.VectorAggregation, error) { | 
					
						
							|  |  |  | 	if vector.Type() != ast.VECTOR { | 
					
						
							|  |  |  | 		return nil, rulesError("Operand of %v aggregation must be of vector type", aggrTypeStr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var aggrTypes = map[string]ast.AggrType{ | 
					
						
							|  |  |  | 		"SUM": ast.SUM, | 
					
						
							|  |  |  | 		"MAX": ast.MAX, | 
					
						
							|  |  |  | 		"MIN": ast.MIN, | 
					
						
							|  |  |  | 		"AVG": ast.AVG, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	aggrType, ok := aggrTypes[aggrTypeStr] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, rulesError("Unknown aggregation type '%v'", aggrTypeStr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ast.NewVectorAggregation(aggrType, vector.(ast.VectorNode), groupBy), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewArithExpr(opTypeStr string, lhs ast.Node, rhs ast.Node) (ast.Node, error) { | 
					
						
							|  |  |  | 	var opTypes = map[string]ast.BinOpType{ | 
					
						
							|  |  |  | 		"+":   ast.ADD, | 
					
						
							|  |  |  | 		"-":   ast.SUB, | 
					
						
							|  |  |  | 		"*":   ast.MUL, | 
					
						
							|  |  |  | 		"/":   ast.DIV, | 
					
						
							|  |  |  | 		"%":   ast.MOD, | 
					
						
							|  |  |  | 		">":   ast.GT, | 
					
						
							|  |  |  | 		"<":   ast.LT, | 
					
						
							|  |  |  | 		"==":  ast.EQ, | 
					
						
							|  |  |  | 		"!=":  ast.NE, | 
					
						
							|  |  |  | 		">=":  ast.GE, | 
					
						
							|  |  |  | 		"<=":  ast.LE, | 
					
						
							|  |  |  | 		"AND": ast.AND, | 
					
						
							|  |  |  | 		"OR":  ast.OR, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	opType, ok := opTypes[opTypeStr] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, rulesError("Invalid binary operator \"%v\"", opTypeStr) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	expr, err := ast.NewArithExpr(opType, lhs, rhs) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, rulesError(err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return expr, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewMatrix(vector ast.Node, intervalStr string) (ast.MatrixNode, error) { | 
					
						
							|  |  |  | 	switch vector.(type) { | 
					
						
							|  |  |  | 	case *ast.VectorLiteral: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return nil, rulesError("Intervals are currently only supported for vector literals.") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-11 08:12:34 +08:00
										 |  |  | 	interval, err := stringToDuration(intervalStr) | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	vectorLiteral := vector.(*ast.VectorLiteral) | 
					
						
							|  |  |  | 	return ast.NewMatrixLiteral(vectorLiteral, interval), nil | 
					
						
							|  |  |  | } |