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  }