Skip to content

Commit bc634f2

Browse files
committed
Merge branch 'master' into go_routines
2 parents 991539e + 7a65016 commit bc634f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3397
-994
lines changed

pkg/api/api.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ func Register(r *macaron.Macaron) {
244244
r.Get("/search/", Search)
245245

246246
// metrics
247-
r.Get("/metrics/test", wrap(GetTestMetrics))
247+
r.Post("/tsdb/query", bind(dtos.MetricRequest{}), wrap(QueryMetrics))
248+
r.Get("/tsdb/testdata/scenarios", wrap(GetTestDataScenarios))
248249

249250
// metrics
250251
r.Get("/metrics", wrap(GetInternalMetrics))

pkg/api/dtos/models.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,10 @@ func (slice DataSourceList) Swap(i, j int) {
9696
slice[i], slice[j] = slice[j], slice[i]
9797
}
9898

99-
type MetricQueryResultDto struct {
100-
Data []MetricQueryResultDataDto `json:"data"`
101-
}
102-
103-
type MetricQueryResultDataDto struct {
104-
Target string `json:"target"`
105-
DataPoints [][2]float64 `json:"datapoints"`
99+
type MetricRequest struct {
100+
From string `json:"from"`
101+
To string `json:"to"`
102+
Queries []*simplejson.Json `json:"queries"`
106103
}
107104

108105
type UserStars struct {

pkg/api/index.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
165165
}
166166
}
167167

168-
if c.OrgRole == m.ROLE_ADMIN {
168+
if len(appLink.Children) > 0 && c.OrgRole == m.ROLE_ADMIN {
169169
appLink.Children = append(appLink.Children, &dtos.NavLink{Divider: true})
170170
appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "fa fa-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/edit"})
171171
}

pkg/api/metrics.go

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,54 @@ package api
22

33
import (
44
"encoding/json"
5-
"math/rand"
65
"net/http"
7-
"strconv"
86

97
"github.com/grafana/grafana/pkg/api/dtos"
108
"github.com/grafana/grafana/pkg/metrics"
119
"github.com/grafana/grafana/pkg/middleware"
10+
"github.com/grafana/grafana/pkg/tsdb"
11+
"github.com/grafana/grafana/pkg/tsdb/testdata"
1212
"github.com/grafana/grafana/pkg/util"
1313
)
1414

15-
func GetTestMetrics(c *middleware.Context) Response {
16-
from := c.QueryInt64("from")
17-
to := c.QueryInt64("to")
18-
maxDataPoints := c.QueryInt64("maxDataPoints")
19-
stepInSeconds := (to - from) / maxDataPoints
20-
21-
result := dtos.MetricQueryResultDto{}
22-
result.Data = make([]dtos.MetricQueryResultDataDto, 1)
23-
24-
for seriesIndex := range result.Data {
25-
points := make([][2]float64, maxDataPoints)
26-
walker := rand.Float64() * 100
27-
time := from
28-
29-
for i := range points {
30-
points[i][0] = walker
31-
points[i][1] = float64(time)
32-
walker += rand.Float64() - 0.5
33-
time += stepInSeconds
34-
}
15+
// POST /api/tsdb/query
16+
func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response {
17+
timeRange := tsdb.NewTimeRange(reqDto.From, reqDto.To)
18+
19+
request := &tsdb.Request{TimeRange: timeRange}
20+
21+
for _, query := range reqDto.Queries {
22+
request.Queries = append(request.Queries, &tsdb.Query{
23+
RefId: query.Get("refId").MustString("A"),
24+
MaxDataPoints: query.Get("maxDataPoints").MustInt64(100),
25+
IntervalMs: query.Get("intervalMs").MustInt64(1000),
26+
Model: query,
27+
DataSource: &tsdb.DataSourceInfo{
28+
Name: "Grafana TestDataDB",
29+
PluginId: "grafana-testdata-datasource",
30+
},
31+
})
32+
}
33+
34+
resp, err := tsdb.HandleRequest(request)
35+
if err != nil {
36+
return ApiError(500, "Metric request error", err)
37+
}
38+
39+
return Json(200, &resp)
40+
}
3541

36-
result.Data[seriesIndex].Target = "test-series-" + strconv.Itoa(seriesIndex)
37-
result.Data[seriesIndex].DataPoints = points
42+
// GET /api/tsdb/testdata/scenarios
43+
func GetTestDataScenarios(c *middleware.Context) Response {
44+
result := make([]interface{}, 0)
45+
46+
for _, scenario := range testdata.ScenarioRegistry {
47+
result = append(result, map[string]interface{}{
48+
"id": scenario.Id,
49+
"name": scenario.Name,
50+
"description": scenario.Description,
51+
"stringInput": scenario.StringInput,
52+
})
3853
}
3954

4055
return Json(200, &result)

pkg/plugins/datasource_plugin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ type DataSourcePlugin struct {
66
FrontendPluginBase
77
Annotations bool `json:"annotations"`
88
Metrics bool `json:"metrics"`
9+
Alerting bool `json:"alerting"`
910
BuiltIn bool `json:"builtIn"`
1011
Mixed bool `json:"mixed"`
1112
App string `json:"app"`

pkg/plugins/frontend_plugin.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin) {
4343
appSubPath := strings.Replace(fp.PluginDir, app.PluginDir, "", 1)
4444
fp.IncludedInAppId = app.Id
4545
fp.BaseUrl = app.BaseUrl
46-
fp.Module = util.JoinUrlFragments("plugins/"+app.Id, appSubPath) + "/module"
46+
47+
if isExternalPlugin(app.PluginDir) {
48+
fp.Module = util.JoinUrlFragments("plugins/"+app.Id, appSubPath) + "/module"
49+
} else {
50+
fp.Module = util.JoinUrlFragments("app/plugins/app/"+app.Id, appSubPath) + "/module"
51+
}
4752
}
4853

4954
func (fp *FrontendPluginBase) handleModuleDefaults() {

pkg/services/alerting/conditions/evaluator.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/grafana/grafana/pkg/components/simplejson"
77
"github.com/grafana/grafana/pkg/services/alerting"
8+
"gopkg.in/guregu/null.v3"
89
)
910

1011
var (
@@ -13,13 +14,13 @@ var (
1314
)
1415

1516
type AlertEvaluator interface {
16-
Eval(reducedValue *float64) bool
17+
Eval(reducedValue null.Float) bool
1718
}
1819

1920
type NoDataEvaluator struct{}
2021

21-
func (e *NoDataEvaluator) Eval(reducedValue *float64) bool {
22-
return reducedValue == nil
22+
func (e *NoDataEvaluator) Eval(reducedValue null.Float) bool {
23+
return reducedValue.Valid == false
2324
}
2425

2526
type ThresholdEvaluator struct {
@@ -43,16 +44,16 @@ func newThresholdEvaludator(typ string, model *simplejson.Json) (*ThresholdEvalu
4344
return defaultEval, nil
4445
}
4546

46-
func (e *ThresholdEvaluator) Eval(reducedValue *float64) bool {
47-
if reducedValue == nil {
47+
func (e *ThresholdEvaluator) Eval(reducedValue null.Float) bool {
48+
if reducedValue.Valid == false {
4849
return false
4950
}
5051

5152
switch e.Type {
5253
case "gt":
53-
return *reducedValue > e.Threshold
54+
return reducedValue.Float64 > e.Threshold
5455
case "lt":
55-
return *reducedValue < e.Threshold
56+
return reducedValue.Float64 < e.Threshold
5657
}
5758

5859
return false
@@ -86,16 +87,18 @@ func newRangedEvaluator(typ string, model *simplejson.Json) (*RangedEvaluator, e
8687
return rangedEval, nil
8788
}
8889

89-
func (e *RangedEvaluator) Eval(reducedValue *float64) bool {
90-
if reducedValue == nil {
90+
func (e *RangedEvaluator) Eval(reducedValue null.Float) bool {
91+
if reducedValue.Valid == false {
9192
return false
9293
}
9394

95+
floatValue := reducedValue.Float64
96+
9497
switch e.Type {
9598
case "within_range":
96-
return (e.Lower < *reducedValue && e.Upper > *reducedValue) || (e.Upper < *reducedValue && e.Lower > *reducedValue)
99+
return (e.Lower < floatValue && e.Upper > floatValue) || (e.Upper < floatValue && e.Lower > floatValue)
97100
case "outside_range":
98-
return (e.Upper < *reducedValue && e.Lower < *reducedValue) || (e.Upper > *reducedValue && e.Lower > *reducedValue)
101+
return (e.Upper < floatValue && e.Lower < floatValue) || (e.Upper > floatValue && e.Lower > floatValue)
99102
}
100103

101104
return false

pkg/services/alerting/conditions/evaluator_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package conditions
33
import (
44
"testing"
55

6+
"gopkg.in/guregu/null.v3"
7+
68
"github.com/grafana/grafana/pkg/components/simplejson"
79
. "github.com/smartystreets/goconvey/convey"
810
)
@@ -14,7 +16,7 @@ func evalutorScenario(json string, reducedValue float64, datapoints ...float64)
1416
evaluator, err := NewAlertEvaluator(jsonModel)
1517
So(err, ShouldBeNil)
1618

17-
return evaluator.Eval(&reducedValue)
19+
return evaluator.Eval(null.FloatFrom(reducedValue))
1820
}
1921

2022
func TestEvalutors(t *testing.T) {
@@ -51,6 +53,6 @@ func TestEvalutors(t *testing.T) {
5153
evaluator, err := NewAlertEvaluator(jsonModel)
5254
So(err, ShouldBeNil)
5355

54-
So(evaluator.Eval(nil), ShouldBeTrue)
56+
So(evaluator.Eval(null.FloatFromPtr(nil)), ShouldBeTrue)
5557
})
5658
}

pkg/services/alerting/conditions/query.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ type AlertQuery struct {
3434
}
3535

3636
func (c *QueryCondition) Eval(context *alerting.EvalContext) {
37-
timerange := tsdb.NewTimerange(c.Query.From, c.Query.To)
38-
seriesList, err := c.executeQuery(context, timerange)
37+
timeRange := tsdb.NewTimeRange(c.Query.From, c.Query.To)
38+
seriesList, err := c.executeQuery(context, timeRange)
3939
if err != nil {
4040
context.Error = err
4141
return
@@ -46,21 +46,21 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) {
4646
reducedValue := c.Reducer.Reduce(series)
4747
evalMatch := c.Evaluator.Eval(reducedValue)
4848

49-
if reducedValue == nil {
49+
if reducedValue.Valid == false {
5050
emptySerieCount++
5151
continue
5252
}
5353

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

6060
if evalMatch {
6161
context.EvalMatches = append(context.EvalMatches, &alerting.EvalMatch{
6262
Metric: series.Name,
63-
Value: *reducedValue,
63+
Value: reducedValue.Float64,
6464
})
6565
}
6666
}
@@ -69,7 +69,7 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) {
6969
context.Firing = len(context.EvalMatches) > 0
7070
}
7171

72-
func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timerange tsdb.TimeRange) (tsdb.TimeSeriesSlice, error) {
72+
func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange *tsdb.TimeRange) (tsdb.TimeSeriesSlice, error) {
7373
getDsInfo := &m.GetDataSourceByIdQuery{
7474
Id: c.Query.DatasourceId,
7575
OrgId: context.Rule.OrgId,
@@ -79,7 +79,7 @@ func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timerange t
7979
return nil, fmt.Errorf("Could not find datasource")
8080
}
8181

82-
req := c.getRequestForAlertRule(getDsInfo.Result, timerange)
82+
req := c.getRequestForAlertRule(getDsInfo.Result, timeRange)
8383
result := make(tsdb.TimeSeriesSlice, 0)
8484

8585
resp, err := c.HandleRequest(req)
@@ -105,9 +105,9 @@ func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timerange t
105105
return result, nil
106106
}
107107

108-
func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource, timerange tsdb.TimeRange) *tsdb.Request {
108+
func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource, timeRange *tsdb.TimeRange) *tsdb.Request {
109109
req := &tsdb.Request{
110-
TimeRange: timerange,
110+
TimeRange: timeRange,
111111
Queries: []*tsdb.Query{
112112
{
113113
RefId: "A",

pkg/services/alerting/conditions/query_test.go

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package conditions
33
import (
44
"testing"
55

6+
null "gopkg.in/guregu/null.v3"
7+
68
"github.com/grafana/grafana/pkg/bus"
79
"github.com/grafana/grafana/pkg/components/simplejson"
810
m "github.com/grafana/grafana/pkg/models"
@@ -41,31 +43,27 @@ func TestQueryCondition(t *testing.T) {
4143
})
4244

4345
Convey("should fire when avg is above 100", func() {
44-
one := float64(120)
45-
two := float64(0)
46-
ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", [][2]*float64{{&one, &two}})}
46+
points := tsdb.NewTimeSeriesPointsFromArgs(120, 0)
47+
ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", points)}
4748
ctx.exec()
4849

4950
So(ctx.result.Error, ShouldBeNil)
5051
So(ctx.result.Firing, ShouldBeTrue)
5152
})
5253

5354
Convey("Should not fire when avg is below 100", func() {
54-
one := float64(90)
55-
two := float64(0)
56-
ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", [][2]*float64{{&one, &two}})}
55+
points := tsdb.NewTimeSeriesPointsFromArgs(90, 0)
56+
ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", points)}
5757
ctx.exec()
5858

5959
So(ctx.result.Error, ShouldBeNil)
6060
So(ctx.result.Firing, ShouldBeFalse)
6161
})
6262

6363
Convey("Should fire if only first serie matches", func() {
64-
one := float64(120)
65-
two := float64(0)
6664
ctx.series = tsdb.TimeSeriesSlice{
67-
tsdb.NewTimeSeries("test1", [][2]*float64{{&one, &two}}),
68-
tsdb.NewTimeSeries("test2", [][2]*float64{{&two, &two}}),
65+
tsdb.NewTimeSeries("test1", tsdb.NewTimeSeriesPointsFromArgs(120, 0)),
66+
tsdb.NewTimeSeries("test2", tsdb.NewTimeSeriesPointsFromArgs(0, 0)),
6967
}
7068
ctx.exec()
7169

@@ -76,8 +74,8 @@ func TestQueryCondition(t *testing.T) {
7674
Convey("Empty series", func() {
7775
Convey("Should set NoDataFound both series are empty", func() {
7876
ctx.series = tsdb.TimeSeriesSlice{
79-
tsdb.NewTimeSeries("test1", [][2]*float64{}),
80-
tsdb.NewTimeSeries("test2", [][2]*float64{}),
77+
tsdb.NewTimeSeries("test1", tsdb.NewTimeSeriesPointsFromArgs()),
78+
tsdb.NewTimeSeries("test2", tsdb.NewTimeSeriesPointsFromArgs()),
8179
}
8280
ctx.exec()
8381

@@ -86,10 +84,9 @@ func TestQueryCondition(t *testing.T) {
8684
})
8785

8886
Convey("Should set NoDataFound both series contains null", func() {
89-
one := float64(120)
9087
ctx.series = tsdb.TimeSeriesSlice{
91-
tsdb.NewTimeSeries("test1", [][2]*float64{{nil, &one}}),
92-
tsdb.NewTimeSeries("test2", [][2]*float64{{nil, &one}}),
88+
tsdb.NewTimeSeries("test1", tsdb.TimeSeriesPoints{tsdb.TimePoint{null.FloatFromPtr(nil), null.FloatFrom(0)}}),
89+
tsdb.NewTimeSeries("test2", tsdb.TimeSeriesPoints{tsdb.TimePoint{null.FloatFromPtr(nil), null.FloatFrom(0)}}),
9390
}
9491
ctx.exec()
9592

@@ -98,11 +95,9 @@ func TestQueryCondition(t *testing.T) {
9895
})
9996

10097
Convey("Should not set NoDataFound if one serie is empty", func() {
101-
one := float64(120)
102-
two := float64(0)
10398
ctx.series = tsdb.TimeSeriesSlice{
104-
tsdb.NewTimeSeries("test1", [][2]*float64{}),
105-
tsdb.NewTimeSeries("test2", [][2]*float64{{&one, &two}}),
99+
tsdb.NewTimeSeries("test1", tsdb.NewTimeSeriesPointsFromArgs()),
100+
tsdb.NewTimeSeries("test2", tsdb.NewTimeSeriesPointsFromArgs(120, 0)),
106101
}
107102
ctx.exec()
108103

0 commit comments

Comments
 (0)