1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
#####################
GRPC-Java OpenTracing
#####################
============
Installation
============
This package is available on Maven Central and can be added to your project as follows:
**Maven**
.. code-block::
<dependencies>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>grpc-opentracing</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
**Gradle**
.. code-block::
compile 'io.opentracing.contrib:grpc-opentracing:0.2.0'
==========
Quickstart
==========
If you want to add basic tracing to your clients and servers, you can do so in a few short and simple steps, as shown below. (These code snippets use the grpc example's ``GreeterGrpc``, generated by protocol buffers.)
**Servers**
- Instantiate a tracer
- Create a ``ServerTracingInterceptor``
- Intercept a service
- (Optional) Access the `current span`_
.. _current span: `Current Span Context`_
.. code-block:: java
import io.opentracing.Tracer;
public class YourServer {
private int port;
private Server server;
// Any io.opentracing.Tracer implementation will do here. For instance,
// https://github.com/uber/jaeger-client-java/blob/master/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
// generates Zipkin-compatible data.
private final Tracer tracer;
private void start() throws IOException {
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(this.tracer);
server = ServerBuilder.forPort(port)
.addService(tracingInterceptor.intercept(someServiceDef))
.build()
.start();
}
}
**Clients**
- Instantiate a tracer
- Create a ``ClientTracingInterceptor``
- Intercept the client channel
.. code-block:: java
import io.opentracing.Tracer;
public class YourClient {
private final ManagedChannel channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
// Any io.opentracing.Tracer implementation will do here. For instance,
// https://github.com/uber/jaeger-client-java/blob/master/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
// generates Zipkin-compatible data.
private final Tracer tracer;
public YourClient(String host, int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(this.tracer)
blockingStub = GreeterGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
}
}
There's an example of a simple traced client (`TracedClient`) and server (`TracedService`) in `src/test`.
==============
Server Tracing
==============
A ``ServerTracingInterceptor`` uses default settings, which you can override by creating it using a ``ServerTracingInterceptor.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**:
.. code-block:: java
ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withTracedAttributes(ServerRequestAttribute.HEADERS,
ServerRequestAttribute.METHOD_TYPE)
.build();
==============
Client Tracing
==============
A ``ClientTracingInterceptor`` also has default settings, which you can override by creating it using a ``ClientTracingInterceptor.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. This is needed if you want your client to continue a trace instead of starting a new one. More details in the `Active Span Source`_ 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**:
.. code-block:: java
import io.opentracing.Span;
ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
.Builder(tracer)
.withStreaming()
.withVerbosity()
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
// construct some operation name from the method descriptor
}
})
.withActiveSpanSource(new ActiveSpanSource() {
@Override
public Span getActiveSpan() {
// implement how to get the current active span, for example:
return OpenTracingContextKey.activeSpan();
}
})
.withTracingAttributes(ClientRequestAttribute.ALL_CALL_OPTIONS,
ClientRequestAttribute.HEADERS)
.build();
.. _Operation Name: `Operation Names`_
.. _Active Span Source: `Active Span Sources`_
====================
Current Span Context
====================
In your server request handler, you can access the current active span for that request by calling
.. code-block:: java
Span span = OpenTracingContextKey.activeSpan();
This is useful if you want to manually set tags on the span, log important events, or create a new child span for internal units of work. You can also use this key to wrap these internal units of work with a new context that has a user-defined active span.
For example:
.. code-block:: java
Tracer tracer = ...;
// some unit of internal work that you want to trace
Runnable internalWork = someInternalWork
// a wrapper that traces the work of the runnable
class TracedRunnable implements Runnable {
Runnable work;
Tracer tracer;
TracedRunnable(Runnable work, Tracer tracer) {
this.work = work;
this.tracer = tracer;
}
public void run() {
// create a child span for the current active span
Span span = tracer
.buildSpan("internal-work")
.asChildOf(OpenTracingContextKey.activeSpan())
.start();
// create a new context with the child span as the active span
Context contextWithNewSpan = Context.current()
.withValue(OpenTracingContextKey.get(), span);
// wrap the original work and run it
Runnable tracedWork = contextWithNewSpan.wrap(this.work);
tracedWork.run();
// make sure to finish any manually created spans!
span.finish();
}
}
Runnable tracedInternalWork = new TracedRunnable(internalWork, tracer);
tracedInternalWork.run();
===============
Operation Names
===============
The default operation name for any span is the RPC method name (``io.grpc.MethodDescriptor.getFullMethodName()``). However, you may want to add your own prefixes, alter the name, or define a new name. For examples of good operation names, check out the OpenTracing `semantics`_.
To alter the operation name, you need to add an implementation of the interface ``OperationNameConstructor`` to the ``ClientTracingInterceptor.Builder`` or ``ServerTracingInterceptor.Builder``. For example, if you want to add a prefix to the default operation name of your ClientInterceptor, your code would look like this:
.. code-block:: java
ClientTracingInterceptor interceptor = ClientTracingInterceptor.Builder ...
.withOperationName(new OperationNameConstructor() {
@Override
public <ReqT, RespT> String constructOperationName(MethodDescriptor<ReqT, RespT> method) {
return "your-prefix" + method.getFullMethodName();
}
})
.with....
.build()
.. _semantics: http://opentracing.io/spec/#operation-names
===================
Active Span Sources
===================
If you want your client to continue a trace rather than starting a new one, then you can tell your ``ClientTracingInterceptor`` 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:
.. code-block:: java
import io.opentracing.Span;
ClientTracingInterceptor interceptor = new ClientTracingInterceptor
.Builder(tracer)
...
.withActiveSpanSource(new ActiveSpanSource() {
@Override
public Span getActiveSpan() {
return Context.get(OPENTRACING_SPAN_KEY);
}
})
...
.build();
We also provide two built-in implementations:
* ``ActiveSpanSource.GRPC_CONTEXT`` uses the current ``io.grpc.Context`` and returns the active span for ``OpenTracingContextKey``. This is the default active span source.
* ``ActiveSpanSource.NONE`` always returns null as the active span, which means the client will always start a new trace
===================================
Integrating with Other Interceptors
===================================
Although we provide ``ServerTracingInterceptor.intercept(service)`` and ``ClientTracingInterceptor.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):
**Servers**
.. code-block:: java
server = ServerBuilder.forPort(port)
.addService(ServerInterceptors.intercept(service, someInterceptor,
someOtherInterceptor, serverTracingInterceptor))
.build()
.start();
**Clients**
.. code-block:: java
blockingStub = GreeterGrpc.newBlockingStub(ClientInterceptors.intercept(channel,
someInterceptor, someOtherInterceptor, clientTracingInterceptor));
======================
Releasing new versions
======================
Create a gradle.properties in this directory. It should look approximately like this:
.. code-block::
sonatypeUsername=bensigelman
sonatypePassword=<your OSSRH sonatype password>
signing.keyId=<`gpg --list-keys` output, minus the prefix like "2048R/">
signing.password=<your gpg password>
signing.secretKeyRingFile=/Your/Homedir/.gnupg/secring.gpg
Then run:
.. code-block::
$ gradle uploadArchives closeAndPromoteRepository
|