go实现的一个监控日志报警程序

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
	}

}

你可能感兴趣的:(GO语言,程序点滴)