diff --git a/cfg.example.json b/cfg.example.json index ac6aa4e..c9e3cf9 100644 --- a/cfg.example.json +++ b/cfg.example.json @@ -26,6 +26,8 @@ "userSmsQueue": "/queue/user/sms", "userMailQueue": "/queue/user/mail" }, + "database": "root:@tcp(127.0.0.1:3306)/alarm?loc=Local&parseTime=true", + "maxIdle": 100, "api": { "portal": "http://falcon.example.com", "uic": "http://uic.example.com", diff --git a/cron/consumer.go b/cron/consumer.go index 210c5b3..25e1bf5 100644 --- a/cron/consumer.go +++ b/cron/consumer.go @@ -6,6 +6,7 @@ import ( "github.com/open-falcon/alarm/g" "github.com/open-falcon/alarm/redis" "github.com/open-falcon/common/model" + "github.com/open-falcon/alarm/db" "log" ) @@ -20,6 +21,14 @@ func consume(event *model.Event, isHigh bool) { return } + // save event in db + db.AddEvent(event, action) + if event.Status == "PROBLEM" { + db.AddAlert(event, action) + } else if event.Status == "OK" { + db.UpdateAlert(event, action) + } + if action.Callback == 1 { HandleCallback(event, action) return diff --git a/db/alert.go b/db/alert.go new file mode 100644 index 0000000..67e2b06 --- /dev/null +++ b/db/alert.go @@ -0,0 +1,69 @@ +package db + +import ( + "fmt" + cmodel "github.com/open-falcon/common/model" + "github.com/open-falcon/common/utils" + "github.com/open-falcon/alarm/api" + "log" +) + +func AddAlert(event *cmodel.Event, action *api.Action) { + sql := fmt.Sprintf("insert into alerts(event_id, endpoint, counter, max_step, current_step, priority, expression_id, strategy_id, content, note, status, team, event_time) values ('%s', '%s', '%s', %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", + event.Id, + event.Endpoint, + event.Counter(), + event.MaxStep(), + event.CurrentStep, + event.Priority(), + event.ExpressionId(), + event.StrategyId(), + getEventContent(event), + event.Note(), + event.Status, + action.Uic, + utils.UnixTsFormat(event.EventTime)) + + _, err := DB.Exec(sql) + if err != nil { + log.Println("exec", sql, "failed", err) + } +} + +func UpdateAlert(event *cmodel.Event, action *api.Action) { + sql := "" + if event.Status == "OK" { + sql = fmt.Sprintf("update alerts set status = 'OK', recovery_time = NOW() where event_id='%s' and status = 'PROBLEM'", event.Id) + _, err := DB.Exec(sql) + if err != nil { + log.Println("exec", sql, "failed", err) + } + } else { + sql := fmt.Sprintf("insert into alerts(event_id, endpoint, counter, max_step, current_step, priority, expression_id, strategy_id, content, note, status, team, event_time) values ('%s', '%s', '%s', %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", + event.Id, + event.Endpoint, + event.Counter(), + event.MaxStep(), + event.CurrentStep, + event.Priority(), + event.ExpressionId(), + event.StrategyId(), + getEventContent(event), + event.Note(), + event.Status, + action.Uic, + utils.UnixTsFormat(event.EventTime)) + _, err := DB.Exec(sql) + if err != nil { + log.Println("exec", sql, "failed", err) + } + } +} + +func MarkSolvedAlert(event_id string) { + sql := fmt.Sprintf("update alerts set status = 'OK', recovery_time = NOW() where event_id='%s' and status = 'PROBLEM'", event_id) + _, err := DB.Exec(sql) + if err != nil { + log.Println("exec", sql, "failed", err) + } +} diff --git a/db/db.go b/db/db.go new file mode 100644 index 0000000..7a91811 --- /dev/null +++ b/db/db.go @@ -0,0 +1,25 @@ +package db + +import ( + "database/sql" + _ "github.com/go-sql-driver/mysql" + "log" + "github.com/open-falcon/alarm/g" +) + +var DB *sql.DB + +func Init() { + var err error + DB, err = sql.Open("mysql", g.Config().Database) + if err != nil { + log.Fatalln("open db fail:", err) + } + + DB.SetMaxIdleConns(g.Config().MaxIdle) + + err = DB.Ping() + if err != nil { + log.Fatalln("ping db fail:", err) + } +} diff --git a/db/event.go b/db/event.go new file mode 100644 index 0000000..93db5dc --- /dev/null +++ b/db/event.go @@ -0,0 +1,78 @@ +package db + +import ( + "fmt" + cmodel "github.com/open-falcon/common/model" + "github.com/open-falcon/common/utils" + "github.com/open-falcon/alarm/api" + "github.com/open-falcon/alarm/g" + "log" + "time" +) + +func AddEvent(event *cmodel.Event, action *api.Action) { + sql := fmt.Sprintf("insert into events(event_id, endpoint, counter, max_step, current_step, priority, expression_id, strategy_id, content, note, status, team, event_time) values ('%s', '%s', '%s', %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", + event.Id, + event.Endpoint, + event.Counter(), + event.MaxStep(), + event.CurrentStep, + event.Priority(), + event.ExpressionId(), + event.StrategyId(), + getEventContent(event), + event.Note(), + event.Status, + action.Uic, + utils.UnixTsFormat(event.EventTime)) + + _, err := DB.Exec(sql) + if err != nil { + log.Println("exec", sql, "failed", err) + } +} + +func MarkSolvedEvent(event *g.EventDto) { + sql := fmt.Sprintf("insert into events(event_id, endpoint, counter, max_step, current_step, priority, expression_id, strategy_id, content, note, status, team, event_time) values ('%s', '%s', '%s', %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", + event.Id, + event.Endpoint, + event.Counter, + event.MaxStep, + 1, + event.Priority, + event.ExpressionId, + event.StrategyId, + "mark it solved", + event.Note, + "OK", + "", + utils.UnixTsFormat(time.Now().Unix())) + + _, err := DB.Exec(sql) + if err != nil { + log.Println("exec", sql, "failed", err) + } +} + +func getEventContent(event *cmodel.Event) string { + priority := 0 + maxStep := 0 + if event.Strategy != nil { + priority = event.Strategy.Priority + maxStep = event.Strategy.MaxStep + } else { + priority = event.Expression.Priority + maxStep = event.Expression.MaxStep + } + content := fmt.Sprintf("[P%d #%d/%d] %s %s %s%s%s", + priority, + event.CurrentStep, + maxStep, + event.Counter(), + event.Func(), + utils.ReadableFloat(event.LeftValue), + event.Operator(), + utils.ReadableFloat(event.RightValue()), + ) + return content +} diff --git a/g/cfg.go b/g/cfg.go index aa15b70..a170095 100644 --- a/g/cfg.go +++ b/g/cfg.go @@ -39,6 +39,8 @@ type GlobalConfig struct { Queue *QueueConfig `json:"queue"` Redis *RedisConfig `json:"redis"` Api *ApiConfig `json:"api"` + Database string `json:"database"` + MaxIdle int `json:"maxIdle"` } var ( diff --git a/g/eventdto.go b/g/eventdto.go index 75cbd30..7760a0d 100644 --- a/g/eventdto.go +++ b/g/eventdto.go @@ -59,6 +59,12 @@ func (this *SafeEvents) Delete(id string) { delete(this.M, id) } +func (this *SafeEvents) Get(id string) *EventDto { + this.Lock() + defer this.Unlock() + return this.M[id] +} + func (this *SafeEvents) Len() int { this.RLock() defer this.RUnlock() diff --git a/g/g.go b/g/g.go index 1845f0d..f531d23 100644 --- a/g/g.go +++ b/g/g.go @@ -6,7 +6,7 @@ import ( ) const ( - VERSION = "2.0.2" + VERSION = "2.0.3" ) func init() { diff --git a/http/controller.go b/http/controller.go index da58eea..9e3fa12 100644 --- a/http/controller.go +++ b/http/controller.go @@ -8,6 +8,7 @@ import ( "github.com/astaxie/beego" "github.com/open-falcon/alarm/g" + "github.com/open-falcon/alarm/db" "github.com/toolkits/file" ) @@ -73,6 +74,11 @@ func (this *MainController) Solve() { idArr := strings.Split(ids, ",,") for i := 0; i < len(idArr); i++ { + event := g.Events.Get(idArr[i]) + if event != nil { + db.MarkSolvedEvent(event) + db.MarkSolvedAlert(idArr[i]) + } g.Events.Delete(idArr[i]) } diff --git a/main.go b/main.go index 5becef4..cb62648 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/open-falcon/alarm/cron" "github.com/open-falcon/alarm/g" + "github.com/open-falcon/alarm/db" "github.com/open-falcon/alarm/http" "os" "os/signal" @@ -29,6 +30,7 @@ func main() { g.ParseConfig(*cfg) g.InitRedisConnPool() + db.Init() go http.Start()