allinssl/backend/scheduler/monitor.go

195 lines
5.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package scheduler
import (
"ALLinSSL/backend/internal/monitor"
"ALLinSSL/backend/internal/report"
"ALLinSSL/backend/public"
"encoding/json"
"fmt"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
var (
MonitorErrCount = make(map[int64]int)
monitorErrCountMu sync.Mutex
)
// 通知模板,先写死,后续做成配置
var MonitorErrTemplate = "监控名称:%v\n类型%v\n域名%v\n错误信息%v\n请及时处理\n检测时间%v"
func Monitor() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Monitor 主流程捕获 panic: %v\n", r)
}
}()
s, err := monitor.GetSqlite()
if err != nil {
fmt.Println(err)
}
defer s.Close()
s1, err := report.GetSqlite()
if err != nil {
fmt.Println(err)
return
}
defer s1.Close()
s1.TableName = "report"
data, err := s.Select()
if err != nil {
fmt.Println(err)
}
now := time.Now()
loc := now.Location()
var wg sync.WaitGroup
for _, v := range data {
if v["active"].(int64) == 1 {
lastTimeStr, ok := v["last_time"].(string)
if !ok || lastTimeStr == "" {
lastTimeStr = "1970-01-01 00:00:00"
}
lastTime, err := time.ParseInLocation("2006-01-02 15:04:05", lastTimeStr, loc)
if err != nil {
// fmt.Println(err)
continue
}
monitorType, ok := v["monitor_type"].(string)
if !ok {
fmt.Println("监控类型错误")
return
}
target, ok := v["target"].(string)
if !ok {
fmt.Println("监控目标错误")
return
}
advanceDay, ok := v["advance_day"].(int64)
if !ok {
advanceDay = 30 // 默认提前30天
}
if now.Sub(lastTime).Minutes() >= float64(v["cycle"].(int64)) {
wg.Add(1)
go func(v map[string]any) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("监控任务发生错误: %v\n", r)
// 打印堆栈
buf := make([]byte, 1<<16) // 64KB
n := runtime.Stack(buf, false)
fmt.Println("堆栈信息:\n", string(buf[:n]))
}
}()
defer wg.Done()
gs := *s
var (
certInfo *monitor.CertInfo
certJson string
Err error
checkErr string
)
switch monitorType {
case "https":
certInfo, Err = monitor.CheckHttps(target, int(advanceDay))
case "smtp":
certInfo, Err = monitor.CheckSmtp(target, int(advanceDay))
default:
Err = fmt.Errorf("不支持的监控类型:%s", monitorType)
}
if Err != nil {
checkErr = Err.Error()
} else {
if certInfo.VerifyError != "" && (!certInfo.Valid || certInfo.DaysLeft <= int(advanceDay)) {
checkErr = certInfo.VerifyError
}
certBytes, err := json.Marshal(certInfo)
if err == nil {
certJson = string(certBytes)
}
}
id := v["id"].(int64)
// 此处应该发送错误邮件
if checkErr != "" {
// 更新监控记录
valid := -1 // 状态为异常
if certInfo != nil && certInfo.Valid {
valid = 1 // 状态为正常
}
gs.Where("id=?", []interface{}{id}).Update(map[string]any{
"last_time": now.Format("2006-01-02 15:04:05"),
"except_end_time": now.Format("2006-01-02 15:04:05"),
"info": certJson,
"valid": valid, // 状态为异常
})
// 新增错误记录
if certInfo == nil || !certInfo.Valid {
gs.TableName = "err_record"
gs.Insert(map[string]any{
"id": public.GenerateUUID(),
"monitor_id": id,
"create_time": now.Format("2006-01-02 15:04:05"),
"msg": checkErr,
"info": certJson,
})
}
monitorErrCountMu.Lock()
MonitorErrCount[id] += 1
errCount := MonitorErrCount[id]
monitorErrCountMu.Unlock()
repeatSendGap, ok := v["repeat_send_gap"].(int64)
if !ok {
repeatSendGap = 10
}
reportTypes, ok := v["report_types"].(string)
if ok && errCount == 1 {
reportTypeArr := strings.Split(reportTypes, ",")
for _, reportType := range reportTypeArr {
if reportType == "" {
continue
}
rdata, err := s1.Where("type=?", []interface{}{reportType}).Select()
if err != nil {
return
}
if len(rdata) <= 0 {
return
}
report.Notify(map[string]any{
"provider": reportType,
"provider_id": strconv.FormatInt(rdata[0]["id"].(int64), 10),
"subject": "ALLinSSL 监控通知",
"body": fmt.Sprintf(MonitorErrTemplate, v["name"], monitorType, v["target"], strings.Split(checkErr, "")[0], now.Format("2006-01-02 15:04:05")),
})
}
}
monitorErrCountMu.Lock()
if MonitorErrCount[id] >= int(repeatSendGap) {
MonitorErrCount[id] = 0
}
monitorErrCountMu.Unlock()
} else {
// 更新监控记录
gs.Where("id=?", []interface{}{id}).Update(map[string]any{
"last_time": now.Format("2006-01-02 15:04:05"),
"info": certJson,
"valid": 1, // 状态为正常
})
monitorErrCountMu.Lock()
MonitorErrCount[id] = 0
monitorErrCountMu.Unlock()
}
}(v)
}
}
}
wg.Wait()
}