Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - ravirajj/java-grpc: OpenTracing Instrumentation for gRPC · GitHub
Skip to content

Repository files navigation

Build StatusCoverage StatusReleased VersionApache-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
importio.opentracing.Tracer;
publicclassYourServer {
privateintport;
privateServerserver;
privatefinalTracertracer;
privatevoidstart() throwsIOException {
TracingServerInterceptortracingInterceptor = newTracingServerInterceptor(this.tracer);
// If GlobalTracer is used: TracingServerInterceptorserver = 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
importio.opentracing.Tracer;
publicclassYourClient {
privatefinalManagedChannelchannel;
privatefinalGreeterGrpc.GreeterBlockingStubblockingStub;
privatefinalTracertracer;
publicYourClient(Stringhost, intport) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor(this.tracer);
// If GlobalTracer is used: TracingClientInterceptorblockingStub = 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

TracingServerInterceptortracingInterceptor = newTracingServerInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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

importio.opentracing.Span;
TracingClientInterceptortracingInterceptor = newTracingClientInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
// implement how to get the current active span, for example:returnOpenTracingContextKey.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

Spanspan = 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:

Tracertracer = ...;
// some unit of internal work that you want to traceRunnableinternalWork = someInternalWork// a wrapper that traces the work of the runnableclassTracedRunnableimplementsRunnable {
Runnablework;
Tracertracer;
TracedRunnable(Runnablework, Tracertracer) {
this.work = work;
this.tracer = tracer;
}
publicvoidrun() {
// create a child span for the current active spanSpanspan = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active spanContextcontextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run itRunnabletracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!span.finish();
}
}
RunnabletracedInternalWork = newTracedRunnable(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:

TracingClientInterceptorinterceptor = TracingClientInterceptor.Builder ...
.withOperationName(newOperationNameConstructor() {
@Overridepublic <ReqT, RespT> StringconstructOperationName(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:

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanSource(newActiveSpanSource() {
@OverridepublicSpangetActiveSpan() {
returnContext.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

importio.opentracing.Span;
TracingClientInterceptorinterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withActiveSpanContextSource(newActiveSpanContextSource() {
@OverridepublicSpanContextgetActiveSpanContext() {
returnContext.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.

TracingClientInterceptorclientInterceptor = newTracingClientInterceptor
.Builder(tracer)
...
.withClientSpanDecorator(newClientSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, MethodDescriptormethod, CallOptionscallOptions) {
span.setTag("some_tag", "some_value");
span.log("Example log");
}
})
.withClientCloseDecorator(newClientCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
span.setTag("some_other_tag", "some_other_value");
}
})
...
.build();
TracingServerInterceptorserverInterceptor = newTracingServerInterceptor
.Builder(tracer)
...
.withServerSpanDecorator(newServerSpanDecorator() {
@OverridepublicvoidinterceptCall(Spanspan, ServerCallcall, Metadataheaders) {
span.setTag("some_tag", "some_value");
span.log("Intercepting server call");
}
})
.withServerCloseDecorator(newServerCloseDecorator() {
@Overridepublicvoidclose(Spanspan, Statusstatus, Metadatatrailers) {
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.

About

OpenTracing Instrumentation for gRPC

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages