open-telemetry / open-telemetry/opentelemetry-java-instrumentation

gRPC server instrumentation: no spans created for unknown service

Open
#15,690 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
2.6k
Forks
1.2k
Avg merge
2d 18h
Merged PRs (30d)
228

Description

Let's say I made a configuration mistake: my gRPC client calls serivce-a, but it's not registered on the gRPC server I called.

Expected: grpc instrumentation records a client and server spans, both have error code set to UNIMPLEMENTED.
Actual: only client span is recorded, server span is not recorded at all

It happens because interceptors are not called if service is not found.
Interestingly enough native gRPC instrumentation does trace the span. It uses ServerStreamTracer.Factory mechanism instead of interceptors.

It may be configured similarly to interceptors

server = ServerBuilder.forPort(port)
        .intercept(new ServerInterceptor() {
            @Override
            public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
                // this is what we use today and it's not called with unknown services
                return next.startCall(call, headers);
            }
        })
        .addService(new GreeterImpl())
        .addStreamTracerFactory(new ServerStreamTracer.Factory() {

            @Override
            public ServerStreamTracer newServerStreamTracer(String fullMethodName, Metadata headers) {
                return new ServerStreamTracer() {
                      // this one is used by native grpc instrumentation and is called
                      ...
                };
            }
        })
        .build();

Note: tracing unknown methods leads to potential unbound cardinality around service and methods name.
See https://github.com/open-telemetry/semantic-conventions/issues/3196#issuecomment-3634616347 for the details.

The proposed (in https://github.com/open-telemetry/semantic-conventions/pull/3223) solutions would be to:

  • use ServerStreamTracer to start span, delay setting rpc.service | method attribute(s), initial span name would be _OTHER
  • use server interceptor as well - when interceptor is called, it means method is available on the server update span name to actual method name
  • populate rpc.method | service attribute(s) when span ends
  • support config option to set 'known methods'.
    • if it's not provided, use above logic, method name then is not available for sampling
    • If it's provided, span name and method name would be populated at start time according to the config and available for sampling. No need for logic in the interceptor.
    • this config option also helps with edge case when server accepts arbitrary methods.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by examining the gRPC server instrumentation's current ServerInterceptor path and compare it with the native OpenTelemetryTracingModule and ServerStreamTracer.Factory mechanism described in the issue. Reproduce a call to an unregistered service and verify the current client-only span behavior. Done means unknown-service calls produce the expected client and server spans with UNIMPLEMENTED while addressing the stated cardinality concerns.

Written by the indexing model from the issue text.

Assessment

Tech stack
grpc, java
Domain
observability
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.