Skip to content

Commit e727db1

Browse files
committed
Add support for B3 parentspanid
Fixes #236
1 parent ff63d8c commit e727db1

File tree

3 files changed

+57
-3
lines changed

3 files changed

+57
-3
lines changed

Diff for: opentelemetry-sdk/src/opentelemetry/sdk/context/propagation/b3_format.py

+25-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class B3Format(HTTPTextFormat):
2727
SINGLE_HEADER_KEY = "b3"
2828
TRACE_ID_KEY = "x-b3-traceid"
2929
SPAN_ID_KEY = "x-b3-spanid"
30+
PARENT_SPAN_ID_KEY = "x-b3-parentspanid"
3031
SAMPLED_KEY = "x-b3-sampled"
3132
FLAGS_KEY = "x-b3-flags"
3233
_SAMPLE_PROPAGATE_VALUES = set(["1", "True", "true", "d"])
@@ -35,6 +36,7 @@ class B3Format(HTTPTextFormat):
3536
def extract(cls, get_from_carrier, carrier):
3637
trace_id = format_trace_id(trace.INVALID_TRACE_ID)
3738
span_id = format_span_id(trace.INVALID_SPAN_ID)
39+
parent_span_id = format_span_id(trace.INVALID_SPAN_ID)
3840
sampled = "0"
3941
flags = None
4042

@@ -55,7 +57,7 @@ def extract(cls, get_from_carrier, carrier):
5557
elif len(fields) == 3:
5658
trace_id, span_id, sampled = fields
5759
elif len(fields) == 4:
58-
trace_id, span_id, sampled, _parent_span_id = fields
60+
trace_id, span_id, sampled, parent_span_id = fields
5961
else:
6062
return trace.INVALID_SPAN_CONTEXT
6163
else:
@@ -71,6 +73,12 @@ def extract(cls, get_from_carrier, carrier):
7173
)
7274
or span_id
7375
)
76+
parent_span_id = (
77+
_extract_first_element(
78+
get_from_carrier(carrier, cls.PARENT_SPAN_ID_KEY)
79+
)
80+
or parent_span_id
81+
)
7482
sampled = (
7583
_extract_first_element(
7684
get_from_carrier(carrier, cls.SAMPLED_KEY)
@@ -91,12 +99,22 @@ def extract(cls, get_from_carrier, carrier):
9199
# header is set to allow.
92100
if sampled in cls._SAMPLE_PROPAGATE_VALUES or flags == "1":
93101
options |= trace.TraceOptions.SAMPLED
102+
103+
trace_state = trace.TraceState()
104+
105+
if parent_span_id != trace.INVALID_SPAN_ID:
106+
# FIXME This is a workaround for the error specified below being
107+
# raised because of a pylint issue. Remove this when the issue is
108+
# fixed in pylint.
109+
# pylint: disable=E1137
110+
trace_state[cls.PARENT_SPAN_ID_KEY] = int(parent_span_id, 16)
111+
94112
return trace.SpanContext(
95113
# trace an span ids are encoded in hex, so must be converted
96114
trace_id=int(trace_id, 16),
97115
span_id=int(span_id, 16),
98116
trace_options=trace.TraceOptions(options),
99-
trace_state=trace.TraceState(),
117+
trace_state=trace_state,
100118
)
101119

102120
@classmethod
@@ -108,6 +126,11 @@ def inject(cls, context, set_in_carrier, carrier):
108126
set_in_carrier(
109127
carrier, cls.SPAN_ID_KEY, format_span_id(context.span_id)
110128
)
129+
set_in_carrier(
130+
carrier,
131+
cls.PARENT_SPAN_ID_KEY,
132+
format_span_id(context.trace_state[cls.PARENT_SPAN_ID_KEY]),
133+
)
111134
set_in_carrier(carrier, cls.SAMPLED_KEY, "1" if sampled else "0")
112135

113136

Diff for: opentelemetry-sdk/tests/context/propagation/test_b3_format.py

+30
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ def setUpClass(cls):
3535
cls.serialized_span_id = b3_format.format_span_id(
3636
trace.generate_span_id()
3737
)
38+
cls.serialized_parent_span_id = b3_format.format_span_id(
39+
trace.generate_span_id()
40+
)
3841

3942
def test_extract_multi_header(self):
4043
"""Test the extraction of B3 headers."""
4144
carrier = {
4245
FORMAT.TRACE_ID_KEY: self.serialized_trace_id,
4346
FORMAT.SPAN_ID_KEY: self.serialized_span_id,
47+
FORMAT.PARENT_SPAN_ID_KEY: self.serialized_parent_span_id,
4448
FORMAT.SAMPLED_KEY: "1",
4549
}
4650
span_context = FORMAT.extract(get_as_list, carrier)
@@ -52,6 +56,10 @@ def test_extract_multi_header(self):
5256
self.assertEqual(
5357
new_carrier[FORMAT.SPAN_ID_KEY], self.serialized_span_id
5458
)
59+
self.assertEqual(
60+
new_carrier[FORMAT.PARENT_SPAN_ID_KEY],
61+
self.serialized_parent_span_id,
62+
)
5563
self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1")
5664

5765
def test_extract_single_header(self):
@@ -72,6 +80,28 @@ def test_extract_single_header(self):
7280
)
7381
self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1")
7482

83+
carrier = {
84+
FORMAT.SINGLE_HEADER_KEY: "{}-{}-1-{}".format(
85+
self.serialized_trace_id,
86+
self.serialized_span_id,
87+
self.serialized_parent_span_id,
88+
)
89+
}
90+
span_context = FORMAT.extract(get_as_list, carrier)
91+
new_carrier = {}
92+
FORMAT.inject(span_context, dict.__setitem__, new_carrier)
93+
self.assertEqual(
94+
new_carrier[FORMAT.TRACE_ID_KEY], self.serialized_trace_id
95+
)
96+
self.assertEqual(
97+
new_carrier[FORMAT.SPAN_ID_KEY], self.serialized_span_id
98+
)
99+
self.assertEqual(
100+
new_carrier[FORMAT.PARENT_SPAN_ID_KEY],
101+
self.serialized_parent_span_id,
102+
)
103+
self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1")
104+
75105
def test_extract_header_precedence(self):
76106
"""A single b3 header should take precedence over multiple
77107
headers.

Diff for: tox.ini

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ python =
2121
[testenv]
2222
deps =
2323
test: pytest
24+
ipdb
2425
coverage: pytest-cov
2526
mypy,mypyinstalled: mypy~=0.740
2627

@@ -70,7 +71,7 @@ commands_pre =
7071
mypyinstalled: pip install file://{toxinidir}/opentelemetry-api/
7172

7273
commands =
73-
test: pytest
74+
test: pytest {posargs}
7475
coverage: {toxinidir}/scripts/coverage.sh
7576

7677
mypy: mypy --namespace-packages opentelemetry-api/src/opentelemetry/

0 commit comments

Comments
 (0)