修改客户端日志为 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

+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)