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

Commit ad75bf5

Browse files
authored
Improve the integration modules to share tracer between threads (#133)
1 parent 8a10cde commit ad75bf5

File tree

12 files changed

+110
-34
lines changed

12 files changed

+110
-34
lines changed

opencensus/trace/config_integration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
PATH_PREFIX = 'opencensus.trace.ext'
2424

2525

26-
def trace_integrations(integrations):
26+
def trace_integrations(integrations, tracer=None):
2727
"""Enable tracing on the selected integrations.
2828
2929
:type integrations: list
@@ -35,7 +35,7 @@ def trace_integrations(integrations):
3535
try:
3636
path_to_module = '{}.{}.trace'.format(PATH_PREFIX, item)
3737
module = importlib.import_module(path_to_module)
38-
module.trace_integration()
38+
module.trace_integration(tracer=tracer)
3939
integrated.append(item)
4040
except Exception:
4141
log.warning(

opencensus/trace/ext/google_cloud_clientlibs/trace.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,25 @@
3535
CREATE_CHANNEL = 'create_channel'
3636

3737

38-
def trace_integration():
38+
def trace_integration(tracer=None):
3939
"""Trace the Google Cloud Client libraries by integrating with
4040
the transport level including HTTP and gRPC.
4141
"""
4242
log.info('Integrated module: {}'.format(MODULE_NAME))
4343

4444
# Integrate with gRPC
45-
trace_grpc()
45+
trace_grpc(tracer)
4646

4747
# Integrate with HTTP
48-
trace_http()
48+
trace_http(tracer)
4949

5050

51-
def trace_grpc():
51+
def trace_grpc(tracer=None):
5252
"""Integrate with gRPC."""
5353
# Wrap google.cloud._helpers.make_secure_channel
5454
make_secure_channel_func = getattr(_helpers, MAKE_SECURE_CHANNEL)
5555
make_secure_channel_wrapped = wrap_make_secure_channel(
56-
make_secure_channel_func)
56+
make_secure_channel_func, tracer)
5757
setattr(
5858
_helpers,
5959
MAKE_SECURE_CHANNEL,
@@ -62,34 +62,37 @@ def trace_grpc():
6262
# Wrap the grpc.insecure_channel.
6363
insecure_channel_func = getattr(grpc, INSECURE_CHANNEL)
6464
insecure_channel_wrapped = wrap_insecure_channel(
65-
insecure_channel_func)
65+
insecure_channel_func, tracer)
6666
setattr(
6767
grpc,
6868
INSECURE_CHANNEL,
6969
insecure_channel_wrapped)
7070

7171
# Wrap google.api_core.grpc_helpers.create_channel
7272
create_channel_func = getattr(grpc_helpers, CREATE_CHANNEL)
73-
create_channel_wrapped = wrap_create_channel(create_channel_func)
73+
create_channel_wrapped = wrap_create_channel(create_channel_func, tracer)
7474
setattr(
7575
grpc_helpers,
7676
CREATE_CHANNEL,
7777
create_channel_wrapped)
7878

7979

80-
def trace_http():
80+
def trace_http(tracer=None):
8181
"""Integrate with HTTP (requests library)."""
82-
trace_requests()
82+
trace_requests(tracer)
8383

8484

85-
def wrap_make_secure_channel(make_secure_channel_func):
85+
def wrap_make_secure_channel(make_secure_channel_func, tracer=None):
8686
"""Wrap the google.cloud._helpers.make_secure_channel."""
8787
def call(*args, **kwargs):
8888
channel = make_secure_channel_func(*args, **kwargs)
8989

9090
try:
9191
host = kwargs.get('host')
92-
_tracer = execution_context.get_opencensus_tracer()
92+
if tracer is None:
93+
_tracer = execution_context.get_opencensus_tracer()
94+
else: # pragma: NO COVER
95+
_tracer = tracer
9396
tracer_interceptor = OpenCensusClientInterceptor(_tracer, host)
9497
intercepted_channel = grpc.intercept_channel(
9598
channel, tracer_interceptor)
@@ -102,14 +105,17 @@ def call(*args, **kwargs):
102105
return call
103106

104107

105-
def wrap_insecure_channel(insecure_channel_func):
108+
def wrap_insecure_channel(insecure_channel_func, tracer=None):
106109
"""Wrap the grpc.insecure_channel."""
107110
def call(*args, **kwargs):
108111
channel = insecure_channel_func(*args, **kwargs)
109112

110113
try:
111114
target = kwargs.get('target')
112-
_tracer = execution_context.get_opencensus_tracer()
115+
if tracer is None:
116+
_tracer = execution_context.get_opencensus_tracer()
117+
else: # pragma: NO COVER
118+
_tracer = tracer
113119
tracer_interceptor = OpenCensusClientInterceptor(_tracer, target)
114120
intercepted_channel = grpc.intercept_channel(
115121
channel, tracer_interceptor)
@@ -122,14 +128,17 @@ def call(*args, **kwargs):
122128
return call
123129

124130

125-
def wrap_create_channel(create_channel_func):
131+
def wrap_create_channel(create_channel_func, tracer=None):
126132
"""Wrap the google.api_core.grpc_helpers.create_channel."""
127133
def call(*args, **kwargs):
128134
channel = create_channel_func(*args, **kwargs)
129135

130136
try:
131137
target = kwargs.get('target')
132-
_tracer = execution_context.get_opencensus_tracer()
138+
if tracer is None:
139+
_tracer = execution_context.get_opencensus_tracer()
140+
else: # pragma: NO COVER
141+
_tracer = tracer
133142
tracer_interceptor = OpenCensusClientInterceptor(_tracer, target)
134143
intercepted_channel = grpc.intercept_channel(
135144
channel, tracer_interceptor)

opencensus/trace/ext/grpc/client_interceptor.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
TIMEOUT = 3
3434

35+
# Do not trace StackDriver Trace exporter activities to avoid deadlock.
36+
CLOUD_TRACE = 'google.devtools.cloudtrace'
37+
3538

3639
class _ClientCallDetails(
3740
collections.namedtuple(
@@ -137,6 +140,10 @@ def _trace_future_exception(self, response):
137140

138141
def intercept_unary_unary(
139142
self, continuation, client_call_details, request):
143+
if CLOUD_TRACE in client_call_details.method:
144+
response = continuation(client_call_details, request)
145+
return response
146+
140147
new_details, new_request, current_span = self._intercept_call(
141148
client_call_details=client_call_details,
142149
request_iterator=iter((request,)),
@@ -152,6 +159,10 @@ def intercept_unary_unary(
152159

153160
def intercept_unary_stream(self, continuation, client_call_details,
154161
request):
162+
if CLOUD_TRACE in client_call_details.method:
163+
response = continuation(client_call_details, request)
164+
return response
165+
155166
new_details, new_request_iterator, current_span = self._intercept_call(
156167
client_call_details=client_call_details,
157168
request_iterator=iter((request,)),
@@ -166,6 +177,10 @@ def intercept_unary_stream(self, continuation, client_call_details,
166177

167178
def intercept_stream_unary(self, continuation, client_call_details,
168179
request_iterator):
180+
if CLOUD_TRACE in client_call_details.method:
181+
response = continuation(client_call_details, request_iterator)
182+
return response
183+
169184
new_details, new_request_iterator, current_span = self._intercept_call(
170185
client_call_details=client_call_details,
171186
request_iterator=request_iterator,
@@ -181,6 +196,10 @@ def intercept_stream_unary(self, continuation, client_call_details,
181196

182197
def intercept_stream_stream(self, continuation, client_call_details,
183198
request_iterator):
199+
if CLOUD_TRACE in client_call_details.method:
200+
response = continuation(client_call_details, request_iterator)
201+
return response
202+
184203
new_details, new_request_iterator, current_span = self._intercept_call(
185204
client_call_details=client_call_details,
186205
request_iterator=request_iterator,

opencensus/trace/ext/httplib/trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES['HTTP_STATUS_CODE']
3737

3838

39-
def trace_integration():
39+
def trace_integration(tracer=None):
4040
"""Wrap the httplib to trace."""
4141
log.info('Integrated module: {}'.format(MODULE_NAME))
4242

opencensus/trace/ext/mysql/trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
CONN_WRAP_METHOD = 'connect'
2424

2525

26-
def trace_integration():
26+
def trace_integration(tracer=None):
2727
"""Wrap the mysql connector to trace it."""
2828
logging.info('Integrated module: {}'.format(MODULE_NAME))
2929
conn_func = getattr(mysql.connector, CONN_WRAP_METHOD)

opencensus/trace/ext/postgresql/trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
QUERY_WRAP_METHODS = ['execute', 'executemany']
3131

3232

33-
def trace_integration():
33+
def trace_integration(tracer=None):
3434
"""Wrap the mysql connector to trace it."""
3535
log.info('Integrated module: {}'.format(MODULE_NAME))
3636
conn_func = getattr(psycopg2, CONN_WRAP_METHOD)

opencensus/trace/ext/pymysql/trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
CONN_WRAP_METHOD = 'connect'
2424

2525

26-
def trace_integration():
26+
def trace_integration(tracer=None):
2727
"""Wrap the mysql connector to trace it."""
2828
logging.info('Integrated module: {}'.format(MODULE_NAME))
2929
conn_func = getattr(pymysql, CONN_WRAP_METHOD)

opencensus/trace/ext/requests/trace.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@
2727
SESSION_CLASS_NAME = 'Session'
2828

2929

30-
def trace_integration():
30+
def trace_integration(tracer=None):
3131
"""Wrap the requests library to trace it."""
3232
log.info('Integrated module: {}'.format(MODULE_NAME))
3333

34+
execution_context.set_opencensus_tracer(tracer)
35+
3436
# Wrap the requests functions
3537
for func in REQUESTS_WRAP_METHODS:
3638
requests_func = getattr(requests, func)

opencensus/trace/ext/sqlalchemy/trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
MODULE_NAME = 'sqlalchemy'
2626

2727

28-
def trace_integration():
28+
def trace_integration(tracer=None):
2929
"""Integrate with SQLAlchemy to trace it using event listener.
3030
3131
See: http://docs.sqlalchemy.org/en/latest/core/events.html

opencensus/trace/tracers/noop_tracer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class NoopTracer(base.Tracer):
1919
"""No-op implementation of the :class:`Tracer` interface, all methods are
2020
no-ops. Should be used when tracing is not enabled or not sampled.
2121
"""
22+
span_context = None
23+
2224
def finish(self):
2325
"""End spans and send to reporter."""
2426
return None

0 commit comments

Comments
 (0)