gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/debug/buffer/buffer.go (about) 1 // Package buffer provides a simple ring buffer for storing local data 2 package buffer 3 4 import ( 5 "sync" 6 "time" 7 8 "github.com/google/uuid" 9 ) 10 11 type stream struct { 12 id string 13 entries chan *Entry 14 stop chan bool 15 } 16 17 // Buffer is ring buffer 18 type Buffer struct { 19 size int 20 sync.RWMutex 21 vals []*Entry 22 streams map[string]stream 23 } 24 25 // Entry is ring buffer data entry 26 type Entry struct { 27 Value interface{} 28 Timestamp time.Time 29 } 30 31 // New returns a new buffer of the given size 32 func New(i int) *Buffer { 33 return &Buffer{ 34 size: i, 35 streams: make(map[string]stream), 36 } 37 } 38 39 // Put adds a new value to ring buffer 40 func (b *Buffer) Put(v interface{}) { 41 b.Lock() 42 defer b.Unlock() 43 44 // append to values 45 entry := &Entry{ 46 Value: v, 47 Timestamp: time.Now(), 48 } 49 b.vals = append(b.vals, entry) 50 51 // trim if bigger than size required 52 if len(b.vals) > b.size { 53 b.vals = b.vals[1:] 54 } 55 56 // TODO: this is fucking ugly 57 for _, stream := range b.streams { 58 select { 59 case <-stream.stop: 60 delete(b.streams, stream.id) 61 close(stream.entries) 62 case stream.entries <- entry: 63 } 64 } 65 } 66 67 // Get returns the last n entries 68 func (b *Buffer) Get(n int) []*Entry { 69 b.RLock() 70 defer b.RUnlock() 71 72 // reset any invalid values 73 if n > b.size || n < 0 { 74 n = b.size 75 } 76 77 // create a delta 78 delta := b.size - n 79 80 // if all the values are less than delta 81 if len(b.vals) < delta { 82 return b.vals 83 } 84 85 // return the delta set 86 return b.vals[delta:] 87 } 88 89 // Return the entries since a specific time 90 func (b *Buffer) Since(t time.Time) []*Entry { 91 b.RLock() 92 defer b.RUnlock() 93 94 // return all the values 95 if t.IsZero() { 96 return b.vals 97 } 98 99 // if its in the future return nothing 100 if time.Since(t).Seconds() < 0.0 { 101 return nil 102 } 103 104 for i, v := range b.vals { 105 // find the starting point 106 d := v.Timestamp.Sub(t) 107 108 // return the values 109 if d.Seconds() > 0.0 { 110 return b.vals[i:] 111 } 112 } 113 114 return nil 115 } 116 117 // Stream logs from the buffer 118 func (b *Buffer) Stream(stop chan bool) <-chan *Entry { 119 b.Lock() 120 defer b.Unlock() 121 122 entries := make(chan *Entry, 128) 123 id := uuid.New().String() 124 b.streams[id] = stream{ 125 id: id, 126 entries: entries, 127 stop: stop, 128 } 129 130 return entries 131 } 132 133 // Size returns the size of the ring buffer 134 func (b *Buffer) Size() int { 135 return b.size 136 }