Beispiel #1
0
// eval takes an expression or string (which it turns into an expression), executes it and returns the result.
// It can also takes a ResultSlice so callers can transparantly handle different inputs.
// The filter argument constrains the result to matching tags in the current context.
// The series argument asserts that the result is a time series.
func (c *Context) eval(v interface{}, filter bool, series bool, autods int) (res expr.ResultSlice, title string, err error) {
	switch v := v.(type) {
	case string:
		var e *expr.Expr
		e, err = expr.New(v, c.schedule.RuleConf.GetFuncs(c.schedule.SystemConf.EnabledBackends()))
		if err != nil {
			return nil, "", fmt.Errorf("%s: %v", v, err)
		}
		res, title, err = c.evalExpr(e, filter, series, autods)
		if err != nil {
			return
		}
	case *expr.Expr:
		res, title, err = c.evalExpr(v, filter, series, autods)
		if err != nil {
			return
		}
	case expr.ResultSlice:
		res = v
	default:
		return nil, "", fmt.Errorf("expected string, expression or resultslice, got %T (%v)", v, v)
	}
	if filter {
		res = res.Filter(c.AlertKey.Group())
	}
	if series {
		for _, k := range res {
			if k.Type() != models.TypeSeriesSet {
				return nil, "", fmt.Errorf("need a series, got %v (%v)", k.Type(), k)
			}
		}
	}
	return res, title, err
}
Beispiel #2
0
// eval takes an expression or string (which it turns into an expression), executes it and returns the result.
// It can also takes a ResultSlice so callers can transparantly handle different inputs.
// The filter argument constrains the result to matching tags in the current context.
// The series argument asserts that the result is a time series.
func (c *Context) eval(v interface{}, filter bool, series bool, autods int) (res expr.ResultSlice, title string, err error) {
	switch v := v.(type) {
	case string:
		e, err := expr.New(v, c.schedule.Conf.Funcs())
		if err != nil {
			return nil, "", fmt.Errorf("%s: %v", v, err)
		}
		res, title, err = c.evalExpr(e, filter, series, autods)
	case *expr.Expr:
		res, title, err = c.evalExpr(v, filter, series, autods)
	case expr.ResultSlice:
		res = v
	default:
		return nil, "", fmt.Errorf("expected string, expression or resultslice, got %T (%v)", v, v)
	}
	if filter {
		res = res.Filter(c.State.Group)
	}
	if series {
		for _, k := range res {
			if k.Type() != parse.TypeSeriesSet {
				return nil, "", fmt.Errorf("need a series, got %v (%v)", k.Type(), k)
			}
		}
	}
	return
}
Beispiel #3
0
func (c *Conf) NewExpr(s string) *expr.Expr {
	exp, err := expr.New(s, c.Funcs())
	if err != nil {
		c.error(err)
	}
	switch exp.Root.Return() {
	case eparse.TypeNumberSet, eparse.TypeScalar:
		break
	default:
		c.errorf("expression must return a number")
	}
	return exp
}
Beispiel #4
0
func NewGraphiteCheckEvaluator(c graphite.Context, check CheckDef) (*GraphiteCheckEvaluator, error) {
	var warnExpr *expr.Expr
	var critExpr *expr.Expr
	var err error
	if check.WarnExpr != "" {
		warnExpr, err = expr.New(check.WarnExpr, expr.Graphite)
		if err != nil {
			return nil, err
		}
	}
	if check.CritExpr != "" {
		critExpr, err = expr.New(check.CritExpr, expr.Graphite)
		if err != nil {
			return nil, err
		}
	}
	return &GraphiteCheckEvaluator{
		Context:  c,
		Check:    check,
		warnExpr: warnExpr,
		critExpr: critExpr,
	}, nil
}
Beispiel #5
0
// ExprGraph returns an svg graph.
// The basename of the requested svg file should be a base64 encoded expression.
func ExprGraph(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	vars := mux.Vars(r)
	bs := vars["bs"]
	b, err := base64.StdEncoding.DecodeString(bs)
	if err != nil {
		return nil, err
	}
	q := string(b)
	if len(q) == 0 {
		return nil, fmt.Errorf("missing expression")
	}
	autods := 1000
	if a := r.FormValue("autods"); a != "" {
		i, err := strconv.Atoi(a)
		if err != nil {
			return nil, err
		}
		autods = i
	}
	now := time.Now().UTC()
	if n := r.FormValue("now"); n != "" {
		i, err := strconv.ParseInt(n, 10, 64)
		if err != nil {
			return nil, err
		}
		now = time.Unix(i, 0).UTC()
	}
	e, err := expr.New(q, schedule.Conf.Funcs())
	if err != nil {
		return nil, err
	} else if e.Root.Return() != parse.TypeSeriesSet {
		return nil, fmt.Errorf("egraph: requires an expression that returns a series")
	}
	// it may not strictly be necessary to recreate the contexts each time, but we do to be safe
	tsdbContext := schedule.Conf.TSDBContext()
	graphiteContext := schedule.Conf.GraphiteContext()
	ls := schedule.Conf.LogstashElasticHosts
	influx := schedule.Conf.InfluxConfig
	es := schedule.Conf.ElasticHosts
	res, _, err := e.Execute(tsdbContext, graphiteContext, ls, es, influx, cacheObj, t, now, autods, false, schedule.Search, nil, nil)
	if err != nil {
		return nil, err
	}
	if err := schedule.ExprSVG(t, w, 800, 600, "", res.Results); err != nil {
		return nil, err
	}
	return nil, nil
}
Beispiel #6
0
func (c *Context) evalExpr(e *expr.Expr, filter bool, series bool, autods int) (expr.ResultSlice, string, error) {
	var err error
	if filter {
		e, err = expr.New(opentsdb.ReplaceTags(e.Text, c.State.Group), c.schedule.Conf.Funcs())
		if err != nil {
			return nil, "", err
		}
	}
	if series && e.Root.Return() != parse.TypeSeriesSet {
		return nil, "", fmt.Errorf("need a series, got %T (%v)", e, e)
	}
	res, _, err := e.Execute(c.runHistory.Context, c.runHistory.GraphiteContext, c.runHistory.Logstash, c.runHistory.Cache, nil, c.runHistory.Start, autods, c.Alert.UnjoinedOK, c.schedule.Search, c.schedule.Conf.AlertSquelched(c.Alert), c.runHistory)
	if err != nil {
		return nil, "", fmt.Errorf("%s: %v", e, err)
	}
	return res.Results, e.String(), nil
}
Beispiel #7
0
func Expr(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	e, err := expr.New(r.FormValue("q"), schedule.Conf.Funcs())
	if err != nil {
		return nil, err
	}
	now, err := getTime(r)
	if err != nil {
		return nil, err
	}
	// it may not strictly be necessary to recreate the contexts each time, but we do to be safe
	tsdbContext := schedule.Conf.TSDBContext()
	graphiteContext := schedule.Conf.GraphiteContext()
	ls := schedule.Conf.LogstashElasticHosts
	res, queries, err := e.Execute(tsdbContext, graphiteContext, ls, cacheObj, t, now, 0, false, schedule.Search, nil, nil)
	if err != nil {
		return nil, err
	}
	for _, r := range res.Results {
		if r.Computations == nil {
			r.Computations = make(expr.Computations, 0)
		}
	}
	ret := struct {
		Type    string
		Results []*expr.Result
		Queries map[string]opentsdb.Request
	}{
		e.Tree.Root.Return().String(),
		res.Results,
		make(map[string]opentsdb.Request),
	}
	for _, q := range queries {
		if e, err := url.QueryUnescape(q.String()); err == nil {
			ret.Queries[e] = q
		}
	}
	return ret, nil
}
Beispiel #8
0
func (c *Context) evalExpr(e *expr.Expr, filter bool, series bool, autods int) (expr.ResultSlice, string, error) {
	var err error
	if filter {
		e, err = expr.New(opentsdb.ReplaceTags(e.Text, c.AlertKey.Group()), c.schedule.RuleConf.GetFuncs(c.schedule.SystemConf.EnabledBackends()))
		if err != nil {
			return nil, "", err
		}
	}
	if series && e.Root.Return() != models.TypeSeriesSet {
		return nil, "", fmt.Errorf("need a series, got %T (%v)", e, e)
	}
	providers := &expr.BosunProviders{
		Cache:     c.runHistory.Cache,
		Search:    c.schedule.Search,
		Squelched: c.schedule.RuleConf.AlertSquelched(c.Alert),
		History:   c.schedule,
	}
	res, _, err := e.Execute(c.runHistory.Backends, providers, nil, c.runHistory.Start, autods, c.Alert.UnjoinedOK)
	if err != nil {
		return nil, "", fmt.Errorf("%s: %v", e, err)
	}
	return res.Results, e.String(), nil
}
Beispiel #9
0
func Expr(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (v interface{}, err error) {
	defer func() {
		if pan := recover(); pan != nil {
			v = nil
			err = fmt.Errorf("%v", pan)
		}
	}()
	text, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(strings.TrimSpace(string(text)), "\n")
	var expression string
	vars := map[string]string{}
	varRegex := regexp.MustCompile(`(\$\w+)\s*=(.*)`)
	for i, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		// last line is expression we care about
		if i == len(lines)-1 {
			expression = schedule.Conf.Expand(line, vars, false)
		} else { // must be a variable declatation
			matches := varRegex.FindStringSubmatch(line)
			if len(matches) == 0 {
				return nil, fmt.Errorf("Expect all lines before final expression to be variable declarations of form `$foo = something`")
			}
			name := strings.TrimSpace(matches[1])
			value := strings.TrimSpace(matches[2])
			vars[name] = schedule.Conf.Expand(value, vars, false)
		}
	}
	e, err := expr.New(expression, schedule.Conf.Funcs())
	if err != nil {
		return nil, err
	}
	now, err := getTime(r)
	if err != nil {
		return nil, err
	}
	// it may not strictly be necessary to recreate the contexts each time, but we do to be safe
	tsdbContext := schedule.Conf.TSDBContext()
	graphiteContext := schedule.Conf.GraphiteContext()
	ls := schedule.Conf.LogstashElasticHosts
	influx := schedule.Conf.InfluxConfig
	es := schedule.Conf.ElasticHosts
	res, queries, err := e.Execute(tsdbContext, graphiteContext, ls, es, influx, cacheObj, t, now, 0, false, schedule.Search, nil, nil)
	if err != nil {
		return nil, err
	}
	for _, r := range res.Results {
		if r.Computations == nil {
			r.Computations = make(models.Computations, 0)
		}
	}
	ret := struct {
		Type    string
		Results []*expr.Result
		Queries map[string]opentsdb.Request
	}{
		e.Tree.Root.Return().String(),
		res.Results,
		make(map[string]opentsdb.Request),
	}
	for _, q := range queries {
		if e, err := url.QueryUnescape(q.String()); err == nil {
			ret.Queries[e] = q
		}
	}
	return ret, nil
}
Beispiel #10
0
// ExprGraph returns an svg graph.
// The basename of the requested svg file should be a base64 encoded expression.
func ExprGraph(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	vars := mux.Vars(r)
	bs := vars["bs"]
	format := vars["format"]
	b, err := base64.StdEncoding.DecodeString(bs)
	if err != nil {
		return nil, err
	}
	q := string(b)
	if len(q) == 0 {
		return nil, fmt.Errorf("missing expression")
	}
	autods := 1000
	if a := r.FormValue("autods"); a != "" {
		i, err := strconv.Atoi(a)
		if err != nil {
			return nil, err
		}
		autods = i
	}
	now := time.Now().UTC()
	if n := r.FormValue("now"); n != "" {
		i, err := strconv.ParseInt(n, 10, 64)
		if err != nil {
			return nil, err
		}
		now = time.Unix(i, 0).UTC()
	}
	e, err := expr.New(q, schedule.RuleConf.GetFuncs(schedule.SystemConf.EnabledBackends()))
	if err != nil {
		return nil, err
	} else if e.Root.Return() != models.TypeSeriesSet {
		return nil, fmt.Errorf("egraph: requires an expression that returns a series")
	}
	// it may not strictly be necessary to recreate the contexts each time, but we do to be safe
	backends := &expr.Backends{
		TSDBContext:     schedule.SystemConf.GetTSDBContext(),
		GraphiteContext: schedule.SystemConf.GetGraphiteContext(),
		InfluxConfig:    schedule.SystemConf.GetInfluxContext(),
		LogstashHosts:   schedule.SystemConf.GetLogstashContext(),
		ElasticHosts:    schedule.SystemConf.GetElasticContext(),
		AnnotateContext: schedule.SystemConf.GetAnnotateContext(),
	}
	providers := &expr.BosunProviders{
		Cache:     cacheObj,
		Search:    schedule.Search,
		Squelched: nil,
		History:   nil,
	}
	res, _, err := e.Execute(backends, providers, t, now, autods, false)
	if err != nil {
		return nil, err
	}
	switch format {
	case "svg":
		if err := schedule.ExprSVG(t, w, 800, 600, "", res.Results); err != nil {
			return nil, err
		}
	case "png":
		if err := schedule.ExprPNG(t, w, 800, 600, "", res.Results); err != nil {
			return nil, err
		}
	}
	return nil, nil
}