2020-11-12 21:11:30 +08:00
package ngalert
import (
2020-12-17 22:00:09 +08:00
"context"
2021-10-01 00:51:20 +08:00
"net/url"
2020-12-17 22:00:09 +08:00
"time"
2021-10-07 22:33:50 +08:00
"github.com/benbjohnson/clock"
2020-11-12 21:11:30 +08:00
"github.com/grafana/grafana/pkg/api/routing"
2021-09-10 00:25:22 +08:00
"github.com/grafana/grafana/pkg/infra/kvstore"
2020-11-12 21:11:30 +08:00
"github.com/grafana/grafana/pkg/infra/log"
2021-03-24 22:20:44 +08:00
"github.com/grafana/grafana/pkg/services/datasourceproxy"
2020-11-12 21:11:30 +08:00
"github.com/grafana/grafana/pkg/services/datasources"
2021-10-07 22:33:50 +08:00
"github.com/grafana/grafana/pkg/services/encryption"
2021-09-10 00:25:22 +08:00
"github.com/grafana/grafana/pkg/services/ngalert/api"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
2021-03-24 22:20:44 +08:00
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
2021-09-10 00:25:22 +08:00
"github.com/grafana/grafana/pkg/services/ngalert/state"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/quota"
2021-03-24 22:20:44 +08:00
"github.com/grafana/grafana/pkg/services/sqlstore"
2020-11-12 21:11:30 +08:00
"github.com/grafana/grafana/pkg/setting"
2021-03-24 22:20:44 +08:00
"github.com/grafana/grafana/pkg/tsdb"
2021-09-10 00:25:22 +08:00
"golang.org/x/sync/errgroup"
2020-11-12 21:11:30 +08:00
)
2020-12-17 22:00:09 +08:00
const (
// scheduler interval
// changing this value is discouraged
// because this could cause existing alert definition
// with intervals that are not exactly divided by this number
// not to be evaluated
2021-08-25 21:11:22 +08:00
defaultBaseIntervalSeconds = 10
2021-08-06 20:06:56 +08:00
// default alert definition interval
2021-08-25 21:11:22 +08:00
defaultIntervalSeconds int64 = 6 * defaultBaseIntervalSeconds
2020-12-17 22:00:09 +08:00
)
2021-08-25 21:11:22 +08:00
func ProvideService ( cfg * setting . Cfg , dataSourceCache datasources . CacheService , routeRegister routing . RouteRegister ,
2021-09-10 00:25:22 +08:00
sqlStore * sqlstore . SQLStore , kvStore kvstore . KVStore , dataService * tsdb . Service , dataProxy * datasourceproxy . DataSourceProxyService ,
2021-10-07 22:33:50 +08:00
quotaService * quota . QuotaService , encryptionService encryption . Service , m * metrics . NGAlert ) ( * AlertNG , error ) {
2021-08-25 21:11:22 +08:00
ng := & AlertNG {
2021-10-07 22:33:50 +08:00
Cfg : cfg ,
DataSourceCache : dataSourceCache ,
RouteRegister : routeRegister ,
SQLStore : sqlStore ,
KVStore : kvStore ,
DataService : dataService ,
DataProxy : dataProxy ,
QuotaService : quotaService ,
EncryptionService : encryptionService ,
Metrics : m ,
Log : log . New ( "ngalert" ) ,
2021-08-25 21:11:22 +08:00
}
if ng . IsDisabled ( ) {
return ng , nil
}
if err := ng . init ( ) ; err != nil {
return nil , err
}
return ng , nil
}
2020-11-12 21:11:30 +08:00
// AlertNG is the service for evaluating the condition of an alert definition.
type AlertNG struct {
2021-10-07 22:33:50 +08:00
Cfg * setting . Cfg
DataSourceCache datasources . CacheService
RouteRegister routing . RouteRegister
SQLStore * sqlstore . SQLStore
KVStore kvstore . KVStore
DataService * tsdb . Service
DataProxy * datasourceproxy . DataSourceProxyService
QuotaService * quota . QuotaService
EncryptionService encryption . Service
Metrics * metrics . NGAlert
Log log . Logger
schedule schedule . ScheduleService
stateManager * state . Manager
2021-08-06 20:06:56 +08:00
// Alerting notification services
2021-08-24 18:28:09 +08:00
MultiOrgAlertmanager * notifier . MultiOrgAlertmanager
2020-11-12 21:11:30 +08:00
}
2021-08-25 21:11:22 +08:00
func ( ng * AlertNG ) init ( ) error {
2021-09-16 22:33:51 +08:00
var err error
2021-08-25 21:11:22 +08:00
baseInterval := ng . Cfg . AlertingBaseInterval
if baseInterval <= 0 {
baseInterval = defaultBaseIntervalSeconds
}
baseInterval *= time . Second
2021-03-03 23:52:19 +08:00
2021-05-15 04:13:44 +08:00
store := & store . DBstore {
2021-09-28 18:00:16 +08:00
BaseInterval : baseInterval ,
DefaultInterval : ng . getRuleDefaultInterval ( ) ,
SQLStore : ng . SQLStore ,
Logger : ng . Log ,
2021-05-15 04:13:44 +08:00
}
2021-05-14 02:01:38 +08:00
2021-10-07 22:33:50 +08:00
decryptFn := ng . EncryptionService . GetDecryptedValue
2021-09-16 22:33:51 +08:00
multiOrgMetrics := ng . Metrics . GetMultiOrgAlertmanagerMetrics ( )
2021-10-07 22:33:50 +08:00
ng . MultiOrgAlertmanager , err = notifier . NewMultiOrgAlertmanager ( ng . Cfg , store , store , ng . KVStore , decryptFn , multiOrgMetrics , log . New ( "ngalert.multiorg.alertmanager" ) )
2021-09-16 22:33:51 +08:00
if err != nil {
return err
}
2021-08-24 18:28:09 +08:00
// Let's make sure we're able to complete an initial sync of Alertmanagers before we start the alerting components.
if err := ng . MultiOrgAlertmanager . LoadAndSyncAlertmanagersForOrgs ( context . Background ( ) ) ; err != nil {
2021-05-14 02:01:38 +08:00
return err
}
2021-03-03 23:52:19 +08:00
2021-03-09 04:19:21 +08:00
schedCfg := schedule . SchedulerCfg {
2021-08-13 20:14:36 +08:00
C : clock . New ( ) ,
BaseInterval : baseInterval ,
2021-09-28 18:00:16 +08:00
Logger : ng . Log ,
MaxAttempts : ng . Cfg . UnifiedAlerting . MaxAttempts ,
2021-08-13 20:14:36 +08:00
Evaluator : eval . Evaluator { Cfg : ng . Cfg , Log : ng . Log } ,
InstanceStore : store ,
RuleStore : store ,
AdminConfigStore : store ,
2021-08-24 18:28:09 +08:00
OrgStore : store ,
MultiOrgNotifier : ng . MultiOrgAlertmanager ,
2021-09-14 19:55:01 +08:00
Metrics : ng . Metrics . GetSchedulerMetrics ( ) ,
2021-09-20 15:12:21 +08:00
AdminConfigPollInterval : ng . Cfg . UnifiedAlerting . AdminConfigPollInterval ,
2021-09-29 22:16:40 +08:00
DisabledOrgs : ng . Cfg . UnifiedAlerting . DisabledOrgs ,
2021-09-28 18:00:16 +08:00
MinRuleInterval : ng . getRuleMinInterval ( ) ,
2021-01-23 01:27:33 +08:00
}
2021-10-01 00:51:20 +08:00
appUrl , err := url . Parse ( ng . Cfg . AppURL )
if err != nil {
ng . Log . Error ( "Failed to parse application URL. Continue without it." , "error" , err )
appUrl = nil
}
2021-10-05 02:04:37 +08:00
stateManager := state . NewManager ( ng . Log , ng . Metrics . GetStateMetrics ( ) , appUrl , store , store )
2021-10-01 00:51:20 +08:00
scheduler := schedule . NewScheduler ( schedCfg , ng . DataService , appUrl , stateManager )
2021-08-13 20:14:36 +08:00
2021-08-25 21:11:22 +08:00
ng . stateManager = stateManager
2021-10-01 00:51:20 +08:00
ng . schedule = scheduler
2021-03-03 23:52:19 +08:00
2021-03-09 04:19:21 +08:00
api := api . API {
2021-08-24 18:28:09 +08:00
Cfg : ng . Cfg ,
2021-08-25 21:11:22 +08:00
DatasourceCache : ng . DataSourceCache ,
2021-08-24 18:28:09 +08:00
RouteRegister : ng . RouteRegister ,
DataService : ng . DataService ,
Schedule : ng . schedule ,
DataProxy : ng . DataProxy ,
QuotaService : ng . QuotaService ,
2021-10-07 22:33:50 +08:00
EncryptionService : ng . EncryptionService ,
2021-08-24 18:28:09 +08:00
InstanceStore : store ,
RuleStore : store ,
AlertingStore : store ,
AdminConfigStore : store ,
MultiOrgAlertmanager : ng . MultiOrgAlertmanager ,
StateManager : ng . stateManager ,
2021-03-24 22:20:44 +08:00
}
2021-09-14 19:55:01 +08:00
api . RegisterAPIEndpoints ( ng . Metrics . GetAPIMetrics ( ) )
2021-03-03 23:52:19 +08:00
2020-11-12 21:11:30 +08:00
return nil
}
2021-07-27 18:52:59 +08:00
// Run starts the scheduler and Alertmanager.
2020-12-17 22:00:09 +08:00
func ( ng * AlertNG ) Run ( ctx context . Context ) error {
2021-03-09 04:19:21 +08:00
ng . Log . Debug ( "ngalert starting" )
2021-07-08 00:18:31 +08:00
ng . stateManager . Warm ( )
2021-05-14 02:01:38 +08:00
children , subCtx := errgroup . WithContext ( ctx )
2021-09-28 18:00:16 +08:00
if ng . Cfg . UnifiedAlerting . ExecuteAlerts {
children . Go ( func ( ) error {
return ng . schedule . Run ( subCtx )
} )
}
2021-05-14 02:01:38 +08:00
children . Go ( func ( ) error {
2021-08-24 18:28:09 +08:00
return ng . MultiOrgAlertmanager . Run ( subCtx )
2021-05-14 02:01:38 +08:00
} )
return children . Wait ( )
2020-12-17 22:00:09 +08:00
}
2020-11-12 21:11:30 +08:00
// IsDisabled returns true if the alerting service is disable for this instance.
func ( ng * AlertNG ) IsDisabled ( ) bool {
if ng . Cfg == nil {
2020-12-17 22:00:09 +08:00
return true
2020-11-12 21:11:30 +08:00
}
2021-09-29 22:16:40 +08:00
return ! ng . Cfg . UnifiedAlerting . Enabled
2020-11-12 21:11:30 +08:00
}
2021-09-28 18:00:16 +08:00
// getRuleDefaultIntervalSeconds returns the default rule interval if the interval is not set.
// If this constant (1 minute) is lower than the configured minimum evaluation interval then
// this configuration is returned.
func ( ng * AlertNG ) getRuleDefaultInterval ( ) time . Duration {
ruleMinInterval := ng . getRuleMinInterval ( )
if defaultIntervalSeconds < int64 ( ruleMinInterval . Seconds ( ) ) {
return ruleMinInterval
}
return time . Duration ( defaultIntervalSeconds ) * time . Second
}
// getRuleMinIntervalSeconds returns the configured minimum rule interval.
// If this value is less or equal to zero or not divided exactly by the scheduler interval
// the scheduler interval (10 seconds) is returned.
func ( ng * AlertNG ) getRuleMinInterval ( ) time . Duration {
if ng . Cfg . UnifiedAlerting . MinInterval <= 0 {
return defaultBaseIntervalSeconds // if it's not configured; apply default
}
if ng . Cfg . UnifiedAlerting . MinInterval % defaultBaseIntervalSeconds != 0 {
ng . Log . Error ( "Configured minimum evaluation interval is not divided exactly by the scheduler interval and it will fallback to default" , "alertingMinInterval" , ng . Cfg . UnifiedAlerting . MinInterval , "baseIntervalSeconds" , defaultBaseIntervalSeconds , "defaultIntervalSeconds" , defaultIntervalSeconds )
return defaultBaseIntervalSeconds // if it's invalid; apply default
}
return ng . Cfg . UnifiedAlerting . MinInterval
}