Skip to content

Commit 442af03

Browse files
Make B3 propagator spec compliant (#1728)
1 parent d06ba7b commit 442af03

File tree

3 files changed

+52
-67
lines changed

3 files changed

+52
-67
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.0.0...HEAD)
88

9+
### Added
910
- Added `py.typed` file to every package. This should resolve a bunch of mypy
1011
errors for users.
1112
([#1720](https://github.com/open-telemetry/opentelemetry-python/pull/1720))
1213

14+
### Changed
15+
- Adjust `B3Format` propagator to be spec compliant by not modifying context
16+
when propagation headers are not present/invalid/empty
17+
([#1728](https://github.com/open-telemetry/opentelemetry-python/pull/1728))
18+
1319

1420
## [1.0.0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.0.0) - 2021-03-26
1521
### Added

propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ def extract(
5050
context: typing.Optional[Context] = None,
5151
getter: Getter = default_getter,
5252
) -> Context:
53-
trace_id = format_trace_id(trace.INVALID_TRACE_ID)
54-
span_id = format_span_id(trace.INVALID_SPAN_ID)
53+
trace_id = trace.INVALID_TRACE_ID
54+
span_id = trace.INVALID_SPAN_ID
5555
sampled = "0"
5656
flags = None
5757

@@ -73,8 +73,6 @@ def extract(
7373
trace_id, span_id, sampled = fields
7474
elif len(fields) == 4:
7575
trace_id, span_id, sampled, _ = fields
76-
else:
77-
return trace.set_span_in_context(trace.INVALID_SPAN)
7876
else:
7977
trace_id = (
8078
_extract_first_element(getter.get(carrier, self.TRACE_ID_KEY))
@@ -94,18 +92,15 @@ def extract(
9492
)
9593

9694
if (
97-
self._trace_id_regex.fullmatch(trace_id) is None
95+
trace_id == trace.INVALID_TRACE_ID
96+
or span_id == trace.INVALID_SPAN_ID
97+
or self._trace_id_regex.fullmatch(trace_id) is None
9898
or self._span_id_regex.fullmatch(span_id) is None
9999
):
100-
id_generator = trace.get_tracer_provider().id_generator
101-
trace_id = id_generator.generate_trace_id()
102-
span_id = id_generator.generate_span_id()
103-
sampled = "0"
104-
105-
else:
106-
trace_id = int(trace_id, 16)
107-
span_id = int(span_id, 16)
100+
return context
108101

102+
trace_id = int(trace_id, 16)
103+
span_id = int(span_id, 16)
109104
options = 0
110105
# The b3 spec provides no defined behavior for both sample and
111106
# flag values set. Since the setting of at least one implies

propagator/opentelemetry-propagator-b3/tests/test_b3_format.py

Lines changed: 38 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
import unittest
16-
from unittest.mock import Mock, patch
16+
from unittest.mock import Mock
1717

1818
import opentelemetry.propagators.b3 as b3_format # pylint: disable=no-name-in-module,import-error
1919
import opentelemetry.sdk.trace as trace
@@ -231,89 +231,73 @@ def test_64bit_trace_id(self):
231231
new_carrier[FORMAT.TRACE_ID_KEY], "0" * 16 + trace_id_64_bit
232232
)
233233

234-
def test_invalid_single_header(self):
235-
"""If an invalid single header is passed, return an
236-
invalid SpanContext.
237-
"""
234+
def test_extract_invalid_single_header(self):
235+
"""Given unparsable header, do not modify context"""
236+
old_ctx = {}
237+
238238
carrier = {FORMAT.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"}
239-
ctx = FORMAT.extract(carrier)
240-
span_context = trace_api.get_current_span(ctx).get_span_context()
241-
self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID)
242-
self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID)
239+
new_ctx = FORMAT.extract(carrier, old_ctx)
240+
241+
self.assertDictEqual(new_ctx, old_ctx)
242+
243+
def test_extract_missing_trace_id(self):
244+
"""Given no trace ID, do not modify context"""
245+
old_ctx = {}
243246

244-
def test_missing_trace_id(self):
245-
"""If a trace id is missing, populate an invalid trace id."""
246247
carrier = {
247248
FORMAT.SPAN_ID_KEY: self.serialized_span_id,
248249
FORMAT.FLAGS_KEY: "1",
249250
}
251+
new_ctx = FORMAT.extract(carrier, old_ctx)
250252

251-
ctx = FORMAT.extract(carrier)
252-
span_context = trace_api.get_current_span(ctx).get_span_context()
253-
self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID)
254-
255-
@patch(
256-
"opentelemetry.sdk.trace.id_generator.RandomIdGenerator.generate_trace_id"
257-
)
258-
@patch(
259-
"opentelemetry.sdk.trace.id_generator.RandomIdGenerator.generate_span_id"
260-
)
261-
def test_invalid_trace_id(
262-
self, mock_generate_span_id, mock_generate_trace_id
263-
):
264-
"""If a trace id is invalid, generate a trace id."""
253+
self.assertDictEqual(new_ctx, old_ctx)
265254

266-
mock_generate_trace_id.configure_mock(return_value=1)
267-
mock_generate_span_id.configure_mock(return_value=2)
255+
def test_extract_invalid_trace_id(self):
256+
"""Given invalid trace ID, do not modify context"""
257+
old_ctx = {}
268258

269259
carrier = {
270260
FORMAT.TRACE_ID_KEY: "abc123",
271261
FORMAT.SPAN_ID_KEY: self.serialized_span_id,
272262
FORMAT.FLAGS_KEY: "1",
273263
}
264+
new_ctx = FORMAT.extract(carrier, old_ctx)
274265

275-
ctx = FORMAT.extract(carrier)
276-
span_context = trace_api.get_current_span(ctx).get_span_context()
266+
self.assertDictEqual(new_ctx, old_ctx)
277267

278-
self.assertEqual(span_context.trace_id, 1)
279-
self.assertEqual(span_context.span_id, 2)
280-
281-
@patch(
282-
"opentelemetry.sdk.trace.id_generator.RandomIdGenerator.generate_trace_id"
283-
)
284-
@patch(
285-
"opentelemetry.sdk.trace.id_generator.RandomIdGenerator.generate_span_id"
286-
)
287-
def test_invalid_span_id(
288-
self, mock_generate_span_id, mock_generate_trace_id
289-
):
290-
"""If a span id is invalid, generate a trace id."""
291-
292-
mock_generate_trace_id.configure_mock(return_value=1)
293-
mock_generate_span_id.configure_mock(return_value=2)
268+
def test_extract_invalid_span_id(self):
269+
"""Given invalid span ID, do not modify context"""
270+
old_ctx = {}
294271

295272
carrier = {
296273
FORMAT.TRACE_ID_KEY: self.serialized_trace_id,
297274
FORMAT.SPAN_ID_KEY: "abc123",
298275
FORMAT.FLAGS_KEY: "1",
299276
}
277+
new_ctx = FORMAT.extract(carrier, old_ctx)
300278

301-
ctx = FORMAT.extract(carrier)
302-
span_context = trace_api.get_current_span(ctx).get_span_context()
279+
self.assertDictEqual(new_ctx, old_ctx)
303280

304-
self.assertEqual(span_context.trace_id, 1)
305-
self.assertEqual(span_context.span_id, 2)
281+
def test_extract_missing_span_id(self):
282+
"""Given no span ID, do not modify context"""
283+
old_ctx = {}
306284

307-
def test_missing_span_id(self):
308-
"""If a trace id is missing, populate an invalid trace id."""
309285
carrier = {
310286
FORMAT.TRACE_ID_KEY: self.serialized_trace_id,
311287
FORMAT.FLAGS_KEY: "1",
312288
}
289+
new_ctx = FORMAT.extract(carrier, old_ctx)
290+
291+
self.assertDictEqual(new_ctx, old_ctx)
292+
293+
def test_extract_empty_carrier(self):
294+
"""Given no headers at all, do not modify context"""
295+
old_ctx = {}
296+
297+
carrier = {}
298+
new_ctx = FORMAT.extract(carrier, old_ctx)
313299

314-
ctx = FORMAT.extract(carrier)
315-
span_context = trace_api.get_current_span(ctx).get_span_context()
316-
self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID)
300+
self.assertDictEqual(new_ctx, old_ctx)
317301

318302
@staticmethod
319303
def test_inject_empty_context():

0 commit comments

Comments
 (0)