config.go 10 KB

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