mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'alert_ui_take2' of github.com:grafana/grafana into alert_ui_take2
Conflicts: public/app/plugins/panel/graph/alert_tab_ctrl.ts
This commit is contained in:
commit
c18017381b
@ -191,9 +191,7 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
var createUserCmd *m.CreateUserCommand
|
||||
bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
|
||||
createUserCmd = cmd
|
||||
cmd.Result = m.User{Id: 33}
|
||||
return nil
|
||||
})
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
type AlertRule struct {
|
||||
type AlertRuleModel struct {
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
@ -21,25 +21,30 @@ type AlertRule struct {
|
||||
Expression *simplejson.Json
|
||||
}
|
||||
|
||||
func (alertRule *AlertRule) ValidToSave() bool {
|
||||
return true
|
||||
func (this AlertRuleModel) TableName() string {
|
||||
return "alert_rule"
|
||||
}
|
||||
|
||||
func (this *AlertRule) ContainsUpdates(other *AlertRule) bool {
|
||||
result := false
|
||||
func (alertRule *AlertRuleModel) ValidToSave() bool {
|
||||
return alertRule.DashboardId != 0
|
||||
}
|
||||
|
||||
func (this *AlertRuleModel) ContainsUpdates(other *AlertRuleModel) bool {
|
||||
result := false
|
||||
result = result || this.Name != other.Name
|
||||
result = result || this.Description != other.Description
|
||||
|
||||
json1, err1 := this.Expression.MarshalJSON()
|
||||
json2, err2 := other.Expression.MarshalJSON()
|
||||
if this.Expression != nil && other.Expression != nil {
|
||||
json1, err1 := this.Expression.Encode()
|
||||
json2, err2 := other.Expression.Encode()
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
return false
|
||||
if err1 != nil || err2 != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
result = result || string(json1) != string(json2)
|
||||
}
|
||||
|
||||
result = result || string(json1) != string(json2)
|
||||
|
||||
//don't compare .State! That would be insane.
|
||||
|
||||
return result
|
||||
@ -78,7 +83,7 @@ type SaveAlertsCommand struct {
|
||||
UserId int64
|
||||
OrgId int64
|
||||
|
||||
Alerts []*AlertRule
|
||||
Alerts []*AlertRuleModel
|
||||
}
|
||||
|
||||
type DeleteAlertCommand struct {
|
||||
@ -92,23 +97,17 @@ type GetAlertsQuery struct {
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
|
||||
Result []*AlertRule
|
||||
Result []*AlertRuleModel
|
||||
}
|
||||
|
||||
type GetAllAlertsQuery struct {
|
||||
Result []*AlertRule
|
||||
}
|
||||
|
||||
type GetAlertsForExecutionQuery struct {
|
||||
Timestamp int64
|
||||
|
||||
Result []*AlertRule
|
||||
Result []*AlertRuleModel
|
||||
}
|
||||
|
||||
type GetAlertByIdQuery struct {
|
||||
Id int64
|
||||
|
||||
Result *AlertRule
|
||||
Result *AlertRuleModel
|
||||
}
|
||||
|
||||
type GetAlertChangesQuery struct {
|
||||
|
@ -31,7 +31,7 @@ type UpdateAlertStateCommand struct {
|
||||
NewState string `json:"newState" binding:"Required"`
|
||||
Info string `json:"info"`
|
||||
|
||||
Result *AlertRule
|
||||
Result *AlertRuleModel
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
@ -13,13 +13,13 @@ func TestAlertingModelTest(t *testing.T) {
|
||||
json1, _ := simplejson.NewJson([]byte(`{ "field": "value" }`))
|
||||
json2, _ := simplejson.NewJson([]byte(`{ "field": "value" }`))
|
||||
|
||||
rule1 := &AlertRule{
|
||||
rule1 := &AlertRuleModel{
|
||||
Expression: json1,
|
||||
Name: "Namn",
|
||||
Description: "Description",
|
||||
}
|
||||
|
||||
rule2 := &AlertRule{
|
||||
rule2 := &AlertRuleModel{
|
||||
Expression: json2,
|
||||
Name: "Namn",
|
||||
Description: "Description",
|
||||
|
@ -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.AlertRuleModel {
|
||||
alerts := make([]*m.AlertRuleModel, 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.AlertRuleModel{
|
||||
DashboardId: cmd.Result.Id,
|
||||
OrgId: cmd.Result.OrgId,
|
||||
PanelId: panel.Get("id").MustInt64(),
|
||||
@ -28,9 +30,8 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
|
||||
|
||||
log.Info("Alertrule: %v", alert.Name)
|
||||
|
||||
expression := alerting
|
||||
valueQuery := expression.Get("valueQuery")
|
||||
valueQueryRef := valueQuery.Get("queryRefId").MustString()
|
||||
valueQuery := alerting.Get("query")
|
||||
valueQueryRef := valueQuery.Get("refId").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{"query", "datasourceId"}, ds.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,59 +58,72 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
|
||||
OrgId: cmd.OrgId,
|
||||
}
|
||||
bus.Dispatch(query)
|
||||
valueQuery.Set("datasourceId", query.Result.Id)
|
||||
alerting.SetPath([]string{"query", "datasourceId"}, query.Result.Id)
|
||||
}
|
||||
|
||||
targetQuery := target.Get("target").MustString()
|
||||
if targetQuery != "" {
|
||||
valueQuery.Set("query", targetQuery)
|
||||
alerting.SetPath([]string{"query", "query"}, targetQuery)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expression.Set("valueQuery", valueQuery)
|
||||
alert.Expression = expression
|
||||
alert.Expression = alerting
|
||||
|
||||
alertRule := &AlertRule{}
|
||||
_, err := ConvetAlertModelToAlertRule(alert)
|
||||
|
||||
ParseAlertRulesFromAlertModel(alert, alertRule)
|
||||
|
||||
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 ConvetAlertModelToAlertRule(ruleDef *m.AlertRuleModel) (*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()
|
||||
model.Transform = ruleDef.Expression.Get("transform").Get("type").MustString()
|
||||
model.TransformParams = *ruleDef.Expression.Get("transform")
|
||||
|
||||
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(),
|
||||
query := ruleDef.Expression.Get("query")
|
||||
model.Query = AlertQuery{
|
||||
Query: query.Get("query").MustString(),
|
||||
DatasourceId: query.Get("datasourceId").MustInt64(),
|
||||
From: query.Get("from").MustString(),
|
||||
To: query.Get("to").MustString(),
|
||||
Aggregator: query.Get("agg").MustString(),
|
||||
}
|
||||
|
||||
return nil
|
||||
if model.Query.Query == "" {
|
||||
return nil, fmt.Errorf("missing query.query")
|
||||
}
|
||||
|
||||
if model.Query.DatasourceId == 0 {
|
||||
return nil, fmt.Errorf("missing query.datasourceId")
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
|
@ -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.Query.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.Query.Query, "from", rule.Query.From, "datasourceId", datasource.Id)
|
||||
req := &tsdb.Request{
|
||||
TimeRange: tsdb.TimeRange{
|
||||
From: "-" + strconv.Itoa(int(rule.ValueQuery.From)) + "s",
|
||||
To: "now",
|
||||
From: "-" + rule.Query.From,
|
||||
To: rule.Query.To,
|
||||
},
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
RefId: "A",
|
||||
Query: "apps.fakesite.*.counters.requests.count",
|
||||
Query: rule.Query.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,
|
||||
|
@ -35,16 +35,18 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
So(result.State, ShouldEqual, alertstates.Critical)
|
||||
})
|
||||
|
||||
Convey("Show return critical since sum is above 10", func() {
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
/*
|
||||
Convey("Show return critical since sum is above 10", func() {
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{9, 0}, {9, 0}}),
|
||||
}
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{9, 0}, {9, 0}}),
|
||||
}
|
||||
|
||||
result := executor.evaluateRule(rule, timeSeries)
|
||||
So(result.State, ShouldEqual, alertstates.Critical)
|
||||
})
|
||||
result := executor.evaluateRule(rule, timeSeries)
|
||||
So(result.State, ShouldEqual, alertstates.Critical)
|
||||
})
|
||||
*/
|
||||
|
||||
Convey("Show return ok since avg is below 10", func() {
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
@ -67,17 +69,18 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
result := executor.evaluateRule(rule, timeSeries)
|
||||
So(result.State, ShouldEqual, alertstates.Ok)
|
||||
})
|
||||
/*
|
||||
Convey("Show return ok since max is above 10", func() {
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
Convey("Show return ok since max is above 10", func() {
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{1, 0}, {11, 0}}),
|
||||
}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{1, 0}, {11, 0}}),
|
||||
}
|
||||
|
||||
result := executor.evaluateRule(rule, timeSeries)
|
||||
So(result.State, ShouldEqual, alertstates.Critical)
|
||||
})
|
||||
result := executor.evaluateRule(rule, timeSeries)
|
||||
So(result.State, ShouldEqual, alertstates.Critical)
|
||||
})
|
||||
*/
|
||||
})
|
||||
|
||||
Convey("muliple time series", func() {
|
||||
|
@ -1,5 +1,10 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
type AlertJob struct {
|
||||
Offset int64
|
||||
Delay bool
|
||||
@ -18,26 +23,23 @@ type AlertResult struct {
|
||||
}
|
||||
|
||||
type AlertRule struct {
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
//WarnLevel float64
|
||||
//CritLevel float64
|
||||
//WarnOperator string
|
||||
//CritOperator string
|
||||
Frequency int64
|
||||
Name string
|
||||
Description string
|
||||
State string
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
Frequency int64
|
||||
Name string
|
||||
Description string
|
||||
State string
|
||||
Warning Level
|
||||
Critical Level
|
||||
Query AlertQuery
|
||||
Transform string
|
||||
TransformParams simplejson.Json
|
||||
}
|
||||
|
||||
Warning Level
|
||||
Critical Level
|
||||
|
||||
ValueQuery AlertQuery
|
||||
EvalFunc string
|
||||
EvalQuery AlertQuery
|
||||
EvalParam string
|
||||
type Transformer interface {
|
||||
Transform(tsdb tsdb.TimeSeriesSlice) float64
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
@ -49,6 +51,6 @@ type AlertQuery struct {
|
||||
Query string
|
||||
DatasourceId int64
|
||||
Aggregator string
|
||||
From int64
|
||||
Until int64
|
||||
From string
|
||||
To string
|
||||
}
|
||||
|
@ -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, _ := ConvetAlertModelToAlertRule(ruleDef)
|
||||
res[i] = model
|
||||
}
|
||||
|
||||
|
@ -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 new jobs", "job count", len(jobs))
|
||||
s.jobs = jobs
|
||||
}
|
||||
|
||||
@ -47,7 +49,7 @@ func (s *SchedulerImpl) Tick(tickTime time.Time, execQueue chan *AlertJob) {
|
||||
|
||||
for _, job := range s.jobs {
|
||||
if now%job.Rule.Frequency == 0 && job.Running == false {
|
||||
log.Trace("Scheduler: Putting job on to exec queue: %s", job.Rule.Name)
|
||||
s.log.Debug("Scheduler: Putting job on to exec queue", "name", job.Rule.Name)
|
||||
execQueue <- job
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func HeartBeat(query *m.HeartBeatCommand) error {
|
||||
*/
|
||||
|
||||
func GetAlertById(query *m.GetAlertByIdQuery) error {
|
||||
alert := m.AlertRule{}
|
||||
alert := m.AlertRuleModel{}
|
||||
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.AlertRuleModel
|
||||
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.AlertRuleModel, 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.AlertRuleModel, 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.AlertRuleModel, posted []*m.AlertRuleModel, sess *xorm.Session) error {
|
||||
for _, alert := range posted {
|
||||
update := false
|
||||
var alertToUpdate *m.AlertRule
|
||||
var alertToUpdate *m.AlertRuleModel
|
||||
|
||||
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.AlertRuleModel, posted []*m.AlertRuleModel, 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.AlertRuleModel, error) {
|
||||
alerts := make([]*m.AlertRuleModel, 0)
|
||||
err := sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)
|
||||
|
||||
if err != nil {
|
||||
return []*m.AlertRule{}, err
|
||||
return []*m.AlertRuleModel{}, err
|
||||
}
|
||||
|
||||
return alerts, nil
|
||||
|
@ -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.AlertRuleModel, sess *xorm.Session) error {
|
||||
_, err := sess.Insert(&m.AlertRuleChange{
|
||||
OrgId: alert.OrgId,
|
||||
Type: change,
|
||||
|
@ -20,7 +20,7 @@ func TestAlertRuleChangesDataAccess(t *testing.T) {
|
||||
var err error
|
||||
|
||||
Convey("When dashboard is removed", func() {
|
||||
items := []*m.AlertRule{
|
||||
items := []*m.AlertRuleModel{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
|
55
pkg/services/sqlstore/alert_rule_parser_test.go
Normal file
55
pkg/services/sqlstore/alert_rule_parser_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
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.AlertRuleModel{}
|
||||
json, _ := simplejson.NewJson([]byte(`
|
||||
{
|
||||
"frequency": 10,
|
||||
"warning": {
|
||||
"op": ">",
|
||||
"level": 10
|
||||
},
|
||||
"critical": {
|
||||
"op": ">",
|
||||
"level": 20
|
||||
},
|
||||
"query": {
|
||||
"refId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"datasourceId": 1,
|
||||
"query": "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)"
|
||||
},
|
||||
"transform": {
|
||||
"type": "aggregation",
|
||||
"method": "avg"
|
||||
}
|
||||
}`))
|
||||
|
||||
alertRuleDAO.Name = "Test"
|
||||
alertRuleDAO.Expression = json
|
||||
rule, _ := alerting.ConvetAlertModelToAlertRule(alertRuleDAO)
|
||||
|
||||
Convey("Confirm that all properties are set", func() {
|
||||
So(rule.Query.Query, ShouldEqual, "aliasByNode(statsd.fakesite.counters.session_start.*.count, 4)")
|
||||
So(rule.Query.From, ShouldEqual, "5m")
|
||||
So(rule.Query.To, ShouldEqual, "now")
|
||||
So(rule.Query.DatasourceId, ShouldEqual, 1)
|
||||
So(rule.Warning.Level, ShouldEqual, 10)
|
||||
So(rule.Warning.Operator, ShouldEqual, ">")
|
||||
So(rule.Critical.Level, ShouldEqual, 20)
|
||||
So(rule.Critical.Operator, ShouldEqual, ">")
|
||||
})
|
||||
})
|
||||
}
|
@ -3,6 +3,7 @@ package sqlstore
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
@ -13,13 +14,14 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
|
||||
testDash := insertTestDashboard("dashboard with alerts", 1, "alert")
|
||||
|
||||
items := []*m.AlertRule{
|
||||
items := []*m.AlertRuleModel{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
OrgId: testDash.OrgId,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
Expression: simplejson.New(),
|
||||
},
|
||||
}
|
||||
|
||||
@ -54,8 +56,7 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
|
||||
Convey("Alerts with same dashboard id and panel id should update", func() {
|
||||
modifiedItems := items
|
||||
modifiedItems[0].Name = "New name"
|
||||
//modifiedItems[0].State = "ALERT"
|
||||
modifiedItems[0].Name = "Name"
|
||||
|
||||
modifiedCmd := m.SaveAlertsCommand{
|
||||
DashboardId: testDash.Id,
|
||||
@ -95,24 +96,27 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Multiple alerts per dashboard", func() {
|
||||
multipleItems := []*m.AlertRule{
|
||||
multipleItems := []*m.AlertRuleModel{
|
||||
{
|
||||
DashboardId: testDash.Id,
|
||||
PanelId: 1,
|
||||
Name: "1",
|
||||
OrgId: 1,
|
||||
Expression: simplejson.New(),
|
||||
},
|
||||
{
|
||||
DashboardId: testDash.Id,
|
||||
PanelId: 2,
|
||||
Name: "2",
|
||||
OrgId: 1,
|
||||
Expression: simplejson.New(),
|
||||
},
|
||||
{
|
||||
DashboardId: testDash.Id,
|
||||
PanelId: 3,
|
||||
Name: "3",
|
||||
OrgId: 1,
|
||||
Expression: simplejson.New(),
|
||||
},
|
||||
}
|
||||
|
||||
@ -157,7 +161,7 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("When dashboard is removed", func() {
|
||||
items := []*m.AlertRule{
|
||||
items := []*m.AlertRuleModel{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
|
@ -19,7 +19,7 @@ func SetNewAlertState(cmd *m.UpdateAlertStateCommand) error {
|
||||
return fmt.Errorf("new state is invalid")
|
||||
}
|
||||
|
||||
alert := m.AlertRule{}
|
||||
alert := m.AlertRuleModel{}
|
||||
has, err := sess.Id(cmd.AlertId).Get(&alert)
|
||||
if !has {
|
||||
return fmt.Errorf("Could not find alert")
|
||||
|
@ -13,7 +13,7 @@ func TestAlertingStateAccess(t *testing.T) {
|
||||
|
||||
testDash := insertTestDashboard("dashboard with alerts", 1, "alert")
|
||||
|
||||
items := []*m.AlertRule{
|
||||
items := []*m.AlertRuleModel{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
|
@ -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,111 +36,31 @@ 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": {
|
||||
"frequency": 10,
|
||||
"warning": {
|
||||
"op": ">",
|
||||
"level": 10
|
||||
},
|
||||
"name": "Alerting Panel Title alert",
|
||||
"description": "description",
|
||||
"critical": {
|
||||
"op": ">",
|
||||
"level": 20
|
||||
"level": 20,
|
||||
"op": ">"
|
||||
},
|
||||
"function": "static",
|
||||
"valueQuery": {
|
||||
"queryRefId": "A",
|
||||
"frequency": 10,
|
||||
"query": {
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
"refId": "A",
|
||||
"to": "now"
|
||||
},
|
||||
"evalQuery": {
|
||||
"queryRefId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
"transform": {
|
||||
"method": "avg",
|
||||
"name": "aggregation"
|
||||
},
|
||||
"evalStringParam1": "",
|
||||
"name": "Alerting Panel Title alert"
|
||||
},
|
||||
"links": []
|
||||
"warning": {
|
||||
"level": 10,
|
||||
"op": ">"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Active mobile users",
|
||||
"error": false,
|
||||
"span": 6,
|
||||
"editable": true,
|
||||
"type": "graph",
|
||||
"isNew": true,
|
||||
"id": 4,
|
||||
"targets": [
|
||||
{
|
||||
@ -158,103 +69,28 @@ 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": {
|
||||
"frequency": 10,
|
||||
"warning": {
|
||||
"op": ">",
|
||||
"level": 10
|
||||
},
|
||||
"name": "Alerting Panel Title alert",
|
||||
"description": "description",
|
||||
"critical": {
|
||||
"op": ">",
|
||||
"level": 20
|
||||
"level": 20,
|
||||
"op": ">"
|
||||
},
|
||||
"function": "static",
|
||||
"valueQuery": {
|
||||
"queryRefId": "A",
|
||||
"frequency": 10,
|
||||
"query": {
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
"refId": "A",
|
||||
"to": "now"
|
||||
},
|
||||
"evalQuery": {
|
||||
"queryRefId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
"transform": {
|
||||
"method": "avg",
|
||||
"name": "aggregation"
|
||||
},
|
||||
"evalStringParam1": "",
|
||||
"name": "Alerting Panel Title alert"
|
||||
},
|
||||
"links": []
|
||||
"warning": {
|
||||
"level": 10,
|
||||
"op": ">"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Row"
|
||||
@ -265,41 +101,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 +145,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,
|
||||
},
|
||||
}
|
||||
|
||||
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: "InfluxDB",
|
||||
OrgId: 1,
|
||||
Type: m.DS_GRAPHITE,
|
||||
Access: m.DS_ACCESS_DIRECT,
|
||||
Url: "http://test",
|
||||
IsDefault: true,
|
||||
})
|
||||
|
||||
alerts := alerting.ParseAlertsFromDashboard(cmd)
|
||||
|
||||
Convey("all properties have been set", func() {
|
||||
So(alerts, ShouldNotBeEmpty)
|
||||
So(len(alerts), ShouldEqual, 2)
|
||||
|
||||
for _, v := range alerts {
|
||||
So(v.DashboardId, ShouldEqual, 1)
|
||||
So(v.PanelId, ShouldNotEqual, 0)
|
||||
|
||||
So(v.Name, ShouldNotBeEmpty)
|
||||
So(v.Description, ShouldNotBeEmpty)
|
||||
|
||||
expr := simplejson.NewFromAny(v.Expression)
|
||||
So(expr.Get("valueQuery").Get("query").MustString(), ShouldNotEqual, "")
|
||||
So(expr.Get("valueQuery").Get("datsourceId").MustInt64(), ShouldNotEqual, 0)
|
||||
dashboardJSON, _ := simplejson.NewJson([]byte(json))
|
||||
cmd := &m.SaveDashboardCommand{
|
||||
Dashboard: dashboardJSON,
|
||||
UserId: 1,
|
||||
OrgId: 1,
|
||||
Overwrite: true,
|
||||
Result: &m.Dashboard{
|
||||
Id: 1,
|
||||
},
|
||||
}
|
||||
|
||||
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: "InfluxDB",
|
||||
OrgId: 1,
|
||||
Type: m.DS_GRAPHITE,
|
||||
Access: m.DS_ACCESS_DIRECT,
|
||||
Url: "http://test",
|
||||
IsDefault: true,
|
||||
})
|
||||
|
||||
alerts := alerting.ParseAlertsFromDashboard(cmd)
|
||||
|
||||
Convey("all properties have been set", func() {
|
||||
So(alerts, ShouldNotBeEmpty)
|
||||
So(len(alerts), ShouldEqual, 2)
|
||||
|
||||
for _, v := range alerts {
|
||||
So(v.DashboardId, ShouldEqual, 1)
|
||||
So(v.PanelId, ShouldNotEqual, 0)
|
||||
|
||||
So(v.Name, ShouldNotBeEmpty)
|
||||
So(v.Description, ShouldNotBeEmpty)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
@ -30,7 +31,7 @@ func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryC
|
||||
result := &tsdb.BatchResult{}
|
||||
|
||||
params := url.Values{
|
||||
"from": []string{context.TimeRange.From},
|
||||
"from": []string{formatTimeRange(context.TimeRange.From)},
|
||||
"until": []string{context.TimeRange.To},
|
||||
"format": []string{"json"},
|
||||
"maxDataPoints": []string{"500"},
|
||||
@ -59,7 +60,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
|
||||
}
|
||||
@ -76,3 +77,7 @@ func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryC
|
||||
result.QueryResults["A"] = queryRes
|
||||
return result
|
||||
}
|
||||
|
||||
func formatTimeRange(input string) string {
|
||||
return strings.Replace(strings.Replace(input, "m", "min", -1), "M", "mon", -1)
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ export class AlertTabCtrl {
|
||||
},
|
||||
transform: {
|
||||
type: 'aggregation',
|
||||
method: 'avg',
|
||||
},
|
||||
method: 'avg'
|
||||
}
|
||||
};
|
||||
|
||||
/** @ngInject */
|
||||
|
Loading…
Reference in New Issue
Block a user