增加磁盘和网卡硬件信息显示

This commit is contained in:
Alex Yang
2025-12-07 10:30:10 +08:00
parent 611c8dac0e
commit 5112ebe2e0
11 changed files with 6170 additions and 112 deletions

View File

@@ -1,10 +1,16 @@
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"os/signal"
"path/filepath"
"strconv"
"syscall"
"time"
"github.com/gin-gonic/gin"
@@ -34,10 +40,119 @@ func isDefaultDBConfig(cfg *config.Config) bool {
cfg.DB.Database == "monitor"
}
// daemonize 实现守护进程功能
func daemonize() error {
// 检查是否已经是守护进程模式
if os.Getenv("DAEMONIZED") == "1" {
// 设置工作目录
if err := os.Chdir("/"); err != nil {
return fmt.Errorf("failed to chdir to /: %v", err)
}
// 重设文件权限掩码
syscall.Umask(0)
return nil
}
// 获取可执行文件的绝对路径
execPath, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to get executable path: %v", err)
}
// 创建环境变量,标记为守护进程模式
env := append(os.Environ(), "DAEMONIZED=1")
// 启动新进程
cmd := exec.Command(execPath, os.Args[1:]...)
cmd.Env = env
cmd.Stdin = nil
cmd.Stdout = nil
cmd.Stderr = nil
cmd.Dir = "/"
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
}
// 启动进程
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to start daemon: %v", err)
}
// 父进程退出
os.Exit(0)
return nil
}
// savePID 保存进程ID到文件
func savePID() error {
if pidFile == "" {
return nil
}
// 获取当前进程ID
pid := strconv.Itoa(os.Getpid())
// 写入PID文件
if err := os.WriteFile(pidFile, []byte(pid), 0644); err != nil {
return fmt.Errorf("failed to write PID file: %v", err)
}
return nil
}
// removePID 删除PID文件
func removePID() {
if pidFile != "" {
os.Remove(pidFile)
}
}
// 命令行参数
var (
// 是否以守护进程模式运行
daemonMode bool
// 日志文件路径
logFilePath string
// 进程ID文件路径
pidFile string
)
// main 函数启动服务器
func main() {
// 解析命令行参数
flag.BoolVar(&daemonMode, "daemon", false, "Run as daemon (background process)")
flag.BoolVar(&daemonMode, "d", false, "Run as daemon (background process) - shorthand")
flag.StringVar(&logFilePath, "log-file", "", "Path to log file")
flag.StringVar(&logFilePath, "l", "", "Path to log file - shorthand")
flag.StringVar(&pidFile, "pid-file", "/tmp/monitor-backend.pid", "Path to PID file")
flag.StringVar(&pidFile, "p", "/tmp/monitor-backend.pid", "Path to PID file - shorthand")
flag.Parse()
// 配置日志:同时输出到文件和标准输出
logFileName := fmt.Sprintf("monitor-backend-%s.log", time.Now().Format("2006-01-02"))
// 处理日志文件路径
if logFilePath != "" {
// 如果是相对路径,则使用可执行文件所在的目录作为基准目录
if !filepath.IsAbs(logFilePath) {
// 获取可执行文件的目录
execPath, err := os.Executable()
if err != nil {
log.Printf("Warning: Failed to get executable path, using current directory for log file")
logFileName = logFilePath
} else {
execDir := filepath.Dir(execPath)
logFileName = filepath.Join(execDir, logFilePath)
}
} else {
logFileName = logFilePath
}
}
// 打开日志文件
logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Printf("Warning: Failed to open log file %s, logging only to stdout: %v", logFileName, err)
@@ -73,6 +188,28 @@ func main() {
os.Exit(0)
}
// 如果指定了守护进程模式,则启动守护进程
if daemonMode {
if err := daemonize(); err != nil {
log.Fatalf("Failed to daemonize: %v", err)
}
}
// 保存PID文件
if err := savePID(); err != nil {
log.Printf("Warning: Failed to save PID file: %v", err)
}
// 注册信号处理确保进程退出时删除PID文件
go func() {
sigCh := make(chan os.Signal, 1)
// 只处理可以捕获的信号
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
<-sigCh
removePID()
os.Exit(0)
}()
// 创建存储实例
store := storage.NewStorage(cfg)
defer store.Close()
@@ -156,6 +293,19 @@ func main() {
handler.RegisterRoutes(r)
// 处理所有未匹配的路由返回静态文件或index.html
// 静态文件服务的路径处理:如果是相对路径,使用可执行文件所在目录作为基准目录
staticDir := "./static"
if !filepath.IsAbs(staticDir) {
// 获取可执行文件的目录
execPath, err := os.Executable()
if err != nil {
log.Printf("Warning: Failed to get executable path, using current directory for static files")
} else {
execDir := filepath.Dir(execPath)
staticDir = filepath.Join(execDir, staticDir)
}
}
r.NoRoute(func(c *gin.Context) {
// 尝试提供静态文件
file := c.Request.URL.Path
@@ -164,7 +314,7 @@ func main() {
}
// 从static目录提供文件
c.File("./static" + file)
c.File(staticDir + file)
})
// 启动服务器