blob: 44e93533cf3a0311f1dbbbe4f2eed47a1cce5f46 [file] [log] [blame]
Rohan Agrawalc32d9932020-06-15 11:01:47 +00001// Copyright (c) 2017-2018 Uber Technologies, Inc.
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 "errors"
19 "fmt"
20 "io"
21 "strings"
22 "time"
23
24 "github.com/opentracing/opentracing-go"
25
26 "github.com/uber/jaeger-client-go"
27 "github.com/uber/jaeger-client-go/internal/baggage/remote"
28 throttler "github.com/uber/jaeger-client-go/internal/throttler/remote"
29 "github.com/uber/jaeger-client-go/rpcmetrics"
30 "github.com/uber/jaeger-client-go/transport"
31 "github.com/uber/jaeger-lib/metrics"
32)
33
34const defaultSamplingProbability = 0.001
35
36// Configuration configures and creates Jaeger Tracer
37type Configuration struct {
38 // ServiceName specifies the service name to use on the tracer.
39 // Can be provided via environment variable named JAEGER_SERVICE_NAME
40 ServiceName string `yaml:"serviceName"`
41
42 // Disabled can be provided via environment variable named JAEGER_DISABLED
43 Disabled bool `yaml:"disabled"`
44
45 // RPCMetrics can be provided via environment variable named JAEGER_RPC_METRICS
46 RPCMetrics bool `yaml:"rpc_metrics"`
47
48 // Tags can be provided via environment variable named JAEGER_TAGS
49 Tags []opentracing.Tag `yaml:"tags"`
50
51 Sampler *SamplerConfig `yaml:"sampler"`
52 Reporter *ReporterConfig `yaml:"reporter"`
53 Headers *jaeger.HeadersConfig `yaml:"headers"`
54 BaggageRestrictions *BaggageRestrictionsConfig `yaml:"baggage_restrictions"`
55 Throttler *ThrottlerConfig `yaml:"throttler"`
56}
57
58// SamplerConfig allows initializing a non-default sampler. All fields are optional.
59type SamplerConfig struct {
60 // Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote
61 // Can be set by exporting an environment variable named JAEGER_SAMPLER_TYPE
62 Type string `yaml:"type"`
63
64 // Param is a value passed to the sampler.
65 // Valid values for Param field are:
66 // - for "const" sampler, 0 or 1 for always false/true respectively
67 // - for "probabilistic" sampler, a probability between 0 and 1
68 // - for "rateLimiting" sampler, the number of spans per second
69 // - for "remote" sampler, param is the same as for "probabilistic"
70 // and indicates the initial sampling rate before the actual one
71 // is received from the mothership.
72 // Can be set by exporting an environment variable named JAEGER_SAMPLER_PARAM
73 Param float64 `yaml:"param"`
74
75 // SamplingServerURL is the address of jaeger-agent's HTTP sampling server
76 // Can be set by exporting an environment variable named JAEGER_SAMPLER_MANAGER_HOST_PORT
77 SamplingServerURL string `yaml:"samplingServerURL"`
78
79 // SamplingRefreshInterval controls how often the remotely controlled sampler will poll
80 // jaeger-agent for the appropriate sampling strategy.
81 // Can be set by exporting an environment variable named JAEGER_SAMPLER_REFRESH_INTERVAL
82 SamplingRefreshInterval time.Duration `yaml:"samplingRefreshInterval"`
83
84 // MaxOperations is the maximum number of operations that the PerOperationSampler
85 // will keep track of. If an operation is not tracked, a default probabilistic
86 // sampler will be used rather than the per operation specific sampler.
87 // Can be set by exporting an environment variable named JAEGER_SAMPLER_MAX_OPERATIONS.
88 MaxOperations int `yaml:"maxOperations"`
89
90 // Opt-in feature for applications that require late binding of span name via explicit
91 // call to SetOperationName when using PerOperationSampler. When this feature is enabled,
92 // the sampler will return retryable=true from OnCreateSpan(), thus leaving the sampling
93 // decision as non-final (and the span as writeable). This may lead to degraded performance
94 // in applications that always provide the correct span name on trace creation.
95 //
96 // For backwards compatibility this option is off by default.
97 OperationNameLateBinding bool `yaml:"operationNameLateBinding"`
98
99 // Options can be used to programmatically pass additional options to the Remote sampler.
100 Options []jaeger.SamplerOption
101}
102
103// ReporterConfig configures the reporter. All fields are optional.
104type ReporterConfig struct {
105 // QueueSize controls how many spans the reporter can keep in memory before it starts dropping
106 // new spans. The queue is continuously drained by a background go-routine, as fast as spans
107 // can be sent out of process.
108 // Can be set by exporting an environment variable named JAEGER_REPORTER_MAX_QUEUE_SIZE
109 QueueSize int `yaml:"queueSize"`
110
111 // BufferFlushInterval controls how often the buffer is force-flushed, even if it's not full.
112 // It is generally not useful, as it only matters for very low traffic services.
113 // Can be set by exporting an environment variable named JAEGER_REPORTER_FLUSH_INTERVAL
114 BufferFlushInterval time.Duration
115
116 // LogSpans, when true, enables LoggingReporter that runs in parallel with the main reporter
117 // and logs all submitted spans. Main Configuration.Logger must be initialized in the code
118 // for this option to have any effect.
119 // Can be set by exporting an environment variable named JAEGER_REPORTER_LOG_SPANS
120 LogSpans bool `yaml:"logSpans"`
121
122 // LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address
123 // Can be set by exporting an environment variable named JAEGER_AGENT_HOST / JAEGER_AGENT_PORT
124 LocalAgentHostPort string `yaml:"localAgentHostPort"`
125
126 // CollectorEndpoint instructs reporter to send spans to jaeger-collector at this URL
127 // Can be set by exporting an environment variable named JAEGER_ENDPOINT
128 CollectorEndpoint string `yaml:"collectorEndpoint"`
129
130 // User instructs reporter to include a user for basic http authentication when sending spans to jaeger-collector.
131 // Can be set by exporting an environment variable named JAEGER_USER
132 User string `yaml:"user"`
133
134 // Password instructs reporter to include a password for basic http authentication when sending spans to
135 // jaeger-collector. Can be set by exporting an environment variable named JAEGER_PASSWORD
136 Password string `yaml:"password"`
137
138 // HTTPHeaders instructs the reporter to add these headers to the http request when reporting spans.
139 // This field takes effect only when using HTTPTransport by setting the CollectorEndpoint.
140 HTTPHeaders map[string]string `yaml:"http_headers"`
141}
142
143// BaggageRestrictionsConfig configures the baggage restrictions manager which can be used to whitelist
144// certain baggage keys. All fields are optional.
145type BaggageRestrictionsConfig struct {
146 // DenyBaggageOnInitializationFailure controls the startup failure mode of the baggage restriction
147 // manager. If true, the manager will not allow any baggage to be written until baggage restrictions have
148 // been retrieved from jaeger-agent. If false, the manager wil allow any baggage to be written until baggage
149 // restrictions have been retrieved from jaeger-agent.
150 DenyBaggageOnInitializationFailure bool `yaml:"denyBaggageOnInitializationFailure"`
151
152 // HostPort is the hostPort of jaeger-agent's baggage restrictions server
153 HostPort string `yaml:"hostPort"`
154
155 // RefreshInterval controls how often the baggage restriction manager will poll
156 // jaeger-agent for the most recent baggage restrictions.
157 RefreshInterval time.Duration `yaml:"refreshInterval"`
158}
159
160// ThrottlerConfig configures the throttler which can be used to throttle the
161// rate at which the client may send debug requests.
162type ThrottlerConfig struct {
163 // HostPort of jaeger-agent's credit server.
164 HostPort string `yaml:"hostPort"`
165
166 // RefreshInterval controls how often the throttler will poll jaeger-agent
167 // for more throttling credits.
168 RefreshInterval time.Duration `yaml:"refreshInterval"`
169
170 // SynchronousInitialization determines whether or not the throttler should
171 // synchronously fetch credits from the agent when an operation is seen for
172 // the first time. This should be set to true if the client will be used by
173 // a short lived service that needs to ensure that credits are fetched
174 // upfront such that sampling or throttling occurs.
175 SynchronousInitialization bool `yaml:"synchronousInitialization"`
176}
177
178type nullCloser struct{}
179
180func (*nullCloser) Close() error { return nil }
181
182// New creates a new Jaeger Tracer, and a closer func that can be used to flush buffers
183// before shutdown.
184//
185// Deprecated: use NewTracer() function
186func (c Configuration) New(
187 serviceName string,
188 options ...Option,
189) (opentracing.Tracer, io.Closer, error) {
190 if serviceName != "" {
191 c.ServiceName = serviceName
192 }
193
194 return c.NewTracer(options...)
195}
196
197// NewTracer returns a new tracer based on the current configuration, using the given options,
198// and a closer func that can be used to flush buffers before shutdown.
199func (c Configuration) NewTracer(options ...Option) (opentracing.Tracer, io.Closer, error) {
200 if c.Disabled {
201 return &opentracing.NoopTracer{}, &nullCloser{}, nil
202 }
203
204 if c.ServiceName == "" {
205 return nil, nil, errors.New("no service name provided")
206 }
207
208 opts := applyOptions(options...)
209 tracerMetrics := jaeger.NewMetrics(opts.metrics, nil)
210 if c.RPCMetrics {
211 Observer(
212 rpcmetrics.NewObserver(
213 opts.metrics.Namespace(metrics.NSOptions{Name: "jaeger-rpc", Tags: map[string]string{"component": "jaeger"}}),
214 rpcmetrics.DefaultNameNormalizer,
215 ),
216 )(&opts) // adds to c.observers
217 }
218 if c.Sampler == nil {
219 c.Sampler = &SamplerConfig{
220 Type: jaeger.SamplerTypeRemote,
221 Param: defaultSamplingProbability,
222 }
223 }
224 if c.Reporter == nil {
225 c.Reporter = &ReporterConfig{}
226 }
227
228 sampler := opts.sampler
229 if sampler == nil {
230 s, err := c.Sampler.NewSampler(c.ServiceName, tracerMetrics)
231 if err != nil {
232 return nil, nil, err
233 }
234 sampler = s
235 }
236
237 reporter := opts.reporter
238 if reporter == nil {
239 r, err := c.Reporter.NewReporter(c.ServiceName, tracerMetrics, opts.logger)
240 if err != nil {
241 return nil, nil, err
242 }
243 reporter = r
244 }
245
246 tracerOptions := []jaeger.TracerOption{
247 jaeger.TracerOptions.Metrics(tracerMetrics),
248 jaeger.TracerOptions.Logger(opts.logger),
249 jaeger.TracerOptions.CustomHeaderKeys(c.Headers),
250 jaeger.TracerOptions.Gen128Bit(opts.gen128Bit),
251 jaeger.TracerOptions.PoolSpans(opts.poolSpans),
252 jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan),
253 jaeger.TracerOptions.MaxTagValueLength(opts.maxTagValueLength),
254 jaeger.TracerOptions.NoDebugFlagOnForcedSampling(opts.noDebugFlagOnForcedSampling),
255 }
256
257 for _, tag := range opts.tags {
258 tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value))
259 }
260
261 for _, tag := range c.Tags {
262 tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value))
263 }
264
265 for _, obs := range opts.observers {
266 tracerOptions = append(tracerOptions, jaeger.TracerOptions.Observer(obs))
267 }
268
269 for _, cobs := range opts.contribObservers {
270 tracerOptions = append(tracerOptions, jaeger.TracerOptions.ContribObserver(cobs))
271 }
272
273 for format, injector := range opts.injectors {
274 tracerOptions = append(tracerOptions, jaeger.TracerOptions.Injector(format, injector))
275 }
276
277 for format, extractor := range opts.extractors {
278 tracerOptions = append(tracerOptions, jaeger.TracerOptions.Extractor(format, extractor))
279 }
280
281 if c.BaggageRestrictions != nil {
282 mgr := remote.NewRestrictionManager(
283 c.ServiceName,
284 remote.Options.Metrics(tracerMetrics),
285 remote.Options.Logger(opts.logger),
286 remote.Options.HostPort(c.BaggageRestrictions.HostPort),
287 remote.Options.RefreshInterval(c.BaggageRestrictions.RefreshInterval),
288 remote.Options.DenyBaggageOnInitializationFailure(
289 c.BaggageRestrictions.DenyBaggageOnInitializationFailure,
290 ),
291 )
292 tracerOptions = append(tracerOptions, jaeger.TracerOptions.BaggageRestrictionManager(mgr))
293 }
294
295 if c.Throttler != nil {
296 debugThrottler := throttler.NewThrottler(
297 c.ServiceName,
298 throttler.Options.Metrics(tracerMetrics),
299 throttler.Options.Logger(opts.logger),
300 throttler.Options.HostPort(c.Throttler.HostPort),
301 throttler.Options.RefreshInterval(c.Throttler.RefreshInterval),
302 throttler.Options.SynchronousInitialization(
303 c.Throttler.SynchronousInitialization,
304 ),
305 )
306
307 tracerOptions = append(tracerOptions, jaeger.TracerOptions.DebugThrottler(debugThrottler))
308 }
309
310 tracer, closer := jaeger.NewTracer(
311 c.ServiceName,
312 sampler,
313 reporter,
314 tracerOptions...,
315 )
316
317 return tracer, closer, nil
318}
319
320// InitGlobalTracer creates a new Jaeger Tracer, and sets it as global OpenTracing Tracer.
321// It returns a closer func that can be used to flush buffers before shutdown.
322func (c Configuration) InitGlobalTracer(
323 serviceName string,
324 options ...Option,
325) (io.Closer, error) {
326 if c.Disabled {
327 return &nullCloser{}, nil
328 }
329 tracer, closer, err := c.New(serviceName, options...)
330 if err != nil {
331 return nil, err
332 }
333 opentracing.SetGlobalTracer(tracer)
334 return closer, nil
335}
336
337// NewSampler creates a new sampler based on the configuration
338func (sc *SamplerConfig) NewSampler(
339 serviceName string,
340 metrics *jaeger.Metrics,
341) (jaeger.Sampler, error) {
342 samplerType := strings.ToLower(sc.Type)
343 if samplerType == jaeger.SamplerTypeConst {
344 return jaeger.NewConstSampler(sc.Param != 0), nil
345 }
346 if samplerType == jaeger.SamplerTypeProbabilistic {
347 if sc.Param >= 0 && sc.Param <= 1.0 {
348 return jaeger.NewProbabilisticSampler(sc.Param)
349 }
350 return nil, fmt.Errorf(
351 "invalid Param for probabilistic sampler; expecting value between 0 and 1, received %v",
352 sc.Param,
353 )
354 }
355 if samplerType == jaeger.SamplerTypeRateLimiting {
356 return jaeger.NewRateLimitingSampler(sc.Param), nil
357 }
358 if samplerType == jaeger.SamplerTypeRemote || sc.Type == "" {
359 sc2 := *sc
360 sc2.Type = jaeger.SamplerTypeProbabilistic
361 initSampler, err := sc2.NewSampler(serviceName, nil)
362 if err != nil {
363 return nil, err
364 }
365 options := []jaeger.SamplerOption{
366 jaeger.SamplerOptions.Metrics(metrics),
367 jaeger.SamplerOptions.InitialSampler(initSampler),
368 jaeger.SamplerOptions.SamplingServerURL(sc.SamplingServerURL),
369 jaeger.SamplerOptions.MaxOperations(sc.MaxOperations),
370 jaeger.SamplerOptions.OperationNameLateBinding(sc.OperationNameLateBinding),
371 jaeger.SamplerOptions.SamplingRefreshInterval(sc.SamplingRefreshInterval),
372 }
373 options = append(options, sc.Options...)
374 return jaeger.NewRemotelyControlledSampler(serviceName, options...), nil
375 }
376 return nil, fmt.Errorf("unknown sampler type (%s)", sc.Type)
377}
378
379// NewReporter instantiates a new reporter that submits spans to the collector
380func (rc *ReporterConfig) NewReporter(
381 serviceName string,
382 metrics *jaeger.Metrics,
383 logger jaeger.Logger,
384) (jaeger.Reporter, error) {
385 sender, err := rc.newTransport()
386 if err != nil {
387 return nil, err
388 }
389 reporter := jaeger.NewRemoteReporter(
390 sender,
391 jaeger.ReporterOptions.QueueSize(rc.QueueSize),
392 jaeger.ReporterOptions.BufferFlushInterval(rc.BufferFlushInterval),
393 jaeger.ReporterOptions.Logger(logger),
394 jaeger.ReporterOptions.Metrics(metrics))
395 if rc.LogSpans && logger != nil {
396 logger.Infof("Initializing logging reporter\n")
397 reporter = jaeger.NewCompositeReporter(jaeger.NewLoggingReporter(logger), reporter)
398 }
399 return reporter, err
400}
401
402func (rc *ReporterConfig) newTransport() (jaeger.Transport, error) {
403 switch {
404 case rc.CollectorEndpoint != "":
405 httpOptions := []transport.HTTPOption{transport.HTTPBatchSize(1), transport.HTTPHeaders(rc.HTTPHeaders)}
406 if rc.User != "" && rc.Password != "" {
407 httpOptions = append(httpOptions, transport.HTTPBasicAuth(rc.User, rc.Password))
408 }
409 return transport.NewHTTPTransport(rc.CollectorEndpoint, httpOptions...), nil
410 default:
411 return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0)
412 }
413}