github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/canary/writer/writer.go (about)

     1  package writer
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"math/rand"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  )
    11  
    12  const (
    13  	LogEntry = "%s %s\n"
    14  )
    15  
    16  type Writer struct {
    17  	w                    io.Writer
    18  	sent                 chan time.Time
    19  	interval             time.Duration
    20  	outOfOrderPercentage int
    21  	outOfOrderMin        time.Duration
    22  	outOfOrderMax        time.Duration
    23  	size                 int
    24  	prevTsLen            int
    25  	pad                  string
    26  	quit                 chan struct{}
    27  	done                 chan struct{}
    28  }
    29  
    30  func NewWriter(writer io.Writer, sentChan chan time.Time, entryInterval, outOfOrderMin, outOfOrderMax time.Duration, outOfOrderPercentage, entrySize int) *Writer {
    31  
    32  	w := &Writer{
    33  		w:                    writer,
    34  		sent:                 sentChan,
    35  		interval:             entryInterval,
    36  		outOfOrderPercentage: outOfOrderPercentage,
    37  		outOfOrderMin:        outOfOrderMin,
    38  		outOfOrderMax:        outOfOrderMax,
    39  		size:                 entrySize,
    40  		prevTsLen:            0,
    41  		quit:                 make(chan struct{}),
    42  		done:                 make(chan struct{}),
    43  	}
    44  
    45  	go w.run()
    46  
    47  	return w
    48  }
    49  
    50  func (w *Writer) Stop() {
    51  	if w.quit != nil {
    52  		close(w.quit)
    53  		<-w.done
    54  		w.quit = nil
    55  	}
    56  }
    57  
    58  func (w *Writer) run() {
    59  	t := time.NewTicker(w.interval)
    60  	defer func() {
    61  		t.Stop()
    62  		close(w.done)
    63  	}()
    64  	for {
    65  		select {
    66  		case <-t.C:
    67  			t := time.Now()
    68  			if i := rand.Intn(100); i < w.outOfOrderPercentage {
    69  				n := rand.Intn(int(w.outOfOrderMax.Seconds()-w.outOfOrderMin.Seconds())) + int(w.outOfOrderMin.Seconds())
    70  				t = t.Add(-time.Duration(n) * time.Second)
    71  			}
    72  			ts := strconv.FormatInt(t.UnixNano(), 10)
    73  			tsLen := len(ts)
    74  
    75  			// I guess some day this could happen????
    76  			if w.prevTsLen != tsLen {
    77  				var str strings.Builder
    78  				// Total line length includes timestamp, white space separator, new line char.  Subtract those out
    79  				for str.Len() < w.size-tsLen-2 {
    80  					str.WriteString("p")
    81  				}
    82  				w.pad = str.String()
    83  				w.prevTsLen = tsLen
    84  			}
    85  
    86  			fmt.Fprintf(w.w, LogEntry, ts, w.pad)
    87  			w.sent <- t
    88  		case <-w.quit:
    89  			return
    90  		}
    91  	}
    92  
    93  }