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 }