1// Copyright (c) The Thanos Authors. 2// Licensed under the Apache License 2.0. 3 4package jaeger 5 6import ( 7 "fmt" 8 "net/url" 9 "os" 10 "strings" 11 "time" 12 13 "github.com/opentracing/opentracing-go" 14 "github.com/pkg/errors" 15 "github.com/uber/jaeger-client-go" 16 "github.com/uber/jaeger-client-go/config" 17 "gopkg.in/yaml.v2" 18) 19 20// Config - YAML configuration. For details see to https://github.com/jaegertracing/jaeger-client-go#environment-variables. 21type Config struct { 22 ServiceName string `yaml:"service_name"` 23 Disabled bool `yaml:"disabled"` 24 RPCMetrics bool `yaml:"rpc_metrics"` 25 Tags string `yaml:"tags"` 26 SamplerType string `yaml:"sampler_type"` 27 SamplerParam float64 `yaml:"sampler_param"` 28 SamplerManagerHostPort string `yaml:"sampler_manager_host_port"` 29 SamplerMaxOperations int `yaml:"sampler_max_operations"` 30 SamplerRefreshInterval time.Duration `yaml:"sampler_refresh_interval"` 31 ReporterMaxQueueSize int `yaml:"reporter_max_queue_size"` 32 ReporterFlushInterval time.Duration `yaml:"reporter_flush_interval"` 33 ReporterLogSpans bool `yaml:"reporter_log_spans"` 34 Endpoint string `yaml:"endpoint"` 35 User string `yaml:"user"` 36 Password string `yaml:"password"` 37 AgentHost string `yaml:"agent_host"` 38 AgentPort int `yaml:"agent_port"` 39} 40 41// ParseConfigFromYaml uses config YAML to set the tracer's Configuration. 42func ParseConfigFromYaml(cfg []byte) (*config.Configuration, error) { 43 conf := &Config{} 44 45 if err := yaml.Unmarshal(cfg, &conf); err != nil { 46 return nil, err 47 } 48 49 c := &config.Configuration{} 50 51 if conf.ServiceName != "" { 52 c.ServiceName = conf.ServiceName 53 } 54 55 if conf.RPCMetrics { 56 c.RPCMetrics = conf.RPCMetrics 57 } 58 59 if conf.Disabled { 60 c.Disabled = conf.Disabled 61 } 62 63 if conf.Tags != "" { 64 c.Tags = parseTags(conf.Tags) 65 } 66 67 if s, err := samplerConfigFromConfig(*conf); err == nil { 68 c.Sampler = s 69 } else { 70 return nil, errors.Wrap(err, "cannot obtain sampler config from YAML") 71 } 72 73 if r, err := reporterConfigFromConfig(*conf); err == nil { 74 c.Reporter = r 75 } else { 76 return nil, errors.Wrap(err, "cannot obtain reporter config from YAML") 77 } 78 79 return c, nil 80} 81 82// samplerConfigFromConfig creates a new SamplerConfig based on the YAML Config. 83func samplerConfigFromConfig(cfg Config) (*config.SamplerConfig, error) { 84 sc := &config.SamplerConfig{} 85 86 if cfg.SamplerType != "" { 87 sc.Type = cfg.SamplerType 88 } 89 90 if cfg.SamplerParam != 0 { 91 sc.Param = cfg.SamplerParam 92 } 93 94 if cfg.SamplerManagerHostPort != "" { 95 sc.SamplingServerURL = cfg.SamplerManagerHostPort 96 } 97 98 if cfg.SamplerMaxOperations != 0 { 99 sc.MaxOperations = cfg.SamplerMaxOperations 100 } 101 102 if cfg.SamplerRefreshInterval != 0 { 103 sc.SamplingRefreshInterval = cfg.SamplerRefreshInterval 104 } 105 106 return sc, nil 107} 108 109// reporterConfigFromConfig creates a new ReporterConfig based on the YAML Config. 110func reporterConfigFromConfig(cfg Config) (*config.ReporterConfig, error) { 111 rc := &config.ReporterConfig{} 112 113 if cfg.ReporterMaxQueueSize != 0 { 114 rc.QueueSize = cfg.ReporterMaxQueueSize 115 } 116 117 if cfg.ReporterFlushInterval != 0 { 118 rc.BufferFlushInterval = cfg.ReporterFlushInterval 119 } 120 121 if cfg.ReporterLogSpans { 122 rc.LogSpans = cfg.ReporterLogSpans 123 } 124 125 if cfg.Endpoint != "" { 126 u, err := url.ParseRequestURI(cfg.Endpoint) 127 if err != nil { 128 return nil, errors.Wrapf(err, "cannot parse endpoint=%s", cfg.Endpoint) 129 } 130 rc.CollectorEndpoint = u.String() 131 user := cfg.User 132 pswd := cfg.Password 133 if user != "" && pswd == "" || user == "" && pswd != "" { 134 return nil, errors.Errorf("you must set %s and %s parameters together", cfg.User, cfg.Password) 135 } 136 rc.User = user 137 rc.Password = pswd 138 } else { 139 host := jaeger.DefaultUDPSpanServerHost 140 if cfg.AgentHost != "" { 141 host = cfg.AgentHost 142 } 143 144 port := jaeger.DefaultUDPSpanServerPort 145 if cfg.AgentPort != 0 { 146 port = cfg.AgentPort 147 } 148 rc.LocalAgentHostPort = fmt.Sprintf("%s:%d", host, port) 149 } 150 151 return rc, nil 152} 153 154// parseTags parses the given string into a collection of Tags. 155// Spec for this value: 156// - comma separated list of key=value 157// - value can be specified using the notation ${envVar:defaultValue}, where `envVar` 158// is an environment variable and `defaultValue` is the value to use in case the env var is not set. 159func parseTags(sTags string) []opentracing.Tag { 160 pairs := strings.Split(sTags, ",") 161 tags := make([]opentracing.Tag, 0) 162 for _, p := range pairs { 163 kv := strings.SplitN(p, "=", 2) 164 k, v := strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]) 165 166 if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") { 167 ed := strings.SplitN(v[2:len(v)-1], ":", 2) 168 e, d := ed[0], ed[1] 169 v = os.Getenv(e) 170 if v == "" && d != "" { 171 v = d 172 } 173 } 174 175 tag := opentracing.Tag{Key: k, Value: v} 176 tags = append(tags, tag) 177 } 178 179 return tags 180} 181