...
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
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
83 func (f *latencyFile) Close() {
84 f.stop <- struct{}{}
85 _ = f.output.Close()
86 }
87
View as plain text