5
5
"crypto/tls"
6
6
"crypto/x509"
7
7
"fmt"
8
- "go.uber.org/zap"
9
8
"log"
10
9
"maps"
11
10
"net/http"
@@ -41,7 +40,10 @@ import (
41
40
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
42
41
"go.opentelemetry.io/otel/trace"
43
42
"go.opentelemetry.io/otel/trace/noop"
43
+ "go.uber.org/zap"
44
+ "google.golang.org/grpc"
44
45
"google.golang.org/grpc/credentials"
46
+ "google.golang.org/grpc/credentials/insecure"
45
47
"google.golang.org/grpc/resolver"
46
48
)
47
49
63
65
type ServiceOption func (* ServiceOptions )
64
66
65
67
type ServiceOptions struct {
66
- headers map [string ]string
68
+ headers map [string ]string
69
+ grpcConn * grpc.ClientConn
67
70
}
68
71
69
72
func WithHeaders (headers map [string ]string ) ServiceOption {
@@ -75,6 +78,49 @@ func WithHeaders(headers map[string]string) ServiceOption {
75
78
}
76
79
}
77
80
81
+ // Please ref https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc#WithGRPCConn
82
+ // To create the grpc connection with same logic as goagent please use CreateGrpcConn
83
+ func WithGrpcConn (conn * grpc.ClientConn ) ServiceOption {
84
+ return func (opts * ServiceOptions ) {
85
+ opts .grpcConn = conn
86
+ }
87
+ }
88
+
89
+ // Can be used for external clients to reference the underlying connection for otlp grpc exporter
90
+ func CreateGrpcConn (cfg * config.AgentConfig ) (* grpc.ClientConn , error ) {
91
+ endpoint := removeProtocolPrefixForOTLP (cfg .GetReporting ().GetEndpoint ().GetValue ())
92
+
93
+ dialOpts := []grpc.DialOption {}
94
+
95
+ if ! cfg .GetReporting ().GetSecure ().GetValue () {
96
+ dialOpts = append (dialOpts , grpc .WithTransportCredentials (insecure .NewCredentials ()))
97
+ } else {
98
+ certFile := cfg .GetReporting ().GetCertFile ().GetValue ()
99
+ if len (certFile ) > 0 {
100
+ tlsCredentials , err := credentials .NewClientTLSFromFile (certFile , "" )
101
+ if err != nil {
102
+ return nil , fmt .Errorf ("error creating TLS credentials from cert path %s: %v" , certFile , err )
103
+ }
104
+ dialOpts = append (dialOpts , grpc .WithTransportCredentials (tlsCredentials ))
105
+ } else {
106
+ // Default to system certs
107
+ dialOpts = append (dialOpts , grpc .WithTransportCredentials (credentials .NewTLS (& tls.Config {})))
108
+ }
109
+ }
110
+
111
+ if cfg .Reporting .GetEnableGrpcLoadbalancing ().GetValue () {
112
+ resolver .SetDefaultScheme ("dns" )
113
+ dialOpts = append (dialOpts , grpc .WithDefaultServiceConfig (`{"loadBalancingConfig": [ { "round_robin": {} } ]}` ))
114
+ }
115
+
116
+ conn , err := grpc .NewClient (endpoint , dialOpts ... )
117
+ if err != nil {
118
+ return nil , fmt .Errorf ("failed to create gRPC connection to %s: %v" , endpoint , err )
119
+ }
120
+
121
+ return conn , nil
122
+ }
123
+
78
124
func makePropagator (formats []config.PropagationFormat ) propagation.TextMapPropagator {
79
125
var propagators []propagation.TextMapPropagator
80
126
for _ , format := range formats {
@@ -177,6 +223,7 @@ func makeExporterFactory(cfg *config.AgentConfig) func(serviceOpts ...ServiceOpt
177
223
zipkin .WithHeaders (serviceOpts .headers ),
178
224
)
179
225
}
226
+
180
227
case config .TraceReporterType_LOGGING :
181
228
return func (opts ... ServiceOption ) (sdktrace.SpanExporter , error ) {
182
229
// TODO: Define if endpoint could be a filepath to write into a file.
@@ -211,7 +258,7 @@ func makeExporterFactory(cfg *config.AgentConfig) func(serviceOpts ...ServiceOpt
211
258
return otlphttp .New (context .Background (), finalOpts ... )
212
259
}
213
260
214
- default :
261
+ default : // OTLP GRPC
215
262
standardOpts := []otlpgrpc.Option {
216
263
otlpgrpc .WithEndpoint (removeProtocolPrefixForOTLP (cfg .GetReporting ().GetEndpoint ().GetValue ())),
217
264
}
@@ -246,6 +293,11 @@ func makeExporterFactory(cfg *config.AgentConfig) func(serviceOpts ...ServiceOpt
246
293
finalOpts := append ([]otlpgrpc.Option {}, standardOpts ... )
247
294
finalOpts = append (finalOpts , otlpgrpc .WithHeaders (serviceOpts .headers ))
248
295
296
+ // Important: gRPC connection takes precedence over other connection based options
297
+ if serviceOpts .grpcConn != nil {
298
+ finalOpts = append (finalOpts , otlpgrpc .WithGRPCConn (serviceOpts .grpcConn ))
299
+ }
300
+
249
301
return otlptrace .New (
250
302
context .Background (),
251
303
otlpgrpc .NewClient (finalOpts ... ),
@@ -293,20 +345,20 @@ func createCaCertPoolFromFile(certFile string) *x509.CertPool {
293
345
294
346
// Init initializes opentelemetry tracing and returns a shutdown function to flush data immediately
295
347
// on a termination signal.
296
- func Init (cfg * config.AgentConfig ) func () {
297
- return InitWithSpanProcessorWrapper (cfg , nil , versionInfoAttributes )
348
+ func Init (cfg * config.AgentConfig , opts ... ServiceOption ) func () {
349
+ return InitWithSpanProcessorWrapper (cfg , nil , versionInfoAttributes , opts ... )
298
350
}
299
351
300
352
// InitWithSpanProcessorWrapper initializes opentelemetry tracing with a wrapper over span processor
301
353
// and returns a shutdown function to flush data immediately on a termination signal.
302
354
func InitWithSpanProcessorWrapper (cfg * config.AgentConfig , wrapper SpanProcessorWrapper ,
303
- versionInfoAttrs []attribute.KeyValue ) func () {
355
+ versionInfoAttrs []attribute.KeyValue , opts ... ServiceOption ) func () {
304
356
logger , err := zap .NewProduction ()
305
357
if err != nil {
306
358
logger = nil
307
359
log .Printf ("error while creating default zap logger %v" , err )
308
360
}
309
- return InitWithSpanProcessorWrapperAndZap (cfg , wrapper , versionInfoAttrs , logger )
361
+ return InitWithSpanProcessorWrapperAndZap (cfg , wrapper , versionInfoAttrs , logger , opts ... )
310
362
}
311
363
312
364
// InitWithSpanProcessorWrapperAndZap initializes opentelemetry tracing with a wrapper over span processor
@@ -349,11 +401,11 @@ func InitWithSpanProcessorWrapperAndZap(cfg *config.AgentConfig, wrapper SpanPro
349
401
350
402
// Initialize metrics
351
403
metricsShutdownFn := initializeMetrics (cfg , versionInfoAttrs , opts ... )
352
-
353
404
exporterFactory = makeExporterFactory (cfg )
354
405
configFactory = makeConfigFactory (cfg )
355
406
356
- exporter , err := exporterFactory ()
407
+ exporter , err := exporterFactory (opts ... )
408
+
357
409
if err != nil {
358
410
log .Fatal (err )
359
411
}
@@ -374,8 +426,8 @@ func InitWithSpanProcessorWrapperAndZap(cfg *config.AgentConfig, wrapper SpanPro
374
426
if err != nil {
375
427
log .Fatal (err )
376
428
}
377
-
378
429
sampler := sdktrace .AlwaysSample ()
430
+
379
431
tp := sdktrace .NewTracerProvider (
380
432
sdktrace .WithSampler (sampler ),
381
433
sdktrace .WithSpanProcessor (sp ),
0 commit comments