config.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // Copyright (c) 2017 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. package config
  15. import (
  16. "errors"
  17. "fmt"
  18. "io"
  19. "strings"
  20. "time"
  21. "github.com/opentracing/opentracing-go"
  22. "github.com/uber/jaeger-client-go"
  23. "github.com/uber/jaeger-client-go/internal/baggage/remote"
  24. "github.com/uber/jaeger-client-go/rpcmetrics"
  25. )
  26. const defaultSamplingProbability = 0.001
  27. // Configuration configures and creates Jaeger Tracer
  28. type Configuration struct {
  29. Disabled bool `yaml:"disabled"`
  30. Sampler *SamplerConfig `yaml:"sampler"`
  31. Reporter *ReporterConfig `yaml:"reporter"`
  32. Headers *jaeger.HeadersConfig `yaml:"headers"`
  33. RPCMetrics bool `yaml:"rpc_metrics"`
  34. BaggageRestrictions *BaggageRestrictionsConfig `yaml:"baggage_restrictions"`
  35. }
  36. // SamplerConfig allows initializing a non-default sampler. All fields are optional.
  37. type SamplerConfig struct {
  38. // Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote
  39. Type string `yaml:"type"`
  40. // Param is a value passed to the sampler.
  41. // Valid values for Param field are:
  42. // - for "const" sampler, 0 or 1 for always false/true respectively
  43. // - for "probabilistic" sampler, a probability between 0 and 1
  44. // - for "rateLimiting" sampler, the number of spans per second
  45. // - for "remote" sampler, param is the same as for "probabilistic"
  46. // and indicates the initial sampling rate before the actual one
  47. // is received from the mothership
  48. Param float64 `yaml:"param"`
  49. // SamplingServerURL is the address of jaeger-agent's HTTP sampling server
  50. SamplingServerURL string `yaml:"samplingServerURL"`
  51. // MaxOperations is the maximum number of operations that the sampler
  52. // will keep track of. If an operation is not tracked, a default probabilistic
  53. // sampler will be used rather than the per operation specific sampler.
  54. MaxOperations int `yaml:"maxOperations"`
  55. // SamplingRefreshInterval controls how often the remotely controlled sampler will poll
  56. // jaeger-agent for the appropriate sampling strategy.
  57. SamplingRefreshInterval time.Duration `yaml:"samplingRefreshInterval"`
  58. }
  59. // ReporterConfig configures the reporter. All fields are optional.
  60. type ReporterConfig struct {
  61. // QueueSize controls how many spans the reporter can keep in memory before it starts dropping
  62. // new spans. The queue is continuously drained by a background go-routine, as fast as spans
  63. // can be sent out of process.
  64. QueueSize int `yaml:"queueSize"`
  65. // BufferFlushInterval controls how often the buffer is force-flushed, even if it's not full.
  66. // It is generally not useful, as it only matters for very low traffic services.
  67. BufferFlushInterval time.Duration
  68. // LogSpans, when true, enables LoggingReporter that runs in parallel with the main reporter
  69. // and logs all submitted spans. Main Configuration.Logger must be initialized in the code
  70. // for this option to have any effect.
  71. LogSpans bool `yaml:"logSpans"`
  72. // LocalAgentHostPort instructs reporter to send spans to jaeger-agent at this address
  73. LocalAgentHostPort string `yaml:"localAgentHostPort"`
  74. }
  75. // BaggageRestrictionsConfig configures the baggage restrictions manager which can be used to whitelist
  76. // certain baggage keys. All fields are optional.
  77. type BaggageRestrictionsConfig struct {
  78. // DenyBaggageOnInitializationFailure controls the startup failure mode of the baggage restriction
  79. // manager. If true, the manager will not allow any baggage to be written until baggage restrictions have
  80. // been retrieved from jaeger-agent. If false, the manager wil allow any baggage to be written until baggage
  81. // restrictions have been retrieved from jaeger-agent.
  82. DenyBaggageOnInitializationFailure bool `yaml:"denyBaggageOnInitializationFailure"`
  83. // HostPort is the hostPort of jaeger-agent's baggage restrictions server
  84. HostPort string `yaml:"hostPort"`
  85. // RefreshInterval controls how often the baggage restriction manager will poll
  86. // jaeger-agent for the most recent baggage restrictions.
  87. RefreshInterval time.Duration `yaml:"refreshInterval"`
  88. }
  89. type nullCloser struct{}
  90. func (*nullCloser) Close() error { return nil }
  91. // New creates a new Jaeger Tracer, and a closer func that can be used to flush buffers
  92. // before shutdown.
  93. func (c Configuration) New(
  94. serviceName string,
  95. options ...Option,
  96. ) (opentracing.Tracer, io.Closer, error) {
  97. if serviceName == "" {
  98. return nil, nil, errors.New("no service name provided")
  99. }
  100. if c.Disabled {
  101. return &opentracing.NoopTracer{}, &nullCloser{}, nil
  102. }
  103. opts := applyOptions(options...)
  104. tracerMetrics := jaeger.NewMetrics(opts.metrics, nil)
  105. if c.RPCMetrics {
  106. Observer(
  107. rpcmetrics.NewObserver(
  108. opts.metrics.Namespace("jaeger-rpc", map[string]string{"component": "jaeger"}),
  109. rpcmetrics.DefaultNameNormalizer,
  110. ),
  111. )(&opts) // adds to c.observers
  112. }
  113. if c.Sampler == nil {
  114. c.Sampler = &SamplerConfig{
  115. Type: jaeger.SamplerTypeRemote,
  116. Param: defaultSamplingProbability,
  117. }
  118. }
  119. if c.Reporter == nil {
  120. c.Reporter = &ReporterConfig{}
  121. }
  122. sampler, err := c.Sampler.NewSampler(serviceName, tracerMetrics)
  123. if err != nil {
  124. return nil, nil, err
  125. }
  126. reporter := opts.reporter
  127. if reporter == nil {
  128. r, err := c.Reporter.NewReporter(serviceName, tracerMetrics, opts.logger)
  129. if err != nil {
  130. return nil, nil, err
  131. }
  132. reporter = r
  133. }
  134. tracerOptions := []jaeger.TracerOption{
  135. jaeger.TracerOptions.Metrics(tracerMetrics),
  136. jaeger.TracerOptions.Logger(opts.logger),
  137. jaeger.TracerOptions.CustomHeaderKeys(c.Headers),
  138. jaeger.TracerOptions.Gen128Bit(opts.gen128Bit),
  139. jaeger.TracerOptions.ZipkinSharedRPCSpan(opts.zipkinSharedRPCSpan),
  140. }
  141. for _, tag := range opts.tags {
  142. tracerOptions = append(tracerOptions, jaeger.TracerOptions.Tag(tag.Key, tag.Value))
  143. }
  144. for _, obs := range opts.observers {
  145. tracerOptions = append(tracerOptions, jaeger.TracerOptions.Observer(obs))
  146. }
  147. for _, cobs := range opts.contribObservers {
  148. tracerOptions = append(tracerOptions, jaeger.TracerOptions.ContribObserver(cobs))
  149. }
  150. if c.BaggageRestrictions != nil {
  151. mgr := remote.NewRestrictionManager(
  152. serviceName,
  153. remote.Options.Metrics(tracerMetrics),
  154. remote.Options.Logger(opts.logger),
  155. remote.Options.HostPort(c.BaggageRestrictions.HostPort),
  156. remote.Options.RefreshInterval(c.BaggageRestrictions.RefreshInterval),
  157. remote.Options.DenyBaggageOnInitializationFailure(
  158. c.BaggageRestrictions.DenyBaggageOnInitializationFailure,
  159. ),
  160. )
  161. tracerOptions = append(tracerOptions, jaeger.TracerOptions.BaggageRestrictionManager(mgr))
  162. }
  163. tracer, closer := jaeger.NewTracer(
  164. serviceName,
  165. sampler,
  166. reporter,
  167. tracerOptions...)
  168. return tracer, closer, nil
  169. }
  170. // InitGlobalTracer creates a new Jaeger Tracer, and sets it as global OpenTracing Tracer.
  171. // It returns a closer func that can be used to flush buffers before shutdown.
  172. func (c Configuration) InitGlobalTracer(
  173. serviceName string,
  174. options ...Option,
  175. ) (io.Closer, error) {
  176. if c.Disabled {
  177. return &nullCloser{}, nil
  178. }
  179. tracer, closer, err := c.New(serviceName, options...)
  180. if err != nil {
  181. return nil, err
  182. }
  183. opentracing.SetGlobalTracer(tracer)
  184. return closer, nil
  185. }
  186. // NewSampler creates a new sampler based on the configuration
  187. func (sc *SamplerConfig) NewSampler(
  188. serviceName string,
  189. metrics *jaeger.Metrics,
  190. ) (jaeger.Sampler, error) {
  191. samplerType := strings.ToLower(sc.Type)
  192. if samplerType == jaeger.SamplerTypeConst {
  193. return jaeger.NewConstSampler(sc.Param != 0), nil
  194. }
  195. if samplerType == jaeger.SamplerTypeProbabilistic {
  196. if sc.Param >= 0 && sc.Param <= 1.0 {
  197. return jaeger.NewProbabilisticSampler(sc.Param)
  198. }
  199. return nil, fmt.Errorf(
  200. "Invalid Param for probabilistic sampler: %v. Expecting value between 0 and 1",
  201. sc.Param,
  202. )
  203. }
  204. if samplerType == jaeger.SamplerTypeRateLimiting {
  205. return jaeger.NewRateLimitingSampler(sc.Param), nil
  206. }
  207. if samplerType == jaeger.SamplerTypeRemote || sc.Type == "" {
  208. sc2 := *sc
  209. sc2.Type = jaeger.SamplerTypeProbabilistic
  210. initSampler, err := sc2.NewSampler(serviceName, nil)
  211. if err != nil {
  212. return nil, err
  213. }
  214. options := []jaeger.SamplerOption{
  215. jaeger.SamplerOptions.Metrics(metrics),
  216. jaeger.SamplerOptions.InitialSampler(initSampler),
  217. jaeger.SamplerOptions.SamplingServerURL(sc.SamplingServerURL),
  218. }
  219. if sc.MaxOperations != 0 {
  220. options = append(options, jaeger.SamplerOptions.MaxOperations(sc.MaxOperations))
  221. }
  222. if sc.SamplingRefreshInterval != 0 {
  223. options = append(options, jaeger.SamplerOptions.SamplingRefreshInterval(sc.SamplingRefreshInterval))
  224. }
  225. return jaeger.NewRemotelyControlledSampler(serviceName, options...), nil
  226. }
  227. return nil, fmt.Errorf("Unknown sampler type %v", sc.Type)
  228. }
  229. // NewReporter instantiates a new reporter that submits spans to tcollector
  230. func (rc *ReporterConfig) NewReporter(
  231. serviceName string,
  232. metrics *jaeger.Metrics,
  233. logger jaeger.Logger,
  234. ) (jaeger.Reporter, error) {
  235. sender, err := rc.newTransport()
  236. if err != nil {
  237. return nil, err
  238. }
  239. reporter := jaeger.NewRemoteReporter(
  240. sender,
  241. jaeger.ReporterOptions.QueueSize(rc.QueueSize),
  242. jaeger.ReporterOptions.BufferFlushInterval(rc.BufferFlushInterval),
  243. jaeger.ReporterOptions.Logger(logger),
  244. jaeger.ReporterOptions.Metrics(metrics))
  245. if rc.LogSpans && logger != nil {
  246. logger.Infof("Initializing logging reporter\n")
  247. reporter = jaeger.NewCompositeReporter(jaeger.NewLoggingReporter(logger), reporter)
  248. }
  249. return reporter, err
  250. }
  251. func (rc *ReporterConfig) newTransport() (jaeger.Transport, error) {
  252. return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0)
  253. }