/
logging.go
148 lines (132 loc) · 3.79 KB
/
logging.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
Copyright (c) Facebook, Inc. and its affiliates.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package daemon
import (
"encoding/csv"
"fmt"
"io"
"math/rand"
"strconv"
"time"
)
// LogSample has all the measurements we may want to log
type LogSample struct {
MasterOffsetNS float64
MasterOffsetMeanNS float64
MasterOffsetStddevNS float64
PathDelayNS float64
PathDelayMeanNS float64
PathDelayStddevNS float64
FreqAdjustmentPPB float64
FreqAdjustmentMeanPPB float64
FreqAdjustmentStddevPPB float64
MeasurementNS float64
MeasurementMeanNS float64
MeasurementStddevNS float64
WindowNS float64
ClockAccuracyMean float64
}
var header = []string{
"offset",
"offset_mean",
"offset_stddev",
"delay",
"delay_mean",
"delay_stddev",
"freq",
"freq_mean",
"freq_stddev",
"measurement",
"measurement_mean",
"measurement_stddev",
"window",
"clock_accuracy_mean",
}
func shouldLog(sampleRate int) bool {
if sampleRate < 1 {
return false
}
// randomized sampling
return rand.Intn(sampleRate) == 0
}
// CSVRecords returns all data from this sample as CSV. Must by synced with `header` variable.
func (s *LogSample) CSVRecords() []string {
return []string{
strconv.FormatFloat(s.MasterOffsetNS, 'f', -1, 64),
strconv.FormatFloat(s.MasterOffsetMeanNS, 'f', -1, 64),
strconv.FormatFloat(s.MasterOffsetStddevNS, 'f', -1, 64),
strconv.FormatFloat(s.PathDelayNS, 'f', -1, 64),
strconv.FormatFloat(s.PathDelayMeanNS, 'f', -1, 64),
strconv.FormatFloat(s.PathDelayStddevNS, 'f', -1, 64),
strconv.FormatFloat(s.FreqAdjustmentPPB, 'f', -1, 64),
strconv.FormatFloat(s.FreqAdjustmentMeanPPB, 'f', -1, 64),
strconv.FormatFloat(s.FreqAdjustmentStddevPPB, 'f', -1, 64),
strconv.FormatFloat(s.MeasurementNS, 'f', -1, 64),
strconv.FormatFloat(s.MeasurementMeanNS, 'f', -1, 64),
strconv.FormatFloat(s.MeasurementStddevNS, 'f', -1, 64),
strconv.FormatFloat(s.WindowNS, 'f', -1, 64),
strconv.FormatFloat(s.ClockAccuracyMean, 'f', -1, 64),
}
}
// Logger is something that can store LogSample somewhere
type Logger interface {
Log(*LogSample) error
}
// CSVLogger logs Sample as CSV into given writer
type CSVLogger struct {
csvwriter *csv.Writer
sampleRate int
printedHeader bool
}
// NewCSVLogger returns new CSVLogger
func NewCSVLogger(w io.Writer, sampleRate int) *CSVLogger {
return &CSVLogger{
csvwriter: csv.NewWriter(w),
sampleRate: sampleRate,
}
}
// Log implements Logger interface
func (l *CSVLogger) Log(s *LogSample) error {
if !l.printedHeader {
if err := l.csvwriter.Write(header); err != nil {
return err
}
l.printedHeader = true
}
if !shouldLog(l.sampleRate) {
return nil
}
csv := s.CSVRecords()
if err := l.csvwriter.Write(csv); err != nil {
return err
}
l.csvwriter.Flush()
return nil
}
// DummyLogger logs M and W to given writer
type DummyLogger struct {
w io.Writer
sampleRate int
}
// NewDummyLogger returns new DummyLogger
func NewDummyLogger(w io.Writer, sampleRate int) *DummyLogger {
return &DummyLogger{w: w, sampleRate: sampleRate}
}
// Log implements Logger interface
func (l *DummyLogger) Log(s *LogSample) error {
if !shouldLog(l.sampleRate) {
return nil
}
_, err := fmt.Fprintf(l.w, "m = %v, w = %v\n", time.Duration(s.MeasurementNS), time.Duration(s.WindowNS))
return err
}