whois
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user