alerting: fix a bunch of lint issues. (#17128)

This commit is contained in:
Carl Bergquist 2019-05-20 12:13:32 +02:00 committed by GitHub
parent a564a54b13
commit bd5bcea5d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 122 additions and 111 deletions

View File

@ -17,44 +17,43 @@ import (
"golang.org/x/sync/errgroup"
)
// AlertingService is the background process that
// schedules alert evaluations and makes sure notifications
// are sent.
type AlertingService struct {
RenderService rendering.Service `inject:""`
execQueue chan *Job
//clock clock.Clock
execQueue chan *Job
ticker *Ticker
scheduler Scheduler
evalHandler EvalHandler
ruleReader RuleReader
scheduler scheduler
evalHandler evalHandler
ruleReader ruleReader
log log.Logger
resultHandler ResultHandler
resultHandler resultHandler
}
func init() {
registry.RegisterService(&AlertingService{})
}
func NewEngine() *AlertingService {
e := &AlertingService{}
e.Init()
return e
}
// IsDisabled returns true if the alerting service is disable for this instance.
func (e *AlertingService) IsDisabled() bool {
return !setting.AlertingEnabled || !setting.ExecuteAlerts
}
// Init initalizes the AlertingService.
func (e *AlertingService) Init() error {
e.ticker = NewTicker(time.Now(), time.Second*0, clock.New())
e.execQueue = make(chan *Job, 1000)
e.scheduler = NewScheduler()
e.scheduler = newScheduler()
e.evalHandler = NewEvalHandler()
e.ruleReader = NewRuleReader()
e.ruleReader = newRuleReader()
e.log = log.New("alerting.engine")
e.resultHandler = NewResultHandler(e.RenderService)
e.resultHandler = newResultHandler(e.RenderService)
return nil
}
// Run starts the alerting service background process.
func (e *AlertingService) Run(ctx context.Context) error {
alertGroup, ctx := errgroup.WithContext(ctx)
alertGroup.Go(func() error { return e.alertingTicker(ctx) })
@ -80,7 +79,7 @@ func (e *AlertingService) alertingTicker(grafanaCtx context.Context) error {
case tick := <-e.ticker.C:
// TEMP SOLUTION update rules ever tenth tick
if tickIndex%10 == 0 {
e.scheduler.Update(e.ruleReader.Fetch())
e.scheduler.Update(e.ruleReader.fetch())
}
e.scheduler.Tick(tick, e.execQueue)
@ -211,7 +210,7 @@ func (e *AlertingService) processJob(attemptID int, attemptChan chan int, cancel
// dont reuse the evalContext and get its own context.
evalContext.Ctx = resultHandleCtx
evalContext.Rule.State = evalContext.GetNewState()
e.resultHandler.Handle(evalContext)
e.resultHandler.handle(evalContext)
span.Finish()
e.log.Debug("Job Execution completed", "timeMs", evalContext.GetDurationMs(), "alertId", evalContext.Rule.Id, "name", evalContext.Rule.Name, "firing", evalContext.Firing, "attemptID", attemptID)
close(attemptChan)

View File

@ -17,7 +17,8 @@ import (
func TestEngineTimeouts(t *testing.T) {
Convey("Alerting engine timeout tests", t, func() {
engine := NewEngine()
engine := &AlertingService{}
engine.Init()
setting.AlertingNotificationTimeout = 30 * time.Second
setting.AlertingMaxAttempts = 3
engine.resultHandler = &FakeResultHandler{}
@ -89,7 +90,7 @@ func (handler *FakeCommonTimeoutHandler) Eval(evalContext *EvalContext) {
evalContext.Error = errors.New("Fake evaluation timeout test failure; wrong response")
}
func (handler *FakeCommonTimeoutHandler) Handle(evalContext *EvalContext) error {
func (handler *FakeCommonTimeoutHandler) handle(evalContext *EvalContext) error {
// 1. prepare mock server
path := "/resulthandle"
srv := runBusyServer(path, handler.ServerBusySleepDuration)

View File

@ -6,9 +6,10 @@ import (
"math"
"testing"
"time"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
"time"
)
type FakeEvalHandler struct {
@ -32,13 +33,14 @@ func (handler *FakeEvalHandler) Eval(evalContext *EvalContext) {
type FakeResultHandler struct{}
func (handler *FakeResultHandler) Handle(evalContext *EvalContext) error {
func (handler *FakeResultHandler) handle(evalContext *EvalContext) error {
return nil
}
func TestEngineProcessJob(t *testing.T) {
Convey("Alerting engine job processing", t, func() {
engine := NewEngine()
engine := &AlertingService{}
engine.Init()
setting.AlertingEvaluationTimeout = 30 * time.Second
setting.AlertingNotificationTimeout = 30 * time.Second
setting.AlertingMaxAttempts = 3

View File

@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
// EvalContext is the context object for an alert evaluation.
type EvalContext struct {
Firing bool
IsTestRun bool
@ -33,6 +34,7 @@ type EvalContext struct {
Ctx context.Context
}
// NewEvalContext is the EvalContext constructor.
func NewEvalContext(alertCtx context.Context, rule *Rule) *EvalContext {
return &EvalContext{
Ctx: alertCtx,
@ -45,12 +47,14 @@ func NewEvalContext(alertCtx context.Context, rule *Rule) *EvalContext {
}
}
// StateDescription contains visual information about the alert state.
type StateDescription struct {
Color string
Text string
Data string
}
// GetStateModel returns the `StateDescription` based on current state.
func (c *EvalContext) GetStateModel() *StateDescription {
switch c.Rule.State {
case models.AlertStateOK:
@ -78,18 +82,21 @@ func (c *EvalContext) GetStateModel() *StateDescription {
}
}
func (c *EvalContext) ShouldUpdateAlertState() bool {
func (c *EvalContext) shouldUpdateAlertState() bool {
return c.Rule.State != c.PrevAlertState
}
func (a *EvalContext) GetDurationMs() float64 {
return float64(a.EndTime.Nanosecond()-a.StartTime.Nanosecond()) / float64(1000000)
// GetDurationMs returns the duration of the alert evaluation.
func (c *EvalContext) GetDurationMs() float64 {
return float64(c.EndTime.Nanosecond()-c.StartTime.Nanosecond()) / float64(1000000)
}
// GetNotificationTitle returns the title of the alert rule including alert state.
func (c *EvalContext) GetNotificationTitle() string {
return "[" + c.GetStateModel().Text + "] " + c.Rule.Name
}
// GetDashboardUID returns the dashboard uid for the alert rule.
func (c *EvalContext) GetDashboardUID() (*models.DashboardRef, error) {
if c.dashboardRef != nil {
return c.dashboardRef, nil
@ -106,6 +113,7 @@ func (c *EvalContext) GetDashboardUID() (*models.DashboardRef, error) {
const urlFormat = "%s?fullscreen&edit&tab=alert&panelId=%d&orgId=%d"
// GetRuleUrl returns the url to the dashboard containing the alert.
func (c *EvalContext) GetRuleUrl() (string, error) {
if c.IsTestRun {
return setting.AppUrl, nil
@ -118,7 +126,7 @@ func (c *EvalContext) GetRuleUrl() (string, error) {
return fmt.Sprintf(urlFormat, models.GetFullDashboardUrl(ref.Uid, ref.Slug), c.Rule.PanelId, c.Rule.OrgId), nil
}
// GetNewState returns the new state from the alert rule evaluation
// GetNewState returns the new state from the alert rule evaluation.
func (c *EvalContext) GetNewState() models.AlertStateType {
ns := getNewStateInternal(c)
if ns != models.AlertStateAlerting || c.Rule.For == 0 {

View File

@ -18,7 +18,7 @@ func TestStateIsUpdatedWhenNeeded(t *testing.T) {
ctx.PrevAlertState = models.AlertStateOK
ctx.Rule.State = models.AlertStateAlerting
if !ctx.ShouldUpdateAlertState() {
if !ctx.shouldUpdateAlertState() {
t.Fatalf("expected should updated to be true")
}
})
@ -27,7 +27,7 @@ func TestStateIsUpdatedWhenNeeded(t *testing.T) {
ctx.PrevAlertState = models.AlertStateOK
ctx.Rule.State = models.AlertStateOK
if ctx.ShouldUpdateAlertState() {
if ctx.shouldUpdateAlertState() {
t.Fatalf("expected should updated to be false")
}
})

View File

@ -9,11 +9,13 @@ import (
"github.com/grafana/grafana/pkg/infra/metrics"
)
// DefaultEvalHandler is responsible for evaluating the alert rule.
type DefaultEvalHandler struct {
log log.Logger
alertJobTimeout time.Duration
}
// NewEvalHandler is the `DefaultEvalHandler` constructor.
func NewEvalHandler() *DefaultEvalHandler {
return &DefaultEvalHandler{
log: log.New("alerting.evalHandler"),
@ -21,6 +23,7 @@ func NewEvalHandler() *DefaultEvalHandler {
}
}
// Eval evaluated the alert rule.
func (e *DefaultEvalHandler) Eval(context *EvalContext) {
firing := true
noDataFound := true

View File

@ -11,7 +11,7 @@ import (
"github.com/grafana/grafana/pkg/models"
)
// DashAlertExtractor extracts alerts from the dashboard json
// DashAlertExtractor extracts alerts from the dashboard json.
type DashAlertExtractor struct {
User *models.SignedInUser
Dash *models.Dashboard
@ -19,7 +19,7 @@ type DashAlertExtractor struct {
log log.Logger
}
// NewDashAlertExtractor returns a new DashAlertExtractor
// NewDashAlertExtractor returns a new DashAlertExtractor.
func NewDashAlertExtractor(dash *models.Dashboard, orgID int64, user *models.SignedInUser) *DashAlertExtractor {
return &DashAlertExtractor{
User: user,
@ -207,7 +207,7 @@ func validateAlertRule(alert *models.Alert) bool {
return alert.ValidToSave()
}
// GetAlerts extracts alerts from the dashboard json and does full validation on the alert json data
// GetAlerts extracts alerts from the dashboard json and does full validation on the alert json data.
func (e *DashAlertExtractor) GetAlerts() ([]*models.Alert, error) {
return e.extractAlerts(validateAlertRule)
}
@ -247,7 +247,7 @@ func (e *DashAlertExtractor) extractAlerts(validateFunc func(alert *models.Alert
}
// ValidateAlerts validates alerts in the dashboard json but does not require a valid dashboard id
// in the first validation pass
// in the first validation pass.
func (e *DashAlertExtractor) ValidateAlerts() error {
_, err := e.extractAlerts(func(alert *models.Alert) bool { return alert.OrgId != 0 && alert.PanelId != 0 })
return err

View File

@ -52,10 +52,10 @@ func TestAlertRuleExtraction(t *testing.T) {
So(err, ShouldBeNil)
Convey("Extractor should not modify the original json", func() {
dashJson, err := simplejson.NewJson(json)
dashJSON, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
getTarget := func(j *simplejson.Json) string {
rowObj := j.Get("rows").MustArray()[0]
@ -68,23 +68,23 @@ func TestAlertRuleExtraction(t *testing.T) {
}
Convey("Dashboard json rows.panels.alert.query.model.target should be empty", func() {
So(getTarget(dashJson), ShouldEqual, "")
So(getTarget(dashJSON), ShouldEqual, "")
})
extractor := NewDashAlertExtractor(dash, 1, nil)
_, _ = extractor.GetAlerts()
Convey("Dashboard json should not be updated after extracting rules", func() {
So(getTarget(dashJson), ShouldEqual, "")
So(getTarget(dashJSON), ShouldEqual, "")
})
})
Convey("Parsing and validating dashboard containing graphite alerts", func() {
dashJson, err := simplejson.NewJson(json)
dashJSON, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@ -147,12 +147,12 @@ func TestAlertRuleExtraction(t *testing.T) {
})
Convey("Panels missing id should return error", func() {
panelWithoutId, err := ioutil.ReadFile("./testdata/panels-missing-id.json")
panelWithoutID, err := ioutil.ReadFile("./testdata/panels-missing-id.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson(panelWithoutId)
dashJSON, err := simplejson.NewJson(panelWithoutID)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
_, err = extractor.GetAlerts()
@ -163,12 +163,12 @@ func TestAlertRuleExtraction(t *testing.T) {
})
Convey("Panel with id set to zero should return error", func() {
panelWithIdZero, err := ioutil.ReadFile("./testdata/panel-with-id-0.json")
panelWithIDZero, err := ioutil.ReadFile("./testdata/panel-with-id-0.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson(panelWithIdZero)
dashJSON, err := simplejson.NewJson(panelWithIDZero)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
_, err = extractor.GetAlerts()
@ -182,9 +182,9 @@ func TestAlertRuleExtraction(t *testing.T) {
json, err := ioutil.ReadFile("./testdata/v5-dashboard.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson(json)
dashJSON, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@ -211,9 +211,9 @@ func TestAlertRuleExtraction(t *testing.T) {
json, err := ioutil.ReadFile("./testdata/influxdb-alert.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson(json)
dashJSON, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@ -240,10 +240,10 @@ func TestAlertRuleExtraction(t *testing.T) {
json, err := ioutil.ReadFile("./testdata/collapsed-panels.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson(json)
dashJSON, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := models.NewDashboardFromJson(dashJson)
dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()

View File

@ -7,15 +7,16 @@ import (
"github.com/grafana/grafana/pkg/models"
)
type EvalHandler interface {
type evalHandler interface {
Eval(evalContext *EvalContext)
}
type Scheduler interface {
type scheduler interface {
Tick(time time.Time, execQueue chan *Job)
Update(rules []*Rule)
}
// Notifier is responsible for sending alert notifications.
type Notifier interface {
Notify(evalContext *EvalContext) error
GetType() string
@ -48,6 +49,7 @@ func (notifiers notifierStateSlice) ShouldUploadImage() bool {
return false
}
// ConditionResult is the result of a condition evaluation.
type ConditionResult struct {
Firing bool
NoDataFound bool
@ -55,6 +57,7 @@ type ConditionResult struct {
EvalMatches []*EvalMatch
}
// Condition is responsible for evaluating an alert condition.
type Condition interface {
Eval(result *EvalContext) (*ConditionResult, error)
}

View File

@ -2,6 +2,8 @@ package alerting
import "github.com/grafana/grafana/pkg/components/null"
// Job holds state about when the alert rule should
// be evaluated.
type Job struct {
Offset int64
OffsetWait bool
@ -10,18 +12,15 @@ type Job struct {
Rule *Rule
}
// ResultLogEntry represents log data for the alert evaluation.
type ResultLogEntry struct {
Message string
Data interface{}
}
// EvalMatch represents the serie violating the threshold.
type EvalMatch struct {
Value null.Float `json:"value"`
Metric string `json:"metric"`
Tags map[string]string `json:"tags"`
}
type Level struct {
Operator string
Value float64
}

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
// NotifierPlugin holds meta information about a notifier.
type NotifierPlugin struct {
Type string `json:"type"`
Name string `json:"name"`
@ -21,11 +22,7 @@ type NotifierPlugin struct {
Factory NotifierFactory `json:"-"`
}
type NotificationService interface {
SendIfNeeded(context *EvalContext) error
}
func NewNotificationService(renderService rendering.Service) NotificationService {
func newNotificationService(renderService rendering.Service) *notificationService {
return &notificationService{
log: log.New("alerting.notifier"),
renderService: renderService,
@ -156,8 +153,8 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) {
return nil
}
func (n *notificationService) getNeededNotifiers(orgId int64, notificationUids []string, evalContext *EvalContext) (notifierStateSlice, error) {
query := &models.GetAlertNotificationsWithUidToSendQuery{OrgId: orgId, Uids: notificationUids}
func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids []string, evalContext *EvalContext) (notifierStateSlice, error) {
query := &models.GetAlertNotificationsWithUidToSendQuery{OrgId: orgID, Uids: notificationUids}
if err := bus.Dispatch(query); err != nil {
return nil, err
@ -194,7 +191,7 @@ func (n *notificationService) getNeededNotifiers(orgId int64, notificationUids [
return result, nil
}
// InitNotifier instantiate a new notifier based on the model
// InitNotifier instantiate a new notifier based on the model.
func InitNotifier(model *models.AlertNotification) (Notifier, error) {
notifierPlugin, found := notifierFactories[model.Type]
if !found {
@ -204,6 +201,7 @@ func InitNotifier(model *models.AlertNotification) (Notifier, error) {
return notifierPlugin.Factory(model)
}
// NotifierFactory is a signature for creating notifiers.
type NotifierFactory func(notification *models.AlertNotification) (Notifier, error)
var notifierFactories = make(map[string]*NotifierPlugin)
@ -213,6 +211,7 @@ func RegisterNotifier(plugin *NotifierPlugin) {
notifierFactories[plugin.Type] = plugin
}
// GetNotifiers returns a list of metadata about available notifiers.
func GetNotifiers() []*NotifierPlugin {
list := make([]*NotifierPlugin, 0)

View File

@ -2,7 +2,6 @@ package alerting
import (
"sync"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
@ -10,35 +9,24 @@ import (
"github.com/grafana/grafana/pkg/models"
)
type RuleReader interface {
Fetch() []*Rule
type ruleReader interface {
fetch() []*Rule
}
type DefaultRuleReader struct {
type defaultRuleReader struct {
sync.RWMutex
serverPosition int
clusterSize int
log log.Logger
log log.Logger
}
func NewRuleReader() *DefaultRuleReader {
ruleReader := &DefaultRuleReader{
func newRuleReader() *defaultRuleReader {
ruleReader := &defaultRuleReader{
log: log.New("alerting.ruleReader"),
}
go ruleReader.initReader()
return ruleReader
}
func (arr *DefaultRuleReader) initReader() {
heartbeat := time.NewTicker(time.Second * 10)
for range heartbeat.C {
arr.heartbeat()
}
}
func (arr *DefaultRuleReader) Fetch() []*Rule {
func (arr *defaultRuleReader) fetch() []*Rule {
cmd := &models.GetAllAlertsQuery{}
if err := bus.Dispatch(cmd); err != nil {
@ -58,8 +46,3 @@ func (arr *DefaultRuleReader) Fetch() []*Rule {
metrics.M_Alerting_Active_Alerts.Set(float64(len(res)))
return res
}
func (arr *DefaultRuleReader) heartbeat() {
arr.clusterSize = 1
arr.serverPosition = 1
}

View File

@ -13,23 +13,23 @@ import (
"github.com/grafana/grafana/pkg/services/rendering"
)
type ResultHandler interface {
Handle(evalContext *EvalContext) error
type resultHandler interface {
handle(evalContext *EvalContext) error
}
type DefaultResultHandler struct {
notifier NotificationService
type defaultResultHandler struct {
notifier *notificationService
log log.Logger
}
func NewResultHandler(renderService rendering.Service) *DefaultResultHandler {
return &DefaultResultHandler{
func newResultHandler(renderService rendering.Service) *defaultResultHandler {
return &defaultResultHandler{
log: log.New("alerting.resultHandler"),
notifier: NewNotificationService(renderService),
notifier: newNotificationService(renderService),
}
}
func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
func (handler *defaultResultHandler) handle(evalContext *EvalContext) error {
executionError := ""
annotationData := simplejson.New()
@ -45,7 +45,7 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
}
metrics.M_Alerting_Result_State.WithLabelValues(string(evalContext.Rule.State)).Inc()
if evalContext.ShouldUpdateAlertState() {
if evalContext.shouldUpdateAlertState() {
handler.log.Info("New state change", "alertId", evalContext.Rule.Id, "newState", evalContext.Rule.State, "prev state", evalContext.PrevAlertState)
cmd := &models.SetAlertStateCommand{

View File

@ -12,10 +12,14 @@ import (
)
var (
// ErrFrequencyCannotBeZeroOrLess frequency cannot be below zero
ErrFrequencyCannotBeZeroOrLess = errors.New(`"evaluate every" cannot be zero or below`)
ErrFrequencyCouldNotBeParsed = errors.New(`"evaluate every" field could not be parsed`)
// ErrFrequencyCouldNotBeParsed frequency cannot be parsed
ErrFrequencyCouldNotBeParsed = errors.New(`"evaluate every" field could not be parsed`)
)
// Rule is the in-memory version of an alert rule.
type Rule struct {
Id int64
OrgId int64
@ -35,6 +39,8 @@ type Rule struct {
StateChanges int64
}
// ValidationError is a typed error with meta data
// about the validation error.
type ValidationError struct {
Reason string
Err error
@ -65,8 +71,8 @@ func (e ValidationError) Error() string {
}
var (
ValueFormatRegex = regexp.MustCompile(`^\d+`)
UnitFormatRegex = regexp.MustCompile(`\w{1}$`)
valueFormatRegex = regexp.MustCompile(`^\d+`)
unitFormatRegex = regexp.MustCompile(`\w{1}$`)
)
var unitMultiplier = map[string]int{
@ -79,7 +85,7 @@ var unitMultiplier = map[string]int{
func getTimeDurationStringToSeconds(str string) (int64, error) {
multiplier := 1
matches := ValueFormatRegex.FindAllString(str, 1)
matches := valueFormatRegex.FindAllString(str, 1)
if len(matches) <= 0 {
return 0, ErrFrequencyCouldNotBeParsed
@ -94,7 +100,7 @@ func getTimeDurationStringToSeconds(str string) (int64, error) {
return 0, ErrFrequencyCannotBeZeroOrLess
}
unit := UnitFormatRegex.FindAllString(str, 1)[0]
unit := unitFormatRegex.FindAllString(str, 1)[0]
if val, ok := unitMultiplier[unit]; ok {
multiplier = val
@ -103,6 +109,8 @@ func getTimeDurationStringToSeconds(str string) (int64, error) {
return int64(value * multiplier), nil
}
// NewRuleFromDBAlert mappes an db version of
// alert to an in-memory version.
func NewRuleFromDBAlert(ruleDef *models.Alert) (*Rule, error) {
model := &Rule{}
model.Id = ruleDef.Id
@ -159,10 +167,12 @@ func NewRuleFromDBAlert(ruleDef *models.Alert) (*Rule, error) {
return model, nil
}
// ConditionFactory is the function signature for creating `Conditions`.
type ConditionFactory func(model *simplejson.Json, index int) (Condition, error)
var conditionFactories = make(map[string]ConditionFactory)
// RegisterCondition adds support for alerting conditions.
func RegisterCondition(typeName string, factory ConditionFactory) {
conditionFactories[typeName] = factory
}

View File

@ -8,19 +8,19 @@ import (
"github.com/grafana/grafana/pkg/models"
)
type SchedulerImpl struct {
type schedulerImpl struct {
jobs map[int64]*Job
log log.Logger
}
func NewScheduler() Scheduler {
return &SchedulerImpl{
func newScheduler() scheduler {
return &schedulerImpl{
jobs: make(map[int64]*Job),
log: log.New("alerting.scheduler"),
}
}
func (s *SchedulerImpl) Update(rules []*Rule) {
func (s *schedulerImpl) Update(rules []*Rule) {
s.log.Debug("Scheduling update", "ruleCount", len(rules))
jobs := make(map[int64]*Job)
@ -48,7 +48,7 @@ func (s *SchedulerImpl) Update(rules []*Rule) {
s.jobs = jobs
}
func (s *SchedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) {
func (s *schedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) {
now := tickTime.Unix()
for _, job := range s.jobs {
@ -72,7 +72,7 @@ func (s *SchedulerImpl) Tick(tickTime time.Time, execQueue chan *Job) {
}
}
func (s *SchedulerImpl) enqueue(job *Job, execQueue chan *Job) {
func (s *schedulerImpl) enqueue(job *Job, execQueue chan *Job) {
s.log.Debug("Scheduler: Putting job on to exec queue", "name", job.Rule.Name, "id", job.Rule.Id)
execQueue <- job
}

View File

@ -11,6 +11,8 @@ import (
"github.com/grafana/grafana/pkg/models"
)
// NotificationTestCommand initiates an test
// execution of an alert notification.
type NotificationTestCommand struct {
State models.AlertStateType
Name string
@ -27,7 +29,7 @@ func init() {
}
func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
notifier := NewNotificationService(nil).(*notificationService)
notifier := newNotificationService(nil)
model := &models.AlertNotification{
Name: cmd.Name,

View File

@ -9,6 +9,8 @@ import (
"github.com/grafana/grafana/pkg/models"
)
// AlertTestCommand initiates an test evaluation
// of an alert rule.
type AlertTestCommand struct {
Dashboard *simplejson.Json
PanelId int64

View File

@ -6,7 +6,7 @@ import (
"github.com/benbjohnson/clock"
)
// ticker is a ticker to power the alerting scheduler. it's like a time.Ticker, except:
// Ticker is a ticker to power the alerting scheduler. it's like a time.Ticker, except:
// * it doesn't drop ticks for slow receivers, rather, it queues up. so that callers are in control to instrument what's going on.
// * it automatically ticks every second, which is the right thing in our current design
// * it ticks on second marks or very shortly after. this provides a predictable load pattern