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

Commit 0dee5c8

Browse files
reyangSergeyKanzhelev
authored andcommitted
refactor - move header name to propagator (part 2) (#219)
* refactor - move header name to propagator (part 1) * update the Trace Parent header name to reflect the latest W3C draft * fix lint error * add unit tests for GoogleCloudFormat and TraceContext propagators * refactor - move header name to propagator (part 2) * refactor pyramid_middleware * fix system test cases * change X_CLOUD_TRACE_CONTEXT to X-Cloud-Trace-Context and add Django specific conversion * fix typo * fix unit test for Django
1 parent 6616ffa commit 0dee5c8

10 files changed

Lines changed: 42 additions & 67 deletions

File tree

opencensus/trace/ext/django/middleware.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333

3434
REQUEST_THREAD_LOCAL_KEY = 'django_request'
3535

36-
_DJANGO_TRACE_HEADER = 'HTTP_X_CLOUD_TRACE_CONTEXT'
37-
3836
BLACKLIST_PATHS = 'BLACKLIST_PATHS'
3937
GCP_EXPORTER_PROJECT = 'GCP_EXPORTER_PROJECT'
4038
SAMPLING_RATE = 'SAMPLING_RATE'
@@ -47,6 +45,19 @@
4745
log = logging.getLogger(__name__)
4846

4947

48+
class _DjangoMetaWrapper(object):
49+
"""
50+
Wrapper class which takes HTTP header name and retrieve the value from
51+
Django request.META
52+
"""
53+
54+
def __init__(self, meta=None):
55+
self.meta = meta or _get_django_request().META
56+
57+
def get(self, key):
58+
return self.meta.get('HTTP_' + key.upper().replace('-', '_'))
59+
60+
5061
def _get_django_request():
5162
"""Get Django request from thread local.
5263
@@ -79,19 +90,6 @@ def _set_django_attributes(tracer, request):
7990
tracer.add_attribute_to_current_span('/django/user/name', user_name)
8091

8192

82-
def get_django_header():
83-
"""Get trace context header from django request headers.
84-
85-
:rtype: str
86-
:returns: Trace context header in HTTP request headers.
87-
"""
88-
request = _get_django_request()
89-
90-
header = request.META.get(_DJANGO_TRACE_HEADER)
91-
92-
return header
93-
94-
9593
class OpencensusMiddleware(MiddlewareMixin):
9694
"""Saves the request in thread local"""
9795

@@ -155,8 +153,8 @@ def process_request(self, request):
155153

156154
try:
157155
# Start tracing this request
158-
header = get_django_header()
159-
span_context = self.propagator.from_header(header)
156+
span_context = self.propagator.from_headers(
157+
_DjangoMetaWrapper(_get_django_request().META))
160158

161159
# Reload the tracer with the new span context
162160
tracer = tracer_module.Tracer(

opencensus/trace/ext/flask/flask_middleware.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@
3030
from opencensus.trace.propagation import google_cloud_format
3131
from opencensus.trace.samplers import always_on, probability
3232

33-
34-
_FLASK_TRACE_HEADER = 'X_CLOUD_TRACE_CONTEXT'
35-
3633
HTTP_METHOD = attributes_helper.COMMON_ATTRIBUTES['HTTP_METHOD']
3734
HTTP_URL = attributes_helper.COMMON_ATTRIBUTES['HTTP_URL']
3835
HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES['HTTP_STATUS_CODE']
@@ -169,8 +166,7 @@ def _before_request(self):
169166
return
170167

171168
try:
172-
header = get_flask_header()
173-
span_context = self.propagator.from_header(header)
169+
span_context = self.propagator.from_headers(flask.request.headers)
174170

175171
tracer = tracer_module.Tracer(
176172
span_context=span_context,
@@ -236,18 +232,3 @@ def _teardown_request(self, exception):
236232
tracer.finish()
237233
except Exception: # pragma: NO COVER
238234
log.error('Failed to trace request', exc_info=True)
239-
240-
241-
def get_flask_header():
242-
"""Get trace context header from flask request headers.
243-
244-
:rtype: str
245-
:returns: Trace context header in HTTP request headers.
246-
"""
247-
header = flask.request.headers.get(_FLASK_TRACE_HEADER)
248-
249-
# In case the header is unicode, convert it to string.
250-
if header is not None:
251-
header = str(header.encode('utf-8'))
252-
253-
return header

opencensus/trace/ext/pyramid/pyramid_middleware.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
HTTP_URL = attributes_helper.COMMON_ATTRIBUTES['HTTP_URL']
2727
HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES['HTTP_STATUS_CODE']
2828

29-
_PYRAMID_TRACE_HEADER = 'X_CLOUD_TRACE_CONTEXT'
30-
3129
BLACKLIST_PATHS = 'BLACKLIST_PATHS'
3230

3331

@@ -78,8 +76,7 @@ def _before_request(self, request):
7876
return
7977

8078
try:
81-
header = get_context_header(request)
82-
span_context = self.propagator.from_header(header)
79+
span_context = self.propagator.from_headers(request.headers)
8380

8481
tracer = tracer_module.Tracer(
8582
span_context=span_context,
@@ -117,8 +114,3 @@ def _after_request(self, request, response):
117114
tracer.finish()
118115
except Exception: # pragma: NO COVER
119116
log.error('Failed to trace request', exc_info=True)
120-
121-
122-
def get_context_header(request):
123-
"""Get trace context header from pyramid request headers."""
124-
return request.headers.get(_PYRAMID_TRACE_HEADER)

opencensus/trace/propagation/google_cloud_format.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from opencensus.trace.span_context import SpanContext
1919
from opencensus.trace.trace_options import TraceOptions
2020

21-
_TRACE_CONTEXT_HEADER_NAME = 'X_CLOUD_TRACE_CONTEXT'
21+
_TRACE_CONTEXT_HEADER_NAME = 'X-Cloud-Trace-Context'
2222
_TRACE_CONTEXT_HEADER_FORMAT = '([0-9a-f]{32})(\/([0-9a-f]{16}))?(;o=(\d+))?'
2323
_TRACE_CONTEXT_HEADER_RE = re.compile(_TRACE_CONTEXT_HEADER_FORMAT)
2424
_TRACE_ID_DELIMETER = '/'
@@ -85,9 +85,11 @@ def from_headers(self, headers):
8585
"""
8686
if headers is None:
8787
return SpanContext()
88-
if _TRACE_CONTEXT_HEADER_NAME not in headers:
88+
header = headers.get(_TRACE_CONTEXT_HEADER_NAME)
89+
if header is None:
8990
return SpanContext()
90-
return self.from_header(headers[_TRACE_CONTEXT_HEADER_NAME])
91+
header = str(header.encode('utf-8'))
92+
return self.from_header(header)
9193

9294
def to_header(self, span_context):
9395
"""Convert a SpanContext object to header string.

opencensus/trace/propagation/trace_context_http_header_format.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ def from_headers(self, headers):
8888
"""
8989
if headers is None:
9090
return SpanContext()
91-
if _TRACE_PARENT_HEADER_NAME not in headers:
91+
header = headers.get(_TRACE_PARENT_HEADER_NAME)
92+
if header is None:
9293
return SpanContext()
93-
return self.from_header(headers[_TRACE_PARENT_HEADER_NAME])
94+
header = str(header.encode('utf-8'))
95+
return self.from_header(header)
9496

9597
def to_header(self, span_context):
9698
"""Convert a SpanContext object to header string, using version 0.

tests/system/trace/flask/flask_system_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def setUp(self):
7878
self.process = run_application()
7979

8080
self.headers_trace = {
81-
'X_CLOUD_TRACE_CONTEXT': '{}/{};o={}'.format(
81+
'X-Cloud-Trace-Context': '{}/{};o={}'.format(
8282
self.trace_id, self.span_id, 1)
8383
}
8484

tests/unit/trace/ext/django/test_middleware.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def test_process_request(self):
177177
django_trace_id = '{}/{}'.format(trace_id, span_id)
178178

179179
django_request = RequestFactory().get('/', **{
180-
middleware._DJANGO_TRACE_HEADER: django_trace_id})
180+
'HTTP_X_CLOUD_TRACE_CONTEXT': django_trace_id})
181181

182182
middleware_obj = middleware.OpencensusMiddleware()
183183

@@ -260,7 +260,7 @@ def test_process_response(self):
260260
django_trace_id = '{}/{}'.format(trace_id, span_id)
261261

262262
django_request = RequestFactory().get('/', **{
263-
middleware._DJANGO_TRACE_HEADER: django_trace_id})
263+
google_cloud_format._TRACE_CONTEXT_HEADER_NAME: django_trace_id})
264264

265265
middleware_obj = middleware.OpencensusMiddleware()
266266

tests/unit/trace/ext/flask/test_flask_middleware.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def test_init_app_config_zipkin_exporter(self):
157157
def test__before_request(self):
158158
from opencensus.trace import execution_context
159159

160-
flask_trace_header = 'X_CLOUD_TRACE_CONTEXT'
160+
flask_trace_header = 'X-Cloud-Trace-Context'
161161
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
162162
span_id = '6e0c63257de34c92'
163163
flask_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -187,7 +187,7 @@ def test__before_request(self):
187187
self.assertEqual(span_context.trace_id, trace_id)
188188

189189
def test__before_request_blacklist(self):
190-
flask_trace_header = 'X_CLOUD_TRACE_CONTEXT'
190+
flask_trace_header = 'X-Cloud-Trace-Context'
191191
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
192192
span_id = '6e0c63257de34c92'
193193
flask_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -214,7 +214,7 @@ def test_header_encoding(self):
214214
# in SpanContext because it cannot match the pattern for trace_id,
215215
# And a new trace_id will generate for the context.
216216

217-
flask_trace_header = 'X_CLOUD_TRACE_CONTEXT'
217+
flask_trace_header = 'X-Cloud-Trace-Context'
218218
trace_id = "你好"
219219
span_id = '6e0c63257de34c92'
220220
flask_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -265,7 +265,7 @@ def test_header_is_none(self):
265265
assert isinstance(span.parent_span, base.NullContextManager)
266266

267267
def test__after_request_not_sampled(self):
268-
flask_trace_header = 'X_CLOUD_TRACE_CONTEXT'
268+
flask_trace_header = 'X-Cloud-Trace-Context'
269269
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
270270
span_id = '6e0c63257de34c92'
271271
flask_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -281,7 +281,7 @@ def test__after_request_not_sampled(self):
281281
self.assertEqual(response.status_code, 200)
282282

283283
def test__after_request_sampled(self):
284-
flask_trace_header = 'X_CLOUD_TRACE_CONTEXT'
284+
flask_trace_header = 'X-Cloud-Trace-Context'
285285
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
286286
span_id = '6e0c63257de34c92'
287287
flask_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -296,7 +296,7 @@ def test__after_request_sampled(self):
296296
self.assertEqual(response.status_code, 200)
297297

298298
def test__after_request_blacklist(self):
299-
flask_trace_header = 'X_CLOUD_TRACE_CONTEXT'
299+
flask_trace_header = 'X-Cloud-Trace-Context'
300300
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
301301
span_id = '6e0c63257de34c92'
302302
flask_trace_id = '{}/{}'.format(trace_id, span_id)

tests/unit/trace/ext/pyramid/test_pyramid_middleware.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def tearDown(self):
4040
execution_context.clear()
4141

4242
def test_constructor(self):
43-
pyramid_trace_header = 'X_CLOUD_TRACE_CONTEXT'
43+
pyramid_trace_header = 'X-Cloud-Trace-Context'
4444
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
4545
span_id = '6e0c63257de34c92'
4646
pyramid_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -116,7 +116,7 @@ def dummy_handler(request):
116116
self.assertEqual(middleware.exporter.port, port)
117117

118118
def test__before_request(self):
119-
pyramid_trace_header = 'X_CLOUD_TRACE_CONTEXT'
119+
pyramid_trace_header = 'X-Cloud-Trace-Context'
120120
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
121121
span_id = '6e0c63257de34c92'
122122
pyramid_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -158,7 +158,7 @@ def dummy_handler(request):
158158
self.assertEqual(span_context.trace_id, trace_id)
159159

160160
def test__before_request_blacklist(self):
161-
pyramid_trace_header = 'X_CLOUD_TRACE_CONTEXT'
161+
pyramid_trace_header = 'X-Cloud-Trace-Context'
162162
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
163163
span_id = '6e0c63257de34c92'
164164
pyramid_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -192,7 +192,7 @@ def dummy_handler(request):
192192
assert isinstance(span, base.NullContextManager)
193193

194194
def test__after_request(self):
195-
pyramid_trace_header = 'X_CLOUD_TRACE_CONTEXT'
195+
pyramid_trace_header = 'X-Cloud-Trace-Context'
196196
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
197197
span_id = '6e0c63257de34c92'
198198
pyramid_trace_id = '{}/{}'.format(trace_id, span_id)
@@ -236,7 +236,7 @@ def dummy_handler(request):
236236
self.assertEqual(span.attributes, expected_attributes)
237237

238238
def test__after_request_blacklist(self):
239-
pyramid_trace_header = 'X_CLOUD_TRACE_CONTEXT'
239+
pyramid_trace_header = 'X-Cloud-Trace-Context'
240240
trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05'
241241
span_id = '6e0c63257de34c92'
242242
pyramid_trace_id = '{}/{}'.format(trace_id, span_id)

tests/unit/trace/propagation/test_google_cloud_format.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def test_header_not_match(self):
100100
def test_headers_match(self):
101101
# Trace option is enabled.
102102
headers = {
103-
'X_CLOUD_TRACE_CONTEXT':
103+
'X-Cloud-Trace-Context':
104104
'6e0c63257de34c92bf9efcd03927272e/00f067aa0ba902b7;o=1',
105105
}
106106
expected_trace_id = '6e0c63257de34c92bf9efcd03927272e'
@@ -147,7 +147,7 @@ def test_to_headers(self):
147147

148148
headers = propagator.to_headers(span_context)
149149
expected_headers = {
150-
'X_CLOUD_TRACE_CONTEXT': '{}/{};o={}'.format(trace_id, span_id, 1),
150+
'X-Cloud-Trace-Context': '{}/{};o={}'.format(trace_id, span_id, 1),
151151
}
152152

153153
self.assertEqual(headers, expected_headers)

0 commit comments

Comments
 (0)