Giter Site home page Giter Site logo

java-grpc's Introduction

Build Status Coverage Status Released Version Apache-2.0 license

OpenTracing gRPC Instrumentation

OpenTracing instrumentation for gRPC.

Installation

pom.xml

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-grpc</artifactId>
    <version>VERSION</version>
</dependency>

Usage

Server

  • Instantiate tracer
  • Optionally register tracer with GlobalTracer: GlobalTracer.register(tracer)
  • Create a TracingServerInterceptor
  • Intercept a service
import io.opentracing.Tracer;

    public class YourServer {

        private int port;
        private Server server;
        private final Tracer tracer;

        private void start() throws IOException {
            TracingServerInterceptor tracingInterceptor = TracingServerInterceptor
                .newBuilder()
                .withTracer(this.tracer)
                .build();
            
            // If GlobalTracer is used: 
            TracingServerInterceptor

            server = ServerBuilder.forPort(port)
                .addService(tracingInterceptor.intercept(someServiceDef))
                .build()
                .start();
        }
    }

Client

  • Instantiate a tracer
  • Optionally register tracer with GlobalTracer: GlobalTracer.register(tracer)
  • Create a TracingClientInterceptor
  • Intercept the client channel
import io.opentracing.Tracer;import io.opentracing.contrib.grpc.TracingClientInterceptor;

    public class YourClient {

        private final ManagedChannel channel;
        private final GreeterGrpc.GreeterBlockingStub blockingStub;
        private final Tracer tracer;

        public YourClient(String host, int port) {

            channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext(true)
                .build();

            TracingClientInterceptor tracingInterceptor = TracingClientInterceptor
                .newBuilder()
                .withTracer(this.tracer)
                .build();
            
            // If GlobalTracer is used: 
            TracingClientInterceptor

            blockingStub = GreeterGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
        }
    }

Server Tracing

A TracingServerInterceptor uses default settings, which you can override by creating it using a TracingServerInterceptor.Builder.

  • withOperationName(OperationNameConstructor constructor): Define how the operation name is constructed for all spans created for the intercepted service. Default sets the operation name as the name of the RPC method. More details in the Operation Name section.
  • withStreaming(): Logs to the server span whenever a message is received. Note: This package supports streaming but has not been rigorously tested. If you come across any issues, please let us know.
  • withVerbosity(): Logs to the server span additional events, such as message received, half close (client finished sending messages), and call complete. Default only logs if a call is cancelled.
  • withTracedAttributes(ServerRequestAttribute... attrs): Sets tags on the server span in case you want to track information about the RPC call. See ServerRequestAttribute.java for a list of traceable request attributes.

Example

    TracingServerInterceptor tracingInterceptor = TracingServerInterceptor
        .newBuilder()
        .withTracer(tracer)
        .withStreaming()
        .withVerbosity()
        .withOperationName(new OperationNameConstructor() {
            @Override
            public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
                // construct some operation name from the method descriptor
            }
        })
        .withTracedAttributes(ServerRequestAttribute.HEADERS,
            ServerRequestAttribute.METHOD_TYPE)
        .build();

Client Tracing

A TracingClientInterceptor also has default settings, which you can override by creating it using a TracingClientInterceptor.Builder.

  • withOperationName(String operationName): Define how the operation name is constructed for all spans created for this intercepted client. Default is the name of the RPC method. More details in the Operation Name section.
  • withActiveSpanSource(ActiveSpanSource activeSpanSource): Define how to extract the current active span, if any. More details in the Active Span Sources section.
  • withActiveSpanContextSource(ActiveSpanContextSource activeSpanContextSource): Define how to extract the current active span context, if any. More details in the Active Span Context Sources section.
  • withStreaming(): Logs to the client span whenever a message is sent or a response is received. Note: This package supports streaming but has not been rigorously tested. If you come across any issues, please let us know.
  • withVerbosity(): Logs to the client span additional events, such as call started, message sent, half close (client finished sending messages), response received, and call complete. Default only logs if a call is cancelled.
  • withTracedAttributes(ClientRequestAttribute... attrs): Sets tags on the client span in case you want to track information about the RPC call. See ClientRequestAttribute.java for a list of traceable request attributes.

Example

import io.opentracing.Span;

    TracingClientInterceptor tracingInterceptor = TracingClientInterceptor
        .newBuilder()
        .withTracer(tracer)
        .withStreaming()
        .withVerbosity()
        .withOperationName(new OperationNameConstructor() {
            @Override
            public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
                // construct some operation name from the method descriptor
            }
        })
        .withActiveSpanSource(new ActiveSpanSource() {
            @Override
            public Span getActiveSpan() {
                // implement how to get the current active span, for example:
                return OpenTracingContextKey.activeSpan();
            }
        })
        .withTracingAttributes(ClientRequestAttribute.ALL_CALL_OPTIONS,
            ClientRequestAttribute.HEADERS)
        .build();

Current Span Context

In your server request handler, you can access the current active span for that request by calling

Span span = OpenTracingContextKey.activeSpan();

This is useful if you want to manually set tags on the span, log important events, or create a new child span for internal units of work. You can also use this key to wrap these internal units of work with a new context that has a user-defined active span.

For example:

Tracer tracer = ...;

    // some unit of internal work that you want to trace
    Runnable internalWork = someInternalWork

    // a wrapper that traces the work of the runnable
    class TracedRunnable implements Runnable {
        Runnable work;
        Tracer tracer;

        TracedRunnable(Runnable work, Tracer tracer) {
            this.work = work;
            this.tracer = tracer;
        }

        public void run() {

            // create a child span for the current active span
            Span span = tracer
                .buildSpan("internal-work")
                .asChildOf(OpenTracingContextKey.activeSpan())
                .start();

            // create a new context with the child span as the active span
            Context contextWithNewSpan = Context.current()
                .withValue(OpenTracingContextKey.get(), span);

            // wrap the original work and run it
            Runnable tracedWork = contextWithNewSpan.wrap(this.work);
            tracedWork.run();

            // make sure to finish any manually created spans!
            span.finish();
        }
    }

    Runnable tracedInternalWork = new TracedRunnable(internalWork, tracer);
    tracedInternalWork.run();

Operation Names

The default operation name for any span is the RPC method name (io.grpc.MethodDescriptor.getFullMethodName()). However, you may want to add your own prefixes, alter the name, or define a new name. For examples of good operation names, check out the OpenTracing semantics.

To alter the operation name, you need to add an implementation of the interface OperationNameConstructor to the TracingClientInterceptor.Builder or TracingServerInterceptor.Builder. For example, if you want to add a prefix to the default operation name of your ClientInterceptor, your code would look like this:

 TracingClientInterceptor interceptor = TracingClientInterceptor.Builder ...
        .withOperationName(new OperationNameConstructor() {
            @Override
            public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
                return "your-prefix" + method.getFullMethodName();
            }
        })
        .with....
        .build()

Active Span Sources

If you want your client to continue a trace rather than starting a new one, then you can tell your TracingClientInterceptor how to extract the current active span by building it with your own implementation of the interface ActiveSpanSource. This interface has one method, getActiveSpan, in which you will define how to access the current active span.

For example, if you're creating the client in an environment that has the active span stored in a global dictionary-style context under OPENTRACING_SPAN_KEY, then you could configure your Interceptor as follows:

import io.opentracing.Span;

    TracingClientInterceptor interceptor = TracingClientInterceptor
        .newBuilder().withTracer(tracer)
        ...
        .withActiveSpanSource(new ActiveSpanSource() {
            @Override
            public Span getActiveSpan() {
                return Context.get(OPENTRACING_SPAN_KEY);
            }
        })
        ...
        .build();

We also provide two built-in implementations:

  • ActiveSpanSource.GRPC_CONTEXT uses the current io.grpc.Context and returns the active span for OpenTracingContextKey.
  • ActiveSpanSource.NONE always returns null as the active span, which means the client will retrieve the span from io.opentracing.Tracer.activeSpan(). This is the default active span source.

Active Span Context Sources

Instead of ActiveSpanSource it's possible to use ActiveSpanContextSource if span is not available

import io.opentracing.Span;

    TracingClientInterceptor interceptor = TracingClientInterceptor
        .newBuilder().withTracer(tracer)
        ...
        .withActiveSpanContextSource(new ActiveSpanContextSource() {
            @Override
            public SpanContext getActiveSpanContext() {
                return Context.get(OPENTRACING_SPAN_CONTEXT_KEY);
            }
        })
        ...
        .build();

We also provide two built-in implementations:

  • ActiveSpanContextSource.GRPC_CONTEXT uses the current io.grpc.Context and returns the active span context for OpenTracingContextKey.
  • ActiveSpanContextSource.NONE always returns null as the active span context, which means the client will retrieve the span from io.opentracing.Tracer.activeSpan().context(). This is the default active span context source.

Custom Span Decorators

If you want to add custom tags or logs to the server and client spans, then you can implement the ClientSpanDecorator, ClientCloseDecorator, ServerSpanDecorator, and ServerCloseDecorator interfaces. Multiple different decorators may be added to the builder.

TracingClientInterceptor clientInterceptor = TracingClientInterceptor
    .newBuilder().withTracer(tracer)
    ...
    .withClientSpanDecorator(new ClientSpanDecorator() {
        @Override
        public void interceptCall(Span span, MethodDescriptor method, CallOptions callOptions) {
            span.setTag("some_tag", "some_value");
            span.log("Example log");
        }
    })
    .withClientCloseDecorator(new ClientCloseDecorator() {
        @Override
        public void close(Span span, Status status, Metadata trailers) {
            span.setTag("some_other_tag", "some_other_value");
        }
    })
    ...
    .build();
    
TracingServerInterceptor serverInterceptor = TracingServerInterceptor
    .newBuilder().withTracer(tracer)
    ...
    .withServerSpanDecorator(new ServerSpanDecorator() {
        @Override
        public void interceptCall(Span span, ServerCall call, Metadata headers) {
            span.setTag("some_tag", "some_value");
            span.log("Intercepting server call");
        }
    })
    .withServerCloseDecorator(new ServerCloseDecorator() {
        @Override
        public void close(Span span, Status status, Metadata trailers) {
            span.setTag("some_other_tag", "some_other_value");
        }
    })
    ...
    .build();

Integrating with Other Interceptors

Although we provide TracingServerInterceptor.intercept(service) and TracingClientInterceptor.intercept(channel) methods, you don't want to use these if you're chaining multiple interceptors. Instead, use the following code (preferably putting the tracing interceptor at the top of the interceptor stack so that it traces the entire request lifecycle, including other interceptors):

Server

server = ServerBuilder.forPort(port)
        .addService(ServerInterceptors.intercept(service, someInterceptor,
            someOtherInterceptor, TracingServerInterceptor))
        .build()
        .start();

Client

blockingStub = GreeterGrpc.newBlockingStub(ClientInterceptors.intercept(channel,
        someInterceptor, someOtherInterceptor, TracingClientInterceptor));

License

Apache 2.0 License.

java-grpc's People

Contributors

augi avatar crisbodnar avatar dependabot[bot] avatar eikemeier avatar epkugelmass avatar eugeniyk avatar malafeev avatar pkwarren avatar ravirajj avatar safris avatar tandrup avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

java-grpc's Issues

AbstractMethodError from gRPC client on 0.1.3

I'm getting a severe error with 0.1.3. It doesn't happen with 0.1.2 (or other previous versions). I'm using Lightstep, with packages lightstep-tracer-jre which is 0.17.0, and tracer-grpc at 0.18.0. I'm not sure what happens, but it seems to be similar to this previous issue.

Here is the error:

SEVERE: [Channel<1>: (logging.googleapis.com:443)] Uncaught exception in the SynchronizationContext. Panic!
java.lang.AbstractMethodError: io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder$NettyTransportFactory.newClientTransport(Ljava/net/SocketAddress;Lio/grpc/internal/ClientTransportFactory$ClientTransportOptions;Lio/grpc/ChannelLogger;)Lio/grpc/internal/ConnectionClientTransport;
	at io.grpc.internal.CallCredentialsApplyingTransportFactory.newClientTransport(CallCredentialsApplyingTransportFactory.java:49)
	at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:246)
	at io.grpc.internal.InternalSubchannel.access$400(InternalSubchannel.java:65)
	at io.grpc.internal.InternalSubchannel$2.run(InternalSubchannel.java:196)
	at io.grpc.SynchronizationContext.drain(SynchronizationContext.java:95)
	at io.grpc.SynchronizationContext.execute(SynchronizationContext.java:127)
	at io.grpc.internal.ManagedChannelImpl$NameResolverListener.onResult(ManagedChannelImpl.java:1365)
	at io.grpc.internal.DnsNameResolver$Resolve.resolveInternal(DnsNameResolver.java:311)
	at io.grpc.internal.DnsNameResolver$Resolve.run(DnsNameResolver.java:213)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Any thoughts?

Possible to add tags in the interceptor?

Thanks for this library! I'm trying to set up tracing on a gRPC server now, written in Scala.
I have several tags I would like to add to all endpoints, e.g. the id of the tenant using the service.
Is there a way I can do so in the inteceptor? From what I can gather, to do so one needs to create a span first. I apologize if this is too little information, I'm quite new to tracing.

`TracingServerInterceptor` not closing activated `Scope`s ?

Hey,

We're having java services OOMing and traced the leakage to be related to a non-closed Scope returned from tracer.scopeManager().activate(span).

We fixed those issues and now see OOMs from another service where we don't have the above bug in our code. However, we use the TracingServerInterceptor from this library, and I noticed now that this class does does close the activated Scopes.

From the javadoc of io.opentracing.Tracer you find:

    /**
     * Make a {@link Span} instance active for the current context (usually a thread).
     * This is a shorthand for {@code Tracer.scopeManager().activate(span)}.
     *
     * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a
     * programming error to neglect to call {@link Scope#close()} on the returned instance,
     * and it may lead to memory leaks as the {@link Scope} may remain in the thread-local stack.
     */
    Scope activateSpan(Span span);

Am i missing anything or is there a bug in the code here? Happy to be proven wrong! 😄

Consider reverting change to use NoopTracer if GlobalTracer not registered

this.tracer = GlobalTracer.isRegistered() ? GlobalTracer.get() : NoopTracerFactory.create();

This change in the client/server interceptor broke usage in our gRPC apps as the GlobalTracer is registered lazily after the interceptors are created. The old builder would use GlobalTracer.get() as the default tracer, which would work once the global tracer was registered. The new behavior will use a NoopTracer and setting the GlobalTracer after creating a client/server interceptor will have no effect.

Record gRPC call status in Span

Currently, the OpenTracing gRPC instrumentation doesn't expose the status of a completed gRPC call in the spans. It would be useful for consumers of this library if the ServerCall is wrapped with a SimpleForwardingServerCall which overrides close(Status, Metadata), and an API consumer could set custom tags on the Span based on the Status and Metadata (similar to ServerSpanDecorator).

ClassCastException for TextMapExtractAdapter in version 0.2.0

I'm facing the following exception for io.opentracing.propagation.TextMapExtractAdapter when it tries to extract the context in the Server tracing interception.

I believe this is due to the fact that this adapter doesn't implement TextMap directly, and hence the extract() API cannot cast it properly.

java.lang.ClassCastException: class io.opentracing.propagation.TextMapExtractAdapter cannot be cast to class io.opentracing.propagation.TextMap (io.opentracing.propagation.TextMapExtractAdapter and io.opentracing.propagation.TextMap are in unnamed module of loader 'app')
	at io.jaegertracing.internal.propagation.TextMapCodec.extract(TextMapCodec.java:37) ~[jaeger-core-1.2.0.jar:1.2.0]
	at io.jaegertracing.internal.PropagationRegistry$ExceptionCatchingExtractorDecorator.extract(PropagationRegistry.java:57) [jaeger-core-1.2.0.jar:1.2.0]
	at io.jaegertracing.internal.JaegerTracer.extract(JaegerTracer.java:220) [jaeger-core-1.2.0.jar:1.2.0]
	at io.jaegertracing.internal.JaegerTracer.extract(JaegerTracer.java:63) [jaeger-core-1.2.0.jar:1.2.0]
	at io.opentracing.contrib.ServerTracingInterceptor.getSpanFromHeaders(ServerTracingInterceptor.java:151) [grpc-opentracing-0.2.0.jar:?]
	at io.opentracing.contrib.ServerTracingInterceptor.interceptCall(ServerTracingInterceptor.java:92) [grpc-opentracing-0.2.0.jar:?]
	at io.grpc.ServerInterceptors$InterceptCallHandler.startCall(ServerInterceptors.java:229) [grpc-api-1.21.0.jar:1.21.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startWrappedCall(ServerImpl.java:610) [grpc-core-1.21.0.jar:1.21.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startCall(ServerImpl.java:590) [grpc-core-1.21.0.jar:1.21.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.access$1900(ServerImpl.java:410) [grpc-core-1.21.0.jar:1.21.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1StreamCreated.runInContext(ServerImpl.java:526) [grpc-core-1.21.0.jar:1.21.0]
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) [grpc-core-1.21.0.jar:1.21.0]
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) [grpc-core-1.21.0.jar:1.21.0]
	at <CUSTOM SERVICE CLASS NAME>:25) [concurrent/:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:834) [?:?]```


Please advise how to mitigate this issue. 

Memory leak on intercepting server streaming call

Version: 0.2.3

Steps to reproduce:

  1. Intercept long-running server streaming calls with TracingServerInterceptor
  2. Watch memory consumption increase indefinitely (take a heap dump every few minutes)

Description:
TracingServerInterceptor creates a new span on every call from the client and closes it only when onCancel or onComplete occurs. In the case of server streaming, it means that Span object lives as long as the client-server connection exists and accumulates all the LogData objects that happen in this period of time inside Span internal state.

In our particular case, we have about 400 connections, processing 1 streaming response per second on average. It leads to OOM error every 3-4 hours (having a memory limit of about 5Gb). As a workaround, we could turn off the tracing of server streaming calls:

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {

    if (call.getMethodDescriptor().getType() == MethodDescriptor.MethodType.SERVER_STREAMING) {
        return noopServerCallListener();
    }
  ...

for the long-running server streaming calls, it may be no sense of tracing. So I believe it should be optional (controlled by some property)

Another option is to create and log a new span on server streaming response:

@Override
public void sendMessage(RespT message) {
    if (streaming || verbose) {
        span.log(
                ImmutableMap.<String, Object>builder()
                        .put(Fields.EVENT, GrpcFields.SERVER_CALL_SEND_MESSAGE)
                        .put(Fields.MESSAGE, "Server sent response message")
                        .build());
    }

    if (call.getMethodDescriptor().getType() == MethodDescriptor.MethodType.SERVER_STREAMING) {
        Span streamResponseSpan = getSpanFromHeaders(headerMap, operationNameConstructor.constructOperationName(call.getMethodDescriptor()));
        try (Scope ignored = tracer.scopeManager().activate(streamResponseSpan)) {
            super.sendMessage(message);
        } finally {
            streamResponseSpan.finish();
        }
    } else {
        try (Scope ignored = tracer.scopeManager().activate(span)) {
            super.sendMessage(message);
        }
    }
}

Both workarounds work for us. Please advise if we miss something or if you have a better solution.

Support BINARY format

As per this only TEXT_MAP format is supported.

I think support for BINARY could be added as an option for the user to explicitly specify, and keep TEXT_MAP as the default.

Enable client interceptors for additional metadata

I am trying to write additional Interceptors which add more metadata (project specific) to the spans created by the library interceptors. While this is possible for server spans, I believe it is not possible for client spans. The following code would need to be changed:

private Span createSpanFromParent(SpanContext parentSpanContext, String operationName) {
    if (parentSpanContext == null) {
      return tracer.buildSpan(operationName).start();
    } else {
      return tracer.buildSpan(operationName).asChildOf(parentSpanContext).start();
    }
  }

to

private Span createSpanFromParent(SpanContext parentSpanContext, String operationName) {
    if (parentSpanContext == null) {
      return tracer.buildSpan(operationName).startActive(false);
    } else {
      return tracer.buildSpan(operationName).asChildOf(parentSpanContext).startActive(false);
    }
  }

Then the client interceptor would be able to get the span from the current scope.
Please let me know if there is any other way of doing this which I might not be aware of.

ServerInterceptor code doesn't get invoked for one of the gRPC request on calling multiple requests

We are facing one issue with the server interceptor that the intermittent requests doesn't invoke the interceptor code when continuously calling multiple requests at the same time. This issue is affecting the whole flow since we are setting a really important info regarding the context in the interceptCall function of the ServerInterceptor.
Is there any fix for this to avoid this issue? or is there any alternative?

Server Interceptor Closing Active Span

I have created a test project: https://github.com/nevi-me/opentracing-grpc-test where I intercept both the client and the server.

After intercepting the server, the active span is closed, meaning that any other traces that should belong to the current span end up going to different spans.

If you run the above project, you'll see a null value being printed to the console when there should be an active span. The relevant piece of code is here: https://github.com/nevi-me/opentracing-grpc-test/blob/master/src/main/java/me/nevi/opentracingtest/rpc/RouteGuideServer.kt#L80.

I was expecting the current span to be active, so that any more messages that I log get included into the trace.

AbstractMethodError from gRPC client

As soon as I add the dependency to my build.gradle file, I see this error when attempting to send a request.

frontend [warn] 2018-06-27 10:59:20 -0400 i.g.i.ManagedChannelImpl - [io.grpc.internal.ManagedChannelImpl-25] Unexpected exception from LoadBalancer
java.lang.AbstractMethodError: io.grpc.okhttp.OkHttpChannelBuilder$OkHttpTransportFactory.newClientTransport(Ljava/net/SocketAddress;Ljava/lang/String;Ljava/lang/String;Lio/grpc/internal/ProxyParameters;)Lio/grpc/internal/ConnectionClientTransport;
        at io.grpc.internal.CallCredentialsApplyingTransportFactory.newClientTransport(CallCredentialsApplyingTransportFactory.java:48)
        at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:209)
        at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:188)
        at io.grpc.internal.ManagedChannelImpl$SubchannelImpl.requestConnection(ManagedChannelImpl.java:962)
        at io.grpc.util.RoundRobinLoadBalancerFactory$RoundRobinLoadBalancer.handleResolvedAddressGroups(RoundRobinLoadBalancerFactory.java:126)
        at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl$1.run(ManagedChannelImpl.java:868)
        at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:72)
        at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:834)
        at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:860)
        at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:180)

Any thoughts?

Can ActiveSpanSource accept SpanContext (if Spans aren't readily available)

The ClientTracingInterceptor uses the ActiveSpanSource to determine the parent span and ultimately uses it to build a new span as child of the parent. If it's only being used in that fashion, then a SpanContext is sufficient enough to build the span (the code doesn't actually need to use the full Span object).

We find that in our distributed system with different instrumentation implementations, the Span is not readily available for example in an HTTPServletRequest but the SpanContext is. Is there a way to allow us to all the ActiveSpanSource to return a SpanContext instead of a Span?

NoSuchMethodError on opentracing-grpc 0.2.0

I'm using opentracing-grpc0.2.0 with Grpc clinet, I follow your wikis but got this error, here is my code:

@Resource
brave.Tracing tracing;
public GRPCHelloClient(String ip){
		channel = ManagedChannelBuilder.forAddress(ip,50052) 
                .usePlaintext(true) 
                .build();
io.opentracing.Tracer openTracer = BraveTracer.create(tracing);
		TracingClientInterceptor tracingInterceptor = TracingClientInterceptor.newBuilder().withTracer(tracer).build();
		helloStub = HelloGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
	}
public String hello(String name) {
		Builder builder = HelloRequest.newBuilder();
		builder.setName(name);
		HelloRequest request = builder.build();
		HelloReply reply = helloStub.sayHello(request);
		return reply.getMessage();
	}

and when call hello(), error occurred;

java.lang.NoSuchMethodError: io.opentracing.ScopeManager.activate(Lio/opentracing/Span;)Lio/opentracing/Scope;
	at io.opentracing.contrib.grpc.TracingClientInterceptor.interceptCall(TracingClientInterceptor.java:103) ~[opentracing-grpc-0.2.0.jar:na]
	at io.grpc.ClientInterceptors$InterceptorChannel.newCall(ClientInterceptors.java:156) ~[grpc-core-1.17.1.jar:1.17.1]
	at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:125) ~[grpc-stub-1.17.1.jar:1.17.1]
	at proto.HelloGrpc$HelloBlockingStub.sayHello(HelloGrpc.java:156) ~[classes/:na]
	at com.neo.service.GRPCHelloClient.hello(GRPCHelloClient.java:36) ~[classes/:na]
	at com.neo.controller.HelloController.grpc(HelloController.java:53) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_191]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_191]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_191]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_191]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:873) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:858) ~[spring-webmvc-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.springframework.cloud.sleuth.instrument.web.ExceptionLoggingFilter.doFilter(ExceptionLoggingFilter.java:48) ~[spring-cloud-sleuth-core-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at brave.servlet.TracingFilter.doFilter(TracingFilter.java:86) ~[brave-instrumentation-servlet-5.1.0.jar:na]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.13.RELEASE.jar:5.0.13.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:798) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_191]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_191]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.39.jar:8.5.39]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_191]

and my pom.xml

               <dependency>
		    <groupId>io.opentracing.contrib</groupId>
		    <artifactId>opentracing-spring-cloud-starter</artifactId>
		    <version>0.2.6</version>
		</dependency>
		<dependency>
			<groupId>io.opentracing.contrib</groupId>
			<artifactId>opentracing-spring-zipkin-web-starter</artifactId>
			<version>0.2.0</version>
		</dependency> 
		<dependency>
		    <groupId>io.opentracing.contrib</groupId>
		    <artifactId>opentracing-grpc</artifactId>
		    <version>0.2.0</version>
		</dependency>
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

Am I using the wrong version of io.opentracing.contrib components?

Add standard tags to Spans?

There are some tags which seem like they'd be useful to expose out of the box with the default interceptors, including:

  • kind: client/server
  • component: grpc-java
  • grpc.status: Status.getCode().name()
  • error: true (if status.isOk() returns false)

What is your feeling on adding some of these tags to the Spans created by opentracing-grpc? Should this be provided for all consumers (for consistent instrumentation) or added by consumers using the span decorator interfaces?

Span not continued on the client side

I am using grpc version 1.22.
I have the following code on the client side:

new ClientTracingInterceptor
                .Builder()
                .withActiveSpanSource(() -> 
                        GlobalTracer.get().activeSpan()
                ).build();

but it does not continue a span that started before. I debugged the code and it seems we are in a different thread than the one that called the client when the lambda is called (so GlobalTracer.get().activeSpan() is null. I am not sure how this is supposed to work.

Client span tag "grpc.authority" is not set when authority is not set at call-level

GRPC-Java has two ways of setting the authority for a call, at the Channel level or at the individual call level. This allows for overriding the Channel-level authority per-call. See https://github.com/grpc/grpc-java/blob/master/api/src/main/java/io/grpc/CallOptions.java#L81 and https://github.com/grpc/grpc-java/blob/master/core/src/main/java/io/grpc/internal/CallCredentialsApplyingTransportFactory.java#L98.

The OpenTracing Java GRPC library does not respect this hierarchy/fallback behavior. Instead, only the call-level authority is checked. In most applications, this value will not be set. Like the GRPC-Java library, OpenTracing should then fall back to the channel level value.

Update to gRPC 1.15.0

Would it be possible to update this library to compile against gRPC 1.15.0 (or later)? 1.15.0 has moved to Java 7, so then it would be possible to use Java 7 features in this library (diamond operator, try-with-resources).

Also, I noticed that the generated protobuf code used in this project is compiled with a very old version of gRPC (0.15.0) that gives deprecation warnings when compiled with a newer gRPC library. Would it be possible to update the generated code to use a newer version of the protoc generated code or update the project to use protobuf-maven-plugin to generate code as part of the build?

I have a branch here with the suggested changes (https://github.com/opentracing-contrib/java-grpc/compare/master...pkwarren:update_grpc_1.15?expand=1) but wanted to run this by the maintainers first before raising a PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.