Пример #1
0
func BenchmarkEvalBool_OneOperatorValueChanges_ReferenceNodeInt64_NumberInt64(b *testing.B) {

	scope := stateful.NewScope()
	initialValue := int64(20)

	scope.Set("value", initialValue)

	b.ReportAllocs()
	b.ResetTimer()

	se, err := stateful.NewExpression(&ast.BinaryNode{
		Operator: ast.TokenGreater,
		Left: &ast.ReferenceNode{
			Reference: "value",
		},
		Right: &ast.NumberNode{
			IsInt: true,
			Int64: int64(10),
		},
	})
	if err != nil {
		b.Fatalf("Failed to compile the expression: %v", err)
	}

	// We have maximum value because we want to limit the maximum number in
	// the reference node so we don't get too much big numbers and the benchmark suite will increase our iterations number (b.N)
	currentValue := initialValue
	maximumValue := int64(40)

	var result bool
	for i := 0; i < b.N; i++ {
		b.StopTimer()

		currentValue += int64(1)
		if currentValue > maximumValue {
			currentValue = initialValue

		}
		scope.Set("value", currentValue)

		b.StartTimer()

		result, err := se.EvalBool(scope)
		if err != nil || !result {
			v, _ := scope.Get("value")
			b.Errorf("Failed to evaluate: error=%v, result=%t, value=%v, init=%v, maximum=%v", err, result, v, initialValue, maximumValue)
		}
	}

	evalBoolResult = result
}
Пример #2
0
func benchmarkEvalBool(b *testing.B, scope *stateful.Scope, node ast.Node) {
	b.ReportAllocs()
	b.ResetTimer()

	var err error
	se, err := stateful.NewExpression(node)
	if err != nil {
		b.Fatalf("Failed to compile the expression: %v", err)
	}

	for i := 0; i < b.N; i++ {
		evalBoolResult, err = se.EvalBool(scope)
		if err != nil {
			b.Fatal(err)
		}
	}
}
Пример #3
0
// Create a new CombineNode, which combines a stream with itself dynamically.
func newCombineNode(et *ExecutingTask, n *pipeline.CombineNode, l *log.Logger) (*CombineNode, error) {
	cn := &CombineNode{
		c:                  n,
		node:               node{Node: n, et: et, logger: l},
		expressionsByGroup: make(map[models.GroupID][]stateful.Expression),
		combination:        combination{max: n.Max},
	}
	// Create stateful expressions
	cn.expressions = make([]stateful.Expression, len(n.Lambdas))
	cn.scopePools = make([]stateful.ScopePool, len(n.Lambdas))
	for i, lambda := range n.Lambdas {
		statefulExpr, err := stateful.NewExpression(lambda.Expression)
		if err != nil {
			return nil, fmt.Errorf("Failed to compile %v expression: %v", i, err)
		}
		cn.expressions[i] = statefulExpr
		cn.scopePools[i] = stateful.NewScopePool(stateful.FindReferenceVariables(lambda.Expression))
	}
	cn.node.runF = cn.runCombine
	return cn, nil
}
Пример #4
0
func (k *K8sAutoscaleNode) evalExpr(
	current int,
	group models.GroupID,
	lambda *ast.LambdaNode,
	expressionsMap map[models.GroupID]stateful.Expression,
	pool stateful.ScopePool,
	t time.Time,
	fields models.Fields,
	tags models.Tags,
) (int, error) {
	expr, ok := expressionsMap[group]
	if !ok {
		var err error
		expr, err = stateful.NewExpression(lambda.Expression)
		if err != nil {
			return 0, err
		}
		expressionsMap[group] = expr
	}
	i, err := k.evalInt(int64(current), expr, pool, t, fields, tags)
	return int(i), err
}
Пример #5
0
// Create a new  FromNode which filters data from a source.
func newFromNode(et *ExecutingTask, n *pipeline.FromNode, l *log.Logger) (*FromNode, error) {
	sn := &FromNode{
		node: node{Node: n, et: et, logger: l},
		s:    n,
		db:   n.Database,
		rp:   n.RetentionPolicy,
		name: n.Measurement,
	}
	sn.node.runF = sn.runStream
	sn.allDimensions, sn.dimensions = determineDimensions(n.Dimensions)

	if n.Lambda != nil {
		expr, err := stateful.NewExpression(n.Lambda.Expression)
		if err != nil {
			return nil, fmt.Errorf("Failed to compile from expression: %v", err)
		}

		sn.expression = expr
		sn.scopePool = stateful.NewScopePool(stateful.FindReferenceVariables(n.Lambda.Expression))
	}

	return sn, nil
}
Пример #6
0
// Create a new  EvalNode which applies a transformation func to each point in a stream and returns a single point.
func newEvalNode(et *ExecutingTask, n *pipeline.EvalNode, l *log.Logger) (*EvalNode, error) {
	if len(n.AsList) != len(n.Lambdas) {
		return nil, errors.New("must provide one name per expression via the 'As' property")
	}
	en := &EvalNode{
		node:               node{Node: n, et: et, logger: l},
		e:                  n,
		expressionsByGroup: make(map[models.GroupID][]stateful.Expression),
	}
	// Create stateful expressions
	en.expressions = make([]stateful.Expression, len(n.Lambdas))
	en.refVarList = make([][]string, len(n.Lambdas))
	expressions := make([]ast.Node, len(n.Lambdas))
	for i, lambda := range n.Lambdas {
		expressions[i] = lambda.Expression
		statefulExpr, err := stateful.NewExpression(lambda.Expression)
		if err != nil {
			return nil, fmt.Errorf("Failed to compile %v expression: %v", i, err)
		}
		en.expressions[i] = statefulExpr
		refVars := stateful.FindReferenceVariables(lambda.Expression)
		en.refVarList[i] = refVars
	}
	// Create a single pool for the combination of all expressions
	en.scopePool = stateful.NewScopePool(stateful.FindReferenceVariables(expressions...))

	// Create map of tags
	if l := len(n.TagsList); l > 0 {
		en.tags = make(map[string]bool, l)
		for _, tag := range n.TagsList {
			en.tags[tag] = true
		}
	}

	en.node.runF = en.runEval
	return en, nil
}
Пример #7
0
func (w *WhereNode) runWhere(snapshot []byte) error {
	switch w.Wants() {
	case pipeline.StreamEdge:
		for p, ok := w.ins[0].NextPoint(); ok; p, ok = w.ins[0].NextPoint() {
			w.timer.Start()
			expr := w.expressions[p.Group]
			scopePool := w.scopePools[p.Group]

			if expr == nil {
				compiledExpr, err := stateful.NewExpression(w.w.Lambda.Expression)
				if err != nil {
					return fmt.Errorf("Failed to compile expression in where clause: %v", err)
				}

				expr = compiledExpr
				w.expressions[p.Group] = expr

				scopePool = stateful.NewScopePool(stateful.FindReferenceVariables(w.w.Lambda.Expression))
				w.scopePools[p.Group] = scopePool
			}
			if pass, err := EvalPredicate(expr, scopePool, p.Time, p.Fields, p.Tags); pass {
				w.timer.Pause()
				for _, child := range w.outs {
					err := child.CollectPoint(p)
					if err != nil {
						return err
					}
				}
				w.timer.Resume()
			} else if err != nil {
				w.logger.Println("E! error while evaluating expression:", err)
			}
			w.timer.Stop()
		}
	case pipeline.BatchEdge:
		for b, ok := w.ins[0].NextBatch(); ok; b, ok = w.ins[0].NextBatch() {
			w.timer.Start()
			expr := w.expressions[b.Group]
			scopePool := w.scopePools[b.Group]

			if expr == nil {
				compiledExpr, err := stateful.NewExpression(w.w.Lambda.Expression)
				if err != nil {
					return fmt.Errorf("Failed to compile expression in where clause: %v", err)
				}

				expr = compiledExpr
				w.expressions[b.Group] = expr

				scopePool = stateful.NewScopePool(stateful.FindReferenceVariables(w.w.Lambda.Expression))
				w.scopePools[b.Group] = scopePool
			}
			points := b.Points
			b.Points = make([]models.BatchPoint, 0, len(b.Points))
			for _, p := range points {
				if pass, err := EvalPredicate(expr, scopePool, p.Time, p.Fields, p.Tags); pass {
					if err != nil {
						w.logger.Println("E! error while evaluating WHERE expression:", err)
					}
					b.Points = append(b.Points, p)
				}
			}
			w.timer.Stop()
			for _, child := range w.outs {
				err := child.CollectBatch(b)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}
Пример #8
0
// Create a new  AlertNode which caches the most recent item and exposes it over the HTTP API.
func newAlertNode(et *ExecutingTask, n *pipeline.AlertNode, l *log.Logger) (an *AlertNode, err error) {
	an = &AlertNode{
		node: node{Node: n, et: et, logger: l},
		a:    n,
	}
	an.node.runF = an.runAlert

	// Create buffer pool for the templates
	an.bufPool = sync.Pool{
		New: func() interface{} {
			return new(bytes.Buffer)
		},
	}

	// Parse templates
	an.idTmpl, err = text.New("id").Parse(n.Id)
	if err != nil {
		return nil, err
	}

	an.messageTmpl, err = text.New("message").Parse(n.Message)
	if err != nil {
		return nil, err
	}

	an.detailsTmpl, err = html.New("details").Funcs(html.FuncMap{
		"json": func(v interface{}) html.JS {

			tmpBuffer := an.bufPool.Get().(*bytes.Buffer)
			defer func() {
				tmpBuffer.Reset()
				an.bufPool.Put(tmpBuffer)
			}()

			json.NewEncoder(tmpBuffer).Encode(v)

			return html.JS(tmpBuffer.String())
		},
	}).Parse(n.Details)
	if err != nil {
		return nil, err
	}

	// Construct alert handlers
	an.handlers = make([]AlertHandler, 0)

	for _, post := range n.PostHandlers {
		post := post
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePost(post, ad) })
	}

	for _, email := range n.EmailHandlers {
		email := email
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(email, ad) })
	}
	if len(n.EmailHandlers) == 0 && (et.tm.SMTPService != nil && et.tm.SMTPService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(&pipeline.EmailHandler{}, ad) })
	}
	// If email has been configured with state changes only set it.
	if et.tm.SMTPService != nil &&
		et.tm.SMTPService.Global() &&
		et.tm.SMTPService.StateChangesOnly() {
		n.IsStateChangesOnly = true
	}

	for _, exec := range n.ExecHandlers {
		exec := exec
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleExec(exec, ad) })
	}

	for _, log := range n.LogHandlers {
		log := log
		if !filepath.IsAbs(log.FilePath) {
			return nil, fmt.Errorf("alert log path must be absolute: %s is not absolute", log.FilePath)
		}
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleLog(log, ad) })
	}

	for _, vo := range n.VictorOpsHandlers {
		vo := vo
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(vo, ad) })
	}
	if len(n.VictorOpsHandlers) == 0 && (et.tm.VictorOpsService != nil && et.tm.VictorOpsService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(&pipeline.VictorOpsHandler{}, ad) })
	}

	for _, pd := range n.PagerDutyHandlers {
		pd := pd
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(pd, ad) })
	}
	if len(n.PagerDutyHandlers) == 0 && (et.tm.PagerDutyService != nil && et.tm.PagerDutyService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(&pipeline.PagerDutyHandler{}, ad) })
	}

	for _, sensu := range n.SensuHandlers {
		sensu := sensu
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSensu(sensu, ad) })
	}

	for _, slack := range n.SlackHandlers {
		slack := slack
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(slack, ad) })
	}
	if len(n.SlackHandlers) == 0 && (et.tm.SlackService != nil && et.tm.SlackService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(&pipeline.SlackHandler{}, ad) })
	}
	// If slack has been configured with state changes only set it.
	if et.tm.SlackService != nil &&
		et.tm.SlackService.Global() &&
		et.tm.SlackService.StateChangesOnly() {
		n.IsStateChangesOnly = true
	}

	for _, telegram := range n.TelegramHandlers {
		telegram := telegram
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTelegram(telegram, ad) })
	}
	if len(n.TelegramHandlers) == 0 && (et.tm.TelegramService != nil && et.tm.TelegramService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTelegram(&pipeline.TelegramHandler{}, ad) })
	}
	// If telegram has been configured with state changes only set it.
	if et.tm.TelegramService != nil &&
		et.tm.TelegramService.Global() &&
		et.tm.TelegramService.StateChangesOnly() {
		n.IsStateChangesOnly = true
	}

	for _, hipchat := range n.HipChatHandlers {
		hipchat := hipchat
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(hipchat, ad) })
	}
	if len(n.HipChatHandlers) == 0 && (et.tm.HipChatService != nil && et.tm.HipChatService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(&pipeline.HipChatHandler{}, ad) })
	}
	// If HipChat has been configured with state changes only set it.
	if et.tm.HipChatService != nil &&
		et.tm.HipChatService.Global() &&
		et.tm.HipChatService.StateChangesOnly() {
		n.IsStateChangesOnly = true
	}

	for _, alerta := range n.AlertaHandlers {
		// Validate alerta templates
		rtmpl, err := text.New("resource").Parse(alerta.Resource)
		if err != nil {
			return nil, err
		}
		evtmpl, err := text.New("event").Parse(alerta.Event)
		if err != nil {
			return nil, err
		}
		etmpl, err := text.New("environment").Parse(alerta.Environment)
		if err != nil {
			return nil, err
		}
		gtmpl, err := text.New("group").Parse(alerta.Group)
		if err != nil {
			return nil, err
		}
		vtmpl, err := text.New("value").Parse(alerta.Value)
		if err != nil {
			return nil, err
		}
		ai := alertaHandler{
			AlertaHandler:   alerta,
			resourceTmpl:    rtmpl,
			eventTmpl:       evtmpl,
			environmentTmpl: etmpl,
			groupTmpl:       gtmpl,
			valueTmpl:       vtmpl,
		}
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleAlerta(ai, ad) })
	}

	for _, og := range n.OpsGenieHandlers {
		og := og
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(og, ad) })
	}
	if len(n.OpsGenieHandlers) == 0 && (et.tm.OpsGenieService != nil && et.tm.OpsGenieService.Global()) {
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(&pipeline.OpsGenieHandler{}, ad) })
	}

	for _, talk := range n.TalkHandlers {
		talk := talk
		an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTalk(talk, ad) })
	}

	// Parse level expressions
	an.levels = make([]stateful.Expression, CritAlert+1)
	an.scopePools = make([]stateful.ScopePool, CritAlert+1)

	if n.Info != nil {
		statefulExpression, expressionCompileError := stateful.NewExpression(n.Info.Expression)
		if expressionCompileError != nil {
			return nil, fmt.Errorf("Failed to compile stateful expression for info: %s", expressionCompileError)
		}

		an.levels[InfoAlert] = statefulExpression
		an.scopePools[InfoAlert] = stateful.NewScopePool(stateful.FindReferenceVariables(n.Info.Expression))
	}

	if n.Warn != nil {
		statefulExpression, expressionCompileError := stateful.NewExpression(n.Warn.Expression)
		if expressionCompileError != nil {
			return nil, fmt.Errorf("Failed to compile stateful expression for warn: %s", expressionCompileError)
		}
		an.levels[WarnAlert] = statefulExpression
		an.scopePools[WarnAlert] = stateful.NewScopePool(stateful.FindReferenceVariables(n.Warn.Expression))
	}

	if n.Crit != nil {
		statefulExpression, expressionCompileError := stateful.NewExpression(n.Crit.Expression)
		if expressionCompileError != nil {
			return nil, fmt.Errorf("Failed to compile stateful expression for crit: %s", expressionCompileError)
		}
		an.levels[CritAlert] = statefulExpression
		an.scopePools[CritAlert] = stateful.NewScopePool(stateful.FindReferenceVariables(n.Crit.Expression))
	}

	// Setup states
	if n.History < 2 {
		n.History = 2
	}
	an.states = make(map[models.GroupID]*alertState)

	// Configure flapping
	if n.UseFlapping {
		if n.FlapLow > 1 || n.FlapHigh > 1 {
			return nil, errors.New("alert flap thresholds are percentages and should be between 0 and 1")
		}
	}

	return
}
Пример #9
0
// Evaluate a node using a stack machine in a given scope
func eval(n ast.Node, scope *stateful.Scope, stck *stack, predefinedVars, defaultVars map[string]Var, ignoreMissingVars bool) (err error) {
	switch node := n.(type) {
	case *ast.BoolNode:
		stck.Push(node.Bool)
	case *ast.NumberNode:
		if node.IsInt {
			stck.Push(node.Int64)
		} else {
			stck.Push(node.Float64)
		}
	case *ast.DurationNode:
		stck.Push(node.Dur)
	case *ast.StringNode:
		stck.Push(node.Literal)
	case *ast.RegexNode:
		stck.Push(node.Regex)
	case *ast.UnaryNode:
		err = eval(node.Node, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
		if err != nil {
			return
		}
		err = evalUnary(node, node.Operator, scope, stck)
		if err != nil {
			return
		}
	case *ast.BinaryNode:
		// Switch over to using the stateful expressions for evaluating a BinaryNode
		n, err := resolveIdents(node, scope)
		if err != nil {
			return err
		}
		expr, err := stateful.NewExpression(n)
		if err != nil {
			return err
		}
		value, err := expr.Eval(stateful.NewScope())
		if err != nil {
			return err
		}
		stck.Push(value)
	case *ast.LambdaNode:
		node.Expression, err = resolveIdents(node.Expression, scope)
		if err != nil {
			return
		}
		stck.Push(node)
	case *ast.ListNode:
		nodes := make([]interface{}, len(node.Nodes))
		for i, n := range node.Nodes {
			err = eval(n, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
			if err != nil {
				return
			}
			a := stck.Pop()
			switch typed := a.(type) {
			case *ast.IdentifierNode:
				// Resolve identifier
				a, err = scope.Get(typed.Ident)
				if err != nil {
					return err
				}
			}

			nodes[i] = a
		}
		stck.Push(nodes)
	case *ast.TypeDeclarationNode:
		err = evalTypeDeclaration(node, scope, predefinedVars, defaultVars, ignoreMissingVars)
		if err != nil {
			return
		}
	case *ast.DeclarationNode:
		err = eval(node.Right, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
		if err != nil {
			return
		}
		err = evalDeclaration(node, scope, stck, predefinedVars, defaultVars)
		if err != nil {
			return
		}
	case *ast.ChainNode:
		err = eval(node.Left, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
		if err != nil {
			return
		}
		err = eval(node.Right, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
		if err != nil {
			return
		}
		err = evalChain(node, scope, stck)
		if err != nil {
			return
		}
	case *ast.FunctionNode:
		args := make([]interface{}, len(node.Args))
		for i, arg := range node.Args {
			err = eval(arg, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
			if err != nil {
				return
			}
			a := stck.Pop()
			switch typed := a.(type) {
			case *ast.IdentifierNode:
				// Resolve identifier
				a, err = scope.Get(typed.Ident)
				if err != nil {
					return err
				}
			case unboundFunc:
				// Call global func
				a, err = typed(nil)
				if err != nil {
					return err
				}
			}

			args[i] = a
		}
		err = evalFunc(node, scope, stck, args)
		if err != nil {
			return
		}
	case *ast.ProgramNode:
		for _, n := range node.Nodes {
			err = eval(n, scope, stck, predefinedVars, defaultVars, ignoreMissingVars)
			if err != nil {
				return
			}
			// Pop unused result
			if stck.Len() > 0 {
				ret := stck.Pop()
				if f, ok := ret.(unboundFunc); ok {
					// Call global function
					_, err := f(nil)
					if err != nil {
						return err
					}
				}
			}
		}
	default:
		stck.Push(node)
	}
	return nil
}