ソースを参照

feat(alerting): rename alertrule model to alertruleDAO

bergquist 9 年 前
コミット
ef35184a80

+ 12 - 14
pkg/models/alerts.go

@@ -6,7 +6,7 @@ import (
 	"github.com/grafana/grafana/pkg/components/simplejson"
 )
 
-type AlertRule struct {
+type AlertRuleDAO struct {
 	Id          int64
 	OrgId       int64
 	DashboardId int64
@@ -21,11 +21,15 @@ type AlertRule struct {
 	Expression *simplejson.Json
 }
 
-func (alertRule *AlertRule) ValidToSave() bool {
-	return true
+func (this AlertRuleDAO) TableName() string {
+	return "alert_rule"
 }
 
-func (this *AlertRule) ContainsUpdates(other *AlertRule) bool {
+func (alertRule *AlertRuleDAO) ValidToSave() bool {
+	return alertRule.DashboardId != 0
+}
+
+func (this *AlertRuleDAO) ContainsUpdates(other *AlertRuleDAO) bool {
 	result := false
 
 	result = result || this.Name != other.Name
@@ -78,7 +82,7 @@ type SaveAlertsCommand struct {
 	UserId      int64
 	OrgId       int64
 
-	Alerts []*AlertRule
+	Alerts []*AlertRuleDAO
 }
 
 type DeleteAlertCommand struct {
@@ -92,23 +96,17 @@ type GetAlertsQuery struct {
 	DashboardId int64
 	PanelId     int64
 
-	Result []*AlertRule
+	Result []*AlertRuleDAO
 }
 
 type GetAllAlertsQuery struct {
-	Result []*AlertRule
-}
-
-type GetAlertsForExecutionQuery struct {
-	Timestamp int64
-
-	Result []*AlertRule
+	Result []*AlertRuleDAO
 }
 
 type GetAlertByIdQuery struct {
 	Id int64
 
-	Result *AlertRule
+	Result *AlertRuleDAO
 }
 
 type GetAlertChangesQuery struct {

+ 1 - 1
pkg/models/alerts_state.go

@@ -31,7 +31,7 @@ type UpdateAlertStateCommand struct {
 	NewState string `json:"newState" binding:"Required"`
 	Info     string `json:"info"`
 
-	Result *AlertRule
+	Result *AlertRuleDAO
 }
 
 // Queries

+ 2 - 2
pkg/models/alerts_test.go

@@ -13,13 +13,13 @@ func TestAlertingModelTest(t *testing.T) {
 		json1, _ := simplejson.NewJson([]byte(`{ "field": "value" }`))
 		json2, _ := simplejson.NewJson([]byte(`{ "field": "value" }`))
 
-		rule1 := &AlertRule{
+		rule1 := &AlertRuleDAO{
 			Expression:  json1,
 			Name:        "Namn",
 			Description: "Description",
 		}
 
-		rule2 := &AlertRule{
+		rule2 := &AlertRuleDAO{
 			Expression:  json2,
 			Name:        "Namn",
 			Description: "Description",

+ 37 - 24
pkg/services/alerting/dashboard_parser.go

@@ -1,14 +1,16 @@
 package alerting
 
 import (
+	"fmt"
+
 	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/components/simplejson"
 	"github.com/grafana/grafana/pkg/log"
 	m "github.com/grafana/grafana/pkg/models"
 )
 
-func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
-	alerts := make([]*m.AlertRule, 0)
+func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRuleDAO {
+	alerts := make([]*m.AlertRuleDAO, 0)
 
 	for _, rowObj := range cmd.Dashboard.Get("rows").MustArray() {
 		row := simplejson.NewFromAny(rowObj)
@@ -17,7 +19,7 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
 			panel := simplejson.NewFromAny(panelObj)
 
 			alerting := panel.Get("alerting")
-			alert := &m.AlertRule{
+			alert := &m.AlertRuleDAO{
 				DashboardId: cmd.Result.Id,
 				OrgId:       cmd.Result.OrgId,
 				PanelId:     panel.Get("id").MustInt64(),
@@ -28,8 +30,7 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
 
 			log.Info("Alertrule: %v", alert.Name)
 
-			expression := alerting
-			valueQuery := expression.Get("valueQuery")
+			valueQuery := alerting.Get("valueQuery")
 			valueQueryRef := valueQuery.Get("queryRefId").MustString()
 			for _, targetsObj := range panel.Get("targets").MustArray() {
 				target := simplejson.NewFromAny(targetsObj)
@@ -47,7 +48,7 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
 						if err := bus.Dispatch(query); err == nil {
 							for _, ds := range query.Result {
 								if ds.IsDefault {
-									valueQuery.Set("datasourceId", ds.Id)
+									alerting.SetPath([]string{"valueQuery", "datasourceId"}, ds.Id)
 								}
 							}
 						}
@@ -57,59 +58,71 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
 							OrgId: cmd.OrgId,
 						}
 						bus.Dispatch(query)
-						valueQuery.Set("datasourceId", query.Result.Id)
+						alerting.SetPath([]string{"valueQuery", "datasourceId"}, query.Result.Id)
 					}
 
 					targetQuery := target.Get("target").MustString()
 					if targetQuery != "" {
-						valueQuery.Set("query", targetQuery)
+						alerting.SetPath([]string{"valueQuery", "query"}, targetQuery)
 					}
 				}
 			}
 
-			expression.Set("valueQuery", valueQuery)
-			alert.Expression = expression
-
-			alertRule := &AlertRule{}
+			alert.Expression = alerting
 
-			ParseAlertRulesFromAlertModel(alert, alertRule)
+			_, err := ParseAlertRulesFromAlertModel(alert)
 
-			if alert.ValidToSave() && alertRule.IsValid() {
+			if err == nil && alert.ValidToSave() {
 				alerts = append(alerts, alert)
+			} else {
+				log.Error2("Failed to parse model from expression", "error", err)
 			}
+
 		}
 	}
 
 	return alerts
 }
 
-func (rule *AlertRule) IsValid() bool {
-	return rule.ValueQuery.Query != ""
-}
+func ParseAlertRulesFromAlertModel(ruleDef *m.AlertRuleDAO) (*AlertRule, error) {
+	model := &AlertRule{}
+	model.Id = ruleDef.Id
+	model.OrgId = ruleDef.OrgId
+	model.Name = ruleDef.Name
+	model.Description = ruleDef.Description
+	model.State = ruleDef.State
 
-func ParseAlertRulesFromAlertModel(ruleDef *m.AlertRule, model *AlertRule) error {
 	critical := ruleDef.Expression.Get("critical")
 	model.Critical = Level{
-		Operator: critical.Get("operator").MustString(),
+		Operator: critical.Get("op").MustString(),
 		Level:    critical.Get("level").MustFloat64(),
 	}
 
 	warning := ruleDef.Expression.Get("warning")
 	model.Warning = Level{
-		Operator: warning.Get("operator").MustString(),
+		Operator: warning.Get("op").MustString(),
 		Level:    warning.Get("level").MustFloat64(),
 	}
 
 	model.Frequency = ruleDef.Expression.Get("frequency").MustInt64()
 
 	valueQuery := ruleDef.Expression.Get("valueQuery")
+
 	model.ValueQuery = AlertQuery{
 		Query:        valueQuery.Get("query").MustString(),
 		DatasourceId: valueQuery.Get("datasourceId").MustInt64(),
-		From:         valueQuery.Get("From").MustInt64(),
-		Until:        valueQuery.Get("until").MustInt64(),
-		Aggregator:   valueQuery.Get("aggregator").MustString(),
+		From:         valueQuery.Get("from").MustString(),
+		To:           valueQuery.Get("to").MustString(),
+		Aggregator:   valueQuery.Get("agg").MustString(),
+	}
+
+	if model.ValueQuery.Query == "" {
+		return nil, fmt.Errorf("missing valueQuery query")
+	}
+
+	if model.ValueQuery.DatasourceId == 0 {
+		return nil, fmt.Errorf("missing valueQuery datasourceId")
 	}
 
-	return nil
+	return model, nil
 }

+ 8 - 9
pkg/services/alerting/executor.go

@@ -2,7 +2,6 @@ package alerting
 
 import (
 	"fmt"
-	"strconv"
 
 	"math"
 
@@ -14,7 +13,6 @@ import (
 )
 
 var (
-	resultLogFmt   = "Alerting: executor %s  %1.2f %s %1.2f : %v"
 	descriptionFmt = "Actual value: %1.2f for %s"
 )
 
@@ -102,7 +100,7 @@ func (e *ExecutorImpl) Execute(job *AlertJob, resultQueue chan *AlertResult) {
 
 func (e *ExecutorImpl) executeQuery(job *AlertJob) (tsdb.TimeSeriesSlice, error) {
 	getDsInfo := &m.GetDataSourceByIdQuery{
-		Id:    1,
+		Id:    job.Rule.ValueQuery.DatasourceId,
 		OrgId: job.Rule.OrgId,
 	}
 
@@ -130,15 +128,16 @@ func (e *ExecutorImpl) executeQuery(job *AlertJob) (tsdb.TimeSeriesSlice, error)
 }
 
 func (e *ExecutorImpl) GetRequestForAlertRule(rule *AlertRule, datasource *m.DataSource) *tsdb.Request {
+	log.Debug2("GetRequest", "query", rule.ValueQuery.Query, "from", rule.ValueQuery.From, "datasourceId", datasource.Id)
 	req := &tsdb.Request{
 		TimeRange: tsdb.TimeRange{
-			From: "-" + strconv.Itoa(int(rule.ValueQuery.From)) + "s",
-			To:   "now",
+			From: "-" + rule.ValueQuery.From,
+			To:   rule.ValueQuery.To,
 		},
 		Queries: []*tsdb.Query{
 			{
 				RefId: "A",
-				Query: "apps.fakesite.*.counters.requests.count",
+				Query: rule.ValueQuery.Query,
 				DataSource: &tsdb.DataSourceInfo{
 					Id:       datasource.Id,
 					Name:     datasource.Name,
@@ -156,7 +155,7 @@ func (e *ExecutorImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice
 	e.log.Debug("Evaluating Alerting Rule", "seriesCount", len(series), "ruleName", rule.Name)
 
 	for _, serie := range series {
-		log.Debug("Evaluating series", "series", serie.Name)
+		e.log.Debug("Evaluating series", "series", serie.Name)
 
 		if aggregator["avg"] == nil {
 			continue
@@ -166,7 +165,7 @@ func (e *ExecutorImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice
 		var critOperartor = operators[rule.Critical.Operator]
 		var critResult = critOperartor(aggValue, rule.Critical.Level)
 
-		log.Trace(resultLogFmt, "Crit", serie.Name, aggValue, rule.Critical.Operator, rule.Critical.Level, critResult)
+		e.log.Debug("Alert execution Crit", "name", serie.Name, "aggValue", aggValue, "operator", rule.Critical.Operator, "level", rule.Critical.Level, "result", critResult)
 		if critResult {
 			return &AlertResult{
 				State:       alertstates.Critical,
@@ -177,7 +176,7 @@ func (e *ExecutorImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice
 
 		var warnOperartor = operators[rule.Warning.Operator]
 		var warnResult = warnOperartor(aggValue, rule.Warning.Level)
-		log.Trace(resultLogFmt, "Warn", serie.Name, aggValue, rule.Warning.Operator, rule.Warning.Level, warnResult)
+		e.log.Debug("Alert execution Warn", "name", serie.Name, "aggValue", aggValue, "operator", rule.Warning.Operator, "level", rule.Warning.Level, "result", warnResult)
 		if warnResult {
 			return &AlertResult{
 				State:       alertstates.Warn,

+ 2 - 2
pkg/services/alerting/models.go

@@ -49,6 +49,6 @@ type AlertQuery struct {
 	Query        string
 	DatasourceId int64
 	Aggregator   string
-	From         int64
-	Until        int64
+	From         string
+	To           string
 }

+ 1 - 9
pkg/services/alerting/rule_reader.go

@@ -49,15 +49,7 @@ func (arr *AlertRuleReader) Fetch() []*AlertRule {
 
 	res := make([]*AlertRule, len(cmd.Result))
 	for i, ruleDef := range cmd.Result {
-		model := &AlertRule{}
-		model.Id = ruleDef.Id
-		model.OrgId = ruleDef.OrgId
-		model.Name = ruleDef.Name
-		model.Description = ruleDef.Description
-		model.State = ruleDef.State
-
-		ParseAlertRulesFromAlertModel(ruleDef, model)
-
+		model, _ := ParseAlertRulesFromAlertModel(ruleDef)
 		res[i] = model
 	}
 

+ 4 - 2
pkg/services/alerting/scheduler.go

@@ -8,16 +8,18 @@ import (
 
 type SchedulerImpl struct {
 	jobs map[int64]*AlertJob
+	log  log.Logger
 }
 
 func NewScheduler() Scheduler {
 	return &SchedulerImpl{
 		jobs: make(map[int64]*AlertJob, 0),
+		log:  log.New("alerting.scheduler"),
 	}
 }
 
 func (s *SchedulerImpl) Update(rules []*AlertRule) {
-	log.Debug("Scheduler: Update()")
+	s.log.Debug("Scheduler: Update")
 
 	jobs := make(map[int64]*AlertJob, 0)
 
@@ -38,7 +40,7 @@ func (s *SchedulerImpl) Update(rules []*AlertRule) {
 		jobs[rule.Id] = job
 	}
 
-	log.Debug("Scheduler: Selected %d jobs", len(jobs))
+	s.log.Debug("Scheduler: Selected %d jobs", len(jobs))
 	s.jobs = jobs
 }
 

+ 10 - 10
pkg/services/sqlstore/alert_rule.go

@@ -64,7 +64,7 @@ func HeartBeat(query *m.HeartBeatCommand) error {
 */
 
 func GetAlertById(query *m.GetAlertByIdQuery) error {
-	alert := m.AlertRule{}
+	alert := m.AlertRuleDAO{}
 	has, err := x.Id(query.Id).Get(&alert)
 	if !has {
 		return fmt.Errorf("could not find alert")
@@ -78,7 +78,7 @@ func GetAlertById(query *m.GetAlertByIdQuery) error {
 }
 
 func GetAllAlertQueryHandler(query *m.GetAllAlertsQuery) error {
-	var alerts []*m.AlertRule
+	var alerts []*m.AlertRuleDAO
 	err := x.Sql("select * from alert_rule").Find(&alerts)
 	if err != nil {
 		return err
@@ -131,7 +131,7 @@ func HandleAlertsQuery(query *m.GetAlertsQuery) error {
 		sql.WriteString(")")
 	}
 
-	alerts := make([]*m.AlertRule, 0)
+	alerts := make([]*m.AlertRuleDAO, 0)
 	if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil {
 		return err
 	}
@@ -141,7 +141,7 @@ func HandleAlertsQuery(query *m.GetAlertsQuery) error {
 }
 
 func DeleteAlertDefinition(dashboardId int64, sess *xorm.Session) error {
-	alerts := make([]*m.AlertRule, 0)
+	alerts := make([]*m.AlertRuleDAO, 0)
 	sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)
 
 	for _, alert := range alerts {
@@ -172,10 +172,10 @@ func SaveAlerts(cmd *m.SaveAlertsCommand) error {
 	})
 }
 
-func upsertAlerts(alerts []*m.AlertRule, posted []*m.AlertRule, sess *xorm.Session) error {
+func upsertAlerts(alerts []*m.AlertRuleDAO, posted []*m.AlertRuleDAO, sess *xorm.Session) error {
 	for _, alert := range posted {
 		update := false
-		var alertToUpdate *m.AlertRule
+		var alertToUpdate *m.AlertRuleDAO
 
 		for _, k := range alerts {
 			if alert.PanelId == k.PanelId {
@@ -212,7 +212,7 @@ func upsertAlerts(alerts []*m.AlertRule, posted []*m.AlertRule, sess *xorm.Sessi
 	return nil
 }
 
-func deleteMissingAlerts(alerts []*m.AlertRule, posted []*m.AlertRule, sess *xorm.Session) error {
+func deleteMissingAlerts(alerts []*m.AlertRuleDAO, posted []*m.AlertRuleDAO, sess *xorm.Session) error {
 	for _, missingAlert := range alerts {
 		missing := true
 
@@ -238,12 +238,12 @@ func deleteMissingAlerts(alerts []*m.AlertRule, posted []*m.AlertRule, sess *xor
 	return nil
 }
 
-func GetAlertsByDashboardId2(dashboardId int64, sess *xorm.Session) ([]*m.AlertRule, error) {
-	alerts := make([]*m.AlertRule, 0)
+func GetAlertsByDashboardId2(dashboardId int64, sess *xorm.Session) ([]*m.AlertRuleDAO, error) {
+	alerts := make([]*m.AlertRuleDAO, 0)
 	err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)
 
 	if err != nil {
-		return []*m.AlertRule{}, err
+		return []*m.AlertRuleDAO{}, err
 	}
 
 	return alerts, nil

+ 1 - 1
pkg/services/sqlstore/alert_rule_changes.go

@@ -48,7 +48,7 @@ func GetAlertRuleChanges(query *m.GetAlertChangesQuery) error {
 	return nil
 }
 
-func SaveAlertChange(change string, alert *m.AlertRule, sess *xorm.Session) error {
+func SaveAlertChange(change string, alert *m.AlertRuleDAO, sess *xorm.Session) error {
 	_, err := sess.Insert(&m.AlertRuleChange{
 		OrgId:   alert.OrgId,
 		Type:    change,

+ 1 - 1
pkg/services/sqlstore/alert_rule_changes_test.go

@@ -20,7 +20,7 @@ func TestAlertRuleChangesDataAccess(t *testing.T) {
 		var err error
 
 		Convey("When dashboard is removed", func() {
-			items := []*m.AlertRule{
+			items := []*m.AlertRuleDAO{
 				{
 					PanelId:     1,
 					DashboardId: testDash.Id,

+ 76 - 0
pkg/services/sqlstore/alert_rule_parser_test.go

@@ -0,0 +1,76 @@
+package sqlstore
+
+import (
+	"testing"
+
+	"github.com/grafana/grafana/pkg/components/simplejson"
+	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/services/alerting"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestAlertRuleModelParsing(t *testing.T) {
+
+	Convey("Parsing alertRule from expression", t, func() {
+		alertRuleDAO := &m.AlertRuleDAO{}
+		json, _ := simplejson.NewJson([]byte(`
+      {
+        "critical": {
+          "level": 20,
+          "op": ">"
+        },
+        "description": "Alerting Panel Title alert",
+        "evalQuery": {
+          "agg": "avg",
+          "from": "5m",
+          "params": [
+            "#A",
+            "5m",
+            "now",
+            "avg"
+          ],
+          "queryRefId": "A",
+          "to": "now"
+        },
+        "evalStringParam1": "",
+        "frequency": 10,
+        "function": "static",
+        "name": "Alerting Panel Title alert",
+        "queryRef": "- select query -",
+        "valueQuery": {
+          "agg": "avg",
+          "datasourceId": 1,
+          "from": "5m",
+          "params": [
+            "#A",
+            "5m",
+            "now",
+            "avg"
+          ],
+          "query": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)",
+          "queryRefId": "A",
+          "to": "now"
+        },
+        "warning": {
+          "level": 10,
+          "op": ">"
+        }
+      }`))
+
+		alertRuleDAO.Name = "Test"
+		alertRuleDAO.Expression = json
+		rule, _ := alerting.ParseAlertRulesFromAlertModel(alertRuleDAO)
+
+		Convey("Confirm that all properties are set", func() {
+			So(rule.ValueQuery.Query, ShouldEqual, "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)")
+			So(rule.ValueQuery.From, ShouldEqual, "5m")
+			So(rule.ValueQuery.To, ShouldEqual, "now")
+			So(rule.ValueQuery.DatasourceId, ShouldEqual, 1)
+			So(rule.ValueQuery.Aggregator, ShouldEqual, "avg")
+			So(rule.Warning.Level, ShouldEqual, 10)
+			So(rule.Warning.Operator, ShouldEqual, ">")
+			So(rule.Critical.Level, ShouldEqual, 20)
+			So(rule.Critical.Operator, ShouldEqual, ">")
+		})
+	})
+}

+ 3 - 3
pkg/services/sqlstore/alert_rule_test.go

@@ -13,7 +13,7 @@ func TestAlertingDataAccess(t *testing.T) {
 
 		testDash := insertTestDashboard("dashboard with alerts", 1, "alert")
 
-		items := []*m.AlertRule{
+		items := []*m.AlertRuleDAO{
 			{
 				PanelId:     1,
 				DashboardId: testDash.Id,
@@ -95,7 +95,7 @@ func TestAlertingDataAccess(t *testing.T) {
 		})
 
 		Convey("Multiple alerts per dashboard", func() {
-			multipleItems := []*m.AlertRule{
+			multipleItems := []*m.AlertRuleDAO{
 				{
 					DashboardId: testDash.Id,
 					PanelId:     1,
@@ -157,7 +157,7 @@ func TestAlertingDataAccess(t *testing.T) {
 		})
 
 		Convey("When dashboard is removed", func() {
-			items := []*m.AlertRule{
+			items := []*m.AlertRuleDAO{
 				{
 					PanelId:     1,
 					DashboardId: testDash.Id,

+ 1 - 1
pkg/services/sqlstore/alert_state.go

@@ -19,7 +19,7 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error {
 			return fmt.Errorf("new state is invalid")
 		}
 
-		alert := m.AlertRule{}
+		alert := m.AlertRuleDAO{}
 		has, err := sess.Id(cmd.AlertId).Get(&alert)
 		if !has {
 			return fmt.Errorf("Could not find alert")

+ 1 - 1
pkg/services/sqlstore/alert_state_test.go

@@ -13,7 +13,7 @@ func TestAlertingStateAccess(t *testing.T) {
 
 		testDash := insertTestDashboard("dashboard with alerts", 1, "alert")
 
-		items := []*m.AlertRule{
+		items := []*m.AlertRuleDAO{
 			{
 				PanelId:     1,
 				DashboardId: testDash.Id,

+ 53 - 258
pkg/services/sqlstore/dashboard_parser_test.go

@@ -9,34 +9,25 @@ import (
 	. "github.com/smartystreets/goconvey/convey"
 )
 
-func TestAlertModel(t *testing.T) {
+func TestAlertModelParsing(t *testing.T) {
 
-	Convey("Parsing alerts from dashboard", t, func() {
-		json := `{
+	Convey("Parsing alert info from json", t, func() {
+		Convey("Parsing and validating alerts from dashboards", func() {
+			json := `{
   "id": 57,
   "title": "Graphite 4",
   "originalTitle": "Graphite 4",
   "tags": [
     "graphite"
   ],
-  "style": "dark",
-  "timezone": "browser",
-  "editable": true,
-  "hideControls": false,
-  "sharedCrosshair": false,
   "rows": [
     {
-      "collapse": false,
-      "editable": true,
-      "height": "250px",
+
       "panels": [
         {
           "title": "Active desktop users",
-          "error": false,
-          "span": 6,
           "editable": true,
           "type": "graph",
-          "isNew": true,
           "id": 3,
           "targets": [
             {
@@ -45,65 +36,9 @@ func TestAlertModel(t *testing.T) {
             }
           ],
           "datasource": null,
-          "renderer": "flot",
-          "yaxes": [
-            {
-              "label": null,
-              "show": true,
-              "logBase": 1,
-              "min": null,
-              "max": null,
-              "format": "short"
-            },
-            {
-              "label": null,
-              "show": true,
-              "logBase": 1,
-              "min": null,
-              "max": null,
-              "format": "short"
-            }
-          ],
-          "xaxis": {
-            "show": true
-          },
-          "grid": {
-            "threshold1": null,
-            "threshold2": null,
-            "threshold1Color": "rgba(216, 200, 27, 0.27)",
-            "threshold2Color": "rgba(234, 112, 112, 0.22)"
-          },
-          "lines": true,
-          "fill": 1,
-          "linewidth": 2,
-          "points": false,
-          "pointradius": 5,
-          "bars": false,
-          "stack": false,
-          "percentage": false,
-          "legend": {
-            "show": true,
-            "values": false,
-            "min": false,
-            "max": false,
-            "current": false,
-            "total": false,
-            "avg": false
-          },
-          "nullPointMode": "connected",
-          "steppedLine": false,
-          "tooltip": {
-            "value_type": "cumulative",
-            "shared": true,
-            "msResolution": false
-          },
-          "timeFrom": null,
-          "timeShift": null,
-          "aliasColors": {},
-          "seriesOverrides": [],
-          
-          
           "alerting": {
+            "name": "alert name",
+            "description": "description",
             "frequency": 10,
             "warning": {
               "op": ">",
@@ -140,16 +75,10 @@ func TestAlertModel(t *testing.T) {
             },
             "evalStringParam1": "",
             "name": "Alerting Panel Title alert"
-          },
-          "links": []
+          }
         },
         {
           "title": "Active mobile users",
-          "error": false,
-          "span": 6,
-          "editable": true,
-          "type": "graph",
-          "isNew": true,
           "id": 4,
           "targets": [
             {
@@ -158,65 +87,9 @@ func TestAlertModel(t *testing.T) {
             }
           ],
           "datasource": "graphite2",
-          "renderer": "flot",
-          "yaxes": [
-            {
-              "label": null,
-              "show": true,
-              "logBase": 1,
-              "min": null,
-              "max": null,
-              "format": "short"
-            },
-            {
-              "label": null,
-              "show": true,
-              "logBase": 1,
-              "min": null,
-              "max": null,
-              "format": "short"
-            }
-          ],
-          "xaxis": {
-            "show": true
-          },
-          "grid": {
-            "threshold1": null,
-            "threshold2": null,
-            "threshold1Color": "rgba(216, 200, 27, 0.27)",
-            "threshold2Color": "rgba(234, 112, 112, 0.22)"
-          },
-          "lines": true,
-          "fill": 1,
-          "linewidth": 2,
-          "points": false,
-          "pointradius": 5,
-          "bars": false,
-          "stack": false,
-          "percentage": false,
-          "legend": {
-            "show": true,
-            "values": false,
-            "min": false,
-            "max": false,
-            "current": false,
-            "total": false,
-            "avg": false
-          },
-          "nullPointMode": "connected",
-          "steppedLine": false,
-          "tooltip": {
-            "value_type": "cumulative",
-            "shared": true,
-            "msResolution": false
-          },
-          "timeFrom": null,
-          "timeShift": null,
-          "aliasColors": {
-            "mobile": "#EAB839"
-          },
-          "seriesOverrides": [],
           "alerting": {
+            "name": "alert name",
+            "description": "description",
             "frequency": 10,
             "warning": {
               "op": ">",
@@ -253,8 +126,7 @@ func TestAlertModel(t *testing.T) {
             },
             "evalStringParam1": "",
             "name": "Alerting Panel Title alert"
-          },
-          "links": []
+          }
         }
       ],
       "title": "Row"
@@ -265,41 +137,8 @@ func TestAlertModel(t *testing.T) {
       "height": "250px",
       "panels": [
         {
-          "columns": [],
           "datasource": "InfluxDB",
-          "editable": true,
-          "error": false,
-          "fontSize": "100%",
           "id": 2,
-          "isNew": true,
-          "pageSize": null,
-          "scroll": true,
-          "showHeader": true,
-          "sort": {
-            "col": 0,
-            "desc": true
-          },
-          "span": 6,
-          "styles": [
-            {
-              "dateFormat": "YYYY-MM-DD HH:mm:ss",
-              "pattern": "Time",
-              "type": "date"
-            },
-            {
-              "colorMode": null,
-              "colors": [
-                "rgba(245, 54, 54, 0.9)",
-                "rgba(237, 129, 40, 0.89)",
-                "rgba(50, 172, 45, 0.97)"
-              ],
-              "decimals": 2,
-              "pattern": "/.*/",
-              "thresholds": [],
-              "type": "number",
-              "unit": "short"
-            }
-          ],
           "targets": [
             {
               "dsType": "influxdb",
@@ -342,104 +181,60 @@ func TestAlertModel(t *testing.T) {
           ],
           "title": "Broken influxdb panel",
           "transform": "table",
-          "type": "table",
-          "links": []
+          "type": "table"
         }
       ],
       "title": "New row"
     }
-  ],
-  "time": {
-    "from": "now-1h",
-    "to": "now"
-  },
-  "timepicker": {
-    "now": true,
-    "nowDelay": "5m",
-    "refresh_intervals": [
-      "5s",
-      "10s",
-      "30s",
-      "1m",
-      "5m",
-      "15m",
-      "30m",
-      "1h",
-      "2h",
-      "1d",
-      "7d"
-    ],
-    "time_options": [
-      "5m",
-      "15m",
-      "1h",
-      "6h",
-      "12h",
-      "24h",
-      "2d",
-      "7d",
-      "30d"
-    ]
-  },
-  "templating": {
-    "list": []
-  },
-  "annotations": {
-    "list": []
-  },
-  "schemaVersion": 12,
-  "version": 16,
-  "links": []
+  ]
+
 }`
-		dashboardJson, _ := simplejson.NewJson([]byte(json))
-		cmd := &m.SaveDashboardCommand{
-			Dashboard: dashboardJson,
-			UserId:    1,
-			OrgId:     1,
-			Overwrite: true,
-			Result: &m.Dashboard{
-				Id: 1,
-			},
-		}
+			dashboardJSON, _ := simplejson.NewJson([]byte(json))
+			cmd := &m.SaveDashboardCommand{
+				Dashboard: dashboardJSON,
+				UserId:    1,
+				OrgId:     1,
+				Overwrite: true,
+				Result: &m.Dashboard{
+					Id: 1,
+				},
+			}
 
-		InitTestDB(t)
+			InitTestDB(t)
 
-		AddDataSource(&m.AddDataSourceCommand{
-			Name:      "graphite2",
-			OrgId:     1,
-			Type:      m.DS_INFLUXDB,
-			Access:    m.DS_ACCESS_DIRECT,
-			Url:       "http://test",
-			IsDefault: false,
-			Database:  "site",
-		})
+			AddDataSource(&m.AddDataSourceCommand{
+				Name:      "graphite2",
+				OrgId:     1,
+				Type:      m.DS_INFLUXDB,
+				Access:    m.DS_ACCESS_DIRECT,
+				Url:       "http://test",
+				IsDefault: false,
+				Database:  "site",
+			})
 
-		AddDataSource(&m.AddDataSourceCommand{
-			Name:      "InfluxDB",
-			OrgId:     1,
-			Type:      m.DS_GRAPHITE,
-			Access:    m.DS_ACCESS_DIRECT,
-			Url:       "http://test",
-			IsDefault: true,
-		})
-
-		alerts := alerting.ParseAlertsFromDashboard(cmd)
+			AddDataSource(&m.AddDataSourceCommand{
+				Name:      "InfluxDB",
+				OrgId:     1,
+				Type:      m.DS_GRAPHITE,
+				Access:    m.DS_ACCESS_DIRECT,
+				Url:       "http://test",
+				IsDefault: true,
+			})
 
-		Convey("all properties have been set", func() {
-			So(alerts, ShouldNotBeEmpty)
-			So(len(alerts), ShouldEqual, 2)
+			alerts := alerting.ParseAlertsFromDashboard(cmd)
 
-			for _, v := range alerts {
-				So(v.DashboardId, ShouldEqual, 1)
-				So(v.PanelId, ShouldNotEqual, 0)
+			Convey("all properties have been set", func() {
+				So(alerts, ShouldNotBeEmpty)
+				So(len(alerts), ShouldEqual, 2)
 
-				So(v.Name, ShouldNotBeEmpty)
-				So(v.Description, ShouldNotBeEmpty)
+				for _, v := range alerts {
+					So(v.DashboardId, ShouldEqual, 1)
+					So(v.PanelId, ShouldNotEqual, 0)
 
-				expr := simplejson.NewFromAny(v.Expression)
-				So(expr.Get("valueQuery").Get("query").MustString(), ShouldNotEqual, "")
-				So(expr.Get("valueQuery").Get("datsourceId").MustInt64(), ShouldNotEqual, 0)
-			}
+					So(v.Name, ShouldNotBeEmpty)
+					So(v.Description, ShouldNotBeEmpty)
+				}
+			})
 		})
 	})
 }

+ 1 - 1
pkg/tsdb/graphite/graphite.go

@@ -59,7 +59,7 @@ func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryC
 	var data []TargetResponseDTO
 	err = json.Unmarshal(body, &data)
 	if err != nil {
-		glog.Info("Failed to unmarshal graphite response", "error", err)
+		glog.Info("Failed to unmarshal graphite response", "error", err, "body", string(body))
 		result.Error = err
 		return result
 	}

+ 2 - 2
public/app/plugins/panel/graph/alert_tab_ctrl.ts

@@ -54,13 +54,13 @@ export class AlertTabCtrl {
     function: 'static',
     valueQuery: {
       queryRefId: 'A',
-      from: '5m',
+      from: '600s',
       to: 'now',
       agg: 'avg',
     },
     evalQuery: {
       queryRefId: 'A',
-      from: '5m',
+      from: '600s',
       to: 'now',
       agg: 'avg',
     },