Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
937d662
Add DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT to config inversion
MilanGarnier Jun 25, 2026
b02308e
Add DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT to config
MilanGarnier Jul 1, 2026
c7248f0
rebase
MilanGarnier Jul 8, 2026
21ccf65
add branch for PropagationBehaviorExtract::to_string_view
MilanGarnier Jul 7, 2026
ccf96b3
Remove trailing newline from supported-configurations.json
MilanGarnier Jul 8, 2026
153370e
finalize tracer config
MilanGarnier Jul 10, 2026
06145d8
full restart link implementation
MilanGarnier Jul 10, 2026
201958b
on_extract_headers: store with synthetic ids to avoid collisions (same
MilanGarnier Jul 10, 2026
14a1732
span link flags field
MilanGarnier Jul 13, 2026
25a7fab
flags comve from merged context insted of w3c only, and wrtie tracestate
MilanGarnier Jul 13, 2026
f61aece
format
MilanGarnier Jul 13, 2026
16eb8a7
rename IGNORE to IGNORE_ because windows exists
MilanGarnier Jul 13, 2026
fd2039c
Merge branch 'milan.garnier/span-links-support' into milan.garnier/pr…
MilanGarnier Jul 15, 2026
3e874a4
fix typo in parametric server
MilanGarnier Jul 15, 2026
f3a52a2
Update include/datadog/tracer.h
MilanGarnier Jul 16, 2026
c230de0
Update include/datadog/propagation_behavior_extract.h
MilanGarnier Jul 16, 2026
334ff71
rename: IGNORE_ to IGNORE, undefining IGNORE legacy macro on windows
MilanGarnier Jul 16, 2026
11a5e30
test: keep trace_id = 0 in first span link test
MilanGarnier Jul 16, 2026
668ccd5
test: cover explicit CONTINUE extraction and baggage across propagati…
MilanGarnier Jul 17, 2026
25b8fd1
refactor(tracing): code review refactors
MilanGarnier Jul 20, 2026
4b96aa9
refact(tracing): nit change comment
MilanGarnier Jul 20, 2026
7e0bf41
refactor(tracing): move span link attributes type to span.h
MilanGarnier Jul 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ cc_library(
"src/datadog/parse_util.cpp",
"src/datadog/parse_util.h",
"src/datadog/platform_util.h",
"src/datadog/propagation_behavior_extract.cpp",
"src/datadog/propagation_style.cpp",
"src/datadog/random.cpp",
"src/datadog/random.h",
Expand Down Expand Up @@ -122,6 +123,7 @@ cc_library(
"include/datadog/logger.h",
"include/datadog/null_collector.h",
"include/datadog/optional.h",
"include/datadog/propagation_behavior_extract.h",
"include/datadog/propagation_style.h",
"include/datadog/rate.h",
"include/datadog/remote_config/capability.h",
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ target_sources(dd-trace-cpp-objects
include/datadog/logger.h
include/datadog/null_collector.h
include/datadog/optional.h
include/datadog/propagation_behavior_extract.h
include/datadog/propagation_style.h
include/datadog/rate.h
include/datadog/runtime_id.h
Expand Down Expand Up @@ -196,6 +197,7 @@ target_sources(dd-trace-cpp-objects
src/datadog/logger.cpp
src/datadog/msgpack.cpp
src/datadog/parse_util.cpp
src/datadog/propagation_behavior_extract.cpp
src/datadog/propagation_style.cpp
src/datadog/random.cpp
src/datadog/rate.cpp
Expand Down
1 change: 1 addition & 0 deletions include/datadog/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum class ConfigName : char {
TAGS,
EXTRACTION_STYLES,
INJECTION_STYLES,
PROPAGATION_BEHAVIOR_EXTRACT,
STARTUP_LOGS,
REPORT_TELEMETRY,
DELEGATE_SAMPLING,
Expand Down
1 change: 1 addition & 0 deletions include/datadog/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace environment {
ENV_DEFAULT_RESOLVED_IN_CODE("Defaults to process name when unset.")) \
MACRO(DD_SPAN_SAMPLING_RULES, ARRAY, "[]") \
MACRO(DD_SPAN_SAMPLING_RULES_FILE, STRING, "") \
MACRO(DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT, STRING, "continue") \
MACRO(DD_TRACE_PROPAGATION_STYLE_EXTRACT, ARRAY, \
"datadog,tracecontext,baggage") \
MACRO(DD_TRACE_PROPAGATION_STYLE_INJECT, ARRAY, \
Expand Down
36 changes: 36 additions & 0 deletions include/datadog/propagation_behavior_extract.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

// This component provides an `enum class`, `PropagationBehaviorExtract`, that
// indicates a trace context extraction or injection format to be used.
// `TracerConfig` has one `std::vector<PropagationStyle>` for extraction and
// another for injection. See `tracer_config.h`.

#include "optional.h"
#include "string_view.h"

// Undefine legacy Windows macro so it can be a value in the enum
#ifdef IGNORE
#undef IGNORE
#endif

namespace datadog {
namespace tracing {

enum class PropagationBehaviorExtract {
// Propagate extracted context normally
CONTINUE,
// Restart a new trace (new sampling decision, no parent)
// Reference previous trace through a span-link
RESTART,
// Discard entirely incoming context
IGNORE,
};

StringView to_string_view(PropagationBehaviorExtract behavior);

// defaults to CONTINUE if empty or unsupported
Optional<PropagationBehaviorExtract> parse_propagation_behavior_extract(
StringView text);

} // namespace tracing
} // namespace datadog
6 changes: 4 additions & 2 deletions include/datadog/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ struct SpanConfig;
struct SpanData;
class TraceSegment;

// The map type used for user-supplied span-link attributes.
using SpanLinkAttributes = std::unordered_map<std::string, std::string>;

class Span {
std::shared_ptr<TraceSegment> trace_segment_;
SpanData* data_;
Expand Down Expand Up @@ -171,8 +174,7 @@ class Span {
// sampling decision when one has not already been made.
SpanContext context() const;

// Add a span link to this span using the specified context. `attributes` are
// optional user-supplied attributes associated with the link.
// Add a link to this span.
void add_link(const SpanContext& context,
const SpanLinkAttributes& attributes = {});

Expand Down
19 changes: 11 additions & 8 deletions include/datadog/span_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,30 @@
// of a span. It can be supplied to `Span::add_link` to associate a span with a
// span in this or another trace.

#include <cstdint>
#include <string>
#include <unordered_map>

#include "optional.h"
#include "trace_id.h"

namespace datadog::tracing {

// The map type used for user-supplied span-link attributes.
using SpanLinkAttributes = std::unordered_map<std::string, std::string>;

struct SpanContext {
class SpanContext {
public:
// 128-bit trace ID of the span.
TraceID trace_id;
// ID of the span within its trace.
std::uint64_t span_id = 0;
std::uint64_t span_id;
// W3C `tracestate` header value, if any.
Optional<std::string> tracestate;
// W3C trace flags, if any.
Optional<std::uint32_t> flags;

SpanContext(TraceID trace_id, std::uint64_t span_id,
Optional<std::string> tracestate = nullopt,
Optional<std::uint32_t> flags = nullopt)
: trace_id(trace_id),
span_id(span_id),
tracestate(tracestate),
flags(flags) {}
};

} // namespace datadog::tracing
10 changes: 5 additions & 5 deletions include/datadog/trace_segment.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include <cstddef>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -57,6 +56,8 @@ class SpanSampler;
class TraceSampler;
class ConfigManager;

using W3CLinkContext = std::pair<std::string, std::uint32_t>;

class TraceSegment {
mutable std::mutex mutex_;

Expand All @@ -76,8 +77,8 @@ class TraceSegment {
std::vector<std::unique_ptr<SpanData>> spans_;
std::size_t num_finished_spans_;
Optional<SamplingDecision> sampling_decision_;
Optional<std::string> additional_w3c_tracestate_;
Optional<std::string> additional_datadog_w3c_tracestate_;
const Optional<std::string> additional_w3c_tracestate_;
const Optional<std::string> additional_datadog_w3c_tracestate_;

std::shared_ptr<ConfigManager> config_manager_;

Expand Down Expand Up @@ -115,8 +116,7 @@ class TraceSegment {
// `nullopt` instead of forcing (and thereby permanently finalizing) one.
// Used by `Span::context` without prematurely deciding sampling for the
// trace.
Optional<std::pair<std::string, std::uint32_t>> w3c_link_context(
const SpanData& span) const;
Optional<W3CLinkContext> w3c_link_context(const SpanData& span) const;

Logger& logger() const;

Expand Down
5 changes: 5 additions & 0 deletions include/datadog/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "expected.h"
#include "id_generator.h"
#include "optional.h"
#include "propagation_behavior_extract.h"
#include "span.h"
#include "span_config.h"
#include "tracer_config.h"
Expand Down Expand Up @@ -45,6 +46,7 @@ class Tracer {
Clock clock_;
std::vector<PropagationStyle> injection_styles_;
std::vector<PropagationStyle> extraction_styles_;
PropagationBehaviorExtract propagation_behavior_extract_;
Optional<std::string> hostname_;
std::size_t tags_header_max_size_;
// Store the tracer configuration in an in-memory file, allowing it to be
Expand Down Expand Up @@ -75,6 +77,9 @@ class Tracer {
// `config`. If there is no tracing information in `reader`, then return an
// error with code `Error::NO_SPAN_TO_EXTRACT`. If a failure occurs, then
// return an error with some other code.
// Depending of the propagation_behavior_restart config, it can continue the
// trace, restart a new trace (with link), or discard the span (returning
// the same result as if there was no tracing information)
Expected<Span> extract_span(const DictReader& reader);
Expected<Span> extract_span(const DictReader& reader,
const SpanConfig& config);
Expand Down
11 changes: 11 additions & 0 deletions include/datadog/tracer_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "datadog_agent_config.h"
#include "expected.h"
#include "http_endpoint_calculation_mode.h"
#include "propagation_behavior_extract.h"
#include "propagation_style.h"
#include "runtime_id.h"
#include "span_defaults.h"
Expand Down Expand Up @@ -107,6 +108,14 @@ struct TracerConfig {
// environment variables.
Optional<std::vector<PropagationStyle>> extraction_styles;

// `propagation_behavior_extract` indicates how to handle incoming trace
// context. `continue`: default behavior, all trace contexts are propagated.
// `restart`: restart a new trace (new sampling decision) with a span link to
// the remote one. baggage is propagated. `ignore`: discard entirely any
// existing trace context and start a new trace. Overridden by
// DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT
Optional<PropagationBehaviorExtract> propagation_behavior_extract;

// `report_hostname` indicates whether the tracer will include the result of
// `gethostname` with traces sent to the collector.
Optional<bool> report_hostname;
Expand Down Expand Up @@ -224,6 +233,8 @@ class FinalizedTracerConfig final {
std::vector<PropagationStyle> injection_styles;
std::vector<PropagationStyle> extraction_styles;

PropagationBehaviorExtract propagation_behavior_extract;

bool report_hostname;
std::size_t tags_header_size;
std::shared_ptr<Logger> logger;
Expand Down
1 change: 1 addition & 0 deletions src/datadog/extracted_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct ExtractedData {
Optional<std::string> additional_datadog_w3c_tracestate;
// `style` is the extraction style used to obtain this `ExtractedData`. It's
// for diagnostics.
Optional<std::string> tracestate_full;
Optional<PropagationStyle> style;
// `headers_examined` are the name/value pairs of HTTP headers (or equivalent
// request meta-data) that were looked up and had values during the
Expand Down
44 changes: 44 additions & 0 deletions src/datadog/propagation_behavior_extract.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <datadog/propagation_behavior_extract.h>

#include <cassert>

#include "json.hpp"
#include "string_util.h"

namespace datadog {
namespace tracing {

StringView to_string_view(PropagationBehaviorExtract behavior) {
switch (behavior) {
case PropagationBehaviorExtract::CONTINUE:
return "continue";
case PropagationBehaviorExtract::RESTART:
return "restart";
case PropagationBehaviorExtract::IGNORE:
return "ignore";
default:
std::abort();
}
}

nlohmann::json to_json(PropagationBehaviorExtract behavior) {
return to_string_view(behavior);
}

Optional<PropagationBehaviorExtract> parse_propagation_behavior_extract(
StringView text) {
auto token = std::string{text};
to_lower(token);

if (token == "continue" || token.empty()) {
return PropagationBehaviorExtract::CONTINUE;
} else if (token == "restart") {
return PropagationBehaviorExtract::RESTART;
} else if (token == "ignore") {
return PropagationBehaviorExtract::IGNORE;
}
return nullopt;
}

} // namespace tracing
} // namespace datadog
16 changes: 4 additions & 12 deletions src/datadog/span.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,10 @@ void Span::set_source(Source source) {
}

SpanContext Span::context() const {
SpanContext context;
context.trace_id = trace_id();
context.span_id = id();
SpanContext context{trace_id(), id()};

if (auto w3c_context = trace_segment_->w3c_link_context(*data_)) {
if (Optional<W3CLinkContext> w3c_context =
trace_segment_->w3c_link_context(*data_)) {
context.tracestate = std::move(w3c_context->first);
context.flags = w3c_context->second;
}
Expand All @@ -179,14 +178,7 @@ SpanContext Span::context() const {

void Span::add_link(const SpanContext& context,
const SpanLinkAttributes& attributes) {
SpanLink link;
link.trace_id = context.trace_id;
link.span_id = context.span_id;
link.tracestate = context.tracestate;
link.flags = context.flags;
link.attributes = attributes;

data_->span_links.push_back(std::move(link));
data_->span_links.emplace_back(context, attributes);
}

TraceSegment& Span::trace_segment() { return *trace_segment_; }
Expand Down
45 changes: 22 additions & 23 deletions src/datadog/span_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#include <cassert>
#include <cstddef>
#include <string>
#include <vector>

#include "msgpack.h"
Expand Down Expand Up @@ -134,28 +133,28 @@ Expected<void> msgpack_encode(std::string& destination, const SpanData& span) {
return msgpack::pack_string(destination, span.service_type);
};

if (span.span_links.empty()) {
return msgpack::pack_map(
destination, "service", pack_service, "name", pack_name, "resource",
pack_resource, "trace_id", pack_trace_id, "span_id", pack_span_id,
"parent_id", pack_parent_id, "start", pack_start, "duration",
pack_duration, "error", pack_error, "meta", pack_meta, "metrics",
pack_metrics, "type", pack_type);
} else {
auto pack_span_links = [&](auto& destination) {
return msgpack::pack_array(
destination, span.span_links,
[](std::string& destination, const SpanLink& link) {
return msgpack_encode(destination, link);
});
};
return msgpack::pack_map(
destination, "service", pack_service, "name", pack_name, "resource",
pack_resource, "trace_id", pack_trace_id, "span_id", pack_span_id,
"parent_id", pack_parent_id, "start", pack_start, "duration",
pack_duration, "error", pack_error, "meta", pack_meta, "metrics",
pack_metrics, "type", pack_type, "span_links", pack_span_links);
}
Expected<void> result =
msgpack::pack_map(destination, span.span_links.empty() ? 12 : 13);
if (!result) return result;

result = msgpack::pack_map_suffix(
destination, "service", pack_service, "name", pack_name, "resource",
pack_resource, "trace_id", pack_trace_id, "span_id", pack_span_id,
"parent_id", pack_parent_id, "start", pack_start, "duration",
pack_duration, "error", pack_error, "meta", pack_meta, "metrics",
pack_metrics, "type", pack_type);
if (!result) return result;

if (span.span_links.empty()) return result;

auto pack_span_links = [&](auto& destination) {
return msgpack::pack_array(
destination, span.span_links,
[](std::string& destination, const SpanLink& link) {
return msgpack_encode(destination, link);
});
};
return msgpack::pack_map_suffix(destination, "span_links", pack_span_links);
}

Expected<void> msgpack_encode(
Expand Down
Loading