11package config
22
3- import "github.com/sirupsen/logrus"
3+ import (
4+ "sync"
5+ "time"
46
5- type thandLogger struct {
7+ "github.com/sirupsen/logrus"
8+ "github.com/thand-io/agent/internal/models"
9+ )
610
7- // Create a stack to psuh on new events and pop off older ones
8- // When an error/warn event is fired, flush the stack to the logger
9- eventStack []* logrus.Entry
11+ type thandLogger struct {
12+ // Ring buffer for storing events
13+ eventBuffer []* models.LogEntry
14+ maxSize int
15+ currentPos int
16+ isFull bool
17+ mu sync.RWMutex
1018}
1119
1220func NewThandLogger () * thandLogger {
13- return & thandLogger {}
21+ return & thandLogger {
22+ eventBuffer : make ([]* models.LogEntry , 1000 ),
23+ maxSize : 1000 ,
24+ currentPos : 0 ,
25+ isFull : false ,
26+ }
1427}
1528
1629func (t * thandLogger ) Fire (entry * logrus.Entry ) error {
30+ t .mu .Lock ()
31+ defer t .mu .Unlock ()
32+
33+ // Add to ring buffer
34+ t .eventBuffer [t .currentPos ] = models .NewLogEntry (entry )
35+ t .currentPos = (t .currentPos + 1 ) % t .maxSize
1736
18- // Push the new event onto the stack
19- t .eventStack = append (t .eventStack , entry )
37+ if t .currentPos == 0 {
38+ t .isFull = true
39+ }
2040
2141 return nil
2242}
@@ -27,13 +47,112 @@ func (t *thandLogger) Levels() []logrus.Level {
2747 logrus .FatalLevel ,
2848 logrus .ErrorLevel ,
2949 logrus .WarnLevel ,
50+ logrus .InfoLevel ,
51+ // logrus.DebugLevel,
52+ // logrus.TraceLevel,
3053 }
3154}
3255
3356func (t * thandLogger ) Clear () {
34- t .eventStack = []* logrus.Entry {}
57+ t .mu .Lock ()
58+ defer t .mu .Unlock ()
59+
60+ t .eventBuffer = make ([]* models.LogEntry , t .maxSize )
61+ t .currentPos = 0
62+ t .isFull = false
3563}
3664
37- func (t * thandLogger ) GetEvents () []* logrus.Entry {
38- return t .eventStack
65+ func (t * thandLogger ) GetEvents () []* models.LogEntry {
66+ t .mu .RLock ()
67+ defer t .mu .RUnlock ()
68+
69+ if ! t .isFull {
70+ // Return only filled portion
71+ result := make ([]* models.LogEntry , t .currentPos )
72+ copy (result , t .eventBuffer [:t .currentPos ])
73+ return result
74+ }
75+
76+ // Return in chronological order (oldest first)
77+ result := make ([]* models.LogEntry , t .maxSize )
78+ copy (result , t .eventBuffer [t .currentPos :])
79+ copy (result [t .maxSize - t .currentPos :], t .eventBuffer [:t .currentPos ])
80+ return result
81+ }
82+
83+ func (t * thandLogger ) GetRecentEvents (count int ) []* models.LogEntry {
84+ events := t .GetEvents ()
85+ if len (events ) <= count {
86+ return events
87+ }
88+ return events [len (events )- count :]
89+ }
90+
91+ // LogFilter contains the filtering criteria for log events
92+ type LogFilter struct {
93+ // Filter by log levels (if empty, all levels are included)
94+ Levels []logrus.Level `json:"levels,omitempty"`
95+ // Filter events after this time (if nil, no time filter from start)
96+ Since * time.Time `json:"since,omitempty"`
97+ // Filter events before this time (if nil, no time filter to end)
98+ Until * time.Time `json:"until,omitempty"`
99+ // Maximum number of events to return (if 0, no limit)
100+ Limit int `json:"limit,omitempty"`
101+ }
102+
103+ // GetEventsWithFilter returns events that match the specified filter criteria
104+ func (t * thandLogger ) GetEventsWithFilter (filter LogFilter ) []* models.LogEntry {
105+ t .mu .RLock ()
106+ defer t .mu .RUnlock ()
107+
108+ allEvents := t .getEventsInternal ()
109+ var filtered []* models.LogEntry
110+
111+ // Create a map for quick level lookup if levels are specified
112+ levelMap := make (map [logrus.Level ]bool )
113+ if len (filter .Levels ) > 0 {
114+ for _ , level := range filter .Levels {
115+ levelMap [level ] = true
116+ }
117+ }
118+
119+ for _ , entry := range allEvents {
120+ // Filter by log level
121+ if len (filter .Levels ) > 0 && ! levelMap [entry .Level ] {
122+ continue
123+ }
124+
125+ // Filter by time range
126+ if filter .Since != nil && entry .Time .Before (* filter .Since ) {
127+ continue
128+ }
129+ if filter .Until != nil && entry .Time .After (* filter .Until ) {
130+ continue
131+ }
132+
133+ filtered = append (filtered , entry )
134+
135+ // Apply limit if specified
136+ if filter .Limit > 0 && len (filtered ) >= filter .Limit {
137+ break
138+ }
139+ }
140+
141+ return filtered
142+ }
143+
144+ // getEventsInternal returns events without additional locking (assumes caller has lock)
145+ func (t * thandLogger ) getEventsInternal () []* models.LogEntry {
146+ if ! t .isFull {
147+ // Return only filled portion
148+ result := make ([]* models.LogEntry , t .currentPos )
149+ copy (result , t .eventBuffer [:t .currentPos ])
150+ return result
151+ }
152+
153+ // Return in chronological order (oldest first)
154+ result := make ([]* models.LogEntry , t .maxSize )
155+ copy (result , t .eventBuffer [t .currentPos :])
156+ copy (result [t .maxSize - t .currentPos :], t .eventBuffer [:t .currentPos ])
157+ return result
39158}
0 commit comments