Skip to content

Commit 39a6dd0

Browse files
committed
support the "b3multi" and "none" propagation styles
1 parent 313d082 commit 39a6dd0

File tree

8 files changed

+119
-18
lines changed

8 files changed

+119
-18
lines changed

src/datadog/propagation_styles.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ nlohmann::json to_json(const PropagationStyles& styles) {
1616
if (styles.b3) {
1717
selected_names.emplace_back("B3");
1818
}
19+
if (styles.none) {
20+
selected_names.emplace_back("none");
21+
}
1922
return selected_names;
2023
}
2124

src/datadog/propagation_styles.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ namespace datadog {
1111
namespace tracing {
1212

1313
struct PropagationStyles {
14+
// Datadog headers, e.g. X-Datadog-Trace-ID
1415
bool datadog = true;
16+
// B3 multi-header style, e.g. X-B3-TraceID
1517
bool b3 = false;
18+
// The absence of propagation. If this is the only style set, then
19+
// propagation is disabled in the relevant direction (extraction or
20+
// injection).
21+
bool none = false;
1622
};
1723

1824
nlohmann::json to_json(const PropagationStyles&);

src/datadog/trace_segment.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,14 @@ void TraceSegment::inject(DictWriter& writer, const SpanData& span) {
221221
encoded_trace_tags = encode_tags(trace_tags_);
222222
}
223223

224-
// Origin and trace tag headers are always propagated.
224+
// Origin and trace tag headers are always propagated, unless the only
225+
// injection style is "none".
225226
// Other headers depend on the injection styles.
227+
if (injection_styles_.none && !injection_styles_.datadog &&
228+
!injection_styles_.b3) {
229+
return;
230+
}
231+
226232
if (origin_) {
227233
writer.set("x-datadog-origin", *origin_);
228234
}

src/datadog/tracer.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,21 @@ bool operator!=(const ExtractedData& left, const ExtractedData& right) {
174174
left.sampling_priority != right.sampling_priority;
175175
}
176176

177+
nlohmann::json to_json(const ExtractedData& data) {
178+
auto result = nlohmann::json::object({});
179+
#define ADD_FIELD(FIELD) \
180+
if (data.FIELD) { \
181+
result[#FIELD] = *data.FIELD; \
182+
}
183+
ADD_FIELD(trace_id)
184+
ADD_FIELD(parent_id)
185+
ADD_FIELD(origin)
186+
ADD_FIELD(trace_tags)
187+
ADD_FIELD(sampling_priority)
188+
#undef ADD_FIELD
189+
return result;
190+
}
191+
177192
Expected<ExtractedData> extract_data(ExtractionPolicy& extract,
178193
const DictReader& reader) {
179194
ExtractedData extracted_data;
@@ -325,13 +340,24 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
325340
std::string message;
326341
message += "B3 extracted different data than did ";
327342
message += extracted_by;
328-
// TODO: diagnose difference
343+
message += ". B3 extracted ";
344+
message += to_json(*data).dump();
345+
message += " while previously ";
346+
message += extracted_by;
347+
message += " extracted ";
348+
message += to_json(*extracted_data).dump();
349+
message += '.';
329350
return Error{Error::INCONSISTENT_EXTRACTION_STYLES, std::move(message)};
330351
}
331352
extracted_data = *data;
332353
extracted_by = "B3";
333354
}
334355

356+
if (extraction_styles_.none && !extracted_data) {
357+
extracted_data.emplace();
358+
extracted_by = "none";
359+
}
360+
335361
assert(extracted_data);
336362
auto& [trace_id, parent_id, origin, trace_tags, sampling_priority] =
337363
*extracted_data;
@@ -349,7 +375,6 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
349375
// producing a root span
350376
// - if origin is _not_ set, then it's an error
351377
// - trace ID and parent ID means we're extracting a child span
352-
// - parent ID without trace ID is an error
353378

354379
if (!trace_id && !parent_id) {
355380
return Error{Error::NO_SPAN_TO_EXTRACT,

src/datadog/tracer_config.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,10 @@ Expected<PropagationStyles> parse_propagation_styles(StringView input) {
7676
to_lower(token);
7777
if (token == "datadog") {
7878
styles.datadog = true;
79-
} else if (token == "b3") {
79+
} else if (token == "b3" || token == "b3multi") {
8080
styles.b3 = true;
81+
} else if (token == "none") {
82+
styles.none = true;
8183
} else {
8284
std::string message;
8385
message += "Unsupported propagation style \"";
@@ -219,10 +221,12 @@ Expected<FinalizedTracerConfig> finalize_config(const TracerConfig &config) {
219221
result.injection_styles = *styles;
220222
}
221223

222-
if (!result.extraction_styles.datadog && !result.extraction_styles.b3) {
224+
if (!result.extraction_styles.datadog && !result.extraction_styles.b3 &&
225+
!result.extraction_styles.none) {
223226
return Error{Error::MISSING_SPAN_EXTRACTION_STYLE,
224227
"At least one extraction style must be specified."};
225-
} else if (!result.injection_styles.datadog && !result.injection_styles.b3) {
228+
} else if (!result.injection_styles.datadog && !result.injection_styles.b3 &&
229+
!result.injection_styles.none) {
226230
return Error{Error::MISSING_SPAN_INJECTION_STYLE,
227231
"At least one injection style must be specified."};
228232
}

test/span.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ TEST_CASE("injection") {
377377
config.logger = std::make_shared<MockLogger>();
378378
config.injection_styles.datadog = true;
379379
config.injection_styles.b3 = true;
380+
config.injection_styles.none = false;
380381

381382
auto finalized_config = finalize_config(config);
382383
REQUIRE(finalized_config);
@@ -447,3 +448,24 @@ TEST_CASE("injection") {
447448
}
448449
}
449450
}
451+
452+
TEST_CASE("injection can be disabled using the \"none\" style") {
453+
TracerConfig config;
454+
config.defaults.service = "testsvc";
455+
config.defaults.name = "spanny";
456+
config.collector = std::make_shared<MockCollector>();
457+
config.logger = std::make_shared<MockLogger>();
458+
config.injection_styles.datadog = false;
459+
config.injection_styles.b3 = false;
460+
config.injection_styles.none = true; // this one
461+
462+
const auto finalized_config = finalize_config(config);
463+
REQUIRE(finalized_config);
464+
Tracer tracer{*finalized_config};
465+
466+
const auto span = tracer.create_span();
467+
MockDictWriter writer;
468+
span.inject(writer);
469+
const std::unordered_map<std::string, std::string> empty;
470+
REQUIRE(writer.items == empty);
471+
}

test/tracer.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,31 @@ TEST_CASE("span extraction") {
552552
checks(test_case, *span);
553553
}
554554

555+
SECTION("extraction can be disabled using the \"none\" style") {
556+
config.extraction_styles.datadog = false;
557+
config.extraction_styles.b3 = false;
558+
config.extraction_styles.none = true; // this one
559+
560+
const auto finalized_config = finalize_config(config);
561+
REQUIRE(finalized_config);
562+
Tracer tracer{*finalized_config};
563+
const std::unordered_map<std::string, std::string> headers{
564+
// It doesn't matter which headers are present.
565+
// The "none" extraction style will not inspect them, and will return
566+
// the "no span to extract" error.
567+
{"X-Datadog-Trace-ID", "foo"},
568+
{"X-Datadog-Parent-ID", "bar"},
569+
{"X-Datadog-Sampling-Priority", "baz"},
570+
{"X-B3-TraceID", "foo"},
571+
{"X-B3-SpanID", "bar"},
572+
{"X-B3-Sampled", "baz"},
573+
};
574+
MockDictReader reader{headers};
575+
const auto result = tracer.extract_span(reader);
576+
REQUIRE(!result);
577+
REQUIRE(result.error().code == Error::NO_SPAN_TO_EXTRACT);
578+
}
579+
555580
SECTION("x-datadog-tags") {
556581
auto finalized_config = finalize_config(config);
557582
REQUIRE(finalized_config);

test/tracer_config.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ TEST_CASE("TracerConfig propagation styles") {
10081008
REQUIRE(finalized);
10091009
REQUIRE(!finalized->injection_styles.datadog);
10101010
REQUIRE(finalized->injection_styles.b3);
1011+
REQUIRE(!finalized->injection_styles.none);
10111012
}
10121013

10131014
SECTION("parsing") {
@@ -1020,20 +1021,24 @@ TEST_CASE("TracerConfig propagation styles") {
10201021

10211022
// clang-format off
10221023
auto test_case = GENERATE(values<TestCase>({
1023-
{__LINE__, "Datadog", x, {true, false}},
1024-
{__LINE__, "DaTaDoG", x, {true, false}},
1025-
{__LINE__, "B3", x, {false, true}},
1026-
{__LINE__, "b3", x, {false, true}},
1027-
{__LINE__, "Datadog B3", x, {true, true}},
1028-
{__LINE__, "B3 Datadog", x, {true, true}},
1029-
{__LINE__, "b3 datadog", x, {true, true}},
1030-
{__LINE__, "b3, datadog", x, {true, true}},
1031-
{__LINE__, "b3,datadog", x, {true, true}},
1032-
{__LINE__, "b3, datadog", x, {true, true}},
1024+
{__LINE__, "Datadog", x, {true, false, false}},
1025+
{__LINE__, "DaTaDoG", x, {true, false, false}},
1026+
{__LINE__, "B3", x, {false, true, false}},
1027+
{__LINE__, "b3", x, {false, true, false}},
1028+
{__LINE__, "b3MULTI", x, {false, true, false}},
1029+
{__LINE__, "b3, b3multi", x, {false, true, false}},
1030+
{__LINE__, "Datadog B3", x, {true, true, false}},
1031+
{__LINE__, "Datadog B3 none", x, {true, true, true}},
1032+
{__LINE__, "NONE", x, {false, false, true}},
1033+
{__LINE__, "B3 Datadog", x, {true, true, false}},
1034+
{__LINE__, "b3 datadog", x, {true, true, false}},
1035+
{__LINE__, "b3, datadog", x, {true, true, false}},
1036+
{__LINE__, "b3,datadog", x, {true, true, false}},
1037+
{__LINE__, "b3, datadog", x, {true, true, false}},
10331038
{__LINE__, "b3,,datadog", Error::UNKNOWN_PROPAGATION_STYLE},
10341039
{__LINE__, "b3,datadog,w3c", Error::UNKNOWN_PROPAGATION_STYLE},
1035-
{__LINE__, "b3,datadog,datadog", x, {true, true}},
1036-
{__LINE__, " b3 b3 b3, b3 , b3, b3, b3 , b3 b3 b3 ", x, {false, true}},
1040+
{__LINE__, "b3,datadog,datadog", x, {true, true, false}},
1041+
{__LINE__, " b3 b3 b3, b3 , b3, b3, b3 , b3 b3 b3 ", x, {false, true, false}},
10371042
}));
10381043
// clang-format on
10391044

@@ -1052,6 +1057,8 @@ TEST_CASE("TracerConfig propagation styles") {
10521057
test_case.expected_styles.datadog);
10531058
REQUIRE(finalized->injection_styles.b3 ==
10541059
test_case.expected_styles.b3);
1060+
REQUIRE(finalized->injection_styles.none ==
1061+
test_case.expected_styles.none);
10551062
}
10561063
}
10571064
}
@@ -1064,11 +1071,13 @@ TEST_CASE("TracerConfig propagation styles") {
10641071
REQUIRE(finalized);
10651072
REQUIRE(finalized->extraction_styles.datadog);
10661073
REQUIRE(!finalized->extraction_styles.b3);
1074+
REQUIRE(!finalized->extraction_styles.none);
10671075
}
10681076

10691077
SECTION("need at least one") {
10701078
config.extraction_styles.datadog = false;
10711079
config.extraction_styles.b3 = false;
1080+
config.extraction_styles.none = false;
10721081
auto finalized = finalize_config(config);
10731082
REQUIRE(!finalized);
10741083
REQUIRE(finalized.error().code == Error::MISSING_SPAN_EXTRACTION_STYLE);
@@ -1081,6 +1090,7 @@ TEST_CASE("TracerConfig propagation styles") {
10811090
REQUIRE(finalized);
10821091
REQUIRE(!finalized->extraction_styles.datadog);
10831092
REQUIRE(finalized->extraction_styles.b3);
1093+
REQUIRE(!finalized->extraction_styles.none);
10841094
}
10851095

10861096
// It's the same as for injection styles, so let's omit most of the

0 commit comments

Comments
 (0)