responseObserver) {
80 | asyncUnimplementedUnaryCall(METHOD_SAY_HELLO, responseObserver);
81 | }
82 |
83 | @java.lang.Override public io.grpc.ServerServiceDefinition bindService() {
84 | return GreeterGrpc.bindService(this);
85 | }
86 | }
87 |
88 | /**
89 | *
90 | * The greeting service definition.
91 | *
92 | */
93 | @java.lang.Deprecated public static interface GreeterBlockingClient {
94 |
95 | /**
96 | *
97 | * Sends a greeting
98 | *
99 | */
100 | public io.opentracing.contrib.HelloReply sayHello(io.opentracing.contrib.HelloRequest request);
101 | }
102 |
103 | /**
104 | *
105 | * The greeting service definition.
106 | *
107 | */
108 | @java.lang.Deprecated public static interface GreeterFutureClient {
109 |
110 | /**
111 | *
112 | * Sends a greeting
113 | *
114 | */
115 | public com.google.common.util.concurrent.ListenableFuture sayHello(
116 | io.opentracing.contrib.HelloRequest request);
117 | }
118 |
119 | public static class GreeterStub extends io.grpc.stub.AbstractStub
120 | implements Greeter {
121 | private GreeterStub(io.grpc.Channel channel) {
122 | super(channel);
123 | }
124 |
125 | private GreeterStub(io.grpc.Channel channel,
126 | io.grpc.CallOptions callOptions) {
127 | super(channel, callOptions);
128 | }
129 |
130 | @java.lang.Override
131 | protected GreeterStub build(io.grpc.Channel channel,
132 | io.grpc.CallOptions callOptions) {
133 | return new GreeterStub(channel, callOptions);
134 | }
135 |
136 | @java.lang.Override
137 | public void sayHello(io.opentracing.contrib.HelloRequest request,
138 | io.grpc.stub.StreamObserver responseObserver) {
139 | asyncUnaryCall(
140 | getChannel().newCall(METHOD_SAY_HELLO, getCallOptions()), request, responseObserver);
141 | }
142 | }
143 |
144 | public static class GreeterBlockingStub extends io.grpc.stub.AbstractStub
145 | implements GreeterBlockingClient {
146 | private GreeterBlockingStub(io.grpc.Channel channel) {
147 | super(channel);
148 | }
149 |
150 | private GreeterBlockingStub(io.grpc.Channel channel,
151 | io.grpc.CallOptions callOptions) {
152 | super(channel, callOptions);
153 | }
154 |
155 | @java.lang.Override
156 | protected GreeterBlockingStub build(io.grpc.Channel channel,
157 | io.grpc.CallOptions callOptions) {
158 | return new GreeterBlockingStub(channel, callOptions);
159 | }
160 |
161 | @java.lang.Override
162 | public io.opentracing.contrib.HelloReply sayHello(io.opentracing.contrib.HelloRequest request) {
163 | return blockingUnaryCall(
164 | getChannel(), METHOD_SAY_HELLO, getCallOptions(), request);
165 | }
166 | }
167 |
168 | public static class GreeterFutureStub extends io.grpc.stub.AbstractStub
169 | implements GreeterFutureClient {
170 | private GreeterFutureStub(io.grpc.Channel channel) {
171 | super(channel);
172 | }
173 |
174 | private GreeterFutureStub(io.grpc.Channel channel,
175 | io.grpc.CallOptions callOptions) {
176 | super(channel, callOptions);
177 | }
178 |
179 | @java.lang.Override
180 | protected GreeterFutureStub build(io.grpc.Channel channel,
181 | io.grpc.CallOptions callOptions) {
182 | return new GreeterFutureStub(channel, callOptions);
183 | }
184 |
185 | @java.lang.Override
186 | public com.google.common.util.concurrent.ListenableFuture sayHello(
187 | io.opentracing.contrib.HelloRequest request) {
188 | return futureUnaryCall(
189 | getChannel().newCall(METHOD_SAY_HELLO, getCallOptions()), request);
190 | }
191 | }
192 |
193 | @java.lang.Deprecated public static abstract class AbstractGreeter extends GreeterImplBase {}
194 |
195 | private static final int METHODID_SAY_HELLO = 0;
196 |
197 | private static class MethodHandlers implements
198 | io.grpc.stub.ServerCalls.UnaryMethod,
199 | io.grpc.stub.ServerCalls.ServerStreamingMethod,
200 | io.grpc.stub.ServerCalls.ClientStreamingMethod,
201 | io.grpc.stub.ServerCalls.BidiStreamingMethod {
202 | private final Greeter serviceImpl;
203 | private final int methodId;
204 |
205 | public MethodHandlers(Greeter serviceImpl, int methodId) {
206 | this.serviceImpl = serviceImpl;
207 | this.methodId = methodId;
208 | }
209 |
210 | @java.lang.Override
211 | @java.lang.SuppressWarnings("unchecked")
212 | public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) {
213 | switch (methodId) {
214 | case METHODID_SAY_HELLO:
215 | serviceImpl.sayHello((io.opentracing.contrib.HelloRequest) request,
216 | (io.grpc.stub.StreamObserver) responseObserver);
217 | break;
218 | default:
219 | throw new AssertionError();
220 | }
221 | }
222 |
223 | @java.lang.Override
224 | @java.lang.SuppressWarnings("unchecked")
225 | public io.grpc.stub.StreamObserver invoke(
226 | io.grpc.stub.StreamObserver responseObserver) {
227 | switch (methodId) {
228 | default:
229 | throw new AssertionError();
230 | }
231 | }
232 | }
233 |
234 | public static io.grpc.ServiceDescriptor getServiceDescriptor() {
235 | return new io.grpc.ServiceDescriptor(SERVICE_NAME,
236 | METHOD_SAY_HELLO);
237 | }
238 |
239 | @java.lang.Deprecated public static io.grpc.ServerServiceDefinition bindService(
240 | final Greeter serviceImpl) {
241 | return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
242 | .addMethod(
243 | METHOD_SAY_HELLO,
244 | asyncUnaryCall(
245 | new MethodHandlers<
246 | io.opentracing.contrib.HelloRequest,
247 | io.opentracing.contrib.HelloReply>(
248 | serviceImpl, METHODID_SAY_HELLO)))
249 | .build();
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/python/grpc_opentracing/_client.py:
--------------------------------------------------------------------------------
1 | """Implementation of the invocation-side open-tracing interceptor."""
2 |
3 | import sys
4 | import logging
5 | import time
6 |
7 | from six import iteritems
8 |
9 | import grpc
10 | from grpc_opentracing import grpcext
11 | from grpc_opentracing._utilities import get_method_type, get_deadline_millis,\
12 | log_or_wrap_request_or_iterator, RpcInfo
13 | import opentracing
14 | from opentracing.ext import tags as ot_tags
15 |
16 |
17 | class _GuardedSpan(object):
18 |
19 | def __init__(self, span):
20 | self.span = span
21 | self._engaged = True
22 |
23 | def __enter__(self):
24 | self.span.__enter__()
25 | return self
26 |
27 | def __exit__(self, *args, **kwargs):
28 | if self._engaged:
29 | return self.span.__exit__(*args, **kwargs)
30 | else:
31 | return False
32 |
33 | def release(self):
34 | self._engaged = False
35 | return self.span
36 |
37 |
38 | def _inject_span_context(tracer, span, metadata):
39 | headers = {}
40 | try:
41 | tracer.inject(span.context, opentracing.Format.HTTP_HEADERS, headers)
42 | except (opentracing.UnsupportedFormatException,
43 | opentracing.InvalidCarrierException,
44 | opentracing.SpanContextCorruptedException) as e:
45 | logging.exception('tracer.inject() failed')
46 | span.log_kv({'event': 'error', 'error.object': e})
47 | return metadata
48 | metadata = () if metadata is None else tuple(metadata)
49 | return metadata + tuple(iteritems(headers))
50 |
51 |
52 | def _make_future_done_callback(span, rpc_info, log_payloads, span_decorator):
53 |
54 | def callback(response_future):
55 | with span:
56 | code = response_future.code()
57 | if code != grpc.StatusCode.OK:
58 | span.set_tag('error', True)
59 | error_log = {'event': 'error', 'error.kind': str(code)}
60 | details = response_future.details()
61 | if details is not None:
62 | error_log['message'] = details
63 | span.log_kv(error_log)
64 | rpc_info.error = code
65 | if span_decorator is not None:
66 | span_decorator(span, rpc_info)
67 | return
68 | response = response_future.result()
69 | rpc_info.response = response
70 | if log_payloads:
71 | span.log_kv({'response': response})
72 | if span_decorator is not None:
73 | span_decorator(span, rpc_info)
74 |
75 | return callback
76 |
77 |
78 | class OpenTracingClientInterceptor(grpcext.UnaryClientInterceptor,
79 | grpcext.StreamClientInterceptor):
80 |
81 | def __init__(self, tracer, active_span_source, log_payloads,
82 | span_decorator):
83 | self._tracer = tracer
84 | self._active_span_source = active_span_source
85 | self._log_payloads = log_payloads
86 | self._span_decorator = span_decorator
87 |
88 | def _start_span(self, method):
89 | active_span_context = None
90 | if self._active_span_source is not None:
91 | active_span = self._active_span_source.get_active_span()
92 | if active_span is not None:
93 | active_span_context = active_span.context
94 | tags = {
95 | ot_tags.COMPONENT: 'grpc',
96 | ot_tags.SPAN_KIND: ot_tags.SPAN_KIND_RPC_CLIENT
97 | }
98 | return self._tracer.start_span(
99 | operation_name=method, child_of=active_span_context, tags=tags)
100 |
101 | def _trace_result(self, guarded_span, rpc_info, result):
102 | # If the RPC is called asynchronously, release the guard and add a callback
103 | # so that the span can be finished once the future is done.
104 | if isinstance(result, grpc.Future):
105 | result.add_done_callback(
106 | _make_future_done_callback(guarded_span.release(
107 | ), rpc_info, self._log_payloads, self._span_decorator))
108 | return result
109 | response = result
110 | # Handle the case when the RPC is initiated via the with_call
111 | # method and the result is a tuple with the first element as the
112 | # response.
113 | # http://www.grpc.io/grpc/python/grpc.html#grpc.UnaryUnaryMultiCallable.with_call
114 | if isinstance(result, tuple):
115 | response = result[0]
116 | rpc_info.response = response
117 | if self._log_payloads:
118 | guarded_span.span.log_kv({'response': response})
119 | if self._span_decorator is not None:
120 | self._span_decorator(guarded_span.span, rpc_info)
121 | return result
122 |
123 | def _start_guarded_span(self, *args, **kwargs):
124 | return _GuardedSpan(self._start_span(*args, **kwargs))
125 |
126 | def intercept_unary(self, request, metadata, client_info, invoker):
127 | with self._start_guarded_span(client_info.full_method) as guarded_span:
128 | metadata = _inject_span_context(self._tracer, guarded_span.span,
129 | metadata)
130 | rpc_info = RpcInfo(
131 | full_method=client_info.full_method,
132 | metadata=metadata,
133 | timeout=client_info.timeout,
134 | request=request)
135 | if self._log_payloads:
136 | guarded_span.span.log_kv({'request': request})
137 | try:
138 | result = invoker(request, metadata)
139 | except:
140 | e = sys.exc_info()[0]
141 | guarded_span.span.set_tag('error', True)
142 | guarded_span.span.log_kv({'event': 'error', 'error.object': e})
143 | rpc_info.error = e
144 | if self._span_decorator is not None:
145 | self._span_decorator(guarded_span.span, rpc_info)
146 | raise
147 | return self._trace_result(guarded_span, rpc_info, result)
148 |
149 | # For RPCs that stream responses, the result can be a generator. To record
150 | # the span across the generated responses and detect any errors, we wrap the
151 | # result in a new generator that yields the response values.
152 | def _intercept_server_stream(self, request_or_iterator, metadata,
153 | client_info, invoker):
154 | with self._start_span(client_info.full_method) as span:
155 | metadata = _inject_span_context(self._tracer, span, metadata)
156 | rpc_info = RpcInfo(
157 | full_method=client_info.full_method,
158 | metadata=metadata,
159 | timeout=client_info.timeout)
160 | if client_info.is_client_stream:
161 | rpc_info.request = request_or_iterator
162 | if self._log_payloads:
163 | request_or_iterator = log_or_wrap_request_or_iterator(
164 | span, client_info.is_client_stream, request_or_iterator)
165 | try:
166 | result = invoker(request_or_iterator, metadata)
167 | for response in result:
168 | if self._log_payloads:
169 | span.log_kv({'response': response})
170 | yield response
171 | except:
172 | e = sys.exc_info()[0]
173 | span.set_tag('error', True)
174 | span.log_kv({'event': 'error', 'error.object': e})
175 | rpc_info.error = e
176 | if self._span_decorator is not None:
177 | self._span_decorator(span, rpc_info)
178 | raise
179 | if self._span_decorator is not None:
180 | self._span_decorator(span, rpc_info)
181 |
182 | def intercept_stream(self, request_or_iterator, metadata, client_info,
183 | invoker):
184 | if client_info.is_server_stream:
185 | return self._intercept_server_stream(request_or_iterator, metadata,
186 | client_info, invoker)
187 | with self._start_guarded_span(client_info.full_method) as guarded_span:
188 | metadata = _inject_span_context(self._tracer, guarded_span.span,
189 | metadata)
190 | rpc_info = RpcInfo(
191 | full_method=client_info.full_method,
192 | metadata=metadata,
193 | timeout=client_info.timeout,
194 | request=request_or_iterator)
195 | if self._log_payloads:
196 | request_or_iterator = log_or_wrap_request_or_iterator(
197 | guarded_span.span, client_info.is_client_stream,
198 | request_or_iterator)
199 | try:
200 | result = invoker(request_or_iterator, metadata)
201 | except:
202 | e = sys.exc_info()[0]
203 | guarded_span.span.set_tag('error', True)
204 | guarded_span.span.log_kv({'event': 'error', 'error.object': e})
205 | rpc_info.error = e
206 | if self._span_decorator is not None:
207 | self._span_decorator(guarded_span.span, rpc_info)
208 | raise
209 | return self._trace_result(guarded_span, rpc_info, result)
210 |
--------------------------------------------------------------------------------
/java/src/main/java/io/opentracing/contrib/ServerTracingInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.opentracing.contrib;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 | import io.grpc.BindableService;
5 | import io.grpc.Context;
6 | import io.grpc.Contexts;
7 | import io.grpc.Metadata;
8 | import io.grpc.ServerCall;
9 | import io.grpc.ServerCallHandler;
10 | import io.grpc.ServerInterceptor;
11 | import io.grpc.ServerInterceptors;
12 | import io.grpc.ServerServiceDefinition;
13 | import io.grpc.ForwardingServerCallListener;
14 |
15 | import io.opentracing.propagation.Format;
16 | import io.opentracing.propagation.TextMapExtractAdapter;
17 | import io.opentracing.Span;
18 | import io.opentracing.SpanContext;
19 | import io.opentracing.Tracer;
20 |
21 | import java.util.Arrays;
22 | import java.util.HashMap;
23 | import java.util.HashSet;
24 | import java.util.Map;
25 | import java.util.Set;
26 |
27 | /**
28 | * An intercepter that applies tracing via OpenTracing to all requests
29 | * to the server.
30 | */
31 | public class ServerTracingInterceptor implements ServerInterceptor {
32 |
33 | private final Tracer tracer;
34 | private final OperationNameConstructor operationNameConstructor;
35 | private final boolean streaming;
36 | private final boolean verbose;
37 | private final Set tracedAttributes;
38 |
39 | /**
40 | * @param tracer used to trace requests
41 | */
42 | public ServerTracingInterceptor(Tracer tracer) {
43 | this.tracer = tracer;
44 | this.operationNameConstructor = OperationNameConstructor.DEFAULT;
45 | this.streaming = false;
46 | this.verbose = false;
47 | this.tracedAttributes = new HashSet();
48 | }
49 |
50 | private ServerTracingInterceptor(Tracer tracer, OperationNameConstructor operationNameConstructor, boolean streaming,
51 | boolean verbose, Set tracedAttributes) {
52 | this.tracer = tracer;
53 | this.operationNameConstructor = operationNameConstructor;
54 | this.streaming = streaming;
55 | this.verbose = verbose;
56 | this.tracedAttributes = tracedAttributes;
57 | }
58 |
59 | /**
60 | * Add tracing to all requests made to this service.
61 | * @param serviceDef of the service to intercept
62 | * @return the serviceDef with a tracing interceptor
63 | */
64 | public ServerServiceDefinition intercept(ServerServiceDefinition serviceDef) {
65 | return ServerInterceptors.intercept(serviceDef, this);
66 | }
67 |
68 | /**
69 | * Add tracing to all requests made to this service.
70 | * @param bindableService to intercept
71 | * @return the serviceDef with a tracing interceptor
72 | */
73 | public ServerServiceDefinition intercept(BindableService bindableService) {
74 | return ServerInterceptors.intercept(bindableService, this);
75 | }
76 |
77 | @Override
78 | public ServerCall.Listener interceptCall(
79 | ServerCall call,
80 | Metadata headers,
81 | ServerCallHandler next
82 | ) {
83 | Map headerMap = new HashMap();
84 | for (String key : headers.keys()) {
85 | if (!key.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {
86 | String value = headers.get(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER));
87 | headerMap.put(key, value);
88 | }
89 |
90 | }
91 |
92 | final String operationName = operationNameConstructor.constructOperationName(call.getMethodDescriptor());
93 | final Span span = getSpanFromHeaders(headerMap, operationName);
94 |
95 | for (ServerRequestAttribute attr : this.tracedAttributes) {
96 | switch (attr) {
97 | case METHOD_TYPE:
98 | span.setTag("grpc.method_type", call.getMethodDescriptor().getType().toString());
99 | break;
100 | case METHOD_NAME:
101 | span.setTag("grpc.method_name", call.getMethodDescriptor().getFullMethodName());
102 | break;
103 | case CALL_ATTRIBUTES:
104 | span.setTag("grpc.call_attributes", call.getAttributes().toString());
105 | break;
106 | case HEADERS:
107 | span.setTag("grpc.headers", headers.toString());
108 | break;
109 | }
110 | }
111 |
112 | Context ctxWithSpan = Context.current().withValue(OpenTracingContextKey.getKey(), span);
113 | ServerCall.Listener listenerWithContext = Contexts
114 | .interceptCall(ctxWithSpan, call, headers, next);
115 |
116 | ServerCall.Listener tracingListenerWithContext =
117 | new ForwardingServerCallListener.SimpleForwardingServerCallListener(listenerWithContext) {
118 |
119 | @Override
120 | public void onMessage(ReqT message) {
121 | if (streaming || verbose) { span.log(ImmutableMap.of("Message received", message)); }
122 | delegate().onMessage(message);
123 | }
124 |
125 | @Override
126 | public void onHalfClose() {
127 | if (streaming) { span.log("Client finished sending messages"); }
128 | delegate().onHalfClose();
129 | }
130 |
131 | @Override
132 | public void onCancel() {
133 | span.log("Call cancelled");
134 | span.finish();
135 | delegate().onCancel();
136 | }
137 |
138 | @Override
139 | public void onComplete() {
140 | if (verbose) { span.log("Call completed"); }
141 | span.finish();
142 | delegate().onComplete();
143 | }
144 | };
145 |
146 | return tracingListenerWithContext;
147 | }
148 |
149 | private Span getSpanFromHeaders(Map headers, String operationName) {
150 | Span span;
151 | try {
152 | SpanContext parentSpanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS,
153 | new TextMapExtractAdapter(headers));
154 | if (parentSpanCtx == null) {
155 | span = tracer.buildSpan(operationName).startManual();
156 | } else {
157 | span = tracer.buildSpan(operationName).asChildOf(parentSpanCtx).startManual();
158 | }
159 | } catch (IllegalArgumentException iae){
160 | span = tracer.buildSpan(operationName)
161 | .withTag("Error", "Extract failed and an IllegalArgumentException was thrown")
162 | .startManual();
163 | }
164 | return span;
165 | }
166 |
167 | /**
168 | * Builds the configuration of a ServerTracingInterceptor.
169 | */
170 | public static class Builder {
171 | private final Tracer tracer;
172 | private OperationNameConstructor operationNameConstructor;
173 | private boolean streaming;
174 | private boolean verbose;
175 | private Set tracedAttributes;
176 |
177 | /**
178 | * @param tracer to use for this intercepter
179 | * Creates a Builder with default configuration
180 | */
181 | public Builder(Tracer tracer) {
182 | this.tracer = tracer;
183 | this.operationNameConstructor = OperationNameConstructor.DEFAULT;
184 | this.streaming = false;
185 | this.verbose = false;
186 | this.tracedAttributes = new HashSet();
187 | }
188 |
189 | /**
190 | * @param operationNameConstructor for all spans created by this intercepter
191 | * @return this Builder with configured operation name
192 | */
193 | public Builder withOperationName(OperationNameConstructor operationNameConstructor) {
194 | this.operationNameConstructor = operationNameConstructor;
195 | return this;
196 | }
197 |
198 | /**
199 | * @param attributes to set as tags on server spans
200 | * created by this intercepter
201 | * @return this Builder configured to trace request attributes
202 | */
203 | public Builder withTracedAttributes(ServerRequestAttribute... attributes) {
204 | this.tracedAttributes = new HashSet(Arrays.asList(attributes));
205 | return this;
206 | }
207 |
208 | /**
209 | * Logs streaming events to server spans.
210 | * @return this Builder configured to log streaming events
211 | */
212 | public Builder withStreaming() {
213 | this.streaming = true;
214 | return this;
215 | }
216 |
217 | /**
218 | * Logs all request life-cycle events to server spans.
219 | * @return this Builder configured to be verbose
220 | */
221 | public Builder withVerbosity() {
222 | this.verbose = true;
223 | return this;
224 | }
225 |
226 | /**
227 | * @return a ServerTracingInterceptor with this Builder's configuration
228 | */
229 | public ServerTracingInterceptor build() {
230 | return new ServerTracingInterceptor(this.tracer, this.operationNameConstructor,
231 | this.streaming, this.verbose, this.tracedAttributes);
232 | }
233 | }
234 |
235 | public enum ServerRequestAttribute {
236 | HEADERS,
237 | METHOD_TYPE,
238 | METHOD_NAME,
239 | CALL_ATTRIBUTES
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/python/grpc_opentracing/_server.py:
--------------------------------------------------------------------------------
1 | """Implementation of the service-side open-tracing interceptor."""
2 |
3 | import sys
4 | import logging
5 | import re
6 |
7 | import grpc
8 | from grpc_opentracing import grpcext, ActiveSpanSource
9 | from grpc_opentracing._utilities import get_method_type, get_deadline_millis,\
10 | log_or_wrap_request_or_iterator, RpcInfo
11 | import opentracing
12 | from opentracing.ext import tags as ot_tags
13 |
14 |
15 | class _OpenTracingServicerContext(grpc.ServicerContext, ActiveSpanSource):
16 |
17 | def __init__(self, servicer_context, active_span):
18 | self._servicer_context = servicer_context
19 | self._active_span = active_span
20 | self.code = grpc.StatusCode.OK
21 | self.details = None
22 |
23 | def is_active(self, *args, **kwargs):
24 | return self._servicer_context.is_active(*args, **kwargs)
25 |
26 | def time_remaining(self, *args, **kwargs):
27 | return self._servicer_context.time_remaining(*args, **kwargs)
28 |
29 | def cancel(self, *args, **kwargs):
30 | return self._servicer_context.cancel(*args, **kwargs)
31 |
32 | def add_callback(self, *args, **kwargs):
33 | return self._servicer_context.add_callback(*args, **kwargs)
34 |
35 | def invocation_metadata(self, *args, **kwargs):
36 | return self._servicer_context.invocation_metadata(*args, **kwargs)
37 |
38 | def peer(self, *args, **kwargs):
39 | return self._servicer_context.peer(*args, **kwargs)
40 |
41 | def peer_identities(self, *args, **kwargs):
42 | return self._servicer_context.peer_identities(*args, **kwargs)
43 |
44 | def peer_identity_key(self, *args, **kwargs):
45 | return self._servicer_context.peer_identity_key(*args, **kwargs)
46 |
47 | def auth_context(self, *args, **kwargs):
48 | return self._servicer_context.auth_context(*args, **kwargs)
49 |
50 | def send_initial_metadata(self, *args, **kwargs):
51 | return self._servicer_context.send_initial_metadata(*args, **kwargs)
52 |
53 | def set_trailing_metadata(self, *args, **kwargs):
54 | return self._servicer_context.set_trailing_metadata(*args, **kwargs)
55 |
56 | def set_code(self, code):
57 | self.code = code
58 | return self._servicer_context.set_code(code)
59 |
60 | def set_details(self, details):
61 | self.details = details
62 | return self._servicer_context.set_details(details)
63 |
64 | def get_active_span(self):
65 | return self._active_span
66 |
67 |
68 | def _add_peer_tags(peer_str, tags):
69 | ipv4_re = r"ipv4:(?P.+):(?P\d+)"
70 | match = re.match(ipv4_re, peer_str)
71 | if match:
72 | tags[ot_tags.PEER_HOST_IPV4] = match.group('address')
73 | tags[ot_tags.PEER_PORT] = match.group('port')
74 | return
75 | ipv6_re = r"ipv6:\[(?P.+)\]:(?P\d+)"
76 | match = re.match(ipv6_re, peer_str)
77 | if match:
78 | tags[ot_tags.PEER_HOST_IPV6] = match.group('address')
79 | tags[ot_tags.PEER_PORT] = match.group('port')
80 | return
81 | logging.warning('Unrecognized peer: \"%s\"', peer_str)
82 |
83 |
84 | # On the service-side, errors can be signaled either by exceptions or by calling
85 | # `set_code` on the `servicer_context`. This function checks for the latter and
86 | # updates the span accordingly.
87 | def _check_error_code(span, servicer_context, rpc_info):
88 | if servicer_context.code != grpc.StatusCode.OK:
89 | span.set_tag('error', True)
90 | error_log = {'event': 'error', 'error.kind': str(servicer_context.code)}
91 | if servicer_context.details is not None:
92 | error_log['message'] = servicer_context.details
93 | span.log_kv(error_log)
94 | rpc_info.error = servicer_context.code
95 |
96 |
97 | class OpenTracingServerInterceptor(grpcext.UnaryServerInterceptor,
98 | grpcext.StreamServerInterceptor):
99 |
100 | def __init__(self, tracer, log_payloads, span_decorator):
101 | self._tracer = tracer
102 | self._log_payloads = log_payloads
103 | self._span_decorator = span_decorator
104 |
105 | def _start_span(self, servicer_context, method):
106 | span_context = None
107 | error = None
108 | metadata = servicer_context.invocation_metadata()
109 | try:
110 | if metadata:
111 | span_context = self._tracer.extract(
112 | opentracing.Format.HTTP_HEADERS, dict(metadata))
113 | except (opentracing.UnsupportedFormatException,
114 | opentracing.InvalidCarrierException,
115 | opentracing.SpanContextCorruptedException) as e:
116 | logging.exception('tracer.extract() failed')
117 | error = e
118 | tags = {
119 | ot_tags.COMPONENT: 'grpc',
120 | ot_tags.SPAN_KIND: ot_tags.SPAN_KIND_RPC_SERVER
121 | }
122 | _add_peer_tags(servicer_context.peer(), tags)
123 | span = self._tracer.start_span(
124 | operation_name=method, child_of=span_context, tags=tags)
125 | if error is not None:
126 | span.log_kv({'event': 'error', 'error.object': error})
127 | return span
128 |
129 | def intercept_unary(self, request, servicer_context, server_info, handler):
130 | with self._start_span(servicer_context,
131 | server_info.full_method) as span:
132 | rpc_info = RpcInfo(
133 | full_method=server_info.full_method,
134 | metadata=servicer_context.invocation_metadata(),
135 | timeout=servicer_context.time_remaining(),
136 | request=request)
137 | if self._log_payloads:
138 | span.log_kv({'request': request})
139 | servicer_context = _OpenTracingServicerContext(
140 | servicer_context, span)
141 | try:
142 | response = handler(request, servicer_context)
143 | except:
144 | e = sys.exc_info()[0]
145 | span.set_tag('error', True)
146 | span.log_kv({'event': 'error', 'error.object': e})
147 | rpc_info.error = e
148 | if self._span_decorator is not None:
149 | self._span_decorator(span, rpc_info)
150 | raise
151 | if self._log_payloads:
152 | span.log_kv({'response': response})
153 | _check_error_code(span, servicer_context, rpc_info)
154 | rpc_info.response = response
155 | if self._span_decorator is not None:
156 | self._span_decorator(span, rpc_info)
157 | return response
158 |
159 | # For RPCs that stream responses, the result can be a generator. To record
160 | # the span across the generated responses and detect any errors, we wrap the
161 | # result in a new generator that yields the response values.
162 | def _intercept_server_stream(self, request_or_iterator, servicer_context,
163 | server_info, handler):
164 | with self._start_span(servicer_context,
165 | server_info.full_method) as span:
166 | rpc_info = RpcInfo(
167 | full_method=server_info.full_method,
168 | metadata=servicer_context.invocation_metadata(),
169 | timeout=servicer_context.time_remaining())
170 | if not server_info.is_client_stream:
171 | rpc_info.request = request_or_iterator
172 | if self._log_payloads:
173 | request_or_iterator = log_or_wrap_request_or_iterator(
174 | span, server_info.is_client_stream, request_or_iterator)
175 | servicer_context = _OpenTracingServicerContext(
176 | servicer_context, span)
177 | try:
178 | result = handler(request_or_iterator, servicer_context)
179 | for response in result:
180 | if self._log_payloads:
181 | span.log_kv({'response': response})
182 | yield response
183 | except:
184 | e = sys.exc_info()[0]
185 | span.set_tag('error', True)
186 | span.log_kv({'event': 'error', 'error.object': e})
187 | rpc_info.error = e
188 | if self._span_decorator is not None:
189 | self._span_decorator(span, rpc_info)
190 | raise
191 | _check_error_code(span, servicer_context, rpc_info)
192 | if self._span_decorator is not None:
193 | self._span_decorator(span, rpc_info)
194 |
195 | def intercept_stream(self, request_or_iterator, servicer_context,
196 | server_info, handler):
197 | if server_info.is_server_stream:
198 | return self._intercept_server_stream(
199 | request_or_iterator, servicer_context, server_info, handler)
200 | with self._start_span(servicer_context,
201 | server_info.full_method) as span:
202 | rpc_info = RpcInfo(
203 | full_method=server_info.full_method,
204 | metadata=servicer_context.invocation_metadata(),
205 | timeout=servicer_context.time_remaining())
206 | if self._log_payloads:
207 | request_or_iterator = log_or_wrap_request_or_iterator(
208 | span, server_info.is_client_stream, request_or_iterator)
209 | servicer_context = _OpenTracingServicerContext(
210 | servicer_context, span)
211 | try:
212 | response = handler(request_or_iterator, servicer_context)
213 | except:
214 | e = sys.exc_info()[0]
215 | span.set_tag('error', True)
216 | span.log_kv({'event': 'error', 'error.object': e})
217 | rpc_info.error = e
218 | if self._span_decorator is not None:
219 | self._span_decorator(span, rpc_info)
220 | raise
221 | if self._log_payloads:
222 | span.log_kv({'response': response})
223 | _check_error_code(span, servicer_context, rpc_info)
224 | rpc_info.response = response
225 | if self._span_decorator is not None:
226 | self._span_decorator(span, rpc_info)
227 | return response
228 |
--------------------------------------------------------------------------------
/java/src/main/java/io/opentracing/contrib/ClientTracingInterceptor.java:
--------------------------------------------------------------------------------
1 | package io.opentracing.contrib;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 | import io.grpc.*;
5 | import io.opentracing.Span;
6 | import io.opentracing.Tracer;
7 | import io.opentracing.propagation.Format;
8 | import io.opentracing.propagation.TextMap;
9 |
10 | import javax.annotation.Nullable;
11 | import java.util.Map.Entry;
12 | import java.util.*;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * An intercepter that applies tracing via OpenTracing to all client requests.
17 | */
18 | public class ClientTracingInterceptor implements ClientInterceptor {
19 |
20 | private final Tracer tracer;
21 | private final OperationNameConstructor operationNameConstructor;
22 | private final boolean streaming;
23 | private final boolean verbose;
24 | private final Set tracedAttributes;
25 | private final ActiveSpanSource activeSpanSource;
26 |
27 | /**
28 | * @param tracer to use to trace requests
29 | */
30 | public ClientTracingInterceptor(Tracer tracer) {
31 | this.tracer = tracer;
32 | this.operationNameConstructor = OperationNameConstructor.DEFAULT;
33 | this.streaming = false;
34 | this.verbose = false;
35 | this.tracedAttributes = new HashSet();
36 | this.activeSpanSource = ActiveSpanSource.GRPC_CONTEXT;
37 | }
38 |
39 | private ClientTracingInterceptor(Tracer tracer, OperationNameConstructor operationNameConstructor, boolean streaming,
40 | boolean verbose, Set tracedAttributes, ActiveSpanSource activeSpanSource) {
41 | this.tracer = tracer;
42 | this.operationNameConstructor = operationNameConstructor;
43 | this.streaming = streaming;
44 | this.verbose = verbose;
45 | this.tracedAttributes = tracedAttributes;
46 | this.activeSpanSource = activeSpanSource;
47 | }
48 |
49 | /**
50 | * Use this intercepter to trace all requests made by this client channel.
51 | * @param channel to be traced
52 | * @return intercepted channel
53 | */
54 | public Channel intercept(Channel channel) {
55 | return ClientInterceptors.intercept(channel, this);
56 | }
57 |
58 | @Override
59 | public ClientCall interceptCall(
60 | MethodDescriptor method,
61 | CallOptions callOptions,
62 | Channel next
63 | ) {
64 | final String operationName = operationNameConstructor.constructOperationName(method);
65 |
66 | Span activeSpan = this.activeSpanSource.getActiveSpan();
67 | final Span span = createSpanFromParent(activeSpan, operationName);
68 |
69 | for (ClientRequestAttribute attr : this.tracedAttributes) {
70 | switch (attr) {
71 | case ALL_CALL_OPTIONS:
72 | span.setTag("grpc.call_options", callOptions.toString());
73 | break;
74 | case AUTHORITY:
75 | if (callOptions.getAuthority() == null) {
76 | span.setTag("grpc.authority", "null");
77 | } else {
78 | span.setTag("grpc.authority", callOptions.getAuthority());
79 | }
80 | break;
81 | case COMPRESSOR:
82 | if (callOptions.getCompressor() == null) {
83 | span.setTag("grpc.compressor", "null");
84 | } else {
85 | span.setTag("grpc.compressor", callOptions.getCompressor());
86 | }
87 | break;
88 | case DEADLINE:
89 | if (callOptions.getDeadline() == null) {
90 | span.setTag("grpc.deadline_millis", "null");
91 | } else {
92 | span.setTag("grpc.deadline_millis", callOptions.getDeadline().timeRemaining(TimeUnit.MILLISECONDS));
93 | }
94 | break;
95 | case METHOD_NAME:
96 | span.setTag("grpc.method_name", method.getFullMethodName());
97 | break;
98 | case METHOD_TYPE:
99 | if (method.getType() == null) {
100 | span.setTag("grpc.method_type", "null");
101 | } else {
102 | span.setTag("grpc.method_type", method.getType().toString());
103 | }
104 | break;
105 | case HEADERS:
106 | break;
107 | }
108 | }
109 |
110 | return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) {
111 |
112 | @Override
113 | public void start(Listener responseListener, Metadata headers) {
114 | if (verbose) {
115 | span.log("Started call");
116 | }
117 | if (tracedAttributes.contains(ClientRequestAttribute.HEADERS)) {
118 | span.setTag("grpc.headers", headers.toString());
119 | }
120 |
121 | tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new TextMap() {
122 | @Override
123 | public void put(String key, String value) {
124 | Metadata.Key headerKey = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
125 | headers.put(headerKey, value);
126 | }
127 | @Override
128 | public Iterator> iterator() {
129 | throw new UnsupportedOperationException(
130 | "TextMapInjectAdapter should only be used with Tracer.inject()");
131 | }
132 | });
133 |
134 | Listener tracingResponseListener = new ForwardingClientCallListener
135 | .SimpleForwardingClientCallListener(responseListener) {
136 |
137 | @Override
138 | public void onHeaders(Metadata headers) {
139 | if (verbose) { span.log(ImmutableMap.of("Response headers received", headers.toString())); }
140 | delegate().onHeaders(headers);
141 | }
142 |
143 | @Override
144 | public void onMessage(RespT message) {
145 | if (streaming || verbose) { span.log("Response received"); }
146 | delegate().onMessage(message);
147 | }
148 |
149 | @Override
150 | public void onClose(Status status, Metadata trailers) {
151 | if (verbose) {
152 | if (status.getCode().value() == 0) { span.log("Call closed"); }
153 | else { span.log(ImmutableMap.of("Call failed", status.getDescription())); }
154 | }
155 | span.finish();
156 | delegate().onClose(status, trailers);
157 | }
158 | };
159 | delegate().start(tracingResponseListener, headers);
160 | }
161 |
162 | @Override
163 | public void cancel(@Nullable String message, @Nullable Throwable cause) {
164 | String errorMessage;
165 | if (message == null) {
166 | errorMessage = "Error";
167 | } else {
168 | errorMessage = message;
169 | }
170 | if (cause == null) {
171 | span.log(errorMessage);
172 | } else {
173 | span.log(ImmutableMap.of(errorMessage, cause.getMessage()));
174 | }
175 | delegate().cancel(message, cause);
176 | }
177 |
178 | @Override
179 | public void halfClose() {
180 | if (streaming) { span.log("Finished sending messages"); }
181 | delegate().halfClose();
182 | }
183 |
184 | @Override
185 | public void sendMessage(ReqT message) {
186 | if (streaming || verbose) { span.log("Message sent"); }
187 | delegate().sendMessage(message);
188 | }
189 | };
190 | }
191 |
192 | private Span createSpanFromParent(Span parentSpan, String operationName) {
193 | if (parentSpan == null) {
194 | return tracer.buildSpan(operationName).startManual();
195 | } else {
196 | return tracer.buildSpan(operationName).asChildOf(parentSpan).startManual();
197 | }
198 | }
199 |
200 | /**
201 | * Builds the configuration of a ClientTracingInterceptor.
202 | */
203 | public static class Builder {
204 |
205 | private Tracer tracer;
206 | private OperationNameConstructor operationNameConstructor;
207 | private boolean streaming;
208 | private boolean verbose;
209 | private Set tracedAttributes;
210 | private ActiveSpanSource activeSpanSource;
211 |
212 | /**
213 | * @param tracer to use for this intercepter
214 | * Creates a Builder with default configuration
215 | */
216 | public Builder(Tracer tracer) {
217 | this.tracer = tracer;
218 | this.operationNameConstructor = OperationNameConstructor.DEFAULT;
219 | this.streaming = false;
220 | this.verbose = false;
221 | this.tracedAttributes = new HashSet();
222 | this.activeSpanSource = ActiveSpanSource.GRPC_CONTEXT;
223 | }
224 |
225 | /**
226 | * @param operationNameConstructor to name all spans created by this intercepter
227 | * @return this Builder with configured operation name
228 | */
229 | public Builder withOperationName(OperationNameConstructor operationNameConstructor) {
230 | this.operationNameConstructor = operationNameConstructor;
231 | return this;
232 | }
233 |
234 | /**
235 | * Logs streaming events to client spans.
236 | * @return this Builder configured to log streaming events
237 | */
238 | public Builder withStreaming() {
239 | this.streaming = true;
240 | return this;
241 | }
242 |
243 | /**
244 | * @param tracedAttributes to set as tags on client spans
245 | * created by this intercepter
246 | * @return this Builder configured to trace attributes
247 | */
248 | public Builder withTracedAttributes(ClientRequestAttribute... tracedAttributes) {
249 | this.tracedAttributes = new HashSet(
250 | Arrays.asList(tracedAttributes));
251 | return this;
252 | }
253 |
254 | /**
255 | * Logs all request life-cycle events to client spans.
256 | * @return this Builder configured to be verbose
257 | */
258 | public Builder withVerbosity() {
259 | this.verbose = true;
260 | return this;
261 | }
262 |
263 | /**
264 | * @param activeSpanSource that provides a method of getting the
265 | * active span before the client call
266 | * @return this Builder configured to start client span as children
267 | * of the span returned by activeSpanSource.getActiveSpan()
268 | */
269 | public Builder withActiveSpanSource(ActiveSpanSource activeSpanSource) {
270 | this.activeSpanSource = activeSpanSource;
271 | return this;
272 | }
273 |
274 | /**
275 | * @return a ClientTracingInterceptor with this Builder's configuration
276 | */
277 | public ClientTracingInterceptor build() {
278 | return new ClientTracingInterceptor(this.tracer, this.operationNameConstructor,
279 | this.streaming, this.verbose, this.tracedAttributes, this.activeSpanSource);
280 | }
281 | }
282 |
283 | public enum ClientRequestAttribute {
284 | METHOD_TYPE,
285 | METHOD_NAME,
286 | DEADLINE,
287 | COMPRESSOR,
288 | AUTHORITY,
289 | ALL_CALL_OPTIONS,
290 | HEADERS
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/go/otgrpc/test/otgrpc_testing/test.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go.
2 | // source: test.proto
3 | // DO NOT EDIT!
4 |
5 | /*
6 | Package otgrpc_testing is a generated protocol buffer package.
7 |
8 | It is generated from these files:
9 | test.proto
10 |
11 | It has these top-level messages:
12 | SimpleRequest
13 | SimpleResponse
14 | */
15 | package otgrpc_testing
16 |
17 | import proto "github.com/golang/protobuf/proto"
18 | import fmt "fmt"
19 | import math "math"
20 |
21 | import (
22 | context "golang.org/x/net/context"
23 | grpc "google.golang.org/grpc"
24 | )
25 |
26 | // Reference imports to suppress errors if they are not otherwise used.
27 | var _ = proto.Marshal
28 | var _ = fmt.Errorf
29 | var _ = math.Inf
30 |
31 | // This is a compile-time assertion to ensure that this generated file
32 | // is compatible with the proto package it is being compiled against.
33 | // A compilation error at this line likely means your copy of the
34 | // proto package needs to be updated.
35 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
36 |
37 | type SimpleRequest struct {
38 | Payload int32 `protobuf:"varint,1,opt,name=payload" json:"payload,omitempty"`
39 | }
40 |
41 | func (m *SimpleRequest) Reset() { *m = SimpleRequest{} }
42 | func (m *SimpleRequest) String() string { return proto.CompactTextString(m) }
43 | func (*SimpleRequest) ProtoMessage() {}
44 | func (*SimpleRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
45 |
46 | func (m *SimpleRequest) GetPayload() int32 {
47 | if m != nil {
48 | return m.Payload
49 | }
50 | return 0
51 | }
52 |
53 | type SimpleResponse struct {
54 | Payload int32 `protobuf:"varint,1,opt,name=payload" json:"payload,omitempty"`
55 | }
56 |
57 | func (m *SimpleResponse) Reset() { *m = SimpleResponse{} }
58 | func (m *SimpleResponse) String() string { return proto.CompactTextString(m) }
59 | func (*SimpleResponse) ProtoMessage() {}
60 | func (*SimpleResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
61 |
62 | func (m *SimpleResponse) GetPayload() int32 {
63 | if m != nil {
64 | return m.Payload
65 | }
66 | return 0
67 | }
68 |
69 | func init() {
70 | proto.RegisterType((*SimpleRequest)(nil), "otgrpc.testing.SimpleRequest")
71 | proto.RegisterType((*SimpleResponse)(nil), "otgrpc.testing.SimpleResponse")
72 | }
73 |
74 | // Reference imports to suppress errors if they are not otherwise used.
75 | var _ context.Context
76 | var _ grpc.ClientConn
77 |
78 | // This is a compile-time assertion to ensure that this generated file
79 | // is compatible with the grpc package it is being compiled against.
80 | const _ = grpc.SupportPackageIsVersion4
81 |
82 | // Client API for TestService service
83 |
84 | type TestServiceClient interface {
85 | UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error)
86 | StreamingOutputCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error)
87 | StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error)
88 | StreamingBidirectionalCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingBidirectionalCallClient, error)
89 | }
90 |
91 | type testServiceClient struct {
92 | cc *grpc.ClientConn
93 | }
94 |
95 | func NewTestServiceClient(cc *grpc.ClientConn) TestServiceClient {
96 | return &testServiceClient{cc}
97 | }
98 |
99 | func (c *testServiceClient) UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error) {
100 | out := new(SimpleResponse)
101 | err := grpc.Invoke(ctx, "/otgrpc.testing.TestService/UnaryCall", in, out, c.cc, opts...)
102 | if err != nil {
103 | return nil, err
104 | }
105 | return out, nil
106 | }
107 |
108 | func (c *testServiceClient) StreamingOutputCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error) {
109 | stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[0], c.cc, "/otgrpc.testing.TestService/StreamingOutputCall", opts...)
110 | if err != nil {
111 | return nil, err
112 | }
113 | x := &testServiceStreamingOutputCallClient{stream}
114 | if err := x.ClientStream.SendMsg(in); err != nil {
115 | return nil, err
116 | }
117 | if err := x.ClientStream.CloseSend(); err != nil {
118 | return nil, err
119 | }
120 | return x, nil
121 | }
122 |
123 | type TestService_StreamingOutputCallClient interface {
124 | Recv() (*SimpleResponse, error)
125 | grpc.ClientStream
126 | }
127 |
128 | type testServiceStreamingOutputCallClient struct {
129 | grpc.ClientStream
130 | }
131 |
132 | func (x *testServiceStreamingOutputCallClient) Recv() (*SimpleResponse, error) {
133 | m := new(SimpleResponse)
134 | if err := x.ClientStream.RecvMsg(m); err != nil {
135 | return nil, err
136 | }
137 | return m, nil
138 | }
139 |
140 | func (c *testServiceClient) StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error) {
141 | stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[1], c.cc, "/otgrpc.testing.TestService/StreamingInputCall", opts...)
142 | if err != nil {
143 | return nil, err
144 | }
145 | x := &testServiceStreamingInputCallClient{stream}
146 | return x, nil
147 | }
148 |
149 | type TestService_StreamingInputCallClient interface {
150 | Send(*SimpleRequest) error
151 | CloseAndRecv() (*SimpleResponse, error)
152 | grpc.ClientStream
153 | }
154 |
155 | type testServiceStreamingInputCallClient struct {
156 | grpc.ClientStream
157 | }
158 |
159 | func (x *testServiceStreamingInputCallClient) Send(m *SimpleRequest) error {
160 | return x.ClientStream.SendMsg(m)
161 | }
162 |
163 | func (x *testServiceStreamingInputCallClient) CloseAndRecv() (*SimpleResponse, error) {
164 | if err := x.ClientStream.CloseSend(); err != nil {
165 | return nil, err
166 | }
167 | m := new(SimpleResponse)
168 | if err := x.ClientStream.RecvMsg(m); err != nil {
169 | return nil, err
170 | }
171 | return m, nil
172 | }
173 |
174 | func (c *testServiceClient) StreamingBidirectionalCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingBidirectionalCallClient, error) {
175 | stream, err := grpc.NewClientStream(ctx, &_TestService_serviceDesc.Streams[2], c.cc, "/otgrpc.testing.TestService/StreamingBidirectionalCall", opts...)
176 | if err != nil {
177 | return nil, err
178 | }
179 | x := &testServiceStreamingBidirectionalCallClient{stream}
180 | return x, nil
181 | }
182 |
183 | type TestService_StreamingBidirectionalCallClient interface {
184 | Send(*SimpleRequest) error
185 | Recv() (*SimpleResponse, error)
186 | grpc.ClientStream
187 | }
188 |
189 | type testServiceStreamingBidirectionalCallClient struct {
190 | grpc.ClientStream
191 | }
192 |
193 | func (x *testServiceStreamingBidirectionalCallClient) Send(m *SimpleRequest) error {
194 | return x.ClientStream.SendMsg(m)
195 | }
196 |
197 | func (x *testServiceStreamingBidirectionalCallClient) Recv() (*SimpleResponse, error) {
198 | m := new(SimpleResponse)
199 | if err := x.ClientStream.RecvMsg(m); err != nil {
200 | return nil, err
201 | }
202 | return m, nil
203 | }
204 |
205 | // Server API for TestService service
206 |
207 | type TestServiceServer interface {
208 | UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error)
209 | StreamingOutputCall(*SimpleRequest, TestService_StreamingOutputCallServer) error
210 | StreamingInputCall(TestService_StreamingInputCallServer) error
211 | StreamingBidirectionalCall(TestService_StreamingBidirectionalCallServer) error
212 | }
213 |
214 | func RegisterTestServiceServer(s *grpc.Server, srv TestServiceServer) {
215 | s.RegisterService(&_TestService_serviceDesc, srv)
216 | }
217 |
218 | func _TestService_UnaryCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
219 | in := new(SimpleRequest)
220 | if err := dec(in); err != nil {
221 | return nil, err
222 | }
223 | if interceptor == nil {
224 | return srv.(TestServiceServer).UnaryCall(ctx, in)
225 | }
226 | info := &grpc.UnaryServerInfo{
227 | Server: srv,
228 | FullMethod: "/otgrpc.testing.TestService/UnaryCall",
229 | }
230 | handler := func(ctx context.Context, req interface{}) (interface{}, error) {
231 | return srv.(TestServiceServer).UnaryCall(ctx, req.(*SimpleRequest))
232 | }
233 | return interceptor(ctx, in, info, handler)
234 | }
235 |
236 | func _TestService_StreamingOutputCall_Handler(srv interface{}, stream grpc.ServerStream) error {
237 | m := new(SimpleRequest)
238 | if err := stream.RecvMsg(m); err != nil {
239 | return err
240 | }
241 | return srv.(TestServiceServer).StreamingOutputCall(m, &testServiceStreamingOutputCallServer{stream})
242 | }
243 |
244 | type TestService_StreamingOutputCallServer interface {
245 | Send(*SimpleResponse) error
246 | grpc.ServerStream
247 | }
248 |
249 | type testServiceStreamingOutputCallServer struct {
250 | grpc.ServerStream
251 | }
252 |
253 | func (x *testServiceStreamingOutputCallServer) Send(m *SimpleResponse) error {
254 | return x.ServerStream.SendMsg(m)
255 | }
256 |
257 | func _TestService_StreamingInputCall_Handler(srv interface{}, stream grpc.ServerStream) error {
258 | return srv.(TestServiceServer).StreamingInputCall(&testServiceStreamingInputCallServer{stream})
259 | }
260 |
261 | type TestService_StreamingInputCallServer interface {
262 | SendAndClose(*SimpleResponse) error
263 | Recv() (*SimpleRequest, error)
264 | grpc.ServerStream
265 | }
266 |
267 | type testServiceStreamingInputCallServer struct {
268 | grpc.ServerStream
269 | }
270 |
271 | func (x *testServiceStreamingInputCallServer) SendAndClose(m *SimpleResponse) error {
272 | return x.ServerStream.SendMsg(m)
273 | }
274 |
275 | func (x *testServiceStreamingInputCallServer) Recv() (*SimpleRequest, error) {
276 | m := new(SimpleRequest)
277 | if err := x.ServerStream.RecvMsg(m); err != nil {
278 | return nil, err
279 | }
280 | return m, nil
281 | }
282 |
283 | func _TestService_StreamingBidirectionalCall_Handler(srv interface{}, stream grpc.ServerStream) error {
284 | return srv.(TestServiceServer).StreamingBidirectionalCall(&testServiceStreamingBidirectionalCallServer{stream})
285 | }
286 |
287 | type TestService_StreamingBidirectionalCallServer interface {
288 | Send(*SimpleResponse) error
289 | Recv() (*SimpleRequest, error)
290 | grpc.ServerStream
291 | }
292 |
293 | type testServiceStreamingBidirectionalCallServer struct {
294 | grpc.ServerStream
295 | }
296 |
297 | func (x *testServiceStreamingBidirectionalCallServer) Send(m *SimpleResponse) error {
298 | return x.ServerStream.SendMsg(m)
299 | }
300 |
301 | func (x *testServiceStreamingBidirectionalCallServer) Recv() (*SimpleRequest, error) {
302 | m := new(SimpleRequest)
303 | if err := x.ServerStream.RecvMsg(m); err != nil {
304 | return nil, err
305 | }
306 | return m, nil
307 | }
308 |
309 | var _TestService_serviceDesc = grpc.ServiceDesc{
310 | ServiceName: "otgrpc.testing.TestService",
311 | HandlerType: (*TestServiceServer)(nil),
312 | Methods: []grpc.MethodDesc{
313 | {
314 | MethodName: "UnaryCall",
315 | Handler: _TestService_UnaryCall_Handler,
316 | },
317 | },
318 | Streams: []grpc.StreamDesc{
319 | {
320 | StreamName: "StreamingOutputCall",
321 | Handler: _TestService_StreamingOutputCall_Handler,
322 | ServerStreams: true,
323 | },
324 | {
325 | StreamName: "StreamingInputCall",
326 | Handler: _TestService_StreamingInputCall_Handler,
327 | ClientStreams: true,
328 | },
329 | {
330 | StreamName: "StreamingBidirectionalCall",
331 | Handler: _TestService_StreamingBidirectionalCall_Handler,
332 | ServerStreams: true,
333 | ClientStreams: true,
334 | },
335 | },
336 | Metadata: "test.proto",
337 | }
338 |
339 | func init() { proto.RegisterFile("test.proto", fileDescriptor0) }
340 |
341 | var fileDescriptor0 = []byte{
342 | // 210 bytes of a gzipped FileDescriptorProto
343 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x49, 0x2d, 0x2e,
344 | 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xcb, 0x2f, 0x49, 0x2f, 0x2a, 0x48, 0xd6, 0x03,
345 | 0x09, 0x65, 0xe6, 0xa5, 0x2b, 0x69, 0x72, 0xf1, 0x06, 0x67, 0xe6, 0x16, 0xe4, 0xa4, 0x06, 0xa5,
346 | 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x49, 0x70, 0xb1, 0x17, 0x24, 0x56, 0xe6, 0xe4, 0x27, 0xa6,
347 | 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x06, 0xc1, 0xb8, 0x4a, 0x5a, 0x5c, 0x7c, 0x30, 0xa5, 0xc5,
348 | 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0xb8, 0xd5, 0x1a, 0xbd, 0x64, 0xe2, 0xe2, 0x0e, 0x49, 0x2d, 0x2e,
349 | 0x09, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x15, 0xf2, 0xe2, 0xe2, 0x0c, 0xcd, 0x4b, 0x2c, 0xaa,
350 | 0x74, 0x4e, 0xcc, 0xc9, 0x11, 0x92, 0xd5, 0x43, 0x75, 0x84, 0x1e, 0x8a, 0x0b, 0xa4, 0xe4, 0x70,
351 | 0x49, 0x43, 0x6d, 0x0d, 0xe3, 0x12, 0x0e, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0xcd, 0xcc, 0x4b, 0xf7,
352 | 0x2f, 0x2d, 0x29, 0x28, 0x2d, 0xa1, 0x82, 0xa9, 0x06, 0x8c, 0x42, 0xa1, 0x5c, 0x42, 0x70, 0x73,
353 | 0x3d, 0xf3, 0xa8, 0x63, 0xac, 0x06, 0xa3, 0x50, 0x3c, 0x97, 0x14, 0xdc, 0x58, 0xa7, 0xcc, 0x94,
354 | 0xcc, 0xa2, 0xd4, 0xe4, 0x92, 0xcc, 0xfc, 0xbc, 0xc4, 0x1c, 0xaa, 0x18, 0x6f, 0xc0, 0x98, 0xc4,
355 | 0x06, 0x8e, 0x59, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x50, 0x3e, 0xe4, 0xe7, 0x01,
356 | 0x00, 0x00,
357 | }
358 |
--------------------------------------------------------------------------------
/java/README.rst:
--------------------------------------------------------------------------------
1 | #####################
2 | GRPC-Java OpenTracing
3 | #####################
4 |
5 | ============
6 | Installation
7 | ============
8 |
9 | This package is available on Maven Central and can be added to your project as follows:
10 |
11 | **Maven**
12 |
13 | .. code-block::
14 |
15 |
16 |
17 | io.opentracing.contrib
18 | grpc-opentracing
19 | 0.2.0
20 |
21 |
22 |
23 | **Gradle**
24 |
25 | .. code-block::
26 |
27 | compile 'io.opentracing.contrib:grpc-opentracing:0.2.0'
28 |
29 | ==========
30 | Quickstart
31 | ==========
32 |
33 | 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.)
34 |
35 | **Servers**
36 |
37 | - Instantiate a tracer
38 | - Create a ``ServerTracingInterceptor``
39 | - Intercept a service
40 | - (Optional) Access the `current span`_
41 |
42 | .. _current span: `Current Span Context`_
43 |
44 | .. code-block:: java
45 |
46 | import io.opentracing.Tracer;
47 |
48 | public class YourServer {
49 |
50 | private int port;
51 | private Server server;
52 | // Any io.opentracing.Tracer implementation will do here. For instance,
53 | // https://github.com/uber/jaeger-client-java/blob/master/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
54 | // generates Zipkin-compatible data.
55 | private final Tracer tracer;
56 |
57 | private void start() throws IOException {
58 | ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(this.tracer);
59 |
60 | server = ServerBuilder.forPort(port)
61 | .addService(tracingInterceptor.intercept(someServiceDef))
62 | .build()
63 | .start();
64 | }
65 | }
66 |
67 | **Clients**
68 |
69 | - Instantiate a tracer
70 | - Create a ``ClientTracingInterceptor``
71 | - Intercept the client channel
72 |
73 | .. code-block:: java
74 |
75 | import io.opentracing.Tracer;
76 |
77 | public class YourClient {
78 |
79 | private final ManagedChannel channel;
80 | private final GreeterGrpc.GreeterBlockingStub blockingStub;
81 | // Any io.opentracing.Tracer implementation will do here. For instance,
82 | // https://github.com/uber/jaeger-client-java/blob/master/jaeger-core/src/main/java/com/uber/jaeger/Tracer.java
83 | // generates Zipkin-compatible data.
84 | private final Tracer tracer;
85 |
86 | public YourClient(String host, int port) {
87 |
88 | channel = ManagedChannelBuilder.forAddress(host, port)
89 | .usePlaintext(true)
90 | .build();
91 |
92 | ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(this.tracer)
93 |
94 | blockingStub = GreeterGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
95 | }
96 | }
97 |
98 | There's an example of a simple traced client (`TracedClient`) and server (`TracedService`) in `src/test`.
99 |
100 | ==============
101 | Server Tracing
102 | ==============
103 |
104 | A ``ServerTracingInterceptor`` uses default settings, which you can override by creating it using a ``ServerTracingInterceptor.Builder``.
105 |
106 | - ``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.
107 | - ``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.
108 | - ``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.
109 | - ``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.
110 |
111 | **Example**:
112 |
113 | .. code-block:: java
114 |
115 | ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor
116 | .Builder(tracer)
117 | .withStreaming()
118 | .withVerbosity()
119 | .withOperationName(new OperationNameConstructor() {
120 | @Override
121 | public String constructOperationName(MethodDescriptor method) {
122 | // construct some operation name from the method descriptor
123 | }
124 | })
125 | .withTracedAttributes(ServerRequestAttribute.HEADERS,
126 | ServerRequestAttribute.METHOD_TYPE)
127 | .build();
128 |
129 | ==============
130 | Client Tracing
131 | ==============
132 |
133 | A ``ClientTracingInterceptor`` also has default settings, which you can override by creating it using a ``ClientTracingInterceptor.Builder``.
134 |
135 | - ``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.
136 | - ``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.
137 | - ``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.
138 | - ``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.
139 | - ``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.
140 |
141 | **Example**:
142 |
143 | .. code-block:: java
144 |
145 | import io.opentracing.Span;
146 |
147 | ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor
148 | .Builder(tracer)
149 | .withStreaming()
150 | .withVerbosity()
151 | .withOperationName(new OperationNameConstructor() {
152 | @Override
153 | public String constructOperationName(MethodDescriptor method) {
154 | // construct some operation name from the method descriptor
155 | }
156 | })
157 | .withActiveSpanSource(new ActiveSpanSource() {
158 | @Override
159 | public Span getActiveSpan() {
160 | // implement how to get the current active span, for example:
161 | return OpenTracingContextKey.activeSpan();
162 | }
163 | })
164 | .withTracingAttributes(ClientRequestAttribute.ALL_CALL_OPTIONS,
165 | ClientRequestAttribute.HEADERS)
166 | .build();
167 |
168 | .. _Operation Name: `Operation Names`_
169 | .. _Active Span Source: `Active Span Sources`_
170 |
171 | ====================
172 | Current Span Context
173 | ====================
174 |
175 | In your server request handler, you can access the current active span for that request by calling
176 |
177 | .. code-block:: java
178 |
179 | Span span = OpenTracingContextKey.activeSpan();
180 |
181 | 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.
182 |
183 | For example:
184 |
185 | .. code-block:: java
186 |
187 | Tracer tracer = ...;
188 |
189 | // some unit of internal work that you want to trace
190 | Runnable internalWork = someInternalWork
191 |
192 | // a wrapper that traces the work of the runnable
193 | class TracedRunnable implements Runnable {
194 | Runnable work;
195 | Tracer tracer;
196 |
197 | TracedRunnable(Runnable work, Tracer tracer) {
198 | this.work = work;
199 | this.tracer = tracer;
200 | }
201 |
202 | public void run() {
203 |
204 | // create a child span for the current active span
205 | Span span = tracer
206 | .buildSpan("internal-work")
207 | .asChildOf(OpenTracingContextKey.activeSpan())
208 | .start();
209 |
210 | // create a new context with the child span as the active span
211 | Context contextWithNewSpan = Context.current()
212 | .withValue(OpenTracingContextKey.get(), span);
213 |
214 | // wrap the original work and run it
215 | Runnable tracedWork = contextWithNewSpan.wrap(this.work);
216 | tracedWork.run();
217 |
218 | // make sure to finish any manually created spans!
219 | span.finish();
220 | }
221 | }
222 |
223 | Runnable tracedInternalWork = new TracedRunnable(internalWork, tracer);
224 | tracedInternalWork.run();
225 |
226 | ===============
227 | Operation Names
228 | ===============
229 |
230 | 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`_.
231 |
232 | 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:
233 |
234 | .. code-block:: java
235 |
236 | ClientTracingInterceptor interceptor = ClientTracingInterceptor.Builder ...
237 | .withOperationName(new OperationNameConstructor() {
238 | @Override
239 | public String constructOperationName(MethodDescriptor method) {
240 | return "your-prefix" + method.getFullMethodName();
241 | }
242 | })
243 | .with....
244 | .build()
245 |
246 | .. _semantics: http://opentracing.io/spec/#operation-names
247 |
248 | ===================
249 | Active Span Sources
250 | ===================
251 |
252 | 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.
253 |
254 | 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:
255 |
256 | .. code-block:: java
257 |
258 | import io.opentracing.Span;
259 |
260 | ClientTracingInterceptor interceptor = new ClientTracingInterceptor
261 | .Builder(tracer)
262 | ...
263 | .withActiveSpanSource(new ActiveSpanSource() {
264 | @Override
265 | public Span getActiveSpan() {
266 | return Context.get(OPENTRACING_SPAN_KEY);
267 | }
268 | })
269 | ...
270 | .build();
271 |
272 | We also provide two built-in implementations:
273 |
274 | * ``ActiveSpanSource.GRPC_CONTEXT`` uses the current ``io.grpc.Context`` and returns the active span for ``OpenTracingContextKey``. This is the default active span source.
275 | * ``ActiveSpanSource.NONE`` always returns null as the active span, which means the client will always start a new trace
276 |
277 | ===================================
278 | Integrating with Other Interceptors
279 | ===================================
280 |
281 | 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):
282 |
283 | **Servers**
284 |
285 | .. code-block:: java
286 |
287 | server = ServerBuilder.forPort(port)
288 | .addService(ServerInterceptors.intercept(service, someInterceptor,
289 | someOtherInterceptor, serverTracingInterceptor))
290 | .build()
291 | .start();
292 |
293 | **Clients**
294 |
295 | .. code-block:: java
296 |
297 | blockingStub = GreeterGrpc.newBlockingStub(ClientInterceptors.intercept(channel,
298 | someInterceptor, someOtherInterceptor, clientTracingInterceptor));
299 |
300 | ======================
301 | Releasing new versions
302 | ======================
303 |
304 | Create a gradle.properties in this directory. It should look approximately like this:
305 |
306 | .. code-block::
307 |
308 | sonatypeUsername=bensigelman
309 | sonatypePassword=
310 | signing.keyId=<`gpg --list-keys` output, minus the prefix like "2048R/">
311 | signing.password=
312 | signing.secretKeyRingFile=/Your/Homedir/.gnupg/secring.gpg
313 |
314 | Then run:
315 |
316 | .. code-block::
317 |
318 | $ gradle uploadArchives closeAndPromoteRepository
319 |
320 |
--------------------------------------------------------------------------------