| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- package alerting
- import (
- "context"
- "fmt"
- "time"
- "github.com/grafana/grafana/pkg/bus"
- "github.com/grafana/grafana/pkg/log"
- m "github.com/grafana/grafana/pkg/models"
- "github.com/grafana/grafana/pkg/setting"
- )
- type EvalContext struct {
- Firing bool
- IsTestRun bool
- EvalMatches []*EvalMatch
- Logs []*ResultLogEntry
- Error error
- ConditionEvals string
- StartTime time.Time
- EndTime time.Time
- Rule *Rule
- log log.Logger
- dashboardRef *m.DashboardRef
- ImagePublicUrl string
- ImageOnDiskPath string
- NoDataFound bool
- PrevAlertState m.AlertStateType
- Ctx context.Context
- }
- func NewEvalContext(alertCtx context.Context, rule *Rule) *EvalContext {
- return &EvalContext{
- Ctx: alertCtx,
- StartTime: time.Now(),
- Rule: rule,
- Logs: make([]*ResultLogEntry, 0),
- EvalMatches: make([]*EvalMatch, 0),
- log: log.New("alerting.evalContext"),
- PrevAlertState: rule.State,
- }
- }
- type StateDescription struct {
- Color string
- Text string
- Data string
- }
- func (c *EvalContext) GetStateModel() *StateDescription {
- switch c.Rule.State {
- case m.AlertStateOK:
- return &StateDescription{
- Color: "#36a64f",
- Text: "OK",
- }
- case m.AlertStateNoData:
- return &StateDescription{
- Color: "#888888",
- Text: "No Data",
- }
- case m.AlertStateAlerting:
- return &StateDescription{
- Color: "#D63232",
- Text: "Alerting",
- }
- case m.AlertStateUnknown:
- return &StateDescription{
- Color: "#888888",
- Text: "Unknown",
- }
- default:
- panic("Unknown rule state for alert " + c.Rule.State)
- }
- }
- 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)
- }
- func (c *EvalContext) GetNotificationTitle() string {
- return "[" + c.GetStateModel().Text + "] " + c.Rule.Name
- }
- func (c *EvalContext) GetDashboardUID() (*m.DashboardRef, error) {
- if c.dashboardRef != nil {
- return c.dashboardRef, nil
- }
- uidQuery := &m.GetDashboardRefByIdQuery{Id: c.Rule.DashboardId}
- if err := bus.Dispatch(uidQuery); err != nil {
- return nil, err
- }
- c.dashboardRef = uidQuery.Result
- return c.dashboardRef, nil
- }
- const urlFormat = "%s?fullscreen&edit&tab=alert&panelId=%d&orgId=%d"
- func (c *EvalContext) GetRuleUrl() (string, error) {
- if c.IsTestRun {
- return setting.AppUrl, nil
- }
- ref, err := c.GetDashboardUID()
- if err != nil {
- return "", err
- }
- return fmt.Sprintf(urlFormat, m.GetFullDashboardUrl(ref.Uid, ref.Slug), c.Rule.PanelId, c.Rule.OrgId), nil
- }
- // GetNewState returns the new state from the alert rule evaluation
- func (c *EvalContext) GetNewState() m.AlertStateType {
- ns := getNewStateInternal(c)
- if ns != m.AlertStateAlerting || c.Rule.For == 0 {
- return ns
- }
- since := time.Since(c.Rule.LastStateChange)
- if c.PrevAlertState == m.AlertStatePending && since > c.Rule.For {
- return m.AlertStateAlerting
- }
- if c.PrevAlertState == m.AlertStateAlerting {
- return m.AlertStateAlerting
- }
- return m.AlertStatePending
- }
- func getNewStateInternal(c *EvalContext) m.AlertStateType {
- if c.Error != nil {
- c.log.Error("Alert Rule Result Error",
- "ruleId", c.Rule.Id,
- "name", c.Rule.Name,
- "error", c.Error,
- "changing state to", c.Rule.ExecutionErrorState.ToAlertState())
- if c.Rule.ExecutionErrorState == m.ExecutionErrorKeepState {
- return c.PrevAlertState
- }
- return c.Rule.ExecutionErrorState.ToAlertState()
- }
- if c.Firing {
- return m.AlertStateAlerting
- }
- if c.NoDataFound {
- c.log.Info("Alert Rule returned no data",
- "ruleId", c.Rule.Id,
- "name", c.Rule.Name,
- "changing state to", c.Rule.NoDataState.ToAlertState())
- if c.Rule.NoDataState == m.NoDataKeepState {
- return c.PrevAlertState
- }
- return c.Rule.NoDataState.ToAlertState()
- }
- return m.AlertStateOK
- }
|