blob: 0fc3c53fd3149aaaa7c8b8f2bb381e3b3a9d71a6 [file] [log] [blame]
Rohan Agrawalc32d9932020-06-15 11:01:47 +00001// Copyright (c) 2018 The Jaeger Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package config
16
17import (
18 "fmt"
19 "net/url"
20 "os"
21 "strconv"
22 "strings"
23 "time"
24
25 "github.com/opentracing/opentracing-go"
26 "github.com/pkg/errors"
Rohan Agrawalc32d9932020-06-15 11:01:47 +000027 "github.com/uber/jaeger-client-go"
28)
29
30const (
31 // environment variable names
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000032 envServiceName = "JAEGER_SERVICE_NAME"
33 envDisabled = "JAEGER_DISABLED"
34 envRPCMetrics = "JAEGER_RPC_METRICS"
35 envTags = "JAEGER_TAGS"
36 envSamplerType = "JAEGER_SAMPLER_TYPE"
37 envSamplerParam = "JAEGER_SAMPLER_PARAM"
38 envSamplerManagerHostPort = "JAEGER_SAMPLER_MANAGER_HOST_PORT" // Deprecated by envSamplingEndpoint
39 envSamplingEndpoint = "JAEGER_SAMPLING_ENDPOINT"
40 envSamplerMaxOperations = "JAEGER_SAMPLER_MAX_OPERATIONS"
41 envSamplerRefreshInterval = "JAEGER_SAMPLER_REFRESH_INTERVAL"
42 envReporterMaxQueueSize = "JAEGER_REPORTER_MAX_QUEUE_SIZE"
43 envReporterFlushInterval = "JAEGER_REPORTER_FLUSH_INTERVAL"
44 envReporterLogSpans = "JAEGER_REPORTER_LOG_SPANS"
45 envReporterAttemptReconnectingDisabled = "JAEGER_REPORTER_ATTEMPT_RECONNECTING_DISABLED"
46 envReporterAttemptReconnectInterval = "JAEGER_REPORTER_ATTEMPT_RECONNECT_INTERVAL"
47 envEndpoint = "JAEGER_ENDPOINT"
48 envUser = "JAEGER_USER"
49 envPassword = "JAEGER_PASSWORD"
50 envAgentHost = "JAEGER_AGENT_HOST"
51 envAgentPort = "JAEGER_AGENT_PORT"
52 env128bit = "JAEGER_TRACEID_128BIT"
Rohan Agrawalc32d9932020-06-15 11:01:47 +000053)
54
55// FromEnv uses environment variables to set the tracer's Configuration
56func FromEnv() (*Configuration, error) {
57 c := &Configuration{}
58 return c.FromEnv()
59}
60
61// FromEnv uses environment variables and overrides existing tracer's Configuration
62func (c *Configuration) FromEnv() (*Configuration, error) {
63 if e := os.Getenv(envServiceName); e != "" {
64 c.ServiceName = e
65 }
66
67 if e := os.Getenv(envRPCMetrics); e != "" {
68 if value, err := strconv.ParseBool(e); err == nil {
69 c.RPCMetrics = value
70 } else {
71 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envRPCMetrics, e)
72 }
73 }
74
75 if e := os.Getenv(envDisabled); e != "" {
76 if value, err := strconv.ParseBool(e); err == nil {
77 c.Disabled = value
78 } else {
79 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envDisabled, e)
80 }
81 }
82
83 if e := os.Getenv(envTags); e != "" {
84 c.Tags = parseTags(e)
85 }
86
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000087 if e := os.Getenv(env128bit); e != "" {
88 if value, err := strconv.ParseBool(e); err == nil {
89 c.Gen128Bit = value
90 } else {
91 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", env128bit, e)
92 }
93 }
94
Rohan Agrawalc32d9932020-06-15 11:01:47 +000095 if c.Sampler == nil {
96 c.Sampler = &SamplerConfig{}
97 }
98
99 if s, err := c.Sampler.samplerConfigFromEnv(); err == nil {
100 c.Sampler = s
101 } else {
102 return nil, errors.Wrap(err, "cannot obtain sampler config from env")
103 }
104
105 if c.Reporter == nil {
106 c.Reporter = &ReporterConfig{}
107 }
108
109 if r, err := c.Reporter.reporterConfigFromEnv(); err == nil {
110 c.Reporter = r
111 } else {
112 return nil, errors.Wrap(err, "cannot obtain reporter config from env")
113 }
114
115 return c, nil
116}
117
118// samplerConfigFromEnv creates a new SamplerConfig based on the environment variables
119func (sc *SamplerConfig) samplerConfigFromEnv() (*SamplerConfig, error) {
120 if e := os.Getenv(envSamplerType); e != "" {
121 sc.Type = e
122 }
123
124 if e := os.Getenv(envSamplerParam); e != "" {
125 if value, err := strconv.ParseFloat(e, 64); err == nil {
126 sc.Param = value
127 } else {
128 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerParam, e)
129 }
130 }
131
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +0000132 if e := os.Getenv(envSamplingEndpoint); e != "" {
133 sc.SamplingServerURL = e
134 } else if e := os.Getenv(envSamplerManagerHostPort); e != "" {
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000135 sc.SamplingServerURL = e
136 } else if e := os.Getenv(envAgentHost); e != "" {
137 // Fallback if we know the agent host - try the sampling endpoint there
138 sc.SamplingServerURL = fmt.Sprintf("http://%s:%d/sampling", e, jaeger.DefaultSamplingServerPort)
139 }
140
141 if e := os.Getenv(envSamplerMaxOperations); e != "" {
142 if value, err := strconv.ParseInt(e, 10, 0); err == nil {
143 sc.MaxOperations = int(value)
144 } else {
145 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerMaxOperations, e)
146 }
147 }
148
149 if e := os.Getenv(envSamplerRefreshInterval); e != "" {
150 if value, err := time.ParseDuration(e); err == nil {
151 sc.SamplingRefreshInterval = value
152 } else {
153 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envSamplerRefreshInterval, e)
154 }
155 }
156
157 return sc, nil
158}
159
160// reporterConfigFromEnv creates a new ReporterConfig based on the environment variables
161func (rc *ReporterConfig) reporterConfigFromEnv() (*ReporterConfig, error) {
162 if e := os.Getenv(envReporterMaxQueueSize); e != "" {
163 if value, err := strconv.ParseInt(e, 10, 0); err == nil {
164 rc.QueueSize = int(value)
165 } else {
166 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterMaxQueueSize, e)
167 }
168 }
169
170 if e := os.Getenv(envReporterFlushInterval); e != "" {
171 if value, err := time.ParseDuration(e); err == nil {
172 rc.BufferFlushInterval = value
173 } else {
174 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterFlushInterval, e)
175 }
176 }
177
178 if e := os.Getenv(envReporterLogSpans); e != "" {
179 if value, err := strconv.ParseBool(e); err == nil {
180 rc.LogSpans = value
181 } else {
182 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterLogSpans, e)
183 }
184 }
185
186 if e := os.Getenv(envEndpoint); e != "" {
187 u, err := url.ParseRequestURI(e)
188 if err != nil {
189 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envEndpoint, e)
190 }
191 rc.CollectorEndpoint = u.String()
192 user := os.Getenv(envUser)
193 pswd := os.Getenv(envPassword)
194 if user != "" && pswd == "" || user == "" && pswd != "" {
195 return nil, errors.Errorf("you must set %s and %s env vars together", envUser, envPassword)
196 }
197 rc.User = user
198 rc.Password = pswd
199 } else {
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +0000200 useEnv := false
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000201 host := jaeger.DefaultUDPSpanServerHost
202 if e := os.Getenv(envAgentHost); e != "" {
203 host = e
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +0000204 useEnv = true
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000205 }
206
207 port := jaeger.DefaultUDPSpanServerPort
208 if e := os.Getenv(envAgentPort); e != "" {
209 if value, err := strconv.ParseInt(e, 10, 0); err == nil {
210 port = int(value)
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +0000211 useEnv = true
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000212 } else {
213 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envAgentPort, e)
214 }
215 }
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +0000216 if useEnv || rc.LocalAgentHostPort == "" {
217 rc.LocalAgentHostPort = fmt.Sprintf("%s:%d", host, port)
218 }
219
220 if e := os.Getenv(envReporterAttemptReconnectingDisabled); e != "" {
221 if value, err := strconv.ParseBool(e); err == nil {
222 rc.DisableAttemptReconnecting = value
223 } else {
224 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterAttemptReconnectingDisabled, e)
225 }
226 }
227
228 if !rc.DisableAttemptReconnecting {
229 if e := os.Getenv(envReporterAttemptReconnectInterval); e != "" {
230 if value, err := time.ParseDuration(e); err == nil {
231 rc.AttemptReconnectInterval = value
232 } else {
233 return nil, errors.Wrapf(err, "cannot parse env var %s=%s", envReporterAttemptReconnectInterval, e)
234 }
235 }
236 }
Rohan Agrawalc32d9932020-06-15 11:01:47 +0000237 }
238
239 return rc, nil
240}
241
242// parseTags parses the given string into a collection of Tags.
243// Spec for this value:
244// - comma separated list of key=value
245// - value can be specified using the notation ${envVar:defaultValue}, where `envVar`
246// is an environment variable and `defaultValue` is the value to use in case the env var is not set
247func parseTags(sTags string) []opentracing.Tag {
248 pairs := strings.Split(sTags, ",")
249 tags := make([]opentracing.Tag, 0)
250 for _, p := range pairs {
251 kv := strings.SplitN(p, "=", 2)
252 k, v := strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])
253
254 if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") {
255 ed := strings.SplitN(v[2:len(v)-1], ":", 2)
256 e, d := ed[0], ed[1]
257 v = os.Getenv(e)
258 if v == "" && d != "" {
259 v = d
260 }
261 }
262
263 tag := opentracing.Tag{Key: k, Value: v}
264 tags = append(tags, tag)
265 }
266
267 return tags
268}