package log import ( "sync" ) // RingBuffer 内存环形缓冲区 type RingBuffer struct { data []QueryLog capacity int head int tail int count int mu sync.RWMutex } // NewRingBuffer 创建环形缓冲区 func NewRingBuffer(capacity int) *RingBuffer { return &RingBuffer{ data: make([]QueryLog, capacity), capacity: capacity, head: 0, tail: 0, count: 0, } } // Push 添加日志到缓冲区 func (rb *RingBuffer) Push(log QueryLog) { rb.mu.Lock() defer rb.mu.Unlock() // 如果缓冲区已满,覆盖最旧的数据 if rb.count == rb.capacity { rb.head = (rb.head + 1) % rb.capacity } rb.data[rb.tail] = log rb.tail = (rb.tail + 1) % rb.capacity if rb.count < rb.capacity { rb.count++ } } // Query 查询日志 func (rb *RingBuffer) Query(filter LogFilter, page PageParams) ([]QueryLog, int64, error) { rb.mu.RLock() defer rb.mu.RUnlock() // 收集所有符合条件的日志 var filtered []QueryLog for i := 0; i < rb.count; i++ { idx := (rb.head + i) % rb.capacity log := rb.data[idx] // 应用过滤条件 if rb.matchesFilter(log, filter) { filtered = append(filtered, log) } } total := int64(len(filtered)) // 排序 rb.sortLogs(filtered, page.SortField, page.SortDirection) // 分页 start := page.Offset if start >= len(filtered) { return []QueryLog{}, total, nil } end := start + page.Limit if end > len(filtered) { end = len(filtered) } return filtered[start:end], total, nil } // matchesFilter 检查日志是否匹配过滤条件 func (rb *RingBuffer) matchesFilter(log QueryLog, filter LogFilter) bool { // 结果过滤 if filter.Result != "" && log.Result != filter.Result { return false } // 查询类型过滤 if filter.QueryType != "" && log.QueryType != filter.QueryType { return false } // 时间范围过滤 if !filter.StartTime.IsZero() && log.Timestamp.Before(filter.StartTime) { return false } if !filter.EndTime.IsZero() && log.Timestamp.After(filter.EndTime) { return false } // 搜索过滤 if filter.SearchTerm != "" { if !contains(log.Domain, filter.SearchTerm) && !contains(log.ClientIP, filter.SearchTerm) { return false } } return true } // contains 检查字符串是否包含子串(不区分大小写) func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || containsIgnoreCase(s, substr)) } // containsIgnoreCase 不区分大小写的包含检查 func containsIgnoreCase(s, substr string) bool { s = toLower(s) substr = toLower(substr) for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false } // toLower 转换为小写 func toLower(s string) string { result := make([]byte, len(s)) for i := 0; i < len(s); i++ { c := s[i] if c >= 'A' && c <= 'Z' { c = c + ('a' - 'A') } result[i] = c } return string(result) } // sortLogs 对日志进行排序 func (rb *RingBuffer) sortLogs(logs []QueryLog, sortField, sortDirection string) { if sortField == "" { sortField = "timestamp" } if sortDirection == "" { sortDirection = "desc" } // 简单的冒泡排序(适用于小数据量) n := len(logs) for i := 0; i < n-1; i++ { for j := 0; j < n-i-1; j++ { shouldSwap := rb.compareLogs(logs[j], logs[j+1], sortField) if sortDirection == "desc" { shouldSwap = !shouldSwap } if shouldSwap { logs[j], logs[j+1] = logs[j+1], logs[j] } } } } // compareLogs 比较两个日志 func (rb *RingBuffer) compareLogs(a, b QueryLog, sortField string) bool { switch sortField { case "timestamp", "time": return a.Timestamp.Before(b.Timestamp) case "domain": return a.Domain < b.Domain case "clientIp", "client_ip": return a.ClientIP < b.ClientIP case "responseTime", "response_time": return a.ResponseTime < b.ResponseTime default: return a.Timestamp.Before(b.Timestamp) } } // GetStats 获取统计信息 func (rb *RingBuffer) GetStats(timeRange TimeRange) (*LogStats, error) { rb.mu.RLock() defer rb.mu.RUnlock() stats := &LogStats{ QueryTypes: make(map[string]int64), } for i := 0; i < rb.count; i++ { idx := (rb.head + i) % rb.capacity log := rb.data[idx] // 时间范围过滤 if !timeRange.StartTime.IsZero() && log.Timestamp.Before(timeRange.StartTime) { continue } if !timeRange.EndTime.IsZero() && log.Timestamp.After(timeRange.EndTime) { continue } stats.TotalQueries++ stats.AvgResponseTime += float64(log.ResponseTime) switch log.Result { case "blocked": stats.BlockedQueries++ case "allowed": stats.AllowedQueries++ case "error": stats.ErrorQueries++ } stats.QueryTypes[log.QueryType]++ } if stats.TotalQueries > 0 { stats.AvgResponseTime /= float64(stats.TotalQueries) } return stats, nil } // Count 返回当前缓冲区中的日志数量 func (rb *RingBuffer) Count() int { rb.mu.RLock() defer rb.mu.RUnlock() return rb.count } // Clear 清空缓冲区 func (rb *RingBuffer) Clear() { rb.mu.Lock() defer rb.mu.Unlock() rb.head = 0 rb.tail = 0 rb.count = 0 }