perf: add visitReverse to logger ring buffer, avoid full copy in RecentLogs
RecentLogs previously copied ALL ring buffer entries via recent(0), then iterated in reverse to filter. Now uses visitReverse() which iterates newest-to-oldest under read lock, copying only matching entries — eliminates the full-buffer allocation for filtered queries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a9ff9b1bf7
commit
5582ff9551
1 changed files with 26 additions and 9 deletions
|
|
@ -93,6 +93,20 @@ func (rb *logRingBuffer) recent(limit int) []LogEntry {
|
|||
return result
|
||||
}
|
||||
|
||||
// visitReverse iterates entries from newest to oldest under the read lock.
|
||||
// The callback receives a pointer to the internal entry (valid only during
|
||||
// the call). Return false to stop iteration.
|
||||
func (rb *logRingBuffer) visitReverse(fn func(*LogEntry) bool) {
|
||||
rb.mu.RLock()
|
||||
defer rb.mu.RUnlock()
|
||||
for i := 0; i < rb.count; i++ {
|
||||
idx := (rb.head - 1 - i + len(rb.entries)) % len(rb.entries)
|
||||
if !fn(&rb.entries[idx]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LogSubscriber receives log entries matching its filter.
|
||||
type LogSubscriber struct {
|
||||
Ch chan LogEntry
|
||||
|
|
@ -355,20 +369,23 @@ func broadcastToSubscribers(entry LogEntry) {
|
|||
// RecentLogs returns recent log entries from the ring buffer, optionally filtered
|
||||
// by minimum level and component. The Caller field is stripped for security.
|
||||
func RecentLogs(minLevel LogLevel, component string, limit int) []LogEntry {
|
||||
all := ringBuf.recent(0) // get all
|
||||
result := make([]LogEntry, 0, limit)
|
||||
for i := len(all) - 1; i >= 0 && len(result) < limit; i-- {
|
||||
e := all[i]
|
||||
ringBuf.visitReverse(func(e *LogEntry) bool {
|
||||
if len(result) >= limit {
|
||||
return false
|
||||
}
|
||||
if lvl, ok := levelFromName[e.Level]; ok && lvl < minLevel {
|
||||
continue
|
||||
return true
|
||||
}
|
||||
if component != "" && e.Component != component {
|
||||
continue
|
||||
}
|
||||
e.Caller = "" // strip for security
|
||||
e.Fields = SanitizeFields(e.Fields) // mask sensitive values
|
||||
result = append(result, e)
|
||||
return true
|
||||
}
|
||||
entry := *e
|
||||
entry.Caller = ""
|
||||
entry.Fields = SanitizeFields(e.Fields)
|
||||
result = append(result, entry)
|
||||
return true
|
||||
})
|
||||
// Reverse so oldest first
|
||||
for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
|
||||
result[i], result[j] = result[j], result[i]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue