Skip to content

Support automatic baggage propagation from gRPC metadata #368

@o-shevchenko

Description

@o-shevchenko

Description

Spring Boot's management.tracing.baggage.remote-fields configuration automatically propagates baggage from HTTP headers to OpenTelemetry spans. However, this functionality does not work for gRPC metadata headers, requiring manual implementation via a ServerInterceptor.

Expected Behavior

When configuring baggage propagation in application.yml:

management:
  tracing:
    baggage:
      enabled: true
      remote-fields: x-request-id, x-user-id, x-tenant-id
      tag-fields: x-request-id, x-user-id, x-tenant-id

The specified fields from gRPC metadata should be automatically extracted and added as span tags/baggage, similar to how it works for HTTP headers in Spring Boot applications.

Current Behavior

The baggage configuration only works for HTTP requests. When sending gRPC requests with metadata headers:

grpcurl -plaintext -v \
  -H 'x-request-id: trace-check-success-002' \
  -H 'x-tenant-id: test-tenant-dev-001' \
  -d '{"name": "test"}' \
  localhost:9090 \
  MyService/MyMethod

The headers (x-request-id, x-tenant-id) do not appear in OpenTelemetry span tags.

Current Workaround

A manual ServerInterceptor is required to extract metadata and add it to spans:

@GlobalServerInterceptor
class GrpcHeaderInterceptor(
    private val tracer: Tracer,
    private val tracingProperties: TracingProperties
) : ServerInterceptor {

    override fun <ReqT, RespT> interceptCall(
        call: ServerCall<ReqT, RespT>,
        headers: Metadata,
        next: ServerCallHandler<ReqT, RespT>
    ): ServerCall.Listener<ReqT> {
        val currentSpan = tracer.currentSpan()
        val remoteFields = tracingProperties.baggage.remoteFields
        val tagFields = tracingProperties.baggage.tagFields

        remoteFields.forEach { headerName ->
            val key = Metadata.Key.of(headerName, Metadata.ASCII_STRING_MARSHALLER)
            headers.get(key)?.let { value ->
                tracer.createBaggageInScope(headerName, value)

                if (tagFields.contains(headerName)) {
                    currentSpan?.tag(headerName, value)
                }
            }
        }

        return next.startCall(call, headers)
    }
}

Suggested Enhancement

Spring gRPC should provide automatic baggage propagation from gRPC metadata, similar to the existing HTTP header propagation in Spring Boot. This could be:

  1. Automatically enabled when management.tracing.baggage.remote-fields is configured
  2. Integrated with Spring Boot's baggage configuration to avoid duplication
  3. Support both baggage propagation and span tagging as configured

Environment

  • Spring Boot: 4.0.2
  • Spring gRPC: 1.0.2
  • OpenTelemetry: (via spring-boot-starter-opentelemetry)

Benefits

  • Consistent behavior between HTTP and gRPC for observability
  • Reduced boilerplate code for gRPC services
  • Better out-of-the-box tracing experience for gRPC applications
  • Alignment with Spring Boot's observability conventions

Thank you for considering this enhancement!

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions