修改客户端日志为 slog

This commit is contained in:
dushixiang committed 2025-12-30 20:00:35 +08:00
1 parent a92833a5bd
commit 6c499e2464
13 files changed
+292 -168

No files matched your search

+1 -1
View File
@@ -20,4 +20,4 @@ COPY ./bin/agents/pika-agent-linux-${TARGETARCH} ./pika-agent
RUN chmod +x ./pika-agent
# 启动 agent
ENTRYPOINT ["./pika-agent"]
ENTRYPOINT ["./pika-agent", "run"]
+14 -1
View File
@@ -5,12 +5,14 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/dushixiang/pika/pkg/agent/config"
"github.com/dushixiang/pika/pkg/agent/service"
"github.com/dushixiang/pika/pkg/agent/updater"
"github.com/dushixiang/pika/pkg/agent/utils"
"github.com/spf13/cobra"
)
@@ -463,7 +465,13 @@ func registerAgent(cmd *cobra.Command, args []string) {
APIKey: apiKey,
},
Agent: config.AgentConfig{
Name: name,
Name: name,
LogLevel: "info",
LogFile: getHomeLogPath(),
LogMaxSize: 100,
LogMaxBackups: 3,
LogMaxAge: 28,
LogCompress: true,
},
Collector: config.CollectorConfig{
Interval: 5,
@@ -516,6 +524,11 @@ func maskToken(token string) string {
return token[:4] + "****" + token[len(token)-4:]
}
func getHomeLogPath() string {
homeDir := utils.GetSafeHomeDir()
return filepath.Join(homeDir, ".pika", "logs", "agent.log")
}
// showInfo 显示配置信息
func showInfo(cmd *cobra.Command, args []string) {
// 加载配置
+8
View File
@@ -0,0 +1,8 @@
services:
pika-agent:
image: dushixiang/pika-agent:latest
container_name: pika-agent
restart: unless-stopped
network_mode: host
volumes:
- ./pika:/root/.pika/
+2 -2
View File
@@ -29,6 +29,7 @@ require (
github.com/prometheus-community/pro-bing v0.7.0
github.com/robfig/cron/v3 v3.0.1
github.com/shirou/gopsutil/v4 v4.25.11
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.2
github.com/valyala/fasttemplate v1.2.2
@@ -36,6 +37,7 @@ require (
golang.org/x/crypto v0.46.0
golang.org/x/oauth2 v0.34.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
gorm.io/datatypes v1.2.7
gorm.io/gorm v1.31.1
@@ -72,7 +74,6 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
@@ -90,7 +91,6 @@ require (
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.14.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gorm.io/driver/mysql v1.6.0 // indirect
gorm.io/driver/postgres v1.6.0 // indirect
modernc.org/libc v1.67.1 // indirect
+2 -28
View File
@@ -17,8 +17,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
@@ -43,8 +41,6 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
@@ -92,16 +88,12 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/echo/v4 v4.14.0 h1:+tiMrDLxwv6u0oKtD03mv+V1vXXB3wCqPHJqPuIe+7M=
github.com/labstack/echo/v4 v4.14.0/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/libdns/alidns v1.0.6-beta.2 h1:cRhpaFGoQfGgsVWj+rpUdmbP74BCsH96tv3ZOwBPf38=
github.com/libdns/alidns v1.0.6-beta.2/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec=
github.com/libdns/alidns v1.0.6-beta.3 h1:KAmb7FQ1tRzKsaAUGa7ZpGKAMRANwg7+1c7tUbSELq8=
github.com/libdns/alidns v1.0.6-beta.3/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec=
github.com/libdns/cloudflare v0.2.2 h1:XWHv+C1dDcApqazlh08Q6pjytYLgR2a+Y3xrXFu0vsI=
@@ -190,29 +182,18 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY=
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM=
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -224,26 +205,19 @@ golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
+5 -5
View File
@@ -7,7 +7,7 @@ import (
"encoding/hex"
"fmt"
"io"
"log"
"log/slog"
"os"
"os/exec"
"strings"
@@ -29,19 +29,19 @@ type Logger interface {
type defaultLogger struct{}
func (l *defaultLogger) Debug(format string, args ...interface{}) {
log.Printf("[DEBUG] "+format, args...)
slog.Debug(fmt.Sprintf(format, args...))
}
func (l *defaultLogger) Info(format string, args ...interface{}) {
log.Printf("[INFO] "+format, args...)
slog.Info(fmt.Sprintf(format, args...))
}
func (l *defaultLogger) Warn(format string, args ...interface{}) {
log.Printf("[WARN] "+format, args...)
slog.Warn(fmt.Sprintf(format, args...))
}
func (l *defaultLogger) Error(format string, args ...interface{}) {
log.Printf("[ERROR] "+format, args...)
slog.Error(fmt.Sprintf(format, args...))
}
var globalLogger Logger = &defaultLogger{}
+39 -1
View File
@@ -47,6 +47,24 @@ type ServerConfig struct {
type AgentConfig struct {
// Agent 名称(默认使用主机名)
Name string `yaml:"name"`
// 日志等级(debug, info, warn, error,默认为 info)
LogLevel string `yaml:"log_level"`
// 日志文件路径(默认为空,输出到控制台)
LogFile string `yaml:"log_file"`
// 日志文件最大大小(MB,默认 100MB)
LogMaxSize int `yaml:"log_max_size"`
// 日志文件最大备份数(默认 3)
LogMaxBackups int `yaml:"log_max_backups"`
// 日志文件最大保留天数(默认 28 天)
LogMaxAge int `yaml:"log_max_age"`
// 是否压缩旧日志文件(默认 true)
LogCompress bool `yaml:"log_compress"`
}
// CollectorConfig 采集器配置
@@ -93,7 +111,13 @@ func DefaultConfig() *Config {
InsecureSkipVerify: false,
},
Agent: AgentConfig{
Name: "",
Name: "",
LogLevel: "info",
LogFile: "",
LogMaxSize: 100,
LogMaxBackups: 3,
LogMaxAge: 28,
LogCompress: true,
},
Collector: CollectorConfig{
Interval: 5,
@@ -199,6 +223,20 @@ func (c *Config) Validate() error {
}
}
// 验证日志等级
if c.Agent.LogLevel == "" {
c.Agent.LogLevel = "info"
}
validLogLevels := map[string]bool{
"debug": true,
"info": true,
"warn": true,
"error": true,
}
if !validLogLevels[c.Agent.LogLevel] {
return fmt.Errorf("无效的日志等级: %s (可选值: debug, info, warn, error)", c.Agent.LogLevel)
}
return nil
}
+68
View File
@@ -0,0 +1,68 @@
package agent
import (
"io"
"log/slog"
"os"
"strings"
"gopkg.in/natefinch/lumberjack.v2"
)
// LogConfig 日志配置
type LogConfig struct {
Level string
File string
MaxSize int
MaxBackups int
MaxAge int
Compress bool
}
// InitLogger 初始化日志系统
func InitLogger(cfg *LogConfig) {
var level slog.Level
switch strings.ToLower(cfg.Level) {
case "debug":
level = slog.LevelDebug
case "info":
level = slog.LevelInfo
case "warn":
level = slog.LevelWarn
case "error":
level = slog.LevelError
default:
level = slog.LevelInfo
}
var writer io.Writer
// 如果配置了日志文件,使用 lumberjack 进行日志滚动
if cfg.File != "" {
writer = &lumberjack.Logger{
Filename: cfg.File,
MaxSize: cfg.MaxSize, // MB
MaxBackups: cfg.MaxBackups, // 保留的旧日志文件数
MaxAge: cfg.MaxAge, // 天数
Compress: cfg.Compress, // 是否压缩
}
} else {
// 否则输出到标准输出
writer = os.Stdout
}
// 创建文本格式的 handler(更易读)
opts := &slog.HandlerOptions{
Level: level,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
// 格式化时间为更易读的格式
if a.Key == slog.TimeKey {
return slog.String(slog.TimeKey, a.Value.Time().Format("2006-01-02 15:04:05.000"))
}
return a
},
}
handler := slog.NewTextHandler(writer, opts)
logger := slog.New(handler)
slog.SetDefault(logger)
}
+62 -62
View File
@@ -6,7 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"log/slog"
"os"
"runtime"
"sync"
@@ -106,14 +106,14 @@ func (a *Agent) Start(ctx context.Context) error {
// 检查是否是上下文取消
if ctx.Err() != nil {
log.Println("收到停止信号,探针服务退出")
slog.Info("收到停止信号,探针服务退出")
return nil
}
// 连接建立失败或注册失败(使用 backoff)
if err != nil {
retryAfter := b.Duration()
log.Printf("⚠️ 探针运行出错: %v,将在 %v 后重试", err, retryAfter)
slog.Warn("探针运行出错,将在后重试", "error", err, "retryAfter", retryAfter)
select {
case <-time.After(retryAfter):
@@ -124,7 +124,7 @@ func (a *Agent) Start(ctx context.Context) error {
}
// 理论上不会到这里
log.Println("连接意外结束")
slog.Info("连接意外结束")
return nil
}
}
@@ -140,7 +140,7 @@ func (a *Agent) Stop() {
// 返回 error 表示需要重连,返回 nil 可能是正常关闭或上下文取消
func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
wsURL := a.cfg.GetWebSocketURL()
log.Printf("🔌 正在连接到服务器: %s", wsURL)
slog.Info("正在连接到服务器", "url", wsURL)
// 创建自定义的 Dialer
var dialer = websocket.DefaultDialer
@@ -148,7 +148,7 @@ func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
dialer.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
log.Println("⚠️ 警告: 已禁用 TLS 证书验证")
slog.Warn("警告: 已禁用 TLS 证书验证")
}
// 连接到服务器
@@ -168,7 +168,7 @@ func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
// WriteControl 有内置锁,可以安全调用
err := rawConn.WriteControl(websocket.PongMessage, []byte(appData), time.Now().Add(time.Second))
if err == nil {
//log.Println("💓 收到 Ping,已发送 Pong")
//slog.Info("收到 Ping,已发送 Pong")
}
return err
})
@@ -178,7 +178,7 @@ func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
return fmt.Errorf("注册失败: %w", err)
}
log.Println("✅ 探针注册成功,开始监控...")
slog.Info("探针注册成功,开始监控...")
// 创建采集器管理器
collectorManager := collector.NewManager(a.cfg)
@@ -242,11 +242,11 @@ func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
select {
case err := <-errChan:
// 连接已建立,无论什么原因断开都标记为已建立状态
log.Printf("连接断开: %v", err)
slog.Info("连接断开", "error", err)
returnErr = ErrConnectionEstablished
case <-ctx.Done():
// 收到取消信号
log.Println("收到停止信号,准备关闭连接")
slog.Info("收到停止信号,准备关闭连接")
returnErr = ctx.Err()
}
@@ -256,7 +256,7 @@ func (a *Agent) runOnce(ctx context.Context, onConnected func()) error {
// 发送 WebSocket 关闭消息
closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
if err := conn.WriteMessage(websocket.CloseMessage, closeMsg); err != nil {
log.Printf("⚠️ 发送关闭消息失败: %v", err)
slog.Warn("发送关闭消息失败", "error", err)
}
// 等待所有 goroutine 优雅退出
@@ -283,7 +283,7 @@ func (a *Agent) readLoop(conn *websocket.Conn, done chan struct{}) error {
// 解析消息
var msg protocol.InputMessage
if err := json.Unmarshal(message, &msg); err != nil {
log.Printf("⚠️ 解析消息失败: %v", err)
slog.Warn("解析消息失败", "error", err)
continue
}
@@ -311,7 +311,7 @@ func (a *Agent) registerAgent(conn *safeConn) error {
if err != nil {
return fmt.Errorf("加载 agent ID 失败: %w", err)
}
log.Printf("🆔 Agent ID: %s (存储在: %s)", agentID, a.idMgr.GetPath())
slog.Info("Agent ID", "id", agentID, "path", a.idMgr.GetPath())
// 获取主机信息
hostname, _ := os.Hostname()
@@ -369,36 +369,36 @@ func (a *Agent) registerAgent(conn *safeConn) error {
return fmt.Errorf("解析注册响应失败: %w", err)
}
log.Printf("注册成功: AgentId=%s, Status=%s", registerResp.AgentID, registerResp.Status)
slog.Info("注册成功", "agentId", registerResp.AgentID, "status", registerResp.Status)
return nil
}
func (a *Agent) handleMonitorConfig(data json.RawMessage) {
var payload protocol.MonitorConfigPayload
if err := json.Unmarshal(data, &payload); err != nil {
log.Printf("⚠️ 解析监控配置失败: %v", err)
slog.Warn("解析监控配置失败", "error", err)
return
}
if len(payload.Items) == 0 {
log.Println("ℹ️ 收到空的服务监控配置,跳过")
slog.Info("收到空的服务监控配置,跳过")
return
}
conn := a.getActiveConn()
manager := a.getCollectorManager()
if conn == nil || manager == nil {
log.Println("⚠️ 当前连接未就绪,无法执行服务监控任务")
slog.Warn("当前连接未就绪,无法执行服务监控任务")
return
}
log.Printf("📥 收到服务监控配置,总计 %d 个监控项,立即执行检测", len(payload.Items))
slog.Info("收到服务监控配置,立即执行检测", "count", len(payload.Items))
// 立即执行一次监控检测
if err := manager.CollectAndSendMonitor(conn, payload.Items); err != nil {
log.Printf("⚠️ 监控检测失败: %v", err)
slog.Warn("监控检测失败", "error", err)
} else {
log.Printf("✅ 服务监控检测完成,已上报 %d 个监控项结果", len(payload.Items))
slog.Info("服务监控检测完成,已上报监控项结果", "count", len(payload.Items))
}
}
@@ -416,7 +416,7 @@ func (a *Agent) heartbeatLoop(ctx context.Context, conn *safeConn, done chan str
}); err != nil {
return fmt.Errorf("发送心跳失败: %w", err)
}
//log.Println("💓 心跳已发送")
//slog.Info("心跳已发送")
case <-done:
return nil
case <-ctx.Done():
@@ -453,7 +453,7 @@ func (a *Agent) getCollectorManager() *collector.Manager {
func (a *Agent) metricsLoop(ctx context.Context, conn *safeConn, manager *collector.Manager, done chan struct{}) error {
// 立即采集一次动态数据
if err := a.collectAndSendAllMetrics(conn, manager); err != nil {
log.Printf("⚠️ 初始数据采集失败: %v", err)
slog.Warn("初始数据采集失败", "error", err)
}
// 定时采集动态指标
@@ -481,54 +481,54 @@ func (a *Agent) collectAndSendAllMetrics(conn *safeConn, manager *collector.Mana
// CPU 动态指标
if err := manager.CollectAndSendCPU(conn); err != nil {
log.Printf("⚠️ 发送CPU指标失败: %v", err)
slog.Warn("发送CPU指标失败", "error", err)
hasError = true
}
// 内存动态指标
if err := manager.CollectAndSendMemory(conn); err != nil {
log.Printf("⚠️ 发送内存指标失败: %v", err)
slog.Warn("发送内存指标失败", "error", err)
hasError = true
}
// 磁盘指标
if err := manager.CollectAndSendDisk(conn); err != nil {
log.Printf("⚠️ 发送磁盘指标失败: %v", err)
slog.Warn("发送磁盘指标失败", "error", err)
hasError = true
}
// 磁盘 IO 指标
if err := manager.CollectAndSendDiskIO(conn); err != nil {
log.Printf("⚠️ 发送磁盘IO指标失败: %v", err)
slog.Warn("发送磁盘IO指标失败", "error", err)
hasError = true
}
// 网络指标
if err := manager.CollectAndSendNetwork(conn); err != nil {
log.Printf("⚠️ 发送网络指标失败: %v", err)
slog.Warn("发送网络指标失败", "error", err)
hasError = true
}
// 网络连接统计
if err := manager.CollectAndSendNetworkConnection(conn); err != nil {
log.Printf("⚠️ 发送网络连接统计失败: %v", err)
slog.Warn("发送网络连接统计失败", "error", err)
hasError = true
}
// 主机信息
if err := manager.CollectAndSendHost(conn); err != nil {
log.Printf("⚠️ 发送主机信息失败: %v", err)
slog.Warn("发送主机信息失败", "error", err)
hasError = true
}
// GPU 信息(可选)
if err := manager.CollectAndSendGPU(conn); err != nil {
log.Printf("ℹ️ 发送GPU信息失败: %v", err)
slog.Info("发送GPU信息失败", "error", err)
}
// 温度信息(可选)
if err := manager.CollectAndSendTemperature(conn); err != nil {
log.Printf("ℹ️ 发送温度信息失败: %v", err)
slog.Info("发送温度信息失败", "error", err)
}
if hasError {
@@ -542,11 +542,11 @@ func (a *Agent) collectAndSendAllMetrics(conn *safeConn, manager *collector.Mana
func (a *Agent) handleCommand(data json.RawMessage) {
var cmdReq protocol.CommandRequest
if err := json.Unmarshal(data, &cmdReq); err != nil {
log.Printf("⚠️ 解析指令失败: %v", err)
slog.Warn("解析指令失败", "error", err)
return
}
log.Printf("📥 收到指令: %s (ID: %s)", cmdReq.Type, cmdReq.ID)
slog.Info("收到指令", "type", cmdReq.Type, "id", cmdReq.ID)
conn := a.getActiveConn()
// 发送运行中状态
@@ -556,7 +556,7 @@ func (a *Agent) handleCommand(data json.RawMessage) {
case "vps_audit":
a.handleVPSAudit(conn, cmdReq.ID)
default:
log.Printf("⚠️ 未知指令类型: %s", cmdReq.Type)
slog.Warn("未知指令类型", "type", cmdReq.Type)
a.sendCommandResponse(conn, cmdReq.ID, cmdReq.Type, "error", "未知指令类型", "")
}
}
@@ -566,7 +566,7 @@ func (a *Agent) handleVPSAudit(conn *safeConn, cmdID string) {
// 导入 audit 包
result, err := a.runVPSAudit()
if err != nil {
log.Printf("❌ VPS安全审计失败: %v", err)
slog.Error("VPS安全审计失败", "error", err)
a.sendCommandResponse(conn, cmdID, "vps_audit", "error", err.Error(), "")
return
}
@@ -574,12 +574,12 @@ func (a *Agent) handleVPSAudit(conn *safeConn, cmdID string) {
// 将结果序列化为JSON
resultJSON, err := json.Marshal(result)
if err != nil {
log.Printf("❌ 序列化审计结果失败: %v", err)
slog.Error("序列化审计结果失败", "error", err)
a.sendCommandResponse(conn, cmdID, "vps_audit", "error", "序列化结果失败", "")
return
}
log.Println("✅ VPS安全审计完成")
slog.Info("VPS安全审计完成")
a.sendCommandResponse(conn, cmdID, "vps_audit", "success", "", string(resultJSON))
}
@@ -602,7 +602,7 @@ func (a *Agent) sendCommandResponse(conn *safeConn, cmdID, cmdType, status, errM
Type: protocol.MessageTypeCommandResp,
Data: resp,
}); err != nil {
log.Printf("⚠️ 发送指令响应失败: %v", err)
slog.Warn("发送指令响应失败", "error", err)
}
}
@@ -615,22 +615,22 @@ func GetVersion() string {
func (a *Agent) handleTamperProtect(data json.RawMessage) {
var tamperProtectConfig protocol.TamperProtectConfig
if err := json.Unmarshal(data, &tamperProtectConfig); err != nil {
log.Printf("⚠️ 解析防篡改保护配置失败: %v", err)
slog.Warn("解析防篡改保护配置失败", "error", err)
a.sendTamperProtectResponse(false, "解析配置失败", nil, nil, nil, err.Error())
return
}
log.Printf("📥 收到防篡改保护增量配置: Added=%v, Removed=%v", tamperProtectConfig.Added, tamperProtectConfig.Removed)
slog.Info("收到防篡改保护增量配置", "added", tamperProtectConfig.Added, "removed", tamperProtectConfig.Removed)
conn := a.getActiveConn()
if conn == nil {
log.Println("⚠️ 当前连接未就绪,无法执行防篡改保护")
slog.Warn("当前连接未就绪,无法执行防篡改保护")
return
}
// 如果没有新增也没有移除,不需要做任何操作
if len(tamperProtectConfig.Added) == 0 && len(tamperProtectConfig.Removed) == 0 {
log.Println("ℹ️ 配置无变化,跳过更新")
slog.Info("配置无变化,跳过更新")
a.sendTamperProtectResponse(true, "配置无变化", a.tamperProtector.GetProtectedPaths(), []string{}, []string{}, "")
return
}
@@ -640,7 +640,7 @@ func (a *Agent) handleTamperProtect(data json.RawMessage) {
// 应用增量更新
result, err := a.tamperProtector.ApplyIncrementalUpdate(ctx, tamperProtectConfig.Added, tamperProtectConfig.Removed)
if err != nil {
log.Printf("⚠️ 应用增量更新失败: %v", err)
slog.Warn("应用增量更新失败", "error", err)
// 即使有错误也返回部分成功的结果
if result != nil {
a.sendTamperProtectResponse(false, "部分更新失败", result.Current, result.Added, result.Removed, err.Error())
@@ -653,7 +653,7 @@ func (a *Agent) handleTamperProtect(data json.RawMessage) {
// 成功更新
message := fmt.Sprintf("防篡改保护已更新: 新增 %d 个, 移除 %d 个, 当前保护 %d 个目录",
len(result.Added), len(result.Removed), len(result.Current))
log.Printf("✅ %s", message)
slog.Info(message)
a.sendTamperProtectResponse(true, message, result.Current, result.Added, result.Removed, "")
}
@@ -677,7 +677,7 @@ func (a *Agent) sendTamperProtectResponse(success bool, message string, paths []
Type: protocol.MessageTypeTamperProtect,
Data: resp,
}); err != nil {
log.Printf("⚠️ 发送防篡改保护响应失败: %v", err)
slog.Warn("发送防篡改保护响应失败", "error", err)
}
}
@@ -704,9 +704,9 @@ func (a *Agent) tamperEventLoop(ctx context.Context, conn *safeConn, done chan s
Type: protocol.MessageTypeTamperEvent,
Data: eventData,
}); err != nil {
log.Printf("⚠️ 发送防篡改事件失败: %v", err)
slog.Warn("发送防篡改事件失败", "error", err)
} else {
log.Printf("📤 已上报防篡改事件: %s - %s", event.Path, event.Operation)
slog.Info("已上报防篡改事件", "path", event.Path, "operation", event.Operation)
}
}
}
@@ -735,13 +735,13 @@ func (a *Agent) tamperAlertLoop(ctx context.Context, conn *safeConn, done chan s
Type: protocol.MessageTypeTamperAlert,
Data: alertData,
}); err != nil {
log.Printf("⚠️ 发送属性篡改告警失败: %v", err)
slog.Warn("发送属性篡改告警失败", "error", err)
} else {
status := "未恢复"
if alert.Restored {
status = "已恢复"
}
log.Printf("📤 已上报属性篡改告警: %s - %s", alert.Path, status)
slog.Info("已上报属性篡改告警", "path", alert.Path, "status", status)
}
}
}
@@ -751,29 +751,29 @@ func (a *Agent) tamperAlertLoop(ctx context.Context, conn *safeConn, done chan s
func (a *Agent) handleDDNSConfig(data json.RawMessage) {
var ddnsConfig protocol.DDNSConfigData
if err := json.Unmarshal(data, &ddnsConfig); err != nil {
log.Printf("⚠️ 解析 DDNS 配置失败: %v", err)
slog.Warn("解析 DDNS 配置失败", "error", err)
return
}
if !ddnsConfig.Enabled {
log.Println("ℹ️ DDNS 已禁用,跳过 IP 检查")
slog.Info("DDNS 已禁用,跳过 IP 检查")
return
}
conn := a.getActiveConn()
manager := a.getCollectorManager()
if conn == nil || manager == nil {
log.Println("⚠️ 当前连接未就绪,无法执行 DDNS IP 检查")
slog.Warn("当前连接未就绪,无法执行 DDNS IP 检查")
return
}
log.Println("📥 收到 DDNS 配置检查请求,开始采集 IP 地址")
slog.Info("收到 DDNS 配置检查请求,开始采集 IP 地址")
// 采集 IP 地址并上报
if err := a.collectAndSendDDNSIP(conn, manager, &ddnsConfig); err != nil {
log.Printf("⚠️ DDNS IP 采集失败: %v", err)
slog.Warn("DDNS IP 采集失败", "error", err)
} else {
log.Println("✅ DDNS IP 地址已上报")
slog.Info("DDNS IP 地址已上报")
}
}
@@ -785,10 +785,10 @@ func (a *Agent) collectAndSendDDNSIP(conn *safeConn, manager *collector.Manager,
if config.EnableIPv4 {
ipv4, err := a.getIPAddress(manager, config.IPv4GetMethod, config.IPv4GetValue, false)
if err != nil {
log.Printf("⚠️ 获取 IPv4 失败: %v", err)
slog.Warn("获取 IPv4 失败", "error", err)
} else {
ipReport.IPv4 = ipv4
log.Printf("✅ 获取 IPv4: %s", ipv4)
slog.Info("获取 IPv4", "ip", ipv4)
}
}
@@ -796,10 +796,10 @@ func (a *Agent) collectAndSendDDNSIP(conn *safeConn, manager *collector.Manager,
if config.EnableIPv6 {
ipv6, err := a.getIPAddress(manager, config.IPv6GetMethod, config.IPv6GetValue, true)
if err != nil {
log.Printf("⚠️ 获取 IPv6 失败: %v", err)
slog.Warn("获取 IPv6 失败", "error", err)
} else {
ipReport.IPv6 = ipv6
log.Printf("✅ 获取 IPv6: %s", ipv6)
slog.Info("获取 IPv6", "ip", ipv6)
}
}
@@ -834,7 +834,7 @@ func (a *Agent) getIPAddress(manager *collector.Manager, method, value string, i
// handleUninstall 处理服务端发送的卸载指令
func (a *Agent) handleUninstall() {
log.Println("📥 收到服务端卸载指令,开始执行卸载...")
slog.Info("收到服务端卸载指令,开始执行卸载...")
// 获取配置文件路径
cfgPath := a.cfg.Path
@@ -844,11 +844,11 @@ func (a *Agent) handleUninstall() {
// 执行卸载操作
if err := UninstallAgent(cfgPath); err != nil {
log.Printf("❌ 卸载失败: %v", err)
slog.Error("卸载失败", "error", err)
return
}
log.Println("✅ 探针卸载成功,即将退出...")
slog.Info("探针卸载成功,即将退出...")
// 卸载成功后,触发停止信号
if a.cancel != nil {
+38 -18
View File
@@ -3,11 +3,12 @@ package service
import (
"context"
"fmt"
"log"
"log/slog"
"os"
"os/signal"
"syscall"
"github.com/dushixiang/pika/pkg/agent"
"github.com/dushixiang/pika/pkg/agent/config"
"github.com/dushixiang/pika/pkg/agent/id"
"github.com/dushixiang/pika/pkg/agent/sysutil"
@@ -26,9 +27,8 @@ type program struct {
// configureICMP 配置 ICMP 权限(抽取通用逻辑)
func configureICMP() {
if err := sysutil.ConfigureICMPPermissions(); err != nil {
log.Printf("⚠️ 配置 ICMP 权限失败: %v", err)
log.Println(" 提示: ICMP 监控可能需要 root 权限运行,或手动执行:")
log.Println(" sudo sysctl -w net.ipv4.ping_group_range=\"0 2147483647\"")
slog.Warn("配置 ICMP 权限失败", "error", err)
slog.Info("提示: ICMP 监控可能需要 root 权限运行,或手动执行: sudo sysctl -w net.ipv4.ping_group_range=\"0 2147483647\"")
}
}
@@ -41,7 +41,7 @@ func startAgent(ctx context.Context, cfg *config.Config) *Agent {
if cfg.AutoUpdate.Enabled {
upd, err := updater.New(cfg, GetVersion())
if err != nil {
log.Printf("⚠️ 创建更新器失败: %v", err)
slog.Warn("创建更新器失败", "error", err)
} else {
go upd.Start(ctx)
}
@@ -50,7 +50,7 @@ func startAgent(ctx context.Context, cfg *config.Config) *Agent {
// 在后台启动 Agent
go func() {
if err := agent.Start(ctx); err != nil {
log.Printf("⚠️ 探针运行出错: %v", err)
slog.Warn("探针运行出错", "error", err)
}
}()
@@ -59,7 +59,17 @@ func startAgent(ctx context.Context, cfg *config.Config) *Agent {
// Start 启动服务
func (p *program) Start(s service.Service) error {
log.Println("✅ Pika Agent 服务启动中...")
// 初始化日志系统
agent.InitLogger(&agent.LogConfig{
Level: p.cfg.Agent.LogLevel,
File: p.cfg.Agent.LogFile,
MaxSize: p.cfg.Agent.LogMaxSize,
MaxBackups: p.cfg.Agent.LogMaxBackups,
MaxAge: p.cfg.Agent.LogMaxAge,
Compress: p.cfg.Agent.LogCompress,
})
slog.Info("Pika Agent 服务启动中...")
// 初始化系统配置(Linux ICMP 权限等)
configureICMP()
@@ -75,7 +85,7 @@ func (p *program) Start(s service.Service) error {
// Stop 停止服务
func (p *program) Stop(s service.Service) error {
log.Println("📴 Pika Agent 服务停止中...")
slog.Info("Pika Agent 服务停止中...")
if p.cancel != nil {
p.cancel()
@@ -85,7 +95,7 @@ func (p *program) Stop(s service.Service) error {
p.agent.Stop()
}
log.Println("✅ Pika Agent 服务已停止")
slog.Info("Pika Agent 服务已停止")
return nil
}
@@ -206,10 +216,20 @@ func (m *ServiceManager) Run() error {
}
// 交互模式(前台运行)
log.Printf("✅ 配置加载成功")
log.Printf(" 服务器地址: %s", m.cfg.Server.Endpoint)
log.Printf(" 采集间隔: %v", m.cfg.GetCollectorInterval())
log.Printf(" 心跳间隔: %v", m.cfg.GetHeartbeatInterval())
// 初始化日志系统
agent.InitLogger(&agent.LogConfig{
Level: m.cfg.Agent.LogLevel,
File: m.cfg.Agent.LogFile,
MaxSize: m.cfg.Agent.LogMaxSize,
MaxBackups: m.cfg.Agent.LogMaxBackups,
MaxAge: m.cfg.Agent.LogMaxAge,
Compress: m.cfg.Agent.LogCompress,
})
slog.Info("配置加载成功",
"server_endpoint", m.cfg.Server.Endpoint,
"collector_interval", m.cfg.GetCollectorInterval(),
"heartbeat_interval", m.cfg.GetHeartbeatInterval())
// 初始化系统配置(Linux ICMP 权限等)
configureICMP()
@@ -227,12 +247,12 @@ func (m *ServiceManager) Run() error {
// 等待中断信号
<-interrupt
log.Println("📴 收到中断信号,正在关闭...")
slog.Info("收到中断信号,正在关闭...")
cancel()
// 等待 Agent 停止
agent.Stop()
log.Println("✅ 探针已停止")
slog.Info("探针已停止")
return nil
}
@@ -254,7 +274,7 @@ func UninstallAgent(cfgPath string) error {
// 检查服务状态,如果在运行则停止
status, err := mgr.Status()
if err != nil {
log.Printf("⚠️ 获取服务状态失败: %v", err)
slog.Warn("获取服务状态失败", "error", err)
} else if status != "已停止 (Stopped)" {
if err := mgr.Stop(); err != nil {
return fmt.Errorf("停止服务失败: %w", err)
@@ -268,13 +288,13 @@ func UninstallAgent(cfgPath string) error {
// 删除配置文件
if err := os.Remove(cfgPath); err != nil {
log.Printf("⚠️ 删除配置文件失败: %v", err)
slog.Warn("删除配置文件失败", "error", err)
}
// 删除探针 ID 文件
idPath := id.GetIDFilePath()
if err := os.Remove(idPath); err != nil {
log.Printf("⚠️ 删除探针 ID 文件失败: %v", err)
slog.Warn("删除探针 ID 文件失败", "error", err)
}
return nil
+4 -5
View File
@@ -2,7 +2,7 @@ package sysutil
import (
"fmt"
"log"
"log/slog"
"os"
"strconv"
"strings"
@@ -27,19 +27,18 @@ func doConfigureICMPPermissions() error {
// 2. 检查是否已经满足要求 (范围包含 0 到 2147483647)
if currentMin <= 0 && currentMax >= 2147483647 {
log.Printf("✅ ICMP 权限已配置: net.ipv4.ping_group_range=%d %d", currentMin, currentMax)
slog.Info("ICMP 权限已配置", "min", currentMin, "max", currentMax)
return nil
}
// 3. 需要配置,写入新值
log.Printf("🔧 当前 ICMP 配置: net.ipv4.ping_group_range=%d %d (不满足要求)", currentMin, currentMax)
log.Println(" 正在配置为: 0 2147483647")
slog.Info("当前 ICMP 配置不满足要求,正在配置", "current_min", currentMin, "current_max", currentMax, "target", "0 2147483647")
if err := writePingGroupRange(sysctlPath, 0, 2147483647); err != nil {
return fmt.Errorf("配置 ICMP 权限失败: %w", err)
}
log.Println("✅ ICMP 权限配置成功: net.ipv4.ping_group_range=0 2147483647")
slog.Info("ICMP 权限配置成功", "range", "0 2147483647")
return nil
}
+37 -33
View File
@@ -3,7 +3,7 @@ package tamper
import (
"context"
"fmt"
"log"
"log/slog"
"os"
"runtime"
"sync"
@@ -72,7 +72,7 @@ func (p *Protector) ApplyIncrementalUpdate(ctx context.Context, toAdd, toRemove
// 如果没有变化,直接返回
if len(toAdd) == 0 && len(toRemove) == 0 {
log.Println("ℹ️ 防篡改保护目录列表无变化")
slog.Info("防篡改保护目录列表无变化")
return &UpdateResult{
Added: []string{},
Removed: []string{},
@@ -91,15 +91,15 @@ func (p *Protector) ApplyIncrementalUpdate(ctx context.Context, toAdd, toRemove
var removeFailed []string
for _, path := range toRemove {
if !p.paths[path] {
log.Printf("ℹ️ 目录 %s 未被保护,跳过移除", path)
slog.Info("目录未被保护,跳过移除", "path", path)
continue
}
if err := p.removePath(path); err != nil {
log.Printf("⚠️ 移除目录 %s 保护失败: %v", path, err)
slog.Warn("移除目录保护失败", "path", path, "error", err)
removeFailed = append(removeFailed, path)
} else {
delete(p.paths, path)
log.Printf("✅ 已取消保护目录: %s", path)
slog.Info("已取消保护目录", "path", path)
}
}
@@ -107,15 +107,15 @@ func (p *Protector) ApplyIncrementalUpdate(ctx context.Context, toAdd, toRemove
var addFailed []string
for _, path := range toAdd {
if p.paths[path] {
log.Printf("ℹ️ 目录 %s 已被保护,跳过新增", path)
slog.Info("目录已被保护,跳过新增", "path", path)
continue
}
if err := p.addPath(path); err != nil {
log.Printf("⚠️ 添加目录 %s 保护失败: %v", path, err)
slog.Warn("添加目录保护失败", "path", path, "error", err)
addFailed = append(addFailed, path)
} else {
p.paths[path] = true
log.Printf("✅ 已保护目录: %s", path)
slog.Info("已保护目录", "path", path)
}
}
@@ -131,8 +131,10 @@ func (p *Protector) ApplyIncrementalUpdate(ctx context.Context, toAdd, toRemove
return result, fmt.Errorf("部分操作失败: 添加失败 %d 个, 移除失败 %d 个", len(addFailed), len(removeFailed))
}
log.Printf("✅ 防篡改保护已更新: 新增 %d 个目录, 移除 %d 个目录, 当前保护 %d 个目录",
len(result.Added), len(result.Removed), len(result.Current))
slog.Info("防篡改保护已更新",
"新增", len(result.Added),
"移除", len(result.Removed),
"当前保护", len(result.Current))
return result, nil
}
@@ -173,7 +175,7 @@ func (p *Protector) UpdatePaths(ctx context.Context, newPaths []string) (*Update
// 如果没有变化,直接返回
if len(toAdd) == 0 && len(toRemove) == 0 {
log.Println("ℹ️ 防篡改保护目录列表无变化")
slog.Info("防篡改保护目录列表无变化")
return &UpdateResult{
Added: []string{},
Removed: []string{},
@@ -190,11 +192,11 @@ func (p *Protector) UpdatePaths(ctx context.Context, newPaths []string) (*Update
var removeFailed []string
for _, path := range toRemove {
if err := p.removePath(path); err != nil {
log.Printf("⚠️ 移除目录 %s 保护失败: %v", path, err)
slog.Warn("移除目录保护失败", "path", path, "error", err)
removeFailed = append(removeFailed, path)
} else {
delete(p.paths, path)
log.Printf("✅ 已取消保护目录: %s", path)
slog.Info("已取消保护目录", "path", path)
}
}
@@ -202,11 +204,11 @@ func (p *Protector) UpdatePaths(ctx context.Context, newPaths []string) (*Update
var addFailed []string
for _, path := range toAdd {
if err := p.addPath(path); err != nil {
log.Printf("⚠️ 添加目录 %s 保护失败: %v", path, err)
slog.Warn("添加目录保护失败", "path", path, "error", err)
addFailed = append(addFailed, path)
} else {
p.paths[path] = true
log.Printf("✅ 已保护目录: %s", path)
slog.Info("已保护目录", "path", path)
}
}
@@ -222,8 +224,10 @@ func (p *Protector) UpdatePaths(ctx context.Context, newPaths []string) (*Update
return result, fmt.Errorf("部分操作失败: 添加失败 %d 个, 移除失败 %d 个", len(addFailed), len(removeFailed))
}
log.Printf("✅ 防篡改保护已更新: 新增 %d 个目录, 移除 %d 个目录, 当前保护 %d 个目录",
len(result.Added), len(result.Removed), len(result.Current))
slog.Info("防篡改保护已更新",
"新增", len(result.Added),
"移除", len(result.Removed),
"当前保护", len(result.Current))
return result, nil
}
@@ -234,7 +238,7 @@ func (p *Protector) StopAll() error {
defer p.mu.Unlock()
if len(p.paths) == 0 {
log.Println("ℹ️ 没有正在保护的目录")
slog.Info("没有正在保护的目录")
return nil
}
@@ -255,7 +259,7 @@ func (p *Protector) StopAll() error {
// 关闭监控器
if p.watcher != nil {
if err := p.watcher.Close(); err != nil {
log.Printf("⚠️ 关闭文件监控器失败: %v", err)
slog.Warn("关闭文件监控器失败", "error", err)
lastErr = err
}
p.watcher = nil
@@ -265,17 +269,17 @@ func (p *Protector) StopAll() error {
// 移除所有目录的不可变属性
for path := range p.paths {
if err := p.setImmutable(path, false); err != nil {
log.Printf("⚠️ 移除目录 %s 不可变属性失败: %v", path, err)
slog.Warn("移除目录不可变属性失败", "path", path, "error", err)
lastErr = err
} else {
log.Printf("✅ 已取消保护目录: %s", path)
slog.Info("已取消保护目录", "path", path)
}
}
// 清空路径列表
p.paths = make(map[string]bool)
log.Println("✅ 已停止所有防篡改保护")
slog.Info("已停止所有防篡改保护")
return lastErr
}
@@ -333,7 +337,7 @@ func (p *Protector) initWatcher(ctx context.Context) error {
p.checkTicker = time.NewTicker(5 * time.Second)
go p.periodicAttributeCheck()
log.Println("✅ 文件监控器已启动")
slog.Info("文件监控器已启动")
})
return err
}
@@ -362,7 +366,7 @@ func (p *Protector) removePath(path string) error {
// 从监控中移除
if p.watcher != nil {
if err := p.watcher.Remove(path); err != nil {
log.Printf("⚠️ 从监控中移除目录失败: %v", err)
slog.Warn("从监控中移除目录失败", "error", err)
// 继续执行,不返回错误
}
}
@@ -390,7 +394,7 @@ func (p *Protector) watchLoop() {
if !ok {
return
}
log.Printf("⚠️ 文件监控错误: %v", err)
slog.Warn("文件监控错误", "error", err)
}
}
}
@@ -431,9 +435,9 @@ func (p *Protector) handleEvent(event fsnotify.Event) {
// 发送事件(非阻塞)
select {
case p.eventCh <- tamperEvent:
log.Printf("🚨 检测到文件变动: %s - %s (%s)", event.Name, operation, details)
slog.Warn("检测到文件变动", "path", event.Name, "operation", operation, "details", details)
default:
log.Printf("⚠️ 事件队列已满,丢弃事件: %s", event.Name)
slog.Warn("事件队列已满,丢弃事件", "path", event.Name)
}
}
@@ -468,20 +472,20 @@ func (p *Protector) checkAndRestoreImmutable(path string) {
// 检查不可变属性
hasImmutable, err := p.checkImmutable(path)
if err != nil {
log.Printf("⚠️ 检查目录 %s 属性失败: %v", path, err)
slog.Warn("检查目录属性失败", "path", path, "error", err)
return
}
// 如果不可变属性被移除
if !hasImmutable {
log.Printf("🚨 检测到属性篡改: %s 的不可变属性被移除", path)
slog.Warn("检测到属性篡改", "path", path, "details", "不可变属性被移除")
// 尝试恢复属性
restored := false
if err := p.setImmutable(path, true); err != nil {
log.Printf("❌ 恢复目录 %s 不可变属性失败: %v", path, err)
slog.Error("恢复目录不可变属性失败", "path", path, "error", err)
} else {
log.Printf("✅ 已自动恢复目录 %s 的不可变属性", path)
slog.Info("已自动恢复目录的不可变属性", "path", path)
restored = true
}
@@ -495,9 +499,9 @@ func (p *Protector) checkAndRestoreImmutable(path string) {
select {
case p.alertCh <- alert:
log.Printf("📤 已发送属性篡改告警: %s", path)
slog.Info("已发送属性篡改告警", "path", path)
default:
log.Printf("⚠️ 告警队列已满,丢弃告警: %s", path)
slog.Warn("告警队列已满,丢弃告警", "path", path)
}
}
}
+12 -12
View File
@@ -5,7 +5,7 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"log"
"log/slog"
"net/http"
"os"
"time"
@@ -57,11 +57,11 @@ func New(cfg *config.Config, currentVer string) (*Updater, error) {
// Start 启动自动更新检查
func (u *Updater) Start(ctx context.Context) {
if !u.cfg.AutoUpdate.Enabled {
log.Println("自动更新已禁用")
slog.Info("自动更新已禁用")
return
}
log.Printf("自动更新已启用,检查间隔: %v", u.cfg.GetUpdateCheckInterval())
slog.Info("自动更新已启用", "check_interval", u.cfg.GetUpdateCheckInterval())
// 立即检查一次
u.CheckAndUpdate()
@@ -75,7 +75,7 @@ func (u *Updater) Start(ctx context.Context) {
case <-ticker.C:
u.CheckAndUpdate()
case <-ctx.Done():
log.Println("停止自动更新检查")
slog.Info("停止自动更新检查")
return
}
}
@@ -83,30 +83,30 @@ func (u *Updater) Start(ctx context.Context) {
// CheckAndUpdate 检查并更新
func (u *Updater) CheckAndUpdate() {
log.Println("🔍 检查更新...")
slog.Debug("检查更新...")
// 获取最新版本信息
versionInfo, err := u.fetchLatestVersion()
if err != nil {
log.Printf("⚠️ 获取版本信息失败: %v", err)
slog.Warn("获取版本信息失败", "error", err)
return
}
// 比较版本
if versionInfo.Version == u.currentVer {
log.Printf("✅ 当前已是最新版本: %s", u.currentVer)
slog.Debug("当前已是最新版本", "version", u.currentVer)
return
}
log.Printf("🆕 发现新版本: %s (当前版本: %s)", versionInfo.Version, u.currentVer)
slog.Info("发现新版本", "new_version", versionInfo.Version, "current_version", u.currentVer)
// 下载新版本
if err := u.downloadAndUpdate(versionInfo); err != nil {
log.Printf("❌ 更新失败: %v", err)
slog.Error("更新失败", "error", err)
return
}
log.Println("✅ 更新成功,将在下次重启时生效")
slog.Info("更新成功,将在下次重启时生效")
}
// fetchLatestVersion 获取最新版本信息
@@ -137,7 +137,7 @@ func (u *Updater) checkUpdateWithClient(latestVersionURL string) (*VersionInfo,
// downloadAndUpdate 下载并更新
func (u *Updater) downloadAndUpdate(versionInfo *VersionInfo) error {
log.Printf("📥 下载新版本: %s", versionInfo.Version)
slog.Info("下载新版本", "version", versionInfo.Version)
downloadURL := u.cfg.GetDownloadURL()
@@ -157,7 +157,7 @@ func (u *Updater) downloadAndUpdate(versionInfo *VersionInfo) error {
return fmt.Errorf("应用更新失败: %w", err)
}
log.Printf("✅ 更新成功,进程即将退出,等待系统服务重启...")
slog.Info("更新成功,进程即将退出,等待系统服务重启...")
// 退出当前进程,让系统服务管理器(systemd/supervisor等)自动重启
// 注意:这要求服务配置了自动重启(如 systemd 的 Restart=always)