Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit 724bd0b

Browse files
nikhaldic24t
authored andcommitted
Fix gRPC client interceptor for channels reused across traces (#539)
In a typical web server gRPC clients/channels are reused across multiple requests and hence across multiple traces. Previously the `OpenCensusClientInterceptor` was instantiated for each channel with the current tracer from the execution context. This would then lead to all rpcs going through that channel to have the same tracer, essentially grouping all rpcs under whatever happened to be the current trace when the channel was created. Instead instantiate `OpenCensusClientInterceptor` without a tracer by default. The current tracer will be retrieved from the execution context at the start of every rpc span.
1 parent 913d588 commit 724bd0b

File tree

5 files changed

+8
-57
lines changed

5 files changed

+8
-57
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Fix gRPC client tracer reuse bug
6+
([#539](https://github.com/census-instrumentation/opencensus-python/pull/539))
57
- Fix bugs in Prometheus exporter. Use ordered list for histogram buckets.
68
Use `UnknownMetricFamily` for `SumData` instead of `UntypedMetricFamily`.
79
Check if label keys and values match before exporting.

contrib/opencensus-ext-google-cloud-clientlibs/opencensus/ext/google_cloud_clientlibs/trace.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from google.cloud import _helpers
2020
from google.api_core import grpc_helpers
2121

22-
from opencensus.trace import execution_context
2322
from opencensus.ext.grpc.client_interceptor import (
2423
OpenCensusClientInterceptor)
2524

@@ -89,11 +88,7 @@ def call(*args, **kwargs):
8988

9089
try:
9190
host = kwargs.get('host')
92-
if tracer is None:
93-
_tracer = execution_context.get_opencensus_tracer()
94-
else: # pragma: NO COVER
95-
_tracer = tracer
96-
tracer_interceptor = OpenCensusClientInterceptor(_tracer, host)
91+
tracer_interceptor = OpenCensusClientInterceptor(tracer, host)
9792
intercepted_channel = grpc.intercept_channel(
9893
channel, tracer_interceptor)
9994
return intercepted_channel # pragma: NO COVER
@@ -112,11 +107,7 @@ def call(*args, **kwargs):
112107

113108
try:
114109
target = kwargs.get('target')
115-
if tracer is None:
116-
_tracer = execution_context.get_opencensus_tracer()
117-
else: # pragma: NO COVER
118-
_tracer = tracer
119-
tracer_interceptor = OpenCensusClientInterceptor(_tracer, target)
110+
tracer_interceptor = OpenCensusClientInterceptor(tracer, target)
120111
intercepted_channel = grpc.intercept_channel(
121112
channel, tracer_interceptor)
122113
return intercepted_channel # pragma: NO COVER
@@ -135,11 +126,7 @@ def call(*args, **kwargs):
135126

136127
try:
137128
target = kwargs.get('target')
138-
if tracer is None:
139-
_tracer = execution_context.get_opencensus_tracer()
140-
else: # pragma: NO COVER
141-
_tracer = tracer
142-
tracer_interceptor = OpenCensusClientInterceptor(_tracer, target)
129+
tracer_interceptor = OpenCensusClientInterceptor(tracer, target)
143130
intercepted_channel = grpc.intercept_channel(
144131
channel, tracer_interceptor)
145132
return intercepted_channel # pragma: NO COVER

contrib/opencensus-ext-google-cloud-clientlibs/tests/test_google_cloud_clientlibs_trace.py

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,62 +74,46 @@ def test_trace_http(self):
7474
self.assertTrue(mock_trace_requests.called)
7575

7676
def test_wrap_make_secure_channel(self):
77-
mock_tracer = mock.Mock()
7877
mock_interceptor = mock.Mock()
7978
mock_func = mock.Mock()
8079

81-
patch_tracer = mock.patch(
82-
'opencensus.ext.google_cloud_clientlibs.trace'
83-
'.execution_context.'
84-
'get_opencensus_tracer',
85-
return_value=mock_tracer)
8680
patch_interceptor = mock.patch(
8781
'opencensus.ext.google_cloud_clientlibs.trace'
8882
'.OpenCensusClientInterceptor', mock_interceptor)
8983

9084
wrapped = trace.wrap_make_secure_channel(mock_func)
9185

92-
with patch_tracer, patch_interceptor:
86+
with patch_interceptor:
9387
wrapped()
9488

9589
self.assertTrue(mock_interceptor.called)
9690

9791
def test_wrap_insecure_channel(self):
98-
mock_tracer = mock.Mock()
9992
mock_interceptor = mock.Mock()
10093
mock_func = mock.Mock()
10194

102-
patch_tracer = mock.patch(
103-
'opencensus.ext.google_cloud_clientlibs.trace'
104-
'.execution_context.get_opencensus_tracer',
105-
return_value=mock_tracer)
10695
patch_interceptor = mock.patch(
10796
'opencensus.ext.google_cloud_clientlibs.trace'
10897
'.OpenCensusClientInterceptor', mock_interceptor)
10998

11099
wrapped = trace.wrap_insecure_channel(mock_func)
111100

112-
with patch_tracer, patch_interceptor:
101+
with patch_interceptor:
113102
wrapped()
114103

115104
self.assertTrue(mock_interceptor.called)
116105

117106
def test_wrap_create_channel(self):
118-
mock_tracer = mock.Mock()
119107
mock_interceptor = mock.Mock()
120108
mock_func = mock.Mock()
121109

122-
patch_tracer = mock.patch(
123-
'opencensus.ext.google_cloud_clientlibs.trace'
124-
'.execution_context.get_opencensus_tracer',
125-
return_value=mock_tracer)
126110
patch_interceptor = mock.patch(
127111
'opencensus.ext.google_cloud_clientlibs.trace'
128112
'.OpenCensusClientInterceptor', mock_interceptor)
129113

130114
wrapped = trace.wrap_create_channel(mock_func)
131115

132-
with patch_tracer, patch_interceptor:
116+
with patch_interceptor:
133117
wrapped()
134118

135119
self.assertTrue(mock_interceptor.called)

contrib/opencensus-ext-grpc/opencensus/ext/grpc/client_interceptor.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,8 @@ def _start_client_span(self, client_call_details):
8686
attribute_key=attributes_helper.GRPC_ATTRIBUTES.get(GRPC_METHOD),
8787
attribute_value=str(client_call_details.method))
8888

89-
execution_context.set_opencensus_tracer(self.tracer)
90-
execution_context.set_current_span(span)
91-
9289
return span
9390

94-
def _end_span_between_context(self, current_span):
95-
execution_context.set_current_span(current_span)
96-
self.tracer.end_span()
97-
9891
def _intercept_call(
9992
self, client_call_details, request_iterator, grpc_type
10093
):
@@ -139,7 +132,6 @@ def callback(future_response):
139132
span=current_span,
140133
message_event_type=time_event.Type.RECEIVED,
141134
)
142-
execution_context.set_current_span(current_span)
143135
self._trace_future_exception(future_response)
144136
self.tracer.end_span()
145137

contrib/opencensus-ext-grpc/tests/test_client_interceptor.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,6 @@ def test__start_client_span(self):
6161
self.assertTrue(tracer.start_span.called)
6262
self.assertTrue(tracer.add_attribute_to_current_span.called)
6363

64-
def test__end_span_between_context(self):
65-
from opencensus.trace import execution_context
66-
67-
current_span = mock.Mock()
68-
tracer = mock.Mock()
69-
interceptor = client_interceptor.OpenCensusClientInterceptor(
70-
tracer=tracer, host_port='test')
71-
interceptor._end_span_between_context(current_span)
72-
73-
span_in_context = execution_context.get_current_span()
74-
75-
self.assertEqual(span_in_context, current_span)
76-
self.assertTrue(tracer.end_span.called)
77-
7864
def test__intercept_call_metadata_none(self):
7965
tracer = mock.Mock()
8066
tracer.span_context = mock.Mock()

0 commit comments

Comments
 (0)