3333from opentelemetry .trace .status import Status , StatusCode
3434
3535
36- class _GuardedSpan :
37- def __init__ (self , span ):
38- self .span = span
39- self .generated_span = None
40- self ._engaged = True
41-
42- def __enter__ (self ):
43- self .generated_span = self .span .__enter__ ()
44- return self
45-
46- def __exit__ (self , * args , ** kwargs ):
47- if self ._engaged :
48- self .generated_span = None
49- return self .span .__exit__ (* args , ** kwargs )
50- return False
51-
52- def release (self ):
53- self ._engaged = False
54- return self .span
55-
56-
5736class _CarrierSetter (Setter ):
5837 """We use a custom setter in order to be able to lower case
5938 keys as is required by grpc.
@@ -68,7 +47,7 @@ def set(self, carrier: MutableMapping[str, str], key: str, value: str):
6847
6948def _make_future_done_callback (span , rpc_info ):
7049 def callback (response_future ):
71- with span :
50+ with trace . use_span ( span , end_on_exit = True ) :
7251 code = response_future .code ()
7352 if code != grpc .StatusCode .OK :
7453 rpc_info .error = code
@@ -85,7 +64,7 @@ class OpenTelemetryClientInterceptor(
8564 def __init__ (self , tracer ):
8665 self ._tracer = tracer
8766
88- def _start_span (self , method ):
67+ def _start_span (self , method , ** kwargs ):
8968 service , meth = method .lstrip ("/" ).split ("/" , 1 )
9069 attributes = {
9170 SpanAttributes .RPC_SYSTEM : "grpc" ,
@@ -95,16 +74,19 @@ def _start_span(self, method):
9574 }
9675
9776 return self ._tracer .start_as_current_span (
98- name = method , kind = trace .SpanKind .CLIENT , attributes = attributes
77+ name = method ,
78+ kind = trace .SpanKind .CLIENT ,
79+ attributes = attributes ,
80+ ** kwargs ,
9981 )
10082
10183 # pylint:disable=no-self-use
102- def _trace_result (self , guarded_span , rpc_info , result ):
103- # If the RPC is called asynchronously, release the guard and add a
104- # callback so that the span can be finished once the future is done.
84+ def _trace_result (self , span , rpc_info , result ):
85+ # If the RPC is called asynchronously, add a callback to end the span
86+ # when the future is done, else end the span immediately
10587 if isinstance (result , grpc .Future ):
10688 result .add_done_callback (
107- _make_future_done_callback (guarded_span . release () , rpc_info )
89+ _make_future_done_callback (span , rpc_info )
10890 )
10991 return result
11092 response = result
@@ -115,41 +97,54 @@ def _trace_result(self, guarded_span, rpc_info, result):
11597 if isinstance (result , tuple ):
11698 response = result [0 ]
11799 rpc_info .response = response
118-
100+ span . end ()
119101 return result
120102
121- def _start_guarded_span (self , * args , ** kwargs ):
122- return _GuardedSpan (self ._start_span (* args , ** kwargs ))
123-
124- def intercept_unary (self , request , metadata , client_info , invoker ):
103+ def _intercept (self , request , metadata , client_info , invoker ):
125104 if not metadata :
126105 mutable_metadata = OrderedDict ()
127106 else :
128107 mutable_metadata = OrderedDict (metadata )
129-
130- with self ._start_guarded_span (client_info .full_method ) as guarded_span :
131- inject (mutable_metadata , setter = _carrier_setter )
132- metadata = tuple (mutable_metadata .items ())
133-
134- rpc_info = RpcInfo (
135- full_method = client_info .full_method ,
136- metadata = metadata ,
137- timeout = client_info .timeout ,
138- request = request ,
139- )
140-
108+ with self ._start_span (
109+ client_info .full_method ,
110+ end_on_exit = False ,
111+ record_exception = False ,
112+ set_status_on_exception = False ,
113+ ) as span :
114+ result = None
141115 try :
142- result = invoker (request , metadata )
143- except grpc .RpcError as err :
144- guarded_span .generated_span .set_status (
145- Status (StatusCode .ERROR )
116+ inject (mutable_metadata , setter = _carrier_setter )
117+ metadata = tuple (mutable_metadata .items ())
118+
119+ rpc_info = RpcInfo (
120+ full_method = client_info .full_method ,
121+ metadata = metadata ,
122+ timeout = client_info .timeout ,
123+ request = request ,
146124 )
147- guarded_span .generated_span .set_attribute (
148- SpanAttributes .RPC_GRPC_STATUS_CODE , err .code ().value [0 ]
125+
126+ result = invoker (request , metadata )
127+ except Exception as exc :
128+ if isinstance (exc , grpc .RpcError ):
129+ span .set_attribute (
130+ SpanAttributes .RPC_GRPC_STATUS_CODE ,
131+ exc .code ().value [0 ],
132+ )
133+ span .set_status (
134+ Status (
135+ status_code = StatusCode .ERROR ,
136+ description = "{}: {}" .format (type (exc ).__name__ , exc ),
137+ )
149138 )
150- raise err
139+ span .record_exception (exc )
140+ raise exc
141+ finally :
142+ if not result :
143+ span .end ()
144+ return self ._trace_result (span , rpc_info , result )
151145
152- return self ._trace_result (guarded_span , rpc_info , result )
146+ def intercept_unary (self , request , metadata , client_info , invoker ):
147+ return self ._intercept (request , metadata , client_info , invoker )
153148
154149 # For RPCs that stream responses, the result can be a generator. To record
155150 # the span across the generated responses and detect any errors, we wrap
@@ -194,32 +189,6 @@ def intercept_stream(
194189 request_or_iterator , metadata , client_info , invoker
195190 )
196191
197- if not metadata :
198- mutable_metadata = OrderedDict ()
199- else :
200- mutable_metadata = OrderedDict (metadata )
201-
202- with self ._start_guarded_span (client_info .full_method ) as guarded_span :
203- inject (mutable_metadata , setter = _carrier_setter )
204- metadata = tuple (mutable_metadata .items ())
205- rpc_info = RpcInfo (
206- full_method = client_info .full_method ,
207- metadata = metadata ,
208- timeout = client_info .timeout ,
209- request = request_or_iterator ,
210- )
211-
212- rpc_info .request = request_or_iterator
213-
214- try :
215- result = invoker (request_or_iterator , metadata )
216- except grpc .RpcError as err :
217- guarded_span .generated_span .set_status (
218- Status (StatusCode .ERROR )
219- )
220- guarded_span .generated_span .set_attribute (
221- SpanAttributes .RPC_GRPC_STATUS_CODE , err .code ().value [0 ],
222- )
223- raise err
224-
225- return self ._trace_result (guarded_span , rpc_info , result )
192+ return self ._intercept (
193+ request_or_iterator , metadata , client_info , invoker
194+ )
0 commit comments