mirror of https://github.com/allinssl/allinssl
195 lines
5.1 KiB
Go
195 lines
5.1 KiB
Go
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()
|
||
}
|