| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- package logger
- import (
- "database/sql"
- "fmt"
- "time"
- _ "modernc.org/sqlite"
- )
- // auditConfig 审计配置
- type auditConfig struct {
- enabled bool
- dbPath string
- retentionDays int
- bufferSize int
- }
- // AuditOption 审计配置选项
- type AuditOption func(*auditConfig)
- // WithDatabasePath 设置数据库路径
- func WithDatabasePath(path string) AuditOption {
- return func(c *auditConfig) {
- c.dbPath = path
- }
- }
- // WithRetention 设置保留天数
- func WithRetention(days int) AuditOption {
- return func(c *auditConfig) {
- c.retentionDays = days
- }
- }
- // WithBufferSize 设置缓冲区大小
- func WithBufferSize(size int) AuditOption {
- return func(c *auditConfig) {
- c.bufferSize = size
- }
- }
- // WithEnabled 设置是否启用审计
- func WithEnabled(enabled bool) AuditOption {
- return func(c *auditConfig) {
- c.enabled = enabled
- }
- }
- // sqliteAuditLogger SQLite审计日志器实现
- type sqliteAuditLogger struct {
- db *sql.DB
- config *auditConfig
- }
- // NewAuditLogger 创建审计日志器
- func NewAuditLogger(opts ...AuditOption) (AuditLogger, error) {
- config := &auditConfig{
- enabled: true,
- dbPath: "audit.db",
- retentionDays: 90,
- bufferSize: 1000,
- }
- for _, opt := range opts {
- opt(config)
- }
- if !config.enabled {
- return &noOpAuditLogger{}, nil
- }
- db, err := sql.Open("sqlite", config.dbPath)
- if err != nil {
- return nil, fmt.Errorf("failed to open database: %w", err)
- }
- if err := initAuditTable(db); err != nil {
- db.Close()
- return nil, fmt.Errorf("failed to initialize audit table: %w", err)
- }
- return &sqliteAuditLogger{
- db: db,
- config: config,
- }, nil
- }
- // Record 记录审计事件
- func (a *sqliteAuditLogger) Record(entry *AuditEntry) error {
- if entry == nil {
- return fmt.Errorf("audit entry cannot be nil")
- }
- if entry.ID == "" {
- entry.ID = fmt.Sprintf("%d", time.Now().UnixNano())
- }
- if entry.Timestamp.IsZero() {
- entry.Timestamp = time.Now()
- }
- query := `
- INSERT INTO audit_logs (id, timestamp, user_id, username, action, resource, details, ip, user_agent, success, error)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- `
- _, err := a.db.Exec(query,
- entry.ID,
- entry.Timestamp,
- entry.UserID,
- entry.Username,
- entry.Action,
- entry.Resource,
- entry.Details,
- entry.IP,
- entry.UserAgent,
- entry.Success,
- entry.Error,
- )
- if err != nil {
- return fmt.Errorf("failed to record audit entry: %w", err)
- }
- return nil
- }
- // Query 查询审计日志
- func (a *sqliteAuditLogger) Query(filter *AuditFilter) ([]*AuditEntry, error) {
- if filter == nil {
- filter = &AuditFilter{}
- }
- query := `SELECT id, timestamp, user_id, username, action, resource, details, ip, user_agent, success, error FROM audit_logs WHERE 1=1`
- args := []interface{}{}
- if filter.UserID != "" {
- query += " AND user_id = ?"
- args = append(args, filter.UserID)
- }
- if filter.Action != "" {
- query += " AND action = ?"
- args = append(args, filter.Action)
- }
- if filter.Resource != "" {
- query += " AND resource = ?"
- args = append(args, filter.Resource)
- }
- if filter.StartTime != nil {
- query += " AND timestamp >= ?"
- args = append(args, *filter.StartTime)
- }
- if filter.EndTime != nil {
- query += " AND timestamp <= ?"
- args = append(args, *filter.EndTime)
- }
- if filter.Success != nil {
- query += " AND success = ?"
- args = append(args, *filter.Success)
- }
- query += " ORDER BY timestamp DESC"
- if filter.Limit > 0 {
- query += " LIMIT ?"
- args = append(args, filter.Limit)
- }
- if filter.Offset > 0 {
- query += " OFFSET ?"
- args = append(args, filter.Offset)
- }
- rows, err := a.db.Query(query, args...)
- if err != nil {
- return nil, fmt.Errorf("failed to query audit logs: %w", err)
- }
- defer rows.Close()
- var entries []*AuditEntry
- for rows.Next() {
- entry := &AuditEntry{}
- err := rows.Scan(
- &entry.ID,
- &entry.Timestamp,
- &entry.UserID,
- &entry.Username,
- &entry.Action,
- &entry.Resource,
- &entry.Details,
- &entry.IP,
- &entry.UserAgent,
- &entry.Success,
- &entry.Error,
- )
- if err != nil {
- return nil, fmt.Errorf("failed to scan audit entry: %w", err)
- }
- entries = append(entries, entry)
- }
- return entries, nil
- }
- // Cleanup 清理过期数据
- func (a *sqliteAuditLogger) Cleanup(retention time.Duration) error {
- cutoff := time.Now().Add(-retention)
- query := "DELETE FROM audit_logs WHERE timestamp < ?"
- _, err := a.db.Exec(query, cutoff)
- if err != nil {
- return fmt.Errorf("failed to cleanup audit logs: %w", err)
- }
- // 优化数据库
- _, err = a.db.Exec("VACUUM")
- if err != nil {
- return fmt.Errorf("failed to vacuum database: %w", err)
- }
- return nil
- }
- // Sync 同步数据到磁盘
- func (a *sqliteAuditLogger) Sync() error {
- _, err := a.db.Exec("PRAGMA wal_checkpoint(FULL)")
- return err
- }
- // initAuditTable 初始化审计表
- func initAuditTable(db *sql.DB) error {
- query := `
- CREATE TABLE IF NOT EXISTS audit_logs (
- id TEXT PRIMARY KEY,
- timestamp DATETIME NOT NULL,
- user_id TEXT,
- username TEXT,
- action TEXT NOT NULL,
- resource TEXT,
- details TEXT,
- ip TEXT,
- user_agent TEXT,
- success BOOLEAN,
- error TEXT
- );
- CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_logs(timestamp);
- CREATE INDEX IF NOT EXISTS idx_audit_user ON audit_logs(user_id);
- CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_logs(action);
- CREATE INDEX IF NOT EXISTS idx_audit_resource ON audit_logs(resource);
- `
- _, err := db.Exec(query)
- return err
- }
- // noOpAuditLogger 空操作审计日志器(当审计被禁用时使用)
- type noOpAuditLogger struct{}
- func (n *noOpAuditLogger) Record(entry *AuditEntry) error {
- return nil
- }
- func (n *noOpAuditLogger) Query(filter *AuditFilter) ([]*AuditEntry, error) {
- return []*AuditEntry{}, nil
- }
- func (n *noOpAuditLogger) Cleanup(retention time.Duration) error {
- return nil
- }
- func (n *noOpAuditLogger) Sync() error {
- return nil
- }
|