From 0d1fb196136e1413f97d00c80fc1e8a9fbd389b0 Mon Sep 17 00:00:00 2001 From: Barnabas Busa Date: Tue, 3 Mar 2026 12:53:53 +0100 Subject: [PATCH] internal/telemetry: add gRPC transport for OTLP trace export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OTLP specification defines two transports: HTTP (port 4318) and gRPC (port 4317). The existing exporter setup only supports HTTP/HTTPS schemes. This adds gRPC support via URL scheme dispatch: - grpc://host:port → plaintext gRPC - grpcs://host:port → TLS-secured gRPC Many observability backends (Jaeger, Tempo, Datadog) prefer gRPC for its lower overhead. Both otlptracehttp and otlptracegrpc return the same *otlptrace.Exporter type, so only the exporter construction changes. Co-Authored-By: Claude Opus 4.6 --- cmd/utils/flags.go | 6 +++--- go.mod | 1 + go.sum | 2 ++ internal/telemetry/tracesetup/setup.go | 14 ++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 792e0e55ab..81b9f8e1ca 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1063,19 +1063,19 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. RPCTelemetryEndpointFlag = &cli.StringFlag{ Name: "rpc.telemetry.endpoint", - Usage: "Defines where RPC telemetry is sent (e.g., http://localhost:4318)", + Usage: "Defines where RPC telemetry is sent (e.g., http://localhost:4318 or grpc://localhost:4317)", Category: flags.APICategory, } RPCTelemetryUserFlag = &cli.StringFlag{ Name: "rpc.telemetry.username", - Usage: "HTTP Basic Auth username for OpenTelemetry", + Usage: "Basic Auth username for OpenTelemetry", Category: flags.APICategory, } RPCTelemetryPasswordFlag = &cli.StringFlag{ Name: "rpc.telemetry.password", - Usage: "HTTP Basic Auth password for OpenTelemetry", + Usage: "Basic Auth password for OpenTelemetry", Category: flags.APICategory, } diff --git a/go.mod b/go.mod index bfe2df8c0c..6264d10635 100644 --- a/go.mod +++ b/go.mod @@ -63,6 +63,7 @@ require ( github.com/urfave/cli/v2 v2.27.5 go.opentelemetry.io/otel v1.40.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 go.opentelemetry.io/otel/sdk v1.40.0 go.opentelemetry.io/otel/trace v1.40.0 diff --git a/go.sum b/go.sum index b8c0558c8c..085572b8ec 100644 --- a/go.sum +++ b/go.sum @@ -384,6 +384,8 @@ go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= diff --git a/internal/telemetry/tracesetup/setup.go b/internal/telemetry/tracesetup/setup.go index 444416dd26..384917a06d 100644 --- a/internal/telemetry/tracesetup/setup.go +++ b/internal/telemetry/tracesetup/setup.go @@ -30,6 +30,7 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" @@ -101,6 +102,19 @@ func SetupTelemetry(cfg node.OpenTelemetryConfig, stack *node.Node) error { })) } exporter = otlptracehttp.NewUnstarted(opts...) + case "grpc", "grpcs": + opts := []otlptracegrpc.Option{ + otlptracegrpc.WithEndpoint(u.Host), + } + if u.Scheme == "grpc" { + opts = append(opts, otlptracegrpc.WithInsecure()) + } + if cfg.AuthUser != "" { + opts = append(opts, otlptracegrpc.WithHeaders(map[string]string{ + "Authorization": "Basic " + base64.StdEncoding.EncodeToString([]byte(cfg.AuthUser+":"+cfg.AuthPassword)), + })) + } + exporter = otlptracegrpc.NewUnstarted(opts...) default: return fmt.Errorf("unsupported telemetry url scheme: %s", u.Scheme) }