...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package otlpconfig
19
20 import (
21 "crypto/tls"
22 "fmt"
23 "path"
24 "strings"
25 "time"
26
27 "google.golang.org/grpc"
28 "google.golang.org/grpc/backoff"
29 "google.golang.org/grpc/credentials"
30 "google.golang.org/grpc/credentials/insecure"
31 "google.golang.org/grpc/encoding/gzip"
32
33 "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
34 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry"
35 )
36
37 const (
38
39
40 DefaultTracesPath string = "/v1/traces"
41
42
43 DefaultTimeout time.Duration = 10 * time.Second
44 )
45
46 type (
47 SignalConfig struct {
48 Endpoint string
49 Insecure bool
50 TLSCfg *tls.Config
51 Headers map[string]string
52 Compression Compression
53 Timeout time.Duration
54 URLPath string
55
56
57 GRPCCredentials credentials.TransportCredentials
58 }
59
60 Config struct {
61
62 Traces SignalConfig
63
64 RetryConfig retry.Config
65
66
67 ReconnectionPeriod time.Duration
68 ServiceConfig string
69 DialOptions []grpc.DialOption
70 GRPCConn *grpc.ClientConn
71 }
72 )
73
74
75
76 func NewHTTPConfig(opts ...HTTPOption) Config {
77 cfg := Config{
78 Traces: SignalConfig{
79 Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorHTTPPort),
80 URLPath: DefaultTracesPath,
81 Compression: NoCompression,
82 Timeout: DefaultTimeout,
83 },
84 RetryConfig: retry.DefaultConfig,
85 }
86 cfg = ApplyHTTPEnvConfigs(cfg)
87 for _, opt := range opts {
88 cfg = opt.ApplyHTTPOption(cfg)
89 }
90 cfg.Traces.URLPath = cleanPath(cfg.Traces.URLPath, DefaultTracesPath)
91 return cfg
92 }
93
94
95
96
97 func cleanPath(urlPath string, defaultPath string) string {
98 tmp := path.Clean(strings.TrimSpace(urlPath))
99 if tmp == "." {
100 return defaultPath
101 }
102 if !path.IsAbs(tmp) {
103 tmp = fmt.Sprintf("/%s", tmp)
104 }
105 return tmp
106 }
107
108
109
110 func NewGRPCConfig(opts ...GRPCOption) Config {
111 userAgent := "OTel OTLP Exporter Go/" + otlptrace.Version()
112 cfg := Config{
113 Traces: SignalConfig{
114 Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
115 URLPath: DefaultTracesPath,
116 Compression: NoCompression,
117 Timeout: DefaultTimeout,
118 },
119 RetryConfig: retry.DefaultConfig,
120 DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)},
121 }
122 cfg = ApplyGRPCEnvConfigs(cfg)
123 for _, opt := range opts {
124 cfg = opt.ApplyGRPCOption(cfg)
125 }
126
127 if cfg.ServiceConfig != "" {
128 cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig))
129 }
130
131 if cfg.Traces.GRPCCredentials != nil {
132 cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials))
133 } else if cfg.Traces.Insecure {
134 cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
135 } else {
136
137 creds := credentials.NewTLS(nil)
138 cfg.Traces.GRPCCredentials = creds
139 cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(creds))
140 }
141 if cfg.Traces.Compression == GzipCompression {
142 cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
143 }
144 if cfg.ReconnectionPeriod != 0 {
145 p := grpc.ConnectParams{
146 Backoff: backoff.DefaultConfig,
147 MinConnectTimeout: cfg.ReconnectionPeriod,
148 }
149 cfg.DialOptions = append(cfg.DialOptions, grpc.WithConnectParams(p))
150 }
151
152 return cfg
153 }
154
155 type (
156
157 GenericOption interface {
158 ApplyHTTPOption(Config) Config
159 ApplyGRPCOption(Config) Config
160
161
162
163
164 private()
165 }
166
167
168 HTTPOption interface {
169 ApplyHTTPOption(Config) Config
170
171
172
173
174 private()
175 }
176
177
178 GRPCOption interface {
179 ApplyGRPCOption(Config) Config
180
181
182
183
184 private()
185 }
186 )
187
188
189
190 type genericOption struct {
191 fn func(Config) Config
192 }
193
194 func (g *genericOption) ApplyGRPCOption(cfg Config) Config {
195 return g.fn(cfg)
196 }
197
198 func (g *genericOption) ApplyHTTPOption(cfg Config) Config {
199 return g.fn(cfg)
200 }
201
202 func (genericOption) private() {}
203
204 func newGenericOption(fn func(cfg Config) Config) GenericOption {
205 return &genericOption{fn: fn}
206 }
207
208
209
210 type splitOption struct {
211 httpFn func(Config) Config
212 grpcFn func(Config) Config
213 }
214
215 func (g *splitOption) ApplyGRPCOption(cfg Config) Config {
216 return g.grpcFn(cfg)
217 }
218
219 func (g *splitOption) ApplyHTTPOption(cfg Config) Config {
220 return g.httpFn(cfg)
221 }
222
223 func (splitOption) private() {}
224
225 func newSplitOption(httpFn func(cfg Config) Config, grpcFn func(cfg Config) Config) GenericOption {
226 return &splitOption{httpFn: httpFn, grpcFn: grpcFn}
227 }
228
229
230 type httpOption struct {
231 fn func(Config) Config
232 }
233
234 func (h *httpOption) ApplyHTTPOption(cfg Config) Config {
235 return h.fn(cfg)
236 }
237
238 func (httpOption) private() {}
239
240 func NewHTTPOption(fn func(cfg Config) Config) HTTPOption {
241 return &httpOption{fn: fn}
242 }
243
244
245 type grpcOption struct {
246 fn func(Config) Config
247 }
248
249 func (h *grpcOption) ApplyGRPCOption(cfg Config) Config {
250 return h.fn(cfg)
251 }
252
253 func (grpcOption) private() {}
254
255 func NewGRPCOption(fn func(cfg Config) Config) GRPCOption {
256 return &grpcOption{fn: fn}
257 }
258
259
260
261 func WithEndpoint(endpoint string) GenericOption {
262 return newGenericOption(func(cfg Config) Config {
263 cfg.Traces.Endpoint = endpoint
264 return cfg
265 })
266 }
267
268 func WithCompression(compression Compression) GenericOption {
269 return newGenericOption(func(cfg Config) Config {
270 cfg.Traces.Compression = compression
271 return cfg
272 })
273 }
274
275 func WithURLPath(urlPath string) GenericOption {
276 return newGenericOption(func(cfg Config) Config {
277 cfg.Traces.URLPath = urlPath
278 return cfg
279 })
280 }
281
282 func WithRetry(rc retry.Config) GenericOption {
283 return newGenericOption(func(cfg Config) Config {
284 cfg.RetryConfig = rc
285 return cfg
286 })
287 }
288
289 func WithTLSClientConfig(tlsCfg *tls.Config) GenericOption {
290 return newSplitOption(func(cfg Config) Config {
291 cfg.Traces.TLSCfg = tlsCfg.Clone()
292 return cfg
293 }, func(cfg Config) Config {
294 cfg.Traces.GRPCCredentials = credentials.NewTLS(tlsCfg)
295 return cfg
296 })
297 }
298
299 func WithInsecure() GenericOption {
300 return newGenericOption(func(cfg Config) Config {
301 cfg.Traces.Insecure = true
302 return cfg
303 })
304 }
305
306 func WithSecure() GenericOption {
307 return newGenericOption(func(cfg Config) Config {
308 cfg.Traces.Insecure = false
309 return cfg
310 })
311 }
312
313 func WithHeaders(headers map[string]string) GenericOption {
314 return newGenericOption(func(cfg Config) Config {
315 cfg.Traces.Headers = headers
316 return cfg
317 })
318 }
319
320 func WithTimeout(duration time.Duration) GenericOption {
321 return newGenericOption(func(cfg Config) Config {
322 cfg.Traces.Timeout = duration
323 return cfg
324 })
325 }
326
View as plain text