fix(api): add tracing interceptor on connectRPC services (#11147)

# Which Problems Are Solved

ConnectRPC based services (v2 API) was missing the root span of all
requests. Rest calls through grpc-gateway more or less worked properly.
This was due to a missing server interceptor for connectRPC services
itself. Rest call would work as the trace would start on the gateway
already.

# How the Problems Are Solved

Initiate an connectRPC OTEL interceptor and pass it to all services.

# Additional Changes

None

# Additional Context

- noticed internally
- requires backport to v4.x

(cherry picked from commit 5f3f53dca1)
This commit is contained in:
Livio Spring
2025-12-09 11:23:10 +01:00
parent 38c7ce7e52
commit 4aa25347c3
3 changed files with 10 additions and 0 deletions

1
go.mod
View File

@@ -9,6 +9,7 @@ require (
cloud.google.com/go/storage v1.57.1 cloud.google.com/go/storage v1.57.1
connectrpc.com/connect v1.19.1 connectrpc.com/connect v1.19.1
connectrpc.com/grpcreflect v1.3.0 connectrpc.com/grpcreflect v1.3.0
connectrpc.com/otelconnect v0.8.0
dario.cat/mergo v1.0.2 dario.cat/mergo v1.0.2
github.com/BurntSushi/toml v1.5.0 github.com/BurntSushi/toml v1.5.0
github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/DATA-DOG/go-sqlmock v1.5.2

2
go.sum
View File

@@ -28,6 +28,8 @@ connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=
connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc= connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc=
connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs=
connectrpc.com/otelconnect v0.8.0 h1:a4qrN4H8aEE2jAoCxheZYYfEjXMgVPyL9OzPQLBEFXU=
connectrpc.com/otelconnect v0.8.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=

View File

@@ -8,6 +8,7 @@ import (
"strings" "strings"
"connectrpc.com/grpcreflect" "connectrpc.com/grpcreflect"
"connectrpc.com/otelconnect"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/improbable-eng/grpc-web/go/grpcweb"
"github.com/zitadel/logging" "github.com/zitadel/logging"
@@ -54,6 +55,7 @@ type API struct {
targetEncryptionAlgorithm crypto.EncryptionAlgorithm targetEncryptionAlgorithm crypto.EncryptionAlgorithm
translator *i18n.Translator translator *i18n.Translator
connectOTELInterceptor *otelconnect.Interceptor
} }
func (a *API) ListGrpcServices() []string { func (a *API) ListGrpcServices() []string {
@@ -129,6 +131,10 @@ func New(
if err != nil { if err != nil {
return nil, err return nil, err
} }
api.connectOTELInterceptor, err = otelconnect.NewInterceptor()
if err != nil {
return nil, err
}
api.registerHealthServer() api.registerHealthServer()
api.RegisterHandlerOnPrefix("/debug", api.healthHandler()) api.RegisterHandlerOnPrefix("/debug", api.healthHandler())
@@ -191,6 +197,7 @@ func (a *API) RegisterService(ctx context.Context, srv server.Server) error {
func (a *API) registerConnectServer(service server.ConnectServer) { func (a *API) registerConnectServer(service server.ConnectServer) {
prefix, handler := service.RegisterConnectServer( prefix, handler := service.RegisterConnectServer(
connect_middleware.CallDurationHandler(), connect_middleware.CallDurationHandler(),
a.connectOTELInterceptor,
connect_middleware.MetricsHandler(metricTypes, grpc_api.Probes...), connect_middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
connect_middleware.NoCacheInterceptor(), connect_middleware.NoCacheInterceptor(),
connect_middleware.InstanceInterceptor(a.queries, a.externalDomain, a.translator, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName, instance_pb.InstanceService_ServiceDesc.ServiceName), connect_middleware.InstanceInterceptor(a.queries, a.externalDomain, a.translator, system_pb.SystemService_ServiceDesc.ServiceName, healthpb.Health_ServiceDesc.ServiceName, instance_pb.InstanceService_ServiceDesc.ServiceName),