go實現的一個監控日誌報警程式
阿新 • • 發佈:2019-02-14
package main import ( "compile" "encoding/json" "flag" "fmt" "io/ioutil" "libconf/goini" log "log4go" "net/http" "os" "path/filepath" "regexp" "strings" "time" ) const ( AlarmType = iota AlarmTypeTimeout AlarmTypeLost ) //sub struct of outAlarmBody type outAlarmPara struct { Alarmlevel int `json:"alarmlevel"` Alarmtype int `json:"alarmtype"` Url string `json:"url"` Alarmip string `json:"alarmip"` Alarmcontext string `json:"alarmcontext"` Alarmtimer string `json:"alarmtimer"` } //post body to monitor server type outAlarmBody struct { Cpid string `json:"cpid"` Alarms []outAlarmPara `json:"alarms"` } var ver string = "1.0.0" var g_ip string = "" var g_cpid string = "" var g_remoteInterface = "" var pos int64 = 0 //file seek position func trimstring(src string) string { rs := []rune(src) rl := len(src) src = string(rs[0:rl]) return src } //讀取檔案需要經常進行錯誤檢查,這個幫助方法可以精簡下面的錯誤檢查過程。 func check(e error) { if e != nil { panic(e) } } //send alarm to monitor func httpPost(pUrl string, pBody string) { resp, err := http.Post(pUrl, "application/x-www-form-urlencoded", strings.NewReader(pBody)) if err != nil { log.Fatal("httpPost error:" + err.Error()) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { // handle error log.Fatal("no resp error:" + err.Error()) return } fmt.Println(string(body)) log.Debug("ugslb resp with body:%s", string(body)) } func getCurrentDirectory() string { dir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { log.Fatal("in getCurrentDirectory get path error:" + err.Error()) } return strings.Replace(dir, "\\", "/", -1) } func PathExists(path string) (bool, error) { _, err := os.Stat(path) if err == nil { return true, nil } if os.IsNotExist(err) { return false, nil } return false, err } //parse the content like st:20170106180425 func parseTimeVal(dateContent string) (dateTime string) { //fmt.Println(dateContent) log.Debug("date to parse:%s", dateContent) content := strings.Split(dateContent, ":") timeVal := "" if 0 != len(content[1]) { timeformatdate, _ := time.Parse("20060102150405", content[1]) parsedTime := timeformatdate.Format("2006-01-02 15:04:05") log.Debug("timeVal:%s", parsedTime) timeVal = parsedTime } return timeVal } //parse line content like st:20171221150609 et:20171221150614 http://guo1guang.live.OOotvcloud.com/otv/xjgg/livess/channel44/700.m3u8 part func parseLine(line string) (st, et, url string) { content := strings.Split(line, " ") fmt.Println(content, len(content)) stVal := "" etVal := "" urlVal := "" for _, a := range content { if 0 != len(a) { log.Debug("to parse %s, length %d", a, len(a)) if strings.Contains(a, "st") { stVal = parseTimeVal(a) continue } if strings.Contains(a, "et") { etVal = parseTimeVal(a) continue } if strings.Contains(a, "http") { urlVal = a } } } return stVal, etVal, urlVal } func alarmProcess(fileName string) { //analyze the log file, err := os.Open(fileName) check(err) defer file.Close() var alarm_sliceSend []outAlarmPara const blockSize = 1024 * 32 const timeoutPattern = "st.*part$" const lostPattern = "st.*404$" //log.Debug("cur pos:%d, read block size:%d", pos, blockSize) for { o2, err := file.Seek(pos, 0) check(err) b2 := make([]byte, blockSize) n2, err := file.Read(b2) //fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2)) lines := strings.Split(string(b2), "\n") for i, a := range lines { //fmt.Printf("line:%d, value:%q\n", i, a) //check if it is timeout reg, err := regexp.Compile(timeoutPattern) if err != nil { log.Warn(err.Error()) return } if true == reg.MatchString(a) { //parse the line st, et, url := parseLine(a) log.Debug("parse Res: st %s, et %s, url %s", st, et, url) var outAlarm outAlarmPara outAlarm.Alarmtype = AlarmTypeTimeout outAlarm.Alarmlevel = 10 outAlarm.Url = url outAlarm.Alarmip = g_ip outAlarm.Alarmtimer = st outAlarm.Alarmcontext = "超時" alarm_sliceSend = append(alarm_sliceSend, outAlarm) log.Debug("part detected line:%d,%q,%q", i, a, alarm_sliceSend) continue } //check if it is not found reg, err = regexp.Compile(lostPattern) if err != nil { fmt.Println(err) return } //fmt.Printf("lost %q\n", reg.FindAllString(a, -1)) if true == reg.MatchString(a) { st, et, url := parseLine(a) log.Debug("parse Res: st %s, et %s, url %s", st, et, url) var outAlarm outAlarmPara outAlarm.Alarmtype = AlarmTypeLost outAlarm.Alarmlevel = 10 outAlarm.Url = url outAlarm.Alarmip = g_ip outAlarm.Alarmtimer = st outAlarm.Alarmcontext = "缺片" alarm_sliceSend = append(alarm_sliceSend, outAlarm) } } pos += int64(n2) log.Debug("offset %d, read %d, pos %d", o2, n2, pos) if n2 != blockSize { log.Debug("reach end of file") break } } //notify monitor when the timeout happened outM := &outAlarmBody{ g_cpid, alarm_sliceSend, } b, err := json.Marshal(outM) if err != nil { log.Fatal("json encode message failed, %s", string(b)) } else { log.Debug("post content:%s", string(b)) httpPost(g_remoteInterface, string(b)) } } func main() { if err := log.SetupLogWithConf("./log.json"); err != nil { panic(err) } defer log.Close() // ./main -V version := flag.Bool("V", false, "is ok") flag.Parse() if *version { verStr := "ver: " + ver + "\t" fmt.Println("version:", verStr, compile.BuildTime()) return } config_ptr := goini.Init("./dlAlarmConf.ini") stmp := config_ptr.Read_string("root", "cpid", "btv") stmp = trimstring(stmp) g_cpid = stmp log.Debug(g_cpid) stmp = config_ptr.Read_string("root", "localAddr", "127.0.0.1") stmp = trimstring(stmp) g_ip = stmp log.Debug(g_ip) stmp = config_ptr.Read_string("root", "remoteInterface", "http://127.0.0.1/otvcloud/Alarm") stmp = trimstring(stmp) g_remoteInterface = stmp log.Debug(g_remoteInterface) stmp = config_ptr.Read_string("root", "file2Monitor", "/home/otvcloud/hls/123.log") stmp = trimstring(stmp) filePath := stmp log.Debug(filePath) isPathExist, _ := PathExists(filePath) if isPathExist != true { log.Debug("to be monitored file %s not exist?", filePath) return } ticker := time.NewTicker(time.Second * 10) go func() { for _ = range ticker.C { //log.Debug("ticked at %v", time.Now()) alarmProcess(filePath) } }() //maintain the main process limiter := time.Tick(time.Second * 30) for true { <-limiter } }