master
go 111 lines 1.99 KB
Raw
1 package commands
2
3 import (
4 "sync"
5 "time"
6 )
7
8 // ReqLogEntry is an entry in the request log.
9 type ReqLogEntry struct {
10 StartTime time.Time
11 EndTime time.Time
12 Active bool
13 Command string
14 Options map[string]any
15 Args []string
16 ID int
17
18 log *ReqLog
19 }
20
21 // Copy returns a copy of the ReqLogEntry.
22 func (r *ReqLogEntry) Copy() *ReqLogEntry {
23 out := *r
24 out.log = nil
25 return &out
26 }
27
28 // ReqLog is a log of requests.
29 type ReqLog struct {
30 Requests []*ReqLogEntry
31 nextID int
32 lock sync.Mutex
33 keep time.Duration
34 }
35
36 // AddEntry adds an entry to the log.
37 func (rl *ReqLog) AddEntry(rle *ReqLogEntry) {
38 rl.lock.Lock()
39 defer rl.lock.Unlock()
40
41 rle.ID = rl.nextID
42 rl.nextID++
43 rl.Requests = append(rl.Requests, rle)
44
45 if !rle.Active {
46 rl.maybeCleanup()
47 }
48 }
49
50 // ClearInactive removes stale entries.
51 func (rl *ReqLog) ClearInactive() {
52 rl.lock.Lock()
53 defer rl.lock.Unlock()
54
55 k := rl.keep
56 rl.keep = 0
57 rl.cleanup()
58 rl.keep = k
59 }
60
61 func (rl *ReqLog) maybeCleanup() {
62 // only do it every so often or it might
63 // become a perf issue
64 if len(rl.Requests)%10 == 0 {
65 rl.cleanup()
66 }
67 }
68
69 func (rl *ReqLog) cleanup() {
70 i := 0
71 now := time.Now()
72 for j := 0; j < len(rl.Requests); j++ {
73 rj := rl.Requests[j]
74 if rj.Active || rl.Requests[j].EndTime.Add(rl.keep).After(now) {
75 rl.Requests[i] = rl.Requests[j]
76 i++
77 }
78 }
79 rl.Requests = rl.Requests[:i]
80 }
81
82 // SetKeepTime sets a duration after which an entry will be considered inactive.
83 func (rl *ReqLog) SetKeepTime(t time.Duration) {
84 rl.lock.Lock()
85 defer rl.lock.Unlock()
86 rl.keep = t
87 }
88
89 // Report generates a copy of all the entries in the requestlog.
90 func (rl *ReqLog) Report() []*ReqLogEntry {
91 rl.lock.Lock()
92 defer rl.lock.Unlock()
93 out := make([]*ReqLogEntry, len(rl.Requests))
94
95 for i, e := range rl.Requests {
96 out[i] = e.Copy()
97 }
98
99 return out
100 }
101
102 // Finish marks an entry in the log as finished.
103 func (rl *ReqLog) Finish(rle *ReqLogEntry) {
104 rl.lock.Lock()
105 defer rl.lock.Unlock()
106
107 rle.Active = false
108 rle.EndTime = time.Now()
109
110 rl.maybeCleanup()
111 }