Example #1
0
func (c *QueryCondition) Eval(context *alerting.EvalContext) {
	timeRange := tsdb.NewTimeRange(c.Query.From, c.Query.To)
	seriesList, err := c.executeQuery(context, timeRange)
	if err != nil {
		context.Error = err
		return
	}

	emptySerieCount := 0
	for _, series := range seriesList {
		reducedValue := c.Reducer.Reduce(series)
		evalMatch := c.Evaluator.Eval(reducedValue)

		if reducedValue.Valid == false {
			emptySerieCount++
			continue
		}

		if context.IsTestRun {
			context.Logs = append(context.Logs, &alerting.ResultLogEntry{
				Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, evalMatch, series.Name, reducedValue.Float64),
			})
		}

		if evalMatch {
			context.EvalMatches = append(context.EvalMatches, &alerting.EvalMatch{
				Metric: series.Name,
				Value:  reducedValue.Float64,
			})
		}
	}

	context.NoDataFound = emptySerieCount == len(seriesList)
	context.Firing = len(context.EvalMatches) > 0
}
Example #2
0
func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.ConditionResult, error) {
	timeRange := tsdb.NewTimeRange(c.Query.From, c.Query.To)

	seriesList, err := c.executeQuery(context, timeRange)
	if err != nil {
		return nil, err
	}

	emptySerieCount := 0
	evalMatchCount := 0
	var matches []*alerting.EvalMatch

	for _, series := range seriesList {
		reducedValue := c.Reducer.Reduce(series)
		evalMatch := c.Evaluator.Eval(reducedValue)

		if reducedValue.Valid == false {
			emptySerieCount++
		}

		if context.IsTestRun {
			context.Logs = append(context.Logs, &alerting.ResultLogEntry{
				Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %s", c.Index, evalMatch, series.Name, reducedValue),
			})
		}

		if evalMatch {
			evalMatchCount++

			matches = append(matches, &alerting.EvalMatch{
				Metric: series.Name,
				Value:  reducedValue,
			})
		}
	}

	// handle no series special case
	if len(seriesList) == 0 {
		// eval condition for null value
		evalMatch := c.Evaluator.Eval(null.FloatFromPtr(nil))

		if context.IsTestRun {
			context.Logs = append(context.Logs, &alerting.ResultLogEntry{
				Message: fmt.Sprintf("Condition[%d]: Eval: %v, Query Returned No Series (reduced to null/no value)", evalMatch),
			})
		}

		if evalMatch {
			evalMatchCount++
			matches = append(matches, &alerting.EvalMatch{Metric: "NoData", Value: null.FloatFromPtr(nil)})
		}
	}

	return &alerting.ConditionResult{
		Firing:      evalMatchCount > 0,
		NoDataFound: emptySerieCount == len(seriesList),
		Operator:    c.Operator,
		EvalMatches: matches,
	}, nil
}
Example #3
0
// POST /api/tsdb/query
func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
	timeRange := tsdb.NewTimeRange(reqDto.From, reqDto.To)

	request := &tsdb.Request{TimeRange: timeRange}

	for _, query := range reqDto.Queries {
		request.Queries = append(request.Queries, &tsdb.Query{
			RefId:         query.Get("refId").MustString("A"),
			MaxDataPoints: query.Get("maxDataPoints").MustInt64(100),
			IntervalMs:    query.Get("intervalMs").MustInt64(1000),
			Model:         query,
			DataSource: &models.DataSource{
				Name: "Grafana TestDataDB",
				Type: "grafana-testdata-datasource",
			},
		})
	}

	resp, err := tsdb.HandleRequest(context.TODO(), request)
	if err != nil {
		return ApiError(500, "Metric request error", err)
	}

	return Json(200, &resp)
}
Example #4
0
func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.ConditionResult, error) {
	timeRange := tsdb.NewTimeRange(c.Query.From, c.Query.To)

	seriesList, err := c.executeQuery(context, timeRange)
	if err != nil {
		return nil, err
	}

	emptySerieCount := 0
	evalMatchCount := 0
	var matches []*alerting.EvalMatch
	for _, series := range seriesList {
		reducedValue := c.Reducer.Reduce(series)
		evalMatch := c.Evaluator.Eval(reducedValue)

		if reducedValue.Valid == false {
			emptySerieCount++
			continue
		}

		if context.IsTestRun {
			context.Logs = append(context.Logs, &alerting.ResultLogEntry{
				Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, evalMatch, series.Name, reducedValue.Float64),
			})
		}

		if evalMatch {
			evalMatchCount++

			matches = append(matches, &alerting.EvalMatch{
				Metric: series.Name,
				Value:  reducedValue.Float64,
			})
		}
	}

	return &alerting.ConditionResult{
		Firing:      evalMatchCount > 0,
		NoDataFound: emptySerieCount == len(seriesList),
		Operator:    c.Operator,
		EvalMatches: matches,
	}, nil
}
Example #5
0
func TestInfluxdbQueryPart(t *testing.T) {
	Convey("Influxdb query parts", t, func() {

		queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("5m", "now")}
		query := &Query{}

		Convey("render field ", func() {
			part, err := NewQueryPart("field", []string{"value"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "value")
			So(res, ShouldEqual, `"value"`)
		})

		Convey("render nested part", func() {
			part, err := NewQueryPart("derivative", []string{"10s"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "mean(value)")
			So(res, ShouldEqual, "derivative(mean(value), 10s)")
		})

		Convey("render bottom", func() {
			part, err := NewQueryPart("bottom", []string{"3"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "value")
			So(res, ShouldEqual, "bottom(value, 3)")
		})

		Convey("render time with $interval", func() {
			part, err := NewQueryPart("time", []string{"$interval"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "")
			So(res, ShouldEqual, "time($interval)")
		})

		Convey("render time with auto", func() {
			part, err := NewQueryPart("time", []string{"auto"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "")
			So(res, ShouldEqual, "time($__interval)")
		})

		Convey("render spread", func() {
			part, err := NewQueryPart("spread", []string{})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "value")
			So(res, ShouldEqual, `spread(value)`)
		})

		Convey("render suffix", func() {
			part, err := NewQueryPart("math", []string{"/ 100"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "mean(value)")
			So(res, ShouldEqual, "mean(value) / 100")
		})

		Convey("render alias", func() {
			part, err := NewQueryPart("alias", []string{"test"})
			So(err, ShouldBeNil)

			res := part.Render(query, queryContext, "mean(value)")
			So(res, ShouldEqual, `mean(value) AS "test"`)
		})
	})
}
Example #6
0
func TestInfluxdbQueryBuilder(t *testing.T) {

	Convey("Influxdb query builder", t, func() {
		builder := QueryBuilder{}

		qp1, _ := NewQueryPart("field", []string{"value"})
		qp2, _ := NewQueryPart("mean", []string{})

		groupBy1, _ := NewQueryPart("time", []string{"$interval"})
		groupBy2, _ := NewQueryPart("tag", []string{"datacenter"})
		groupBy3, _ := NewQueryPart("fill", []string{"null"})

		tag1 := &Tag{Key: "hostname", Value: "server1", Operator: "="}
		tag2 := &Tag{Key: "hostname", Value: "server2", Operator: "=", Condition: "OR"}

		queryContext := &tsdb.QueryContext{
			TimeRange: tsdb.NewTimeRange("5m", "now"),
		}

		Convey("can build simple query", func() {
			query := &Query{
				Selects:     []*Select{{*qp1, *qp2}},
				Measurement: "cpu",
				Policy:      "policy",
				GroupBy:     []*QueryPart{groupBy1, groupBy3},
				Interval:    "10s",
			}

			rawQuery, err := builder.Build(query, queryContext)
			So(err, ShouldBeNil)
			So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(10s) fill(null)`)
		})

		Convey("can build query with group bys", func() {
			query := &Query{
				Selects:     []*Select{{*qp1, *qp2}},
				Measurement: "cpu",
				GroupBy:     []*QueryPart{groupBy1, groupBy2, groupBy3},
				Tags:        []*Tag{tag1, tag2},
				Interval:    "5s",
			}

			rawQuery, err := builder.Build(query, queryContext)
			So(err, ShouldBeNil)
			So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(5s), "datacenter" fill(null)`)
		})

		Convey("can render time range", func() {
			query := Query{}
			builder := &QueryBuilder{}
			Convey("render from: 2h to now-1h", func() {
				query := Query{}
				queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("2h", "now-1h")}
				So(builder.renderTimeFilter(&query, queryContext), ShouldEqual, "time > now() - 2h and time < now() - 1h")
			})

			Convey("render from: 10m", func() {
				queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("10m", "now")}
				So(builder.renderTimeFilter(&query, queryContext), ShouldEqual, "time > now() - 10m")
			})
		})

		Convey("can build query from raw query", func() {
			query := &Query{
				Selects:     []*Select{{*qp1, *qp2}},
				Measurement: "cpu",
				Policy:      "policy",
				GroupBy:     []*QueryPart{groupBy1, groupBy3},
				Interval:    "10s",
				RawQuery:    "Raw query",
			}

			rawQuery, err := builder.Build(query, queryContext)
			So(err, ShouldBeNil)
			So(rawQuery, ShouldEqual, `Raw query`)
		})
	})
}
Example #7
0
func TestInfluxdbQueryBuilder(t *testing.T) {

	Convey("Influxdb query builder", t, func() {

		qp1, _ := NewQueryPart("field", []string{"value"})
		qp2, _ := NewQueryPart("mean", []string{})

		groupBy1, _ := NewQueryPart("time", []string{"$interval"})
		groupBy2, _ := NewQueryPart("tag", []string{"datacenter"})
		groupBy3, _ := NewQueryPart("fill", []string{"null"})

		tag1 := &Tag{Key: "hostname", Value: "server1", Operator: "="}
		tag2 := &Tag{Key: "hostname", Value: "server2", Operator: "=", Condition: "OR"}

		queryContext := &tsdb.QueryContext{
			TimeRange: tsdb.NewTimeRange("5m", "now"),
		}

		Convey("can build simple query", func() {
			query := &Query{
				Selects:     []*Select{{*qp1, *qp2}},
				Measurement: "cpu",
				Policy:      "policy",
				GroupBy:     []*QueryPart{groupBy1, groupBy3},
				Interval:    "10s",
			}

			rawQuery, err := query.Build(queryContext)
			So(err, ShouldBeNil)
			So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(10s) fill(null)`)
		})

		Convey("can build query with group bys", func() {
			query := &Query{
				Selects:     []*Select{{*qp1, *qp2}},
				Measurement: "cpu",
				GroupBy:     []*QueryPart{groupBy1, groupBy2, groupBy3},
				Tags:        []*Tag{tag1, tag2},
				Interval:    "5s",
			}

			rawQuery, err := query.Build(queryContext)
			So(err, ShouldBeNil)
			So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(5s), "datacenter" fill(null)`)
		})

		Convey("can render time range", func() {
			query := Query{}
			Convey("render from: 2h to now-1h", func() {
				query := Query{}
				queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("2h", "now-1h")}
				So(query.renderTimeFilter(queryContext), ShouldEqual, "time > now() - 2h and time < now() - 1h")
			})

			Convey("render from: 10m", func() {
				queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("10m", "now")}
				So(query.renderTimeFilter(queryContext), ShouldEqual, "time > now() - 10m")
			})
		})

		Convey("can build query from raw query", func() {
			query := &Query{
				Selects:     []*Select{{*qp1, *qp2}},
				Measurement: "cpu",
				Policy:      "policy",
				GroupBy:     []*QueryPart{groupBy1, groupBy3},
				Interval:    "10s",
				RawQuery:    "Raw query",
				UseRawQuery: true,
			}

			rawQuery, err := query.Build(queryContext)
			So(err, ShouldBeNil)
			So(rawQuery, ShouldEqual, `Raw query`)
		})

		Convey("can render normal tags without operator", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: "", Value: `value`, Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'value'`)
		})

		Convey("can render regex tags without operator", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: "", Value: `/value/`, Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" =~ /value/`)
		})

		Convey("can render regex tags", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: "=~", Value: `/value/`, Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" =~ /value/`)
		})

		Convey("can render number tags", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: "=", Value: "10001", Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = '10001'`)
		})

		Convey("can render numbers less then condition tags", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: "<", Value: "10001", Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" < 10001`)
		})

		Convey("can render number greather then condition tags", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: ">", Value: "10001", Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" > 10001`)
		})

		Convey("can render string tags", func() {
			query := &Query{Tags: []*Tag{&Tag{Operator: "=", Value: "value", Key: "key"}}}

			So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" = 'value'`)
		})

		Convey("can render regular measurement", func() {
			query := &Query{Measurement: `apa`, Policy: "policy"}

			So(query.renderMeasurement(), ShouldEqual, ` FROM "policy"."apa"`)
		})

		Convey("can render regexp measurement", func() {
			query := &Query{Measurement: `/apa/`, Policy: "policy"}

			So(query.renderMeasurement(), ShouldEqual, ` FROM "policy"./apa/`)
		})
	})
}