forked from stripe/veneur
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config_parse.go
235 lines (210 loc) · 6.83 KB
/
config_parse.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
package veneur
import (
"io"
"io/ioutil"
"os"
"time"
"github.com/kelseyhightower/envconfig"
"gopkg.in/yaml.v2"
)
var defaultConfig = Config{
Aggregates: []string{"min", "max", "count"},
DatadogFlushMaxPerBody: 25000,
Interval: "10s",
MetricMaxLength: 4096,
PrometheusNetworkType: "tcp",
ReadBufferSizeBytes: 1048576 * 2, // 2 MiB
SpanChannelCapacity: 100,
SplunkHecBatchSize: 100,
SplunkHecMaxConnectionLifetime: "10s", // same as Interval
}
var defaultProxyConfig = ProxyConfig{
MaxIdleConnsPerHost: 100,
TracingClientCapacity: 1024,
TracingClientFlushInterval: "500ms",
TracingClientMetricsInterval: "1s",
}
// ReadProxyConfig unmarshals the proxy config file and slurps in its data.
func ReadProxyConfig(path string) (c ProxyConfig, err error) {
f, err := os.Open(path)
if err != nil {
return c, err
}
defer f.Close()
c, err = readProxyConfig(f)
c.applyDefaults()
return
}
func (c *ProxyConfig) applyDefaults() {
if c.MaxIdleConnsPerHost == 0 {
// It's dangerous to leave this as the default. Since veneur-proxy is
// designed for HA environments with lots of globalstats backends we
// need higher defaults lest we have too small a connection pool and cause
// a glut of TIME_WAIT connections, so set a default.
log.WithField(
"new value", defaultProxyConfig.MaxIdleConnsPerHost,
).Warn("max_idle_conns_per_host being unset may lead to unsafe operations, defaulting!")
c.MaxIdleConnsPerHost = defaultProxyConfig.MaxIdleConnsPerHost
}
if c.TracingClientCapacity == 0 {
c.TracingClientCapacity = defaultProxyConfig.TracingClientCapacity
}
if c.TracingClientFlushInterval == "" {
c.TracingClientFlushInterval = defaultProxyConfig.TracingClientFlushInterval
}
if c.TracingClientMetricsInterval == "" {
c.TracingClientMetricsInterval = defaultProxyConfig.TracingClientMetricsInterval
}
}
func readProxyConfig(r io.Reader) (ProxyConfig, error) {
var c ProxyConfig
bts, err := ioutil.ReadAll(r)
if err != nil {
return c, err
}
unmarshalErr := unmarshalSemiStrictly(bts, &c)
if unmarshalErr != nil {
if _, ok := err.(*UnknownConfigKeys); !ok {
return c, unmarshalErr
}
}
err = envconfig.Process("veneur_proxy", &c)
if err != nil {
return c, err
}
return c, unmarshalErr
}
// UnknownConfigKeys represents a failure to strictly parse a
// configuration YAML file has failed, indicating that the file
// contains unknown keys.
type UnknownConfigKeys struct {
err error
}
func (e *UnknownConfigKeys) Error() string {
return e.err.Error()
}
// ReadConfig unmarshals the config file and slurps in its
// data. ReadConfig can return an error of type *UnknownConfigKeys,
// which means that the file is usable, but contains unknown fields.
func ReadConfig(path string) (c Config, err error) {
f, err := os.Open(path)
if err != nil {
return c, err
}
defer f.Close()
c, err = readConfig(f)
c.applyDefaults()
return
}
func unmarshalSemiStrictly(bts []byte, into interface{}) error {
strictErr := yaml.UnmarshalStrict(bts, into)
if strictErr == nil {
return nil
}
looseErr := yaml.Unmarshal(bts, into)
if looseErr != nil {
return looseErr
}
return &UnknownConfigKeys{strictErr}
}
func readConfig(r io.Reader) (Config, error) {
var c Config
// Unfortunately the YAML package does not
// support reader inputs
// TODO(aditya) convert this when the
// upstream PR lands
bts, err := ioutil.ReadAll(r)
if err != nil {
return c, err
}
unmarshalErr := unmarshalSemiStrictly(bts, &c)
if unmarshalErr != nil {
if _, ok := err.(*UnknownConfigKeys); !ok {
return c, unmarshalErr
}
}
err = envconfig.Process("veneur", &c)
if err != nil {
return c, err
}
// pass back an error about any unknown fields:
return c, unmarshalErr
}
func (c *Config) applyDefaults() {
if len(c.Aggregates) == 0 {
c.Aggregates = defaultConfig.Aggregates
}
if c.Hostname == "" && !c.OmitEmptyHostname {
c.Hostname, _ = os.Hostname()
}
if c.Interval == "" {
c.Interval = defaultConfig.Interval
}
if c.MetricMaxLength == 0 {
c.MetricMaxLength = defaultConfig.MetricMaxLength
}
if c.PrometheusNetworkType == "" {
c.PrometheusNetworkType = defaultConfig.PrometheusNetworkType
}
if c.ReadBufferSizeBytes == 0 {
c.ReadBufferSizeBytes = defaultConfig.ReadBufferSizeBytes
}
if c.SsfBufferSize != 0 {
log.Warn("ssf_buffer_size configuration option has been replaced by datadog_span_buffer_size and will be removed in the next version")
if c.DatadogSpanBufferSize == 0 {
c.DatadogSpanBufferSize = c.SsfBufferSize
}
}
if c.FlushMaxPerBody != 0 {
log.Warn("flush_max_per_body configuration option has been replaced by datadog_flush_max_per_body and will be removed in the next version")
if c.DatadogFlushMaxPerBody == 0 {
c.DatadogFlushMaxPerBody = c.FlushMaxPerBody
}
}
if c.TraceLightstepNumClients != 0 {
log.Warn("trace_lightstep_num_clients configuration option has been replaced by lightstep_num_clients and will be removed in the next version")
if c.LightstepNumClients == 0 {
c.LightstepNumClients = c.TraceLightstepNumClients
}
}
if c.TraceLightstepCollectorHost != "" {
log.Warn("trace_lightstep_collector_host configuration option has been replaced by lightstep_collector_host and will be removed in the next version")
if c.LightstepCollectorHost == "" {
c.LightstepCollectorHost = c.TraceLightstepCollectorHost
}
}
if c.TraceLightstepAccessToken != "" {
log.Warn("trace_lightstep_access_token configuration option has been replaced by lightstep_access_token and will be removed in the next version")
if c.LightstepAccessToken == "" {
c.LightstepAccessToken = c.TraceLightstepAccessToken
}
}
if c.TraceLightstepMaximumSpans != 0 {
log.Warn("trace_lightstep_maximum_spans configuration option has been replaced by lightstep_maximum_spans and will be removed in the next version")
if c.LightstepMaximumSpans == 0 {
c.LightstepMaximumSpans = c.TraceLightstepMaximumSpans
}
}
if c.TraceLightstepReconnectPeriod != "" {
log.Warn("trace_lightstep_reconnect_period configuration option has been replaced by lightstep_reconnect_period and will be removed in the next version")
if c.LightstepReconnectPeriod == "" {
c.LightstepReconnectPeriod = c.TraceLightstepReconnectPeriod
}
}
if c.DatadogFlushMaxPerBody == 0 {
c.DatadogFlushMaxPerBody = defaultConfig.DatadogFlushMaxPerBody
}
if c.SpanChannelCapacity == 0 {
c.SpanChannelCapacity = defaultConfig.SpanChannelCapacity
}
if c.SplunkHecBatchSize == 0 {
c.SplunkHecBatchSize = defaultConfig.SplunkHecBatchSize
}
if c.SplunkHecMaxConnectionLifetime == "" {
c.SplunkHecMaxConnectionLifetime = defaultConfig.SplunkHecMaxConnectionLifetime
}
}
// ParseInterval handles parsing the flush interval as a time.Duration
func (c Config) ParseInterval() (time.Duration, error) {
return time.ParseDuration(c.Interval)
}