106 lines
3.5 KiB
Go
106 lines
3.5 KiB
Go
package handler
|
||||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"fmt"
|
|||
|
|
"net/http"
|
|||
|
|
"os"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"bj_power_mes/common/httpx"
|
|||
|
|
"bj_power_mes/internal/svc"
|
|||
|
|
|
|||
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// diskStatusView 磁盘空间状态视图(附件中心顶部提示 + 定时告警共用)。
|
|||
|
|
type diskStatusView struct {
|
|||
|
|
RootDir string `json:"rootDir"`
|
|||
|
|
UsedPercent int `json:"usedPercent"`
|
|||
|
|
FreeBytes uint64 `json:"freeBytes"`
|
|||
|
|
TotalBytes uint64 `json:"totalBytes"`
|
|||
|
|
WarnPercent int `json:"warnPercent"`
|
|||
|
|
CritPercent int `json:"critPercent"`
|
|||
|
|
Level string `json:"level"` // ok / warn / critical / unknown
|
|||
|
|
Message string `json:"message"`
|
|||
|
|
CheckedAt int64 `json:"checkedAt"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// diskStatus 读取附件根目录所在磁盘剩余空间并给出告警级别。
|
|||
|
|
// 剩余 < DiskCriticalPercent → critical(提示执行备份归档清理);< DiskWarnPercent → warn。
|
|||
|
|
func diskStatus(svcCtx *svc.ServiceContext) diskStatusView {
|
|||
|
|
cfg := svcCtx.Config.Upload
|
|||
|
|
root := cfg.Dir
|
|||
|
|
if root == "" {
|
|||
|
|
root = "uploads"
|
|||
|
|
}
|
|||
|
|
v := diskStatusView{
|
|||
|
|
RootDir: root, WarnPercent: cfg.DiskWarnPercent, CritPercent: cfg.DiskCriticalPercent,
|
|||
|
|
Level: "ok", Message: "磁盘空间正常", CheckedAt: time.Now().Unix(),
|
|||
|
|
}
|
|||
|
|
used, free, total, err := diskUsage(root)
|
|||
|
|
if err != nil {
|
|||
|
|
_ = os.MkdirAll(root, 0o755)
|
|||
|
|
used, free, total, err = diskUsage(root)
|
|||
|
|
}
|
|||
|
|
if err != nil {
|
|||
|
|
v.Level = "unknown"
|
|||
|
|
v.Message = "磁盘空间检测失败:" + err.Error()
|
|||
|
|
return v
|
|||
|
|
}
|
|||
|
|
v.UsedPercent, v.FreeBytes, v.TotalBytes = used, free, total
|
|||
|
|
freePercent := 100 - used
|
|||
|
|
switch {
|
|||
|
|
case freePercent < cfg.DiskCriticalPercent:
|
|||
|
|
v.Level = "critical"
|
|||
|
|
v.Message = fmt.Sprintf("磁盘剩余空间仅 %d%%,低于 %d%%,请立即执行备份归档清理(附件中心可一键归档)", freePercent, cfg.DiskCriticalPercent)
|
|||
|
|
case freePercent < cfg.DiskWarnPercent:
|
|||
|
|
v.Level = "warn"
|
|||
|
|
v.Message = fmt.Sprintf("磁盘剩余空间 %d%%,低于 %d%% 告警线,请及时清理", freePercent, cfg.DiskWarnPercent)
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DiskStatusHandler GET /attachment/disk-status
|
|||
|
|
func DiskStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
httpx.Ok(w, diskStatus(svcCtx))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// StartDiskMonitor 启动磁盘空间监控:每天 DiskCheckHour(默认 7 点) 检测一次,
|
|||
|
|
// 剩余 <20% 告警、<10% 提示清理(写服务日志 + 操作日志,附件中心顶部同步展示)。
|
|||
|
|
func StartDiskMonitor(svcCtx *svc.ServiceContext) {
|
|||
|
|
go func() {
|
|||
|
|
hour := svcCtx.Config.Upload.DiskCheckHour
|
|||
|
|
if hour < 0 || hour > 23 {
|
|||
|
|
hour = 7
|
|||
|
|
}
|
|||
|
|
for {
|
|||
|
|
now := time.Now()
|
|||
|
|
next := time.Date(now.Year(), now.Month(), now.Day(), hour, 0, 0, 0, time.Local)
|
|||
|
|
if !next.After(now) {
|
|||
|
|
next = next.Add(24 * time.Hour)
|
|||
|
|
}
|
|||
|
|
time.Sleep(time.Until(next))
|
|||
|
|
checkDiskOnce(svcCtx)
|
|||
|
|
}
|
|||
|
|
}()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func checkDiskOnce(svcCtx *svc.ServiceContext) {
|
|||
|
|
st := diskStatus(svcCtx)
|
|||
|
|
switch st.Level {
|
|||
|
|
case "critical":
|
|||
|
|
logx.Errorf("[磁盘监控] %s(已用 %d%%,剩余 %d%%)", st.Message, st.UsedPercent, 100-st.UsedPercent)
|
|||
|
|
svcCtx.EventLog.Write(context.Background(), "system.disk", "", "system", "attachment", "disk", st.Message,
|
|||
|
|
map[string]any{"usedPercent": st.UsedPercent, "freeBytes": st.FreeBytes})
|
|||
|
|
case "warn":
|
|||
|
|
logx.Alert("[磁盘监控] " + st.Message)
|
|||
|
|
svcCtx.EventLog.Write(context.Background(), "system.disk", "", "system", "attachment", "disk", st.Message,
|
|||
|
|
map[string]any{"usedPercent": st.UsedPercent, "freeBytes": st.FreeBytes})
|
|||
|
|
default:
|
|||
|
|
logx.Infof("[磁盘监控] 正常:剩余 %d%%(%s)", 100-st.UsedPercent, st.RootDir)
|
|||
|
|
}
|
|||
|
|
}
|