@@ -30,6 +30,10 @@ type Dispatch struct {
30
30
notifyConfigCache * memsto.NotifyConfigCacheType
31
31
taskTplsCache * memsto.TaskTplCache
32
32
33
+ notifyRuleCache * memsto.NotifyRuleCacheType
34
+ notifyChannelCache * memsto.NotifyChannelCacheType
35
+ messageTemplateCache * memsto.MessageTemplateCacheType
36
+
33
37
alerting aconf.Alerting
34
38
35
39
Senders map [string ]sender.Sender
@@ -47,15 +51,19 @@ type Dispatch struct {
47
51
// 创建一个 Notify 实例
48
52
func NewDispatch (alertRuleCache * memsto.AlertRuleCacheType , userCache * memsto.UserCacheType , userGroupCache * memsto.UserGroupCacheType ,
49
53
alertSubscribeCache * memsto.AlertSubscribeCacheType , targetCache * memsto.TargetCacheType , notifyConfigCache * memsto.NotifyConfigCacheType ,
50
- taskTplsCache * memsto.TaskTplCache , alerting aconf.Alerting , ctx * ctx.Context , astats * astats.Stats ) * Dispatch {
54
+ taskTplsCache * memsto.TaskTplCache , notifyRuleCache * memsto.NotifyRuleCacheType , notifyChannelCache * memsto.NotifyChannelCacheType ,
55
+ messageTemplateCache * memsto.MessageTemplateCacheType , alerting aconf.Alerting , ctx * ctx.Context , astats * astats.Stats ) * Dispatch {
51
56
notify := & Dispatch {
52
- alertRuleCache : alertRuleCache ,
53
- userCache : userCache ,
54
- userGroupCache : userGroupCache ,
55
- alertSubscribeCache : alertSubscribeCache ,
56
- targetCache : targetCache ,
57
- notifyConfigCache : notifyConfigCache ,
58
- taskTplsCache : taskTplsCache ,
57
+ alertRuleCache : alertRuleCache ,
58
+ userCache : userCache ,
59
+ userGroupCache : userGroupCache ,
60
+ alertSubscribeCache : alertSubscribeCache ,
61
+ targetCache : targetCache ,
62
+ notifyConfigCache : notifyConfigCache ,
63
+ taskTplsCache : taskTplsCache ,
64
+ notifyRuleCache : notifyRuleCache ,
65
+ notifyChannelCache : notifyChannelCache ,
66
+ messageTemplateCache : messageTemplateCache ,
59
67
60
68
alerting : alerting ,
61
69
@@ -131,6 +139,233 @@ func (e *Dispatch) relaodTpls() error {
131
139
return nil
132
140
}
133
141
142
+ func (e * Dispatch ) HandleEventNotifyV2 (event * models.AlertCurEvent , isSubscribe bool ) {
143
+
144
+ if len (event .NotifyRuleIDs ) > 0 {
145
+ for _ , notifyRuleId := range event .NotifyRuleIDs {
146
+ logger .Infof ("notify rule ids: %v, event: %+v" , notifyRuleId , event )
147
+ notifyRule := e .notifyRuleCache .Get (notifyRuleId )
148
+ if notifyRule == nil {
149
+ continue
150
+ }
151
+
152
+ for i := range notifyRule .NotifyConfigs {
153
+ if ! NotifyRuleApplicable (& notifyRule .NotifyConfigs [i ], event ) {
154
+ continue
155
+ }
156
+ notifyChannel := e .notifyChannelCache .Get (notifyRule .NotifyConfigs [i ].ChannelID )
157
+ messageTemplate := e .messageTemplateCache .Get (notifyRule .NotifyConfigs [i ].TemplateID )
158
+ if notifyChannel == nil {
159
+ logger .Warningf ("notify_id: %d, event:%+v, channel_id:%d, template_id: %d, notify_channel not found" , notifyRuleId , event , notifyRule .NotifyConfigs [i ].ChannelID , notifyRule .NotifyConfigs [i ].TemplateID )
160
+ continue
161
+ }
162
+
163
+ if notifyChannel .RequestType != "flashduty" && messageTemplate == nil {
164
+ logger .Warningf ("notify_id: %d, channel_name: %v, event:%+v, template_id: %d, message_template not found" , notifyRuleId , notifyChannel .Ident , event , notifyRule .NotifyConfigs [i ].TemplateID )
165
+ continue
166
+ }
167
+
168
+ // todo go send
169
+ // todo 聚合 event
170
+ go e .sendV2 ([]* models.AlertCurEvent {event }, notifyRuleId , & notifyRule .NotifyConfigs [i ], notifyChannel , messageTemplate )
171
+ }
172
+ }
173
+ }
174
+ }
175
+
176
+ func NotifyRuleApplicable (notifyConfig * models.NotifyConfig , event * models.AlertCurEvent ) bool {
177
+ tm := time .Unix (event .TriggerTime , 0 )
178
+ triggerTime := tm .Format ("15:04" )
179
+ triggerWeek := int (tm .Weekday ())
180
+
181
+ timeMatch := false
182
+
183
+ if len (notifyConfig .TimeRanges ) == 0 {
184
+ timeMatch = true
185
+ }
186
+ for j := range notifyConfig .TimeRanges {
187
+ if timeMatch {
188
+ break
189
+ }
190
+ enableStime := notifyConfig .TimeRanges [j ].Start
191
+ enableEtime := notifyConfig .TimeRanges [j ].End
192
+ enableDaysOfWeek := notifyConfig .TimeRanges [j ].Week
193
+ length := len (enableDaysOfWeek )
194
+ // enableStime,enableEtime,enableDaysOfWeek三者长度肯定相同,这里循环一个即可
195
+ for i := 0 ; i < length ; i ++ {
196
+ if enableDaysOfWeek [i ] != triggerWeek {
197
+ continue
198
+ }
199
+
200
+ if enableStime < enableEtime {
201
+ if enableEtime == "23:59" {
202
+ // 02:00-23:59,这种情况做个特殊处理,相当于左闭右闭区间了
203
+ if triggerTime < enableStime {
204
+ // mute, 即没生效
205
+ continue
206
+ }
207
+ } else {
208
+ // 02:00-04:00 或者 02:00-24:00
209
+ if triggerTime < enableStime || triggerTime >= enableEtime {
210
+ // mute, 即没生效
211
+ continue
212
+ }
213
+ }
214
+ } else if enableStime > enableEtime {
215
+ // 21:00-09:00
216
+ if triggerTime < enableStime && triggerTime >= enableEtime {
217
+ // mute, 即没生效
218
+ continue
219
+ }
220
+ }
221
+
222
+ // 到这里说明当前时刻在告警规则的某组生效时间范围内,即没有 mute,直接返回 false
223
+ timeMatch = true
224
+ break
225
+ }
226
+ }
227
+
228
+ severityMatch := false
229
+ for i := range notifyConfig .Severities {
230
+ if notifyConfig .Severities [i ] == event .Severity {
231
+ severityMatch = true
232
+ }
233
+ }
234
+
235
+ tagMatch := true
236
+ if len (notifyConfig .LabelKeys ) > 0 {
237
+ tagFilters , err := models .ParseTagFilter (notifyConfig .LabelKeys )
238
+ if err != nil {
239
+ logger .Errorf ("failed to parse tag filter: %v" , err )
240
+ return false
241
+ }
242
+ tagMatch = common .MatchTags (event .TagsMap , tagFilters )
243
+ }
244
+
245
+ attributesMatch := true
246
+ if len (notifyConfig .Attributes ) > 0 {
247
+ tagFilters , err := models .ParseTagFilter (notifyConfig .Attributes )
248
+ if err != nil {
249
+ logger .Errorf ("failed to parse tag filter: %v" , err )
250
+ return false
251
+ }
252
+
253
+ attributesMatch = common .MatchTags (event .JsonTagsAndValue (), tagFilters )
254
+ }
255
+
256
+ return timeMatch && severityMatch && tagMatch && attributesMatch
257
+ }
258
+
259
+ func GetNotifyConfigParams (notifyConfig * models.NotifyConfig , userCache * memsto.UserCacheType , userGroupCache * memsto.UserGroupCacheType ) ([]* models.User , []int64 , map [string ]string ) {
260
+ customParams := make (map [string ]string )
261
+ var userInfos []* models.User
262
+ var flashDutyChannelIDs []int64
263
+ var userInfoParams models.CustomParams
264
+
265
+ for key , value := range notifyConfig .Params {
266
+ switch key {
267
+ case "user_ids" , "user_group_ids" , "ids" :
268
+ if data , err := json .Marshal (value ); err == nil {
269
+ var ids []int64
270
+ if json .Unmarshal (data , & ids ) == nil {
271
+ if key == "user_ids" {
272
+ userInfoParams .UserIDs = ids
273
+ } else if key == "user_group_ids" {
274
+ userInfoParams .UserGroupIDs = ids
275
+ } else if key == "ids" {
276
+ flashDutyChannelIDs = ids
277
+ }
278
+ }
279
+ }
280
+ default :
281
+ customParams [key ] = value .(string )
282
+ }
283
+ }
284
+
285
+ users := userCache .GetByUserIds (userInfoParams .UserIDs )
286
+ visited := make (map [int64 ]bool )
287
+ for _ , user := range users {
288
+ if visited [user .Id ] {
289
+ continue
290
+ }
291
+ visited [user .Id ] = true
292
+ userInfos = append (userInfos , user )
293
+ }
294
+ userGroups := userGroupCache .GetByUserGroupIds (userInfoParams .UserGroupIDs )
295
+ for _ , userGroup := range userGroups {
296
+ for _ , user := range userGroup .Users {
297
+ if visited [user .Id ] {
298
+ continue
299
+ }
300
+ visited [user .Id ] = true
301
+ userInfos = append (userInfos , & user )
302
+ }
303
+ }
304
+
305
+ return userInfos , flashDutyChannelIDs , customParams
306
+ }
307
+
308
+ func (e * Dispatch ) sendV2 (events []* models.AlertCurEvent , notifyRuleId int64 , notifyConfig * models.NotifyConfig , notifyChannel * models.NotifyChannelConfig , messageTemplate * models.MessageTemplate ) {
309
+ if len (events ) == 0 {
310
+ logger .Errorf ("notify_id: %d events is empty" , notifyRuleId )
311
+ return
312
+ }
313
+
314
+ tplContent := messageTemplate .RenderEvent (events )
315
+
316
+ userInfos , flashDutyChannelIDs , customParams := GetNotifyConfigParams (notifyConfig , e .userCache , e .userGroupCache )
317
+
318
+ e .Astats .GaugeNotifyRecordQueueSize .Inc ()
319
+ defer e .Astats .GaugeNotifyRecordQueueSize .Dec ()
320
+
321
+ switch notifyChannel .RequestType {
322
+ case "flashduty" :
323
+ for i := range flashDutyChannelIDs {
324
+ respBody , err := notifyChannel .SendFlashDuty (events , flashDutyChannelIDs [i ], e .notifyChannelCache .GetHttpClient (notifyChannel .ID ))
325
+ logger .Infof ("notify_id: %d, channel_name: %v, event:%+v, IntegrationUrl: %v, respBody: %v, err: %v" , notifyRuleId , notifyChannel .Name , events [0 ], notifyChannel .RequestConfig .FlashDutyRequestConfig .IntegrationUrl , respBody , err )
326
+ sender .NotifyRecord (e .ctx , events , notifyRuleId , notifyChannel .Name , notifyChannel .RequestConfig .FlashDutyRequestConfig .IntegrationUrl , respBody , err )
327
+ }
328
+ return
329
+ case "http" :
330
+ if e .notifyChannelCache .HttpConcurrencyAdd (notifyChannel .ID ) {
331
+ defer e .notifyChannelCache .HttpConcurrencyDone (notifyChannel .ID )
332
+ }
333
+
334
+ if notifyChannel .ParamConfig .UserInfo != nil && len (userInfos ) > 0 {
335
+ for i := range userInfos {
336
+ respBody , err := notifyChannel .SendHTTP (events , tplContent , customParams , userInfos [i ], e .notifyChannelCache .GetHttpClient (notifyChannel .ID ))
337
+ logger .Infof ("notify_id: %d, channel_name: %v, event:%+v, tplContent:%s, customParams:%v, userInfo:%+v, respBody: %v, err: %v" , notifyRuleId , notifyChannel .Name , events [0 ], tplContent , customParams , userInfos [i ], respBody , err )
338
+ sender .NotifyRecord (e .ctx , events , notifyRuleId , notifyChannel .Name , notifyChannel .RequestConfig .HTTPRequestConfig .URL , respBody , err )
339
+ }
340
+ } else {
341
+ respBody , err := notifyChannel .SendHTTP (events , tplContent , customParams , nil , e .notifyChannelCache .GetHttpClient (notifyChannel .ID ))
342
+ logger .Infof ("notify_id: %d, channel_name: %v, event:%+v, tplContent:%s, customParams:%v, respBody: %v, err: %v" , notifyRuleId , notifyChannel .Name , events [0 ], tplContent , customParams , respBody , err )
343
+ sender .NotifyRecord (e .ctx , events , notifyRuleId , notifyChannel .Name , notifyChannel .RequestConfig .HTTPRequestConfig .URL , respBody , err )
344
+ }
345
+
346
+ case "email" :
347
+ err := notifyChannel .SendEmail (events , tplContent , userInfos , e .notifyChannelCache .GetSmtpClient (notifyChannel .ID ))
348
+ if err != nil {
349
+ logger .Errorf ("send email error: %v" , err )
350
+ }
351
+ for i := range userInfos {
352
+ msg := ""
353
+ if err == nil {
354
+ msg = "ok"
355
+ }
356
+
357
+ // todo 这里的通知记录需要调整
358
+ sender .NotifyRecord (e .ctx , events , notifyRuleId , notifyChannel .Name , userInfos [i ].Email , msg , err )
359
+ }
360
+ case "script" :
361
+ target , res , err := notifyChannel .SendScript (events , tplContent , customParams , userInfos )
362
+ logger .Infof ("notify_id: %d, channel_name: %v, event:%+v, tplContent:%s, customParams:%v, target:%s, res:%s, err:%v" , notifyRuleId , notifyChannel .Name , events [0 ], tplContent , customParams , target , res , err )
363
+ sender .NotifyRecord (e .ctx , events , notifyRuleId , notifyChannel .Name , target , res , err )
364
+ default :
365
+ logger .Warningf ("notify_id: %d, channel_name: %v, event:%+v send type not found" , notifyRuleId , notifyChannel .Name , events [0 ])
366
+ }
367
+ }
368
+
134
369
// HandleEventNotify 处理event事件的主逻辑
135
370
// event: 告警/恢复事件
136
371
// isSubscribe: 告警事件是否由subscribe的配置产生
@@ -173,6 +408,7 @@ func (e *Dispatch) HandleEventNotify(event *models.AlertCurEvent, isSubscribe bo
173
408
}
174
409
175
410
// 处理事件发送,这里用一个goroutine处理一个event的所有发送事件
411
+ go e .HandleEventNotifyV2 (event , isSubscribe )
176
412
go e .Send (rule , event , notifyTarget , isSubscribe )
177
413
178
414
// 如果是不是订阅规则出现的event, 则需要处理订阅规则的event
0 commit comments