github.com/letsencrypt/boulder@v0.20251208.0/test/load-generator/latency.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "time" 8 ) 9 10 type point struct { 11 Sent time.Time `json:"sent"` 12 Finished time.Time `json:"finished"` 13 Took int64 `json:"took"` 14 PType string `json:"type"` 15 Action string `json:"action"` 16 } 17 18 type latencyWriter interface { 19 Add(action string, sent, finished time.Time, pType string) 20 Close() 21 } 22 23 type latencyNoop struct{} 24 25 func (ln *latencyNoop) Add(_ string, _, _ time.Time, _ string) {} 26 27 func (ln *latencyNoop) Close() {} 28 29 type latencyFile struct { 30 metrics chan *point 31 output *os.File 32 stop chan struct{} 33 } 34 35 func newLatencyFile(filename string) (latencyWriter, error) { 36 if filename == "" { 37 return &latencyNoop{}, nil 38 } 39 fmt.Printf("[+] Opening results file %s\n", filename) 40 file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, os.ModePerm) 41 if err != nil { 42 return nil, err 43 } 44 f := &latencyFile{ 45 metrics: make(chan *point, 2048), 46 stop: make(chan struct{}, 1), 47 output: file, 48 } 49 go f.write() 50 return f, nil 51 } 52 53 func (f *latencyFile) write() { 54 for { 55 select { 56 case p := <-f.metrics: 57 data, err := json.Marshal(p) 58 if err != nil { 59 panic(err) 60 } 61 _, err = f.output.Write(append(data, []byte("\n")...)) 62 if err != nil { 63 panic(err) 64 } 65 case <-f.stop: 66 return 67 } 68 } 69 } 70 71 // Add writes a point to the file 72 func (f *latencyFile) Add(action string, sent, finished time.Time, pType string) { 73 f.metrics <- &point{ 74 Sent: sent, 75 Finished: finished, 76 Took: finished.Sub(sent).Nanoseconds(), 77 PType: pType, 78 Action: action, 79 } 80 } 81 82 // Close stops f.write() and closes the file, any remaining metrics will be discarded 83 func (f *latencyFile) Close() { 84 f.stop <- struct{}{} 85 _ = f.output.Close() 86 }