package filesystem import ( "encoding/json" "fmt" "os" "path/filepath" "sync" "time" ) // AuditOperation 审计操作类型 type AuditOperation string const ( OperationRead AuditOperation = "read" // 读取文件 OperationWrite AuditOperation = "write" // 写入文件 OperationDelete AuditOperation = "delete" // 删除文件 OperationCreate AuditOperation = "create" // 创建目录 OperationRename AuditOperation = "rename" // 重命名 OperationMove AuditOperation = "move" // 移动 OperationList AuditOperation = "list" // 列出目录 OperationDownload AuditOperation = "download" // 下载 ) // AuditLogEntry 审计日志条目 type AuditLogEntry struct { Timestamp time.Time `json:"timestamp"` // 操作时间 Operation AuditOperation `json:"operation"` // 操作类型 Path string `json:"path"` // 文件路径 OldPath string `json:"old_path,omitempty"` // 原路径(重命名/移动) Size int64 `json:"size,omitempty"` // 文件大小 IsDirectory bool `json:"is_directory"` // 是否为目录 Success bool `json:"success"` // 操作是否成功 Error string `json:"error,omitempty"` // 错误信息 UserAgent string `json:"user_agent,omitempty"` // 用户代理 IPAddress string `json:"ip_address,omitempty"` // IP地址 } // AuditLogger 审计日志记录器 type AuditLogger struct { logFile *os.File logPath string mu sync.Mutex buffer []AuditLogEntry bufferSize int stopChan chan struct{} } // NewAuditLogger 创建审计日志记录器 func NewAuditLogger(logDir string) (*AuditLogger, error) { // 创建日志目录 if err := os.MkdirAll(logDir, 0755); err != nil { return nil, fmt.Errorf("创建日志目录失败: %v", err) } // 生成日志文件名(按日期) timestamp := time.Now().Format("2006-01-02") logPath := filepath.Join(logDir, fmt.Sprintf("audit_%s.log", timestamp)) // 打开日志文件(追加模式) logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { return nil, fmt.Errorf("打开日志文件失败: %v", err) } logger := &AuditLogger{ logFile: logFile, logPath: logPath, buffer: make([]AuditLogEntry, 0, 100), bufferSize: 100, // 缓冲100条记录后批量写入 stopChan: make(chan struct{}), } // 启动后台协程,定期刷新缓冲区 go logger.backgroundFlush() return logger, nil } // Log 记录操作日志 func (a *AuditLogger) Log(entry AuditLogEntry) error { // 设置时间戳 if entry.Timestamp.IsZero() { entry.Timestamp = time.Now() } a.mu.Lock() defer a.mu.Unlock() // 添加到缓冲区 a.buffer = append(a.buffer, entry) // 如果缓冲区满了,立即写入 if len(a.buffer) >= a.bufferSize { if err := a.flush(); err != nil { return err } } return nil } // LogDelete 记录删除操作(便捷方法) func (a *AuditLogger) LogDelete(path string, isDir bool, size int64, err error) { entry := AuditLogEntry{ Timestamp: time.Now(), Operation: OperationDelete, Path: path, Size: size, IsDirectory: isDir, Success: err == nil, } if err != nil { entry.Error = err.Error() } _ = a.Log(entry) } // LogWrite 记录写入操作(便捷方法) func (a *AuditLogger) LogWrite(path string, size int64, err error) { entry := AuditLogEntry{ Timestamp: time.Now(), Operation: OperationWrite, Path: path, Size: size, IsDirectory: false, Success: err == nil, } if err != nil { entry.Error = err.Error() } _ = a.Log(entry) } // LogRead 记录读取操作(便捷方法) func (a *AuditLogger) LogRead(path string, size int64, err error) { entry := AuditLogEntry{ Timestamp: time.Now(), Operation: OperationRead, Path: path, Size: size, IsDirectory: false, Success: err == nil, } if err != nil { entry.Error = err.Error() } _ = a.Log(entry) } // flush 将缓冲区写入文件 func (a *AuditLogger) flush() error { if len(a.buffer) == 0 { return nil } // 序列化所有条目为JSON(每行一个) for _, entry := range a.buffer { data, err := json.Marshal(entry) if err != nil { continue // 序列化失败,跳过该条目 } if _, err := a.logFile.Write(append(data, '\n')); err != nil { return err } } // 刷新到磁盘 if err := a.logFile.Sync(); err != nil { return err } // 清空缓冲区 a.buffer = a.buffer[:0] return nil } // backgroundFlush 后台协程,定期刷新缓冲区 func (a *AuditLogger) backgroundFlush() { ticker := time.NewTicker(5 * time.Second) // 每5秒刷新一次 defer ticker.Stop() for { select { case <-ticker.C: a.mu.Lock() _ = a.flush() a.mu.Unlock() case <-a.stopChan: // 停止前刷新一次 a.mu.Lock() _ = a.flush() a.mu.Unlock() return } } } // Close 关闭审计日志记录器 func (a *AuditLogger) Close() error { close(a.stopChan) a.mu.Lock() defer a.mu.Unlock() // 刷新剩余缓冲区 if err := a.flush(); err != nil { return err } // 关闭文件 return a.logFile.Close() } // GetRecentLogs 获取最近的审计日志 func GetRecentLogs(logDir string, limit int) ([]AuditLogEntry, error) { // 读取今天的日志文件 timestamp := time.Now().Format("2006-01-02") logPath := filepath.Join(logDir, fmt.Sprintf("audit_%s.log", timestamp)) data, err := os.ReadFile(logPath) if err != nil { return nil, err } // 解析JSON(每行一个条目) var entries []AuditLogEntry lines := parseLines(string(data)) // 从后往前读取(最新的在前) start := len(lines) - limit if start < 0 { start = 0 } for i := len(lines) - 1; i >= start; i-- { var entry AuditLogEntry if err := json.Unmarshal([]byte(lines[i]), &entry); err == nil { entries = append(entries, entry) } } return entries, nil } // parseLines 解析文本为行 func parseLines(text string) []string { lines := make([]string, 0) current := "" for _, ch := range text { if ch == '\n' { if current != "" { lines = append(lines, current) current = "" } } else { current += string(ch) } } if current != "" { lines = append(lines, current) } return lines } // 全局审计日志记录器 var globalAuditLogger *AuditLogger var auditLoggerOnce sync.Once // GetAuditLogger 获取全局审计日志记录器 func GetAuditLogger() *AuditLogger { return globalAuditLogger }