bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/models/incidents.go (about) 1 package models 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math" 7 "strconv" 8 "time" 9 10 "bosun.org/opentsdb" 11 ) 12 13 type IncidentState struct { 14 // Since IncidentState is embedded into a template's Context these fields 15 // are available to users. Changes to this object should be reflected 16 // in Bosun's documentation and changes that might break user's teamplates. 17 // need to be considered. 18 Id int64 19 Start time.Time 20 End *time.Time 21 AlertKey AlertKey 22 Alert string // helper data since AlertKeys don't serialize to JSON well 23 Tags string // string representation of Group 24 25 *Result 26 27 // Most recent last. 28 Events []Event `json:",omitempty"` 29 Actions []Action `json:",omitempty"` 30 31 Subject string 32 33 NeedAck bool 34 Open bool 35 36 Unevaluated bool 37 38 CurrentStatus Status 39 WorstStatus Status 40 41 LastAbnormalStatus Status 42 43 LastAbnormalTime Epoch 44 45 PreviousIds []int64 // A list to the previous IncidentIds for the same alert key (alertname+tagset) 46 NextId int64 // The id of the next Incident Id for the same alert key, only added once a future incident has been created 47 48 // set of notifications we have already sent alerts to during the lifetime of the incident 49 Notifications []string 50 } 51 52 // SetNotified marks the notification name as "active" for this incident. 53 // All future actions and unknown notifications will go to all "active" notifications 54 // it returns true if the set was changed (and needs resaving) 55 func (i *IncidentState) SetNotified(not string) bool { 56 for _, n := range i.Notifications { 57 if n == not { 58 return false 59 } 60 } 61 i.Notifications = append(i.Notifications, not) 62 return true 63 } 64 65 type Epoch struct { 66 time.Time 67 } 68 69 func (t Epoch) MarshalJSON() ([]byte, error) { 70 return []byte(fmt.Sprintf("%v", t.UTC().Unix())), nil 71 } 72 73 func (t *Epoch) UnmarshalJSON(b []byte) (err error) { 74 if len(b) == 0 { 75 t.Time = time.Time{} 76 return 77 } 78 epoch, err := strconv.ParseInt(string(b), 10, 64) 79 if err != nil { 80 return err 81 } 82 t.Time = time.Unix(epoch, 0) 83 return 84 } 85 86 type RenderedTemplates struct { 87 Subject string 88 Body string 89 EmailBody []byte 90 EmailSubject []byte 91 Custom map[string]string 92 Attachments []*Attachment 93 } 94 95 func (r *RenderedTemplates) Get(name string) string { 96 if name == "subject" { 97 return r.Subject 98 } 99 if name == "body" { 100 return r.Body 101 } 102 if name == "emailBody" { 103 if r.EmailBody != nil { 104 return string(r.EmailBody) 105 } 106 return r.Body 107 } 108 if name == "emailSubject" { 109 if r.EmailSubject != nil { 110 return string(r.EmailSubject) 111 } 112 return r.Subject 113 } 114 if t, ok := r.Custom[name]; ok { 115 return t 116 } 117 return "" 118 } 119 120 func (r *RenderedTemplates) GetDefault(name string, defaultName string) string { 121 if name == "" { 122 name = defaultName 123 } 124 return r.Get(name) 125 } 126 127 func (s *IncidentState) Group() opentsdb.TagSet { 128 return s.AlertKey.Group() 129 } 130 131 func (s *IncidentState) Last() Event { 132 if len(s.Events) == 0 { 133 return Event{} 134 } 135 return s.Events[len(s.Events)-1] 136 } 137 138 func (s *IncidentState) IsActive() bool { 139 return s.CurrentStatus > StNormal 140 } 141 142 type Event struct { 143 Warn, Crit *Result `json:",omitempty"` 144 Status Status 145 Time time.Time 146 Unevaluated bool 147 } 148 149 type EventsByTime []Event 150 151 func (a EventsByTime) Len() int { return len(a) } 152 func (a EventsByTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 153 func (a EventsByTime) Less(i, j int) bool { return a[i].Time.Before(a[j].Time) } 154 155 // custom float type to support json marshalling of NaN 156 type Float float64 157 158 func (m Float) MarshalJSON() ([]byte, error) { 159 if math.IsNaN(float64(m)) { 160 return []byte("null"), nil 161 } 162 return json.Marshal(float64(m)) 163 } 164 165 func (m *Float) UnmarshalJSON(b []byte) error { 166 if string(b) == "null" { 167 *m = Float(math.NaN()) 168 return nil 169 } 170 var f float64 171 err := json.Unmarshal(b, &f) 172 *m = Float(f) 173 return err 174 } 175 176 type Result struct { 177 Computations `json:",omitempty"` 178 Value Float 179 Expr string 180 } 181 182 type Computations []Computation 183 184 type Computation struct { 185 Text string 186 Value interface{} 187 } 188 189 type FuncType int 190 191 func (f FuncType) String() string { 192 switch f { 193 case TypeNumberSet: 194 return "number" 195 case TypeString: 196 return "string" 197 case TypeSeriesSet: 198 return "series" 199 case TypeScalar: 200 return "scalar" 201 case TypeESQuery: 202 return "esquery" 203 case TypeESIndexer: 204 return "esindexer" 205 case TypeNumberExpr: 206 return "numberexpr" 207 case TypeSeriesExpr: 208 return "seriesexpr" 209 case TypePrefix: 210 return "prefix" 211 case TypeTable: 212 return "table" 213 case TypeVariantSet: 214 return "variantSet" 215 case TypeAzureResourceList: 216 return "azureResources" 217 case TypeAzureAIApps: 218 return "azureAIApps" 219 case TypeInfo: 220 return "info" 221 default: 222 return "unknown" 223 } 224 } 225 226 const ( 227 TypeString FuncType = iota 228 TypePrefix 229 TypeScalar 230 TypeNumberSet 231 TypeSeriesSet 232 TypeESQuery 233 TypeESIndexer 234 TypeNumberExpr 235 TypeSeriesExpr // No implementation yet 236 TypeTable 237 TypeVariantSet 238 TypeAzureResourceList 239 TypeAzureAIApps 240 TypeInfo 241 TypeUnexpected 242 ) 243 244 type Status int 245 246 const ( 247 StNone Status = iota 248 StNormal 249 StWarning 250 StCritical 251 StUnknown 252 ) 253 254 func (s Status) String() string { 255 switch s { 256 case StNormal: 257 return "normal" 258 case StWarning: 259 return "warning" 260 case StCritical: 261 return "critical" 262 case StUnknown: 263 return "unknown" 264 default: 265 return "none" 266 } 267 } 268 269 func (s Status) MarshalJSON() ([]byte, error) { 270 return json.Marshal(s.String()) 271 } 272 273 func (s *Status) UnmarshalJSON(b []byte) error { 274 switch string(b) { 275 case `"normal"`: 276 *s = StNormal 277 case `"warning"`: 278 *s = StWarning 279 case `"critical"`: 280 *s = StCritical 281 case `"unknown"`: 282 *s = StUnknown 283 default: 284 *s = StNone 285 } 286 return nil 287 } 288 289 func (s Status) IsNormal() bool { return s == StNormal } 290 func (s Status) IsWarning() bool { return s == StWarning } 291 func (s Status) IsCritical() bool { return s == StCritical } 292 func (s Status) IsUnknown() bool { return s == StUnknown } 293 294 type Action struct { 295 // These are available to users via the template language. Changes here 296 // should be reflected in the documentation 297 User string 298 Message string 299 Time time.Time 300 Type ActionType 301 Deadline *time.Time `json:",omitempty"` 302 Fullfilled bool 303 Cancelled bool 304 } 305 306 type ActionType int // Available to users in templates, document changes in Bosun docs 307 308 const ( 309 ActionNone ActionType = iota 310 ActionAcknowledge 311 ActionClose 312 ActionForget 313 ActionForceClose 314 ActionPurge 315 ActionNote 316 ActionDelayedClose 317 ActionCancelClose 318 ) 319 320 //ActionShortNames is a map of keys we use in config file (notifications mostly) to reference action types 321 var ActionShortNames = map[string]ActionType{ 322 "Ack": ActionAcknowledge, 323 "Close": ActionClose, 324 "Forget": ActionForget, 325 "ForceClose": ActionForceClose, 326 "Purge": ActionPurge, 327 "Note": ActionNote, 328 "DelayedClose": ActionDelayedClose, 329 "CancelClose": ActionCancelClose, 330 } 331 332 // HumanString gives a better human readable form than the default stringer, which we can't change due to marshalling compatibility now 333 func (a ActionType) HumanString() string { 334 switch a { 335 case ActionAcknowledge: 336 return "Acknowledged" 337 case ActionClose: 338 return "Closed" 339 case ActionForget: 340 return "Forgot" 341 case ActionForceClose: 342 return "Force Closed" 343 case ActionPurge: 344 return "Purged" 345 case ActionNote: 346 return "Commented On" 347 case ActionDelayedClose: 348 return "Delayed Closed" 349 case ActionCancelClose: 350 return "Canceled Close" 351 default: 352 return "none" 353 } 354 } 355 356 func (a ActionType) String() string { 357 switch a { 358 case ActionAcknowledge: 359 return "Acknowledged" 360 case ActionClose: 361 return "Closed" 362 case ActionForget: 363 return "Forgotten" 364 case ActionForceClose: 365 return "ForceClosed" 366 case ActionPurge: 367 return "Purged" 368 case ActionNote: 369 return "Note" 370 case ActionDelayedClose: 371 return "DelayedClose" 372 case ActionCancelClose: 373 return "CancelClose" 374 default: 375 return "none" 376 } 377 } 378 379 func (a ActionType) MarshalJSON() ([]byte, error) { 380 return json.Marshal(a.String()) 381 } 382 383 func (a *ActionType) UnmarshalJSON(b []byte) error { 384 switch string(b) { 385 case `"Acknowledged"`: 386 *a = ActionAcknowledge 387 case `"Closed"`: 388 *a = ActionClose 389 case `"Forgotten"`: 390 *a = ActionForget 391 case `"Purged"`: 392 *a = ActionPurge 393 case `"ForceClosed"`: 394 *a = ActionForceClose 395 case `"Note"`: 396 *a = ActionNote 397 case `"DelayedClose"`: 398 *a = ActionDelayedClose 399 case `"CancelClose"`: 400 *a = ActionCancelClose 401 default: 402 *a = ActionNone 403 } 404 return nil 405 } 406 407 type Attachment struct { 408 Data []byte 409 Filename string 410 ContentType string 411 }