github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/alerts/alertsqlite/alerts_sqlite.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package alertsqlite 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "strings" 24 "time" 25 26 "github.com/google/uuid" 27 "gorm.io/driver/sqlite" 28 _ "gorm.io/driver/sqlite" 29 "gorm.io/gorm" 30 31 "github.com/siglens/siglens/pkg/alerts/alertutils" 32 "github.com/sirupsen/logrus" 33 log "github.com/sirupsen/logrus" 34 ) 35 36 type Sqlite struct { 37 db *gorm.DB 38 ctx context.Context 39 } 40 41 func (p *Sqlite) SetDB(dbConnection *gorm.DB) { 42 p.db = dbConnection 43 } 44 45 func (p *Sqlite) CloseDb() { 46 sqlDB, err := p.db.DB() 47 if err != nil { 48 log.Errorf("Error occurred while closing a DB connection") 49 } 50 defer sqlDB.Close() 51 } 52 53 func (p *Sqlite) Connect() error { 54 dbname := "siglens.db" 55 logger := logrus.New() 56 dbConnection, err := gorm.Open(sqlite.Open(dbname), &gorm.Config{ 57 Logger: alertutils.NewGormLogrusLogger(logger.WithField("component", "gorm"), 100*time.Millisecond), 58 }) 59 if err != nil { 60 log.Errorf("connectAlertDB: error in opening sqlite connection, err: %+v", err) 61 return err 62 } 63 64 p.SetDB(dbConnection) 65 66 err = dbConnection.AutoMigrate(&alertutils.AlertDetails{}) 67 if err != nil { 68 return err 69 } 70 err = dbConnection.AutoMigrate(&alertutils.AlertLabel{}) 71 if err != nil { 72 return err 73 } 74 err = dbConnection.AutoMigrate(&alertutils.AlertHistoryDetails{}) 75 if err != nil { 76 return err 77 } 78 err = dbConnection.AutoMigrate(&alertutils.Notification{}) 79 if err != nil { 80 return err 81 } 82 err = dbConnection.AutoMigrate(&alertutils.Contact{}) 83 if err != nil { 84 return err 85 } 86 err = dbConnection.AutoMigrate(&alertutils.SlackTokenConfig{}) 87 if err != nil { 88 return err 89 } 90 err = dbConnection.AutoMigrate(&alertutils.MinionSearch{}) 91 if err != nil { 92 return err 93 } 94 p.ctx = context.Background() 95 return nil 96 } 97 98 func isValid(str string) bool { 99 return str != "" && str != "*" 100 } 101 102 // checks whether the alert name exists 103 func (p Sqlite) isNewAlertName(alertName string) (bool, error) { 104 if !isValid(alertName) { 105 log.Errorf("isNewAlertName: data validation check failed") 106 return false, errors.New("isNewAlertName: data validation check failed") 107 } 108 if err := p.db.Where("alert_name = ?", alertName).First(&alertutils.AlertDetails{}).Error; err != nil { 109 if err == gorm.ErrRecordNotFound { 110 return true, nil 111 } else { 112 return false, err 113 } 114 } 115 return true, nil 116 } 117 118 // checks based on alert_id, returns true and alert_name if alert exists 119 func (p Sqlite) verifyAlertExists(alert_id string) (bool, string, error) { 120 if !isValid(alert_id) { 121 log.Errorf("verifyAlertExists: data validation check failed %v", alert_id) 122 return false, "", errors.New("verifyAlertExists: data validation check failed") 123 } 124 var alert alertutils.AlertDetails 125 126 if err := p.db.Where("alert_id = ?", alert_id).Find(&alert).First(&alertutils.AlertDetails{}).Error; err != nil { 127 if err == gorm.ErrRecordNotFound { 128 return true, alert.AlertName, nil 129 } else { 130 return false, "", err 131 } 132 } 133 134 return true, "", nil 135 } 136 137 func (p Sqlite) verifyContactExists(contact_id string) (bool, error) { 138 if !isValid(contact_id) { 139 log.Errorf("verifyContactExists: data validation check failed") 140 return false, errors.New("verifyContactExists: data validation check failed") 141 } 142 var contact alertutils.Contact 143 if err := p.db.Where("contact_id = ?", contact_id).Find(&contact).First(&alertutils.Contact{}).Error; err != nil { 144 if err == gorm.ErrRecordNotFound { 145 return true, nil 146 } else { 147 return false, err 148 } 149 } 150 return true, nil 151 } 152 153 // Generates uniq uuid for alert, contact point 154 func CreateUniqId() string { 155 newAlertId := uuid.New().String() 156 return newAlertId 157 } 158 159 // Creates a new record in all_alerts table and notification_details table 160 // In notification_details table, cooldown period will be set as 0 for now 161 // Starts a new cron job for the alert 162 func (p Sqlite) CreateAlert(alertDetails *alertutils.AlertDetails) (alertutils.AlertDetails, error) { 163 if !isValid(alertDetails.AlertName) { 164 log.Errorf("createAlert: data validation check failed") 165 return alertutils.AlertDetails{}, errors.New("createAlert: data validation check failed") 166 } 167 isNewAlertName, _ := p.isNewAlertName(alertDetails.AlertName) 168 169 if !isNewAlertName { 170 log.Errorf("createAlert: alert name already exists") 171 return alertutils.AlertDetails{}, errors.New("alert name already exists") 172 } 173 alert_id := CreateUniqId() 174 state := alertutils.Inactive 175 alertDetails.State = state 176 alertDetails.AlertId = alert_id 177 result := p.db.Create(alertDetails) 178 if result.Error != nil && result.RowsAffected != 1 { 179 log.Errorf("createAlert: unable to create alert:%v", result.Error) 180 return alertutils.AlertDetails{}, result.Error 181 } 182 183 var notification alertutils.Notification 184 notification.CooldownPeriod = 0 185 notification.AlertId = alert_id 186 notification.NotificationId = CreateUniqId() 187 result = p.db.Create(¬ification) 188 if result.Error != nil && result.RowsAffected != 1 { 189 log.Errorf("createAlert: unable to update notification details:%v", result.Error) 190 return alertutils.AlertDetails{}, result.Error 191 } 192 return *alertDetails, nil 193 } 194 195 func (p Sqlite) GetAlert(alert_id string) (*alertutils.AlertDetails, error) { 196 if !isValid(alert_id) { 197 log.Errorf("getAlert: data validation check failed") 198 return nil, errors.New("getAlert: data validation check failed") 199 } 200 var alert alertutils.AlertDetails 201 if err := p.db.Preload("Labels").Where(&alertutils.AlertDetails{AlertId: alert_id}).Find(&alert).Error; err != nil { 202 return nil, err 203 } 204 return &alert, nil 205 206 } 207 208 func (p Sqlite) GetAllAlerts(orgId uint64) ([]alertutils.AlertDetails, error) { 209 alerts := make([]alertutils.AlertDetails, 0) 210 err := p.db.Model(&alerts).Preload("Labels").Where("org_id = ?", orgId).Find(&alerts).Error 211 return alerts, err 212 } 213 214 func (p Sqlite) UpdateSilenceMinutes(updatedSilenceMinutes *alertutils.AlertDetails) error { 215 if !isValid(updatedSilenceMinutes.AlertName) || !isValid(updatedSilenceMinutes.QueryParams.QueryText) { 216 log.Errorf("updateSilenceMinutes: data validation check failed") 217 return errors.New("updateSilenceMinutesupdateSilenceMinutes: data validation check failed") 218 } 219 alertExists, _, err := p.verifyAlertExists(updatedSilenceMinutes.AlertId) 220 if err != nil { 221 log.Errorf("updateSilenceMinutes: unable to verify if alert exists, err: %+v", err) 222 return err 223 } 224 if !alertExists { 225 log.Errorf("updateSilenceMinutes: alert does not exist") 226 return errors.New("alert does not exist") 227 } 228 result := p.db.Save(&updatedSilenceMinutes) 229 if result.Error != nil && result.RowsAffected != 1 { 230 log.Errorf("UpdateSilenceMinutes: unable to update silence minutes details:%v", result.Error) 231 return result.Error 232 } 233 234 return nil 235 } 236 237 // Deletes cron job associated with the alert 238 // Updates the db 239 // Starts a new cron job with a new cron job id 240 // updates alert details except state & cron_job_id 241 func (p Sqlite) UpdateAlert(editedAlert *alertutils.AlertDetails) error { 242 // update alert can update alert name -> still id will remain same 243 // todo: check if contact_id exists 244 if !isValid(editedAlert.AlertName) || !isValid(editedAlert.QueryParams.QueryText) { 245 log.Errorf("updateAlert: data validation check failed") 246 return errors.New("updateAlert: data validation check failed") 247 } 248 alertExists, alertName, err := p.verifyAlertExists(editedAlert.AlertId) 249 if err != nil { 250 log.Errorf("updateAlert: unable to verify if alert exists, err: %+v", err) 251 return err 252 } 253 // new alert means id in request body is incorrect 254 if !alertExists { 255 log.Errorf("updateAlert: alert does not exist") 256 return errors.New("alert does not exist") 257 } 258 // if alert name in request body is same as that present in db, allow update 259 if alertName != editedAlert.AlertName { 260 isNewAlertName, err := p.isNewAlertName(editedAlert.AlertName) 261 if err != nil { 262 log.Errorf("updateAlert: unable to verify if alert name is new, err: %+v", err) 263 return err 264 } 265 if !isNewAlertName { 266 log.Errorf("updateAlert: alert name already exists") 267 return errors.New("alert name already exists") 268 } 269 } 270 result := p.db.Set("gorm:association_autoupdate", true).Save(&editedAlert) 271 if result.Error != nil && result.RowsAffected != 1 { 272 log.Errorf("UpdateAlert: unable to update alert details:%v", result.Error) 273 return result.Error 274 } 275 return nil 276 } 277 278 func (p Sqlite) DeleteAlert(alert_id string) error { 279 if !isValid(alert_id) { 280 log.Errorf("deleteAlert: data validation check failed") 281 return errors.New("deleteAlert: data validation check failed") 282 } 283 var alert alertutils.AlertDetails 284 result := p.db.First(&alert, "alert_id = ?", alert_id) 285 if result.Error != nil { 286 log.Errorf("deleteAlert: error deleting alert %v", result.Error) 287 if errors.Is(result.Error, gorm.ErrRecordNotFound) { 288 log.Errorf("deleteAlert: alert does not exist") 289 return result.Error 290 } else { 291 return result.Error 292 } 293 } 294 err := p.db.Model(&alert).Association("Labels").Clear() 295 if err != nil { 296 log.Errorf("deleteAlert: unable to delete alert :%v", err) 297 return err 298 } 299 300 result = p.db.Delete(&alert) 301 if result.Error != nil && result.RowsAffected != 1 { 302 log.Errorf("deleteAlert: unable to delete alert :%v", result.Error) 303 return result.Error 304 } 305 306 return nil 307 } 308 309 func (p Sqlite) CreateContact(newContact *alertutils.Contact) error { 310 var contact alertutils.Contact 311 result := p.db.First(&contact, "contact_name = ?", newContact.ContactName) 312 if result.Error != nil { 313 if !errors.Is(result.Error, gorm.ErrRecordNotFound) { 314 log.Errorf("CreateContact: contact name already exist") 315 return result.Error 316 } else { 317 contact_id := CreateUniqId() 318 newContact.ContactId = contact_id 319 result = p.db.Create(&newContact) 320 if result.Error != nil && result.RowsAffected != 1 { 321 log.Errorf("CreateContact: unable to create contact:%v", result.Error) 322 return result.Error 323 } 324 } 325 } 326 return nil 327 } 328 329 func (p Sqlite) GetAllContactPoints(org_id uint64) ([]alertutils.Contact, error) { 330 contacts := make([]alertutils.Contact, 0) 331 if err := p.db.Preload("Slack").Where("org_id = ?", org_id).Find(&contacts).Error; err != nil { 332 return nil, err 333 } 334 335 return contacts, nil 336 } 337 338 func (p Sqlite) UpdateContactPoint(contact *alertutils.Contact) error { 339 if !isValid(contact.ContactId) { 340 log.Errorf("updateContactPoint: invalid contact id") 341 return errors.New("invalid contact id") 342 } 343 344 contactExists, err := p.verifyContactExists(contact.ContactId) 345 if err != nil { 346 log.Errorf("updateContactPoint: unable to verify if contact exists, err: %+v", err) 347 return err 348 } 349 // contact does not exist, that means id in request body is incorrect 350 if !contactExists { 351 log.Errorf("updateContactPoint: contact does not exist") 352 return errors.New("contact does not exist") 353 } 354 355 if len(contact.Slack) != 0 { 356 err := p.db.Model(&alertutils.Contact{ContactId: contact.ContactId}).Association("Slack").Clear() 357 if err != nil { 358 log.Errorf("updateContactPoint: unable to update contact : %v, err: %+v", contact.ContactName, err) 359 return err 360 } 361 } 362 if len(contact.Webhook) != 0 { 363 err := p.db.Model(&alertutils.Contact{ContactId: contact.ContactId}).Association("Webhook").Clear() 364 if err != nil { 365 log.Errorf("updateContactPoint: unable to update contact : %v, err: %+v", contact.ContactName, err) 366 return err 367 } 368 } 369 result := p.db.Session(&gorm.Session{FullSaveAssociations: true}).Save(&contact) 370 if result.Error != nil && result.RowsAffected != 1 { 371 log.Errorf("updateContactPoint: unable to update contact : %v, err: %+v", contact.ContactName, err) 372 return result.Error 373 } 374 return nil 375 376 } 377 378 // get contact_id and message from all_alerts table using alert_id 379 func (p Sqlite) GetContactDetails(alert_id string) (string, string, string, error) { 380 381 var alert alertutils.AlertDetails 382 if err := p.db.First(&alert).Where("alert_id = ?", alert_id).Error; err != nil { 383 return "", "", "", err 384 } 385 alert_name := alert.AlertName 386 contact_id := alert.ContactID 387 message := alert.Message 388 condition := alert.Condition 389 value := alert.Value 390 391 newMessage := strings.ReplaceAll(message, "{{alert_rule_name}}", alert_name) 392 newMessage = strings.ReplaceAll(newMessage, "{{query_string}}", alert.QueryParams.QueryLanguage) 393 if condition == 0 { 394 val := "above " + fmt.Sprintf("%1.0f", value) 395 newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val) 396 } else if condition == 1 { 397 val := "below " + fmt.Sprintf("%1.0f", value) 398 newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val) 399 } else if condition == 2 { 400 val := "is equal to " + fmt.Sprintf("%1.0f", value) 401 newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val) 402 } else if condition == 3 { 403 val := "is not equal to " + fmt.Sprintf("%1.0f", value) 404 newMessage = strings.ReplaceAll(newMessage, "{{condition}}", val) 405 } else if condition == 4 { 406 newMessage = strings.ReplaceAll(newMessage, "{{condition}}", "has no value") 407 } 408 newMessage = strings.ReplaceAll(newMessage, "{{queryLanguage}}", alert.QueryParams.QueryLanguage) 409 return contact_id, newMessage, alert_name, nil 410 } 411 412 func (p Sqlite) GetCoolDownDetails(alert_id string) (uint64, time.Time, error) { 413 var notification alertutils.Notification 414 if err := p.db.First(¬ification).Where("alert_id = ?", alert_id).Error; err != nil { 415 return 0, time.Time{}, err 416 } 417 cooldown_period := notification.CooldownPeriod 418 last_sent_time := notification.LastSentTime 419 420 return cooldown_period, last_sent_time, nil 421 } 422 423 func (p Sqlite) DeleteContactPoint(contact_id string) error { 424 if !isValid(contact_id) { 425 log.Errorf("deleteContactPoint: data validation check failed") 426 return errors.New("deleteContactPoint: data validation check failed") 427 } 428 429 contactExists, err := p.verifyContactExists(contact_id) 430 if err != nil { 431 log.Errorf("deleteContactPoint: unable to verify if contact exists, err: %+v", err) 432 return err 433 } 434 // contact does not exist, that means id in request body is incorrect 435 if !contactExists { 436 log.Errorf("deleteContactPoint: contact does not exist") 437 return errors.New("contact does not exist") 438 } 439 440 var contact alertutils.Contact 441 442 result := p.db.First(&contact, "contact_id = ?", contact_id) 443 if result.Error != nil { 444 log.Errorf("deleteContactPoint: error deleting contact %v", result.Error) 445 if errors.Is(result.Error, gorm.ErrRecordNotFound) { 446 log.Errorf("deleteContactPoint: contact does not exist") 447 return result.Error 448 } else { 449 return result.Error 450 } 451 } 452 err = p.db.Model(&contact).Association("Slack").Clear() 453 if err != nil { 454 log.Errorf("deleteContactPoint: unable to delete contact :%v", err) 455 return err 456 } 457 458 result = p.db.Delete(&contact) 459 if result.Error != nil && result.RowsAffected != 1 { 460 log.Errorf("deleteContactPoint: unable to delete contact :%v", result.Error) 461 return result.Error 462 } 463 464 return nil 465 } 466 467 // update last_sent_time in notification_details table 468 func (p Sqlite) UpdateLastSentTime(alert_id string) error { 469 currentTime := time.Now().UTC() 470 if err := p.db.Model(&alertutils.Notification{}).Where("alert_id = ?", alert_id).Update("last_sent_time", currentTime).Error; err != nil { 471 log.Errorf("updateLastSentTime: unable to UpdateLastSentTime, err: %+v", err) 472 return err 473 } 474 return nil 475 } 476 477 func (p Sqlite) UpdateAlertStateByAlertID(alert_id string, alertState alertutils.AlertState) error { 478 if !isValid(alert_id) { 479 log.Errorf("UpdateAlertStateByAlertID: data validation check failed") 480 return errors.New("UpdateAlertStateByAlertID: data validation check failed") 481 } 482 alertExists, _, err := p.verifyAlertExists(alert_id) 483 if err != nil { 484 log.Errorf("UpdateAlertStateByAlertID: unable to verify if alert name exists, err: %+v", err) 485 return err 486 } 487 if !alertExists { 488 log.Errorf("UpdateAlertStateByAlertID: alert does not exist") 489 return errors.New("alert does not exist") 490 } 491 492 if err := p.db.Model(&alertutils.AlertDetails{}).Where("alert_id = ?", alert_id).Update("state", alertState).Error; err != nil { 493 log.Errorf("UpdateAlertStateByAlertID: unable to update alert state, with alert id: %v, err: %+v", alert_id, err) 494 return err 495 } 496 return nil 497 } 498 499 func (p Sqlite) GetEmailAndChannelID(contact_id string) ([]string, []alertutils.SlackTokenConfig, []string, error) { 500 501 var contact = &alertutils.Contact{} 502 if err := p.db.Preload("Slack").First(&contact).Where("contact_id = ?", contact_id).Error; err != nil { 503 log.Errorf("GetEmailAndChannelID: unable to update contact, err: %+v", err) 504 return nil, nil, nil, err 505 } 506 emailArray := contact.Email 507 slackArray := contact.Slack 508 webhookArray := contact.Webhook 509 510 return emailArray, slackArray, webhookArray, nil 511 } 512 513 func (p Sqlite) GetAllMinionSearches(orgId uint64) ([]alertutils.MinionSearch, error) { 514 515 alerts := make([]alertutils.MinionSearch, 0) 516 err := p.db.Model(&alerts).Where("org_id = ?", orgId).Find(&alertutils.MinionSearch{}).Error 517 return alerts, err 518 } 519 520 // Creates a new record in all_alerts table 521 func (p Sqlite) CreateMinionSearch(minionSearchDetails *alertutils.MinionSearch) (alertutils.MinionSearch, error) { 522 if !isValid(minionSearchDetails.AlertName) { 523 log.Errorf("CreateMinionSearch: data validation check failed") 524 return alertutils.MinionSearch{}, errors.New("CreateMinionSearch: data validation check failed") 525 } 526 isNewAlertName, _ := p.isNewAlertName(minionSearchDetails.AlertName) 527 528 if !isNewAlertName { 529 log.Errorf("CreateMinionSearch: alert name already exists") 530 return alertutils.MinionSearch{}, errors.New("alert name already exists") 531 } 532 minionSearchDetails.CreateTimestamp = time.Now() 533 minionSearchDetails.State = alertutils.Inactive 534 535 result := p.db.Create(minionSearchDetails) 536 if result.Error != nil && result.RowsAffected != 1 { 537 log.Errorf("createAlert: unable to create alert:%v", result.Error) 538 return alertutils.MinionSearch{}, result.Error 539 } 540 541 return *minionSearchDetails, nil 542 } 543 544 func (p Sqlite) GetMinionSearch(alert_id string) (*alertutils.MinionSearch, error) { 545 if !isValid(alert_id) { 546 log.Errorf("GetMinionSearch: data validation check failed") 547 return nil, errors.New("GetMinionSearch: data validation check failed") 548 } 549 550 var alert alertutils.MinionSearch 551 if err := p.db.Preload("Labels").Where(&alertutils.AlertDetails{AlertId: alert_id}).Find(&alert).Error; err != nil { 552 return nil, err 553 } 554 return &alert, nil 555 556 } 557 558 func (p Sqlite) UpdateMinionSearchStateByAlertID(alertId string, alertState alertutils.AlertState) error { 559 if !isValid(alertId) { 560 log.Errorf("UpdateMinionSearchStateByAlertID: data validation check failed") 561 return errors.New("UpdateMinionSearchStateByAlertID: data validation check failed") 562 } 563 searchExists, _, err := p.verifyMinionSearchExists(alertId) 564 if err != nil { 565 log.Errorf("UpdateMinionSearchStateByAlertID: unable to verify if alert name exists, err: %+v", err) 566 return err 567 } 568 if !searchExists { 569 log.Errorf("UpdateMinionSearchStateByAlertID: alert does not exist") 570 return errors.New("MinionSearch does not exist") 571 } 572 if err := p.db.Model(&alertutils.MinionSearch{}).Where("alert_id = ?", alertId).Update("state", alertState).Error; err != nil { 573 log.Errorf("UpdateAlertStateByAlertID: unable to update alert state, with alert id: %v, err: %+v", alertId, err) 574 return err 575 } 576 return nil 577 } 578 579 func (p Sqlite) verifyMinionSearchExists(alert_id string) (bool, string, error) { 580 if !isValid(alert_id) { 581 log.Errorf("verifyMinionSearchExists: data validation check failed %v", alert_id) 582 return false, "", errors.New("verifyMinionSearchExists: data validation check failed") 583 } 584 var alert alertutils.MinionSearch 585 586 if err := p.db.Where("alert_id = ?", alert_id).Find(&alert).First(&alertutils.AlertDetails{}).Error; err != nil { 587 if err == gorm.ErrRecordNotFound { 588 return true, alert.AlertName, nil 589 } else { 590 return false, "", err 591 } 592 } 593 return true, "", nil 594 } 595 596 func (p Sqlite) CreateAlertHistory(alertHistoryDetails *alertutils.AlertHistoryDetails) (*alertutils.AlertHistoryDetails, error) { 597 if !isValid(alertHistoryDetails.AlertId) || !isValid(alertHistoryDetails.EventDescription) || !isValid(alertHistoryDetails.UserName) { 598 log.Errorf("CreateAlertHistory: data validation check failed") 599 return nil, errors.New("CreateAlertHistory: data validation check failed") 600 } 601 602 result := p.db.Create(alertHistoryDetails) 603 if result.Error != nil && result.RowsAffected != 1 { 604 log.Errorf("createAlert: unable to create alert:%v", result.Error) 605 return &alertutils.AlertHistoryDetails{}, result.Error 606 } 607 return alertHistoryDetails, nil 608 } 609 610 func (p Sqlite) GetAlertHistory(alertId string) ([]*alertutils.AlertHistoryDetails, error) { 611 if !isValid(alertId) { 612 log.Errorf("GetAlertHistory: data validation check failed") 613 return nil, errors.New("GetAlertHistory: data validation check failed") 614 } 615 616 alertExists, _, err := p.verifyAlertExists(alertId) 617 if err != nil { 618 log.Errorf("GetAlertHistory: unable to verify if alert exists, err: %+v", err) 619 return nil, err 620 } 621 622 if !alertExists { 623 log.Errorf("GetAlertHistory: alert does not exist") 624 return nil, errors.New("alert does not exist") 625 } 626 627 alertHistory := make([]*alertutils.AlertHistoryDetails, 0) 628 629 err = p.db.First(&alertHistory).Where("alert_id = ?", alertId).Error 630 return alertHistory, err 631 632 }