Files
allinssl/backend/scheduler/monitor.go
v-me-50 3e5a41a7e7 【调整】修改版本号
【调整】错误记录表索引
【调整】新增monitor静态文件路由
2025-07-17 16:09:00 +08:00

195 lines
5.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}