You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.2 KiB
110 lines
2.2 KiB
package logbuffer |
|
|
|
import ( |
|
"sync" |
|
"time" |
|
) |
|
|
|
// LogEntry represents a single log entry |
|
type LogEntry struct { |
|
ID int64 `json:"id"` |
|
Timestamp time.Time `json:"timestamp"` |
|
Level string `json:"level"` |
|
Message string `json:"message"` |
|
File string `json:"file,omitempty"` |
|
Line int `json:"line,omitempty"` |
|
} |
|
|
|
// Buffer is a thread-safe ring buffer for log entries |
|
type Buffer struct { |
|
entries []LogEntry |
|
size int |
|
head int // next write position |
|
count int // number of entries |
|
nextID int64 // monotonic ID counter |
|
mu sync.RWMutex |
|
} |
|
|
|
// NewBuffer creates a new ring buffer with the specified size |
|
func NewBuffer(size int) *Buffer { |
|
if size <= 0 { |
|
size = 10000 |
|
} |
|
return &Buffer{ |
|
entries: make([]LogEntry, size), |
|
size: size, |
|
} |
|
} |
|
|
|
// Add adds a log entry to the buffer |
|
func (b *Buffer) Add(entry LogEntry) { |
|
b.mu.Lock() |
|
defer b.mu.Unlock() |
|
|
|
b.nextID++ |
|
entry.ID = b.nextID |
|
|
|
b.entries[b.head] = entry |
|
b.head = (b.head + 1) % b.size |
|
|
|
if b.count < b.size { |
|
b.count++ |
|
} |
|
} |
|
|
|
// Get returns log entries, newest first |
|
// offset is the number of entries to skip from the newest |
|
// limit is the maximum number of entries to return |
|
func (b *Buffer) Get(offset, limit int) []LogEntry { |
|
b.mu.RLock() |
|
defer b.mu.RUnlock() |
|
|
|
if b.count == 0 || offset >= b.count { |
|
return []LogEntry{} |
|
} |
|
|
|
if limit <= 0 { |
|
limit = 100 |
|
} |
|
|
|
available := b.count - offset |
|
if limit > available { |
|
limit = available |
|
} |
|
|
|
result := make([]LogEntry, limit) |
|
|
|
// Start from the newest entry (head - 1) and go backwards |
|
for i := 0; i < limit; i++ { |
|
// Calculate index: newest is at (head - 1), skip offset entries |
|
idx := (b.head - 1 - offset - i + b.size*2) % b.size |
|
result[i] = b.entries[idx] |
|
} |
|
|
|
return result |
|
} |
|
|
|
// Clear removes all entries from the buffer |
|
func (b *Buffer) Clear() { |
|
b.mu.Lock() |
|
defer b.mu.Unlock() |
|
|
|
b.head = 0 |
|
b.count = 0 |
|
// Note: we don't reset nextID to maintain monotonic IDs |
|
} |
|
|
|
// Count returns the number of entries in the buffer |
|
func (b *Buffer) Count() int { |
|
b.mu.RLock() |
|
defer b.mu.RUnlock() |
|
return b.count |
|
} |
|
|
|
// Global buffer instance |
|
var GlobalBuffer *Buffer |
|
|
|
// Init initializes the global log buffer |
|
func Init(size int) { |
|
GlobalBuffer = NewBuffer(size) |
|
}
|
|
|