diff --git a/Dockerfile.agent b/Dockerfile.agent index ca18101..9b12769 100644 --- a/Dockerfile.agent +++ b/Dockerfile.agent @@ -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"] diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 6a56e3b..2f87f32 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -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) { // 加载配置 diff --git a/docker-compose-agent.yaml b/docker-compose-agent.yaml new file mode 100644 index 0000000..3ef4310 --- /dev/null +++ b/docker-compose-agent.yaml @@ -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/ \ No newline at end of file diff --git a/go.mod b/go.mod index 92942ba..e61f322 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 0dd1304..618b0be 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/pkg/agent/audit/utils.go b/pkg/agent/audit/utils.go index 6a76601..76dee71 100644 --- a/pkg/agent/audit/utils.go +++ b/pkg/agent/audit/utils.go @@ -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{} diff --git a/pkg/agent/config/config.go b/pkg/agent/config/config.go index d911b95..65eff0b 100644 --- a/pkg/agent/config/config.go +++ b/pkg/agent/config/config.go @@ -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 } diff --git a/pkg/agent/logger.go b/pkg/agent/logger.go new file mode 100644 index 0000000..96b24b8 --- /dev/null +++ b/pkg/agent/logger.go @@ -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) +} diff --git a/pkg/agent/service/agent.go b/pkg/agent/service/agent.go index 0e369c5..595eaaf 100644 --- a/pkg/agent/service/agent.go +++ b/pkg/agent/service/agent.go @@ -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 { diff --git a/pkg/agent/service/service.go b/pkg/agent/service/service.go index cbe4255..5d101c5 100644 --- a/pkg/agent/service/service.go +++ b/pkg/agent/service/service.go @@ -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 diff --git a/pkg/agent/sysutil/sysctl_linux.go b/pkg/agent/sysutil/sysctl_linux.go index b2250c7..a797e90 100644 --- a/pkg/agent/sysutil/sysctl_linux.go +++ b/pkg/agent/sysutil/sysctl_linux.go @@ -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 } diff --git a/pkg/agent/tamper/tamper_protector.go b/pkg/agent/tamper/tamper_protector.go index 503ea6c..6a9b40b 100644 --- a/pkg/agent/tamper/tamper_protector.go +++ b/pkg/agent/tamper/tamper_protector.go @@ -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) } } } diff --git a/pkg/agent/updater/updater.go b/pkg/agent/updater/updater.go index 16c7cc6..cb03bd3 100644 --- a/pkg/agent/updater/updater.go +++ b/pkg/agent/updater/updater.go @@ -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)