Skip to content

Commit

Permalink
Add support for B3 parentspanid
Browse files Browse the repository at this point in the history
Fixes #236
  • Loading branch information
ocelotl committed Nov 12, 2019
1 parent ff63d8c commit 0cec30a
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class B3Format(HTTPTextFormat):
SINGLE_HEADER_KEY = "b3"
TRACE_ID_KEY = "x-b3-traceid"
SPAN_ID_KEY = "x-b3-spanid"
PARENT_SPAN_ID_KEY = "x-b3-parentspanid"
SAMPLED_KEY = "x-b3-sampled"
FLAGS_KEY = "x-b3-flags"
_SAMPLE_PROPAGATE_VALUES = set(["1", "True", "true", "d"])
Expand All @@ -35,6 +36,7 @@ class B3Format(HTTPTextFormat):
def extract(cls, get_from_carrier, carrier):
trace_id = format_trace_id(trace.INVALID_TRACE_ID)
span_id = format_span_id(trace.INVALID_SPAN_ID)
parent_span_id = format_span_id(trace.INVALID_SPAN_ID)
sampled = "0"
flags = None

Expand All @@ -55,7 +57,7 @@ def extract(cls, get_from_carrier, carrier):
elif len(fields) == 3:
trace_id, span_id, sampled = fields
elif len(fields) == 4:
trace_id, span_id, sampled, _parent_span_id = fields
trace_id, span_id, sampled, parent_span_id = fields
else:
return trace.INVALID_SPAN_CONTEXT
else:
Expand All @@ -71,6 +73,12 @@ def extract(cls, get_from_carrier, carrier):
)
or span_id
)
parent_span_id = (
_extract_first_element(
get_from_carrier(carrier, cls.PARENT_SPAN_ID_KEY)
)
or parent_span_id
)
sampled = (
_extract_first_element(
get_from_carrier(carrier, cls.SAMPLED_KEY)
Expand All @@ -91,12 +99,18 @@ def extract(cls, get_from_carrier, carrier):
# header is set to allow.
if sampled in cls._SAMPLE_PROPAGATE_VALUES or flags == "1":
options |= trace.TraceOptions.SAMPLED

trace_state = trace.TraceState()

if parent_span_id != trace.INVALID_SPAN_ID:
trace_state[cls.PARENT_SPAN_ID_KEY] = int(parent_span_id, 16)

return trace.SpanContext(
# trace an span ids are encoded in hex, so must be converted
trace_id=int(trace_id, 16),
span_id=int(span_id, 16),
trace_options=trace.TraceOptions(options),
trace_state=trace.TraceState(),
trace_state=trace_state,
)

@classmethod
Expand All @@ -108,6 +122,11 @@ def inject(cls, context, set_in_carrier, carrier):
set_in_carrier(
carrier, cls.SPAN_ID_KEY, format_span_id(context.span_id)
)
set_in_carrier(
carrier,
cls.PARENT_SPAN_ID_KEY,
format_span_id(context.trace_state[cls.PARENT_SPAN_ID_KEY]),
)
set_in_carrier(carrier, cls.SAMPLED_KEY, "1" if sampled else "0")


Expand Down
30 changes: 30 additions & 0 deletions opentelemetry-sdk/tests/context/propagation/test_b3_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ def setUpClass(cls):
cls.serialized_span_id = b3_format.format_span_id(
trace.generate_span_id()
)
cls.serialized_parent_span_id = b3_format.format_span_id(
trace.generate_span_id()
)

def test_extract_multi_header(self):
"""Test the extraction of B3 headers."""
carrier = {
FORMAT.TRACE_ID_KEY: self.serialized_trace_id,
FORMAT.SPAN_ID_KEY: self.serialized_span_id,
FORMAT.PARENT_SPAN_ID_KEY: self.serialized_parent_span_id,
FORMAT.SAMPLED_KEY: "1",
}
span_context = FORMAT.extract(get_as_list, carrier)
Expand All @@ -52,6 +56,10 @@ def test_extract_multi_header(self):
self.assertEqual(
new_carrier[FORMAT.SPAN_ID_KEY], self.serialized_span_id
)
self.assertEqual(
new_carrier[FORMAT.PARENT_SPAN_ID_KEY],
self.serialized_parent_span_id,
)
self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1")

def test_extract_single_header(self):
Expand All @@ -72,6 +80,28 @@ def test_extract_single_header(self):
)
self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1")

carrier = {
FORMAT.SINGLE_HEADER_KEY: "{}-{}-1-{}".format(
self.serialized_trace_id,
self.serialized_span_id,
self.serialized_parent_span_id,
)
}
span_context = FORMAT.extract(get_as_list, carrier)
new_carrier = {}
FORMAT.inject(span_context, dict.__setitem__, new_carrier)
self.assertEqual(
new_carrier[FORMAT.TRACE_ID_KEY], self.serialized_trace_id
)
self.assertEqual(
new_carrier[FORMAT.SPAN_ID_KEY], self.serialized_span_id
)
self.assertEqual(
new_carrier[FORMAT.PARENT_SPAN_ID_KEY],
self.serialized_parent_span_id,
)
self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1")

def test_extract_header_precedence(self):
"""A single b3 header should take precedence over multiple
headers.
Expand Down
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ python =
[testenv]
deps =
test: pytest
ipdb
coverage: pytest-cov
mypy,mypyinstalled: mypy~=0.740

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

commands =
test: pytest
test: pytest {posargs}
coverage: {toxinidir}/scripts/coverage.sh

mypy: mypy --namespace-packages opentelemetry-api/src/opentelemetry/
Expand Down

0 comments on commit 0cec30a

Please sign in to comment.