From 64fd7645ac693293e8ea26f734fb249b8cb331dd Mon Sep 17 00:00:00 2001 From: AneesPatel <91919134+AneesPatel@users.noreply.github.com> Date: Tue, 26 May 2026 09:32:09 -0500 Subject: [PATCH 01/59] add micro-benchmarks for TraceID hex formatting and parsing (#311) --- benchmark/CMakeLists.txt | 1 + benchmark/trace_id_bench.cpp | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 benchmark/trace_id_bench.cpp diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 59ea4d9e3..9fad664ff 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(dd_trace_cpp-benchmark benchmark.cpp hasher.cpp + trace_id_bench.cpp ) # Google Benchmark is included as a git submodule. diff --git a/benchmark/trace_id_bench.cpp b/benchmark/trace_id_bench.cpp new file mode 100644 index 000000000..89d4d45da --- /dev/null +++ b/benchmark/trace_id_bench.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include "datadog/hex.h" + +namespace { +namespace dd = datadog::tracing; + +void BM_TraceID_HexPadded(benchmark::State& state, dd::TraceID id) { + for (auto _ : state) { + auto result = id.hex_padded(); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK_CAPTURE(BM_TraceID_HexPadded, NoPadding, + dd::TraceID{0xDEADBEEFCAFEBABEULL, 0x0102030405060708ULL}); +BENCHMARK_CAPTURE(BM_TraceID_HexPadded, WithPadding, dd::TraceID{1, 0}); + +void BM_TraceID_ParseHex(benchmark::State& state, std::string input) { + for (auto _ : state) { + auto result = dd::TraceID::parse_hex(input); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK_CAPTURE(BM_TraceID_ParseHex, 64bit, std::string{"deadbeefcafebabe"}); +BENCHMARK_CAPTURE(BM_TraceID_ParseHex, 128bit, + std::string{"0102030405060708deadbeefcafebabe"}); + +void BM_HexPadded_uint64(benchmark::State& state, std::uint64_t value) { + for (auto _ : state) { + auto result = dd::hex_padded(value); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK_CAPTURE(BM_HexPadded_uint64, NoPadding, 0xDEADBEEFCAFEBABEULL); +BENCHMARK_CAPTURE(BM_HexPadded_uint64, WorstCasePadding, 0x1ULL); + +void BM_Hex_uint64(benchmark::State& state) { + const std::uint64_t value = 0xDEADBEEFCAFEBABEULL; + for (auto _ : state) { + auto result = dd::hex(value); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK(BM_Hex_uint64); + +} // namespace From ed07610af0987bfd0fce9d1d58d5cb09714b17e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:06:32 +0200 Subject: [PATCH 02/59] build(deps): bump the gh-actions-packages group with 2 updates (#323) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/dev.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 719a1ac03..8ef74cc1b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Initialize CodeQL - uses: github/codeql-action/init@c793b717bc78562f491db7b0e93a3a178b099162 # v3.29.5 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: languages: ${{ matrix.language }} @@ -36,4 +36,4 @@ jobs: run: bin/cmake-build --preset=ci-codeql - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c793b717bc78562f491db7b0e93a3a178b099162 # v3.29.5 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 4f7ac95df..0c4622470 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -192,7 +192,7 @@ jobs: env: BRANCH_NAME: ${{ github.head_ref || github.ref_name }} - name: Save artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: system_tests_binaries path: ./binaries/**/* From e18ada46859f2cab510b07b38917257b8ae4d4fe Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Mon, 8 Jun 2026 09:49:25 +0200 Subject: [PATCH 03/59] Get dd_trace_agent_url from Tracer configuration for meaningful System Tests (#325) --- test/system-tests/request_handler.cpp | 38 ++++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/test/system-tests/request_handler.cpp b/test/system-tests/request_handler.cpp index 0e318c388..df6055837 100644 --- a/test/system-tests/request_handler.cpp +++ b/test/system-tests/request_handler.cpp @@ -12,6 +12,22 @@ #include "httplib.h" #include "utils.h" +namespace { + +std::string get_agent_url_from_traces_url(std::string traces_url) { + // Strip the API path from the traces URL to get the agent URL + // This API path is defined in src/datadog/datadog_agent.cpp. + constexpr std::string_view traces_api_path = "/v0.4/traces"; + if (traces_url.size() >= traces_api_path.size() && + traces_url.compare(traces_url.size() - traces_api_path.size(), + traces_api_path.size(), traces_api_path) == 0) { + traces_url.resize(traces_url.size() - traces_api_path.size()); + } + return traces_url; +} + +} // namespace + RequestHandler::RequestHandler( datadog::tracing::FinalizedTracerConfig& tracerConfig, std::shared_ptr scheduler, @@ -47,17 +63,19 @@ void RequestHandler::on_trace_config(const httplib::Request& /* req */, httplib::Response& res) { auto tracer_cfg = nlohmann::json::parse(tracer_.config()); + const std::string agent_url = get_agent_url_from_traces_url( + tracer_cfg["collector"]["config"]["traces_url"]); + // clang-format off - auto response_body = nlohmann::json{ - { "config", { - { "dd_service", tracer_cfg["defaults"]["service"]}, - { "dd_env", tracer_cfg["defaults"]["environment"]}, - { "dd_version", tracer_cfg["environment_variables"]["version"]}, - { "dd_trace_enabled", tracer_cfg["environment_variables"]["report_traces"]}, - { "dd_trace_agent_url", tracer_cfg["environment_variables"]["DD_TRACE_AGENT_URL"]} - } - } - }; + auto response_body = nlohmann::json{ + {"config", { + {"dd_service", tracer_cfg["defaults"]["service"]}, + {"dd_env", tracer_cfg["defaults"]["environment"]}, + {"dd_version", tracer_cfg["defaults"]["version"]}, + {"dd_trace_enabled", tracer_cfg["report_traces"]}, + {"dd_trace_agent_url", agent_url} + }} + }; // clang-format on if (tracer_cfg.contains("trace_sampler")) { From 9bce1641b13813e00c91610259dc325db7511445 Mon Sep 17 00:00:00 2001 From: Gustavo Lopes Date: Tue, 9 Jun 2026 18:39:09 +0100 Subject: [PATCH 04/59] fix(telemetry): refactor to shared_ptr and add deterministic shutdown() (#326) * fix(telemetry): refactor to shared_ptr and add deterministic shutdown() Refactors Telemetry to be heap-allocated via a shared_ptr (enable_shared_from_this + factory create()). Scheduled-task callbacks now capture a weak_from_this() so they become no-ops automatically once the object is no longer reachable. Move semantics are removed. Adds a shutdown() function that cancels scheduled tasks, sends the app-closing payload, and releases the HTTP client. After the call, all HTTP sending becomes a no-op: send_payload() snapshots http_client_ under http_client_mutex_ and returns early if null. http_client_ is reset under the same mutex in shutdown(), so any concurrent call that already holds a live snapshot completes cleanly while new calls short-circuit. If this is the last shared_ptr to the client, the background Curl thread is joined at that point. Rationale: shutdown() cannot guarantee that, after it returns, there are no in-flight HTTP callbacks still holding a reference to Telemetry state. Using a shared_ptr ensures any late callback finds a dead weak_ptr and short-circuits instead of accessing a destroyed object. The load-bearing weak_from_this() captures are the on_response and on_error lambdas inside send_payload(). Those run on CurlImpl's independent event_loop_ thread (via handle_message()), which has no blocking-cancel mechanism. app_closing() calls drain() with a 2-second deadline, so if the agent is slow, requests can still be in flight on the curl thread after shutdown() returns. The weak.lock() guard is what prevents a use-after-free in that window. The weak_from_this() captures in the scheduled-task callbacks (schedule_tasks()) are defense-in-depth for a different concern: ThreadedEventScheduler's cancel() blocks until any in-progress callback finishes, making those captures redundant against the threaded scheduler. However, the EventScheduler interface does not mandate a blocking cancel(), so the captures guard against non-blocking implementations where a callback could otherwise touch Telemetry state after it has been torn down. Also fixes a race in test_span.cpp: disabling telemetry there prevents app_started() from posting to the Curl background thread, which would otherwise fail to reach the (absent) agent asynchronously and call log_error() on the shared MockLogger, racing against the error_count == 0 assertion. Co-Authored-By: Claude Sonnet 4.6 * fix comment wording * run clang-format --------- Co-authored-by: Claude Sonnet 4.6 --- include/datadog/telemetry/telemetry.h | 19 +++ src/datadog/telemetry/telemetry.cpp | 114 +++++++++------ src/datadog/telemetry/telemetry_impl.cpp | 152 +++++++++---------- src/datadog/telemetry/telemetry_impl.h | 38 +++-- test/telemetry/test_telemetry.cpp | 179 +++++++++-------------- test/test_span.cpp | 5 + 6 files changed, 257 insertions(+), 250 deletions(-) diff --git a/include/datadog/telemetry/telemetry.h b/include/datadog/telemetry/telemetry.h index 01574f888..725abed31 100644 --- a/include/datadog/telemetry/telemetry.h +++ b/include/datadog/telemetry/telemetry.h @@ -44,6 +44,25 @@ void init(FinalizedConfiguration configuration, tracing::HTTPClient::URL agent_url, tracing::Clock clock = tracing::default_clock); +/// Deterministically shut down the telemetry module. +/// +/// Cancels all scheduled tasks, sends the app-closing payload, and waits up +/// to 2 seconds for in-flight requests to complete (HTTPClient::drain()). +/// Then releases the HTTP client reference; if this is the last shared_ptr +/// to the client, the background Curl thread is joined synchronously and any +/// remaining in-flight requests are abandoned without firing their callbacks. +/// If other holders of the client remain, the Curl thread continues running +/// and requests may still complete and fire their callbacks after this call +/// returns (the callbacks guard against this with weak_from_this()). After +/// this call all telemetry send functions become no-ops. Safe to call even if +/// telemetry was never initialized, but must be called at most once after a +/// successful init. +/// +/// Call this from the worker process exit path (e.g. before destroying the +/// tracer) so that telemetry's reference to the HTTP client is released +/// promptly, reducing the window before the Curl thread is quiesced. +void shutdown(); + /// Sends configuration changes. /// /// This function is responsible for sending reported configuration changes diff --git a/src/datadog/telemetry/telemetry.cpp b/src/datadog/telemetry/telemetry.cpp index 3cd515459..67b0c844c 100644 --- a/src/datadog/telemetry/telemetry.cpp +++ b/src/datadog/telemetry/telemetry.cpp @@ -22,7 +22,7 @@ using NoopTelemetry = std::monostate; /// `TelemetryProxy` holds either the real implementation or a no-op /// implementation. -using TelemetryProxy = std::variant; +using TelemetryProxy = std::variant>; /// NOTE(@dmehala): Here to facilitate Meyer's singleton construction. struct Ctor_param final { @@ -37,9 +37,9 @@ struct Ctor_param final { TelemetryProxy make_telemetry(const tracing::Optional& init) { if (!init || !init->configuration.enabled) return NoopTelemetry{}; - return Telemetry{init->configuration, init->tracer_signature, init->logger, - init->client, init->scheduler, init->agent_url, - init->clock}; + return Telemetry::create(init->configuration, init->tracer_signature, + init->logger, init->client, init->scheduler, + init->agent_url, init->clock); } TelemetryProxy& instance( @@ -69,20 +69,30 @@ void init(FinalizedConfiguration configuration, event_scheduler, agent_url, clock}); } -void send_configuration_change() { +void shutdown() { std::visit( details::Overload{ - [&](Telemetry& telemetry) { telemetry.send_configuration_change(); }, + [](std::shared_ptr& telemetry) { telemetry->shutdown(); }, [](NoopTelemetry) {}, }, instance()); } +void send_configuration_change() { + std::visit(details::Overload{ + [&](std::shared_ptr& telemetry) { + telemetry->send_configuration_change(); + }, + [](NoopTelemetry) {}, + }, + instance()); +} + void capture_configuration_change( const std::vector& new_configuration) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.capture_configuration_change(new_configuration); + [&](std::shared_ptr& telemetry) { + telemetry->capture_configuration_change(new_configuration); }, [](NoopTelemetry) {}, }, @@ -92,7 +102,9 @@ void capture_configuration_change( namespace log { void warning(std::string message) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { telemetry.log_warning(message); }, + [&](std::shared_ptr& telemetry) { + telemetry->log_warning(message); + }, [](NoopTelemetry) {}, }, instance()); @@ -100,7 +112,9 @@ void warning(std::string message) { void error(std::string message) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { telemetry.log_error(message); }, + [&](std::shared_ptr& telemetry) { + telemetry->log_error(message); + }, [](NoopTelemetry) {}, }, instance()); @@ -108,8 +122,8 @@ void error(std::string message) { void error(std::string message, std::string stacktrace) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.log_error(message, stacktrace); + [&](std::shared_ptr& telemetry) { + telemetry->log_error(message, stacktrace); }, [](auto&&) {}, }, @@ -119,18 +133,19 @@ void error(std::string message, std::string stacktrace) { namespace counter { void increment(const Counter& counter) { - std::visit( - details::Overload{ - [&](Telemetry& telemetry) { telemetry.increment_counter(counter); }, - [](auto&&) {}, - }, - instance()); + std::visit(details::Overload{ + [&](std::shared_ptr& telemetry) { + telemetry->increment_counter(counter); + }, + [](auto&&) {}, + }, + instance()); } void increment(const Counter& counter, const std::vector& tags) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.increment_counter(counter, tags); + [&](std::shared_ptr& telemetry) { + telemetry->increment_counter(counter, tags); }, [](auto&&) {}, }, @@ -138,18 +153,19 @@ void increment(const Counter& counter, const std::vector& tags) { } void decrement(const Counter& counter) { - std::visit( - details::Overload{ - [&](Telemetry& telemetry) { telemetry.decrement_counter(counter); }, - [](auto&&) {}, - }, - instance()); + std::visit(details::Overload{ + [&](std::shared_ptr& telemetry) { + telemetry->decrement_counter(counter); + }, + [](auto&&) {}, + }, + instance()); } void decrement(const Counter& counter, const std::vector& tags) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.decrement_counter(counter, tags); + [&](std::shared_ptr& telemetry) { + telemetry->decrement_counter(counter, tags); }, [](auto&&) {}, }, @@ -157,19 +173,20 @@ void decrement(const Counter& counter, const std::vector& tags) { } void set(const Counter& counter, uint64_t value) { - std::visit( - details::Overload{ - [&](Telemetry& telemetry) { telemetry.set_counter(counter, value); }, - [](auto&&) {}, - }, - instance()); + std::visit(details::Overload{ + [&](std::shared_ptr& telemetry) { + telemetry->set_counter(counter, value); + }, + [](auto&&) {}, + }, + instance()); } void set(const Counter& counter, const std::vector& tags, uint64_t value) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.set_counter(counter, tags, value); + [&](std::shared_ptr& telemetry) { + telemetry->set_counter(counter, tags, value); }, [](auto&&) {}, }, @@ -181,7 +198,9 @@ void set(const Counter& counter, const std::vector& tags, namespace rate { void set(const Rate& rate, uint64_t value) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { telemetry.set_rate(rate, value); }, + [&](std::shared_ptr& telemetry) { + telemetry->set_rate(rate, value); + }, [](auto&&) {}, }, instance()); @@ -189,12 +208,13 @@ void set(const Rate& rate, uint64_t value) { void set(const Rate& rate, const std::vector& tags, uint64_t value) { - std::visit( - details::Overload{ - [&](Telemetry& telemetry) { telemetry.set_rate(rate, tags, value); }, - [](auto&&) {}, - }, - instance()); + std::visit(details::Overload{ + [&](std::shared_ptr& telemetry) { + telemetry->set_rate(rate, tags, value); + }, + [](auto&&) {}, + }, + instance()); } } // namespace rate @@ -202,8 +222,8 @@ namespace distribution { void add(const Distribution& distribution, uint64_t value) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.add_datapoint(distribution, value); + [&](std::shared_ptr& telemetry) { + telemetry->add_datapoint(distribution, value); }, [](auto&&) {}, }, @@ -213,8 +233,8 @@ void add(const Distribution& distribution, uint64_t value) { void add(const Distribution& distribution, const std::vector& tags, uint64_t value) { std::visit(details::Overload{ - [&](Telemetry& telemetry) { - telemetry.add_datapoint(distribution, tags, value); + [&](std::shared_ptr& telemetry) { + telemetry->add_datapoint(distribution, tags, value); }, [](auto&&) {}, }, diff --git a/src/datadog/telemetry/telemetry_impl.cpp b/src/datadog/telemetry/telemetry_impl.cpp index 09ec61a3b..9f1e99143 100644 --- a/src/datadog/telemetry/telemetry_impl.cpp +++ b/src/datadog/telemetry/telemetry_impl.cpp @@ -222,24 +222,46 @@ Telemetry::Telemetry(FinalizedConfiguration config, http_client_(client), clock_(std::move(clock)), scheduler_(event_scheduler), - host_info_(get_host_info()) { - app_started(); - schedule_tasks(); + host_info_(get_host_info()) {} + +std::shared_ptr Telemetry::create( + FinalizedConfiguration config, TracerSignature tracer_signature, + std::shared_ptr logger, + std::shared_ptr client, + std::shared_ptr event_scheduler, + HTTPClient::URL agent_url, Clock clock) { + std::shared_ptr t(new Telemetry( + std::move(config), std::move(tracer_signature), std::move(logger), + std::move(client), std::move(event_scheduler), std::move(agent_url), + std::move(clock))); + t->app_started(); + t->schedule_tasks(); + return t; } void Telemetry::schedule_tasks() { tasks_.emplace_back(scheduler_->schedule_recurring_event( - config_.heartbeat_interval, - [this]() { send_payload("app-heartbeat", heartbeat_and_telemetry()); })); + config_.heartbeat_interval, [weak = weak_from_this()]() { + if (auto self = weak.lock()) { + self->send_payload("app-heartbeat", self->heartbeat_and_telemetry()); + } + })); if (config_.report_metrics) { tasks_.emplace_back(scheduler_->schedule_recurring_event( - config_.metrics_interval, [this]() mutable { capture_metrics(); })); + config_.metrics_interval, [weak = weak_from_this()]() { + if (auto self = weak.lock()) { + self->capture_metrics(); + } + })); } tasks_.emplace_back(scheduler_->schedule_recurring_event( - config_.extended_heartbeat_interval, [this]() { - send_payload("app-extended-heartbeat", extended_heartbeat_payload()); + config_.extended_heartbeat_interval, [weak = weak_from_this()]() { + if (auto self = weak.lock()) { + self->send_payload("app-extended-heartbeat", + self->extended_heartbeat_payload()); + } })); } @@ -250,52 +272,6 @@ Telemetry::~Telemetry() { } } -Telemetry::Telemetry(Telemetry&& rhs) - : config_(std::move(rhs.config_)), - logger_(std::move(rhs.logger_)), - telemetry_endpoint_(std::move(rhs.telemetry_endpoint_)), - tracer_signature_(std::move(rhs.tracer_signature_)), - http_client_(rhs.http_client_), - clock_(std::move(rhs.clock_)), - scheduler_(std::move(rhs.scheduler_)), - counters_(std::move(rhs.counters_)), - counters_snapshot_(std::move(rhs.counters_snapshot_)), - rates_(std::move(rhs.rates_)), - rates_snapshot_(std::move(rhs.rates_snapshot_)), - distributions_(std::move(rhs.distributions_)), - seq_id_(rhs.seq_id_), - config_seq_ids_(rhs.config_seq_ids_), - all_configurations_(rhs.all_configurations_), - host_info_(rhs.host_info_) { - cancel_tasks(rhs.tasks_); - schedule_tasks(); -} - -Telemetry& Telemetry::operator=(Telemetry&& rhs) { - if (&rhs != this) { - cancel_tasks(rhs.tasks_); - std::swap(config_, rhs.config_); - std::swap(logger_, rhs.logger_); - std::swap(telemetry_endpoint_, rhs.telemetry_endpoint_); - std::swap(http_client_, rhs.http_client_); - std::swap(tracer_signature_, rhs.tracer_signature_); - std::swap(http_client_, rhs.http_client_); - std::swap(clock_, rhs.clock_); - std::swap(scheduler_, rhs.scheduler_); - std::swap(counters_, rhs.counters_); - std::swap(counters_snapshot_, rhs.counters_snapshot_); - std::swap(rates_, rhs.rates_); - std::swap(rates_snapshot_, rhs.rates_snapshot_); - std::swap(distributions_, rhs.distributions_); - std::swap(seq_id_, rhs.seq_id_); - std::swap(config_seq_ids_, rhs.config_seq_ids_); - std::swap(all_configurations_, rhs.all_configurations_); - std::swap(host_info_, rhs.host_info_); - schedule_tasks(); - } - return *this; -} - void Telemetry::log_error(std::string message) { if (!config_.report_logs) return; increment_counter(internal_metrics::logs_created, {"level:error"}); @@ -364,6 +340,14 @@ void Telemetry::app_started() { } } +void Telemetry::shutdown() { + // cancel_tasks clears tasks_, so ~Telemetry() becomes a no-op after this. + cancel_tasks(tasks_); + app_closing(); + std::lock_guard l{http_client_mutex_}; + http_client_.reset(); +} + void Telemetry::app_closing() { // Capture metrics in-between two ticks to be sent with the last payload. capture_metrics(); @@ -373,6 +357,13 @@ void Telemetry::app_closing() { } void Telemetry::send_payload(StringView request_type, std::string payload) { + std::shared_ptr client; + { + std::lock_guard l{http_client_mutex_}; + client = http_client_; + } + if (!client) return; + auto set_telemetry_headers = [request_type, payload_size = payload.size(), debug_enabled = config_.debug, &signature = @@ -389,26 +380,27 @@ void Telemetry::send_payload(StringView request_type, std::string payload) { } }; - auto on_response = [this, logger = logger_](int response_status, - const DictReader&, - std::string response_body) { - if (response_status >= 500) { - increment_counter(internal_metrics::responses, - {"status_code:5xx", "endpoint:agent"}); - } else if (response_status >= 400) { - increment_counter(internal_metrics::responses, - {"status_code:4xx", "endpoint:agent"}); - } else if (response_status >= 300) { - increment_counter(internal_metrics::responses, - {"status_code:3xx", "endpoint:agent"}); - } else if (response_status >= 200) { - increment_counter(internal_metrics::responses, - {"status_code:2xx", "endpoint:agent"}); - } else if (response_status >= 100) { - increment_counter(internal_metrics::responses, - {"status_code:1xx", "endpoint:agent"}); + auto on_response = [weak = weak_from_this(), logger = logger_]( + int response_status, const DictReader&, + std::string response_body) { + if (auto self = weak.lock()) { + if (response_status >= 500) { + self->increment_counter(internal_metrics::responses, + {"status_code:5xx", "endpoint:agent"}); + } else if (response_status >= 400) { + self->increment_counter(internal_metrics::responses, + {"status_code:4xx", "endpoint:agent"}); + } else if (response_status >= 300) { + self->increment_counter(internal_metrics::responses, + {"status_code:3xx", "endpoint:agent"}); + } else if (response_status >= 200) { + self->increment_counter(internal_metrics::responses, + {"status_code:2xx", "endpoint:agent"}); + } else if (response_status >= 100) { + self->increment_counter(internal_metrics::responses, + {"status_code:1xx", "endpoint:agent"}); + } } - if (response_status < 200 || response_status >= 300) { logger->log_error([&](auto& stream) { stream << "Unexpected telemetry response status " << response_status @@ -419,9 +411,11 @@ void Telemetry::send_payload(StringView request_type, std::string payload) { }; // Callback for unsuccessful telemetry HTTP requests. - auto on_error = [this, logger = logger_](Error error) { - increment_counter(internal_metrics::errors, - {"type:network", "endpoint:agent"}); + auto on_error = [weak = weak_from_this(), logger = logger_](Error error) { + if (auto self = weak.lock()) { + self->increment_counter(internal_metrics::errors, + {"type:network", "endpoint:agent"}); + } logger->log_error(error.with_prefix( "Error occurred during HTTP request for telemetry: ")); }; @@ -431,9 +425,9 @@ void Telemetry::send_payload(StringView request_type, std::string payload) { payload.size()); auto post_result = - http_client_->post(telemetry_endpoint_, set_telemetry_headers, - std::move(payload), std::move(on_response), - std::move(on_error), clock_().tick + request_timeout); + client->post(telemetry_endpoint_, set_telemetry_headers, + std::move(payload), std::move(on_response), + std::move(on_error), clock_().tick + request_timeout); if (auto* error = post_result.if_error()) { increment_counter(internal_metrics::errors, {"type:network", "endpoint:agent"}); diff --git a/src/datadog/telemetry/telemetry_impl.h b/src/datadog/telemetry/telemetry_impl.h index d916846cb..59503565e 100644 --- a/src/datadog/telemetry/telemetry_impl.h +++ b/src/datadog/telemetry/telemetry_impl.h @@ -9,6 +9,7 @@ #include #include +#include #include #include "json.hpp" @@ -28,7 +29,7 @@ using MetricSnapshot = std::vector>; /// indeed a bottleneck, I'll embrace KISS principle. However, in a future /// iteration we could use multiple producer single consumer queue or /// lock-free queue. -class Telemetry final { +class Telemetry final : public std::enable_shared_from_this { /// Configuration object containing the validated settings for telemetry FinalizedConfiguration config_; /// Shared pointer to the user logger instance. @@ -72,12 +73,21 @@ class Telemetry final { tracing::HostInfo host_info_; + std::mutex http_client_mutex_; + public: - /// Constructor for the Telemetry class - /// - /// @param configuration The finalized configuration settings. - /// @param logger User logger instance. - /// @param metrics A vector user metrics to report. + static std::shared_ptr create( + FinalizedConfiguration configuration, + tracing::TracerSignature tracer_signature, + std::shared_ptr logger, + std::shared_ptr client, + std::shared_ptr event_scheduler, + tracing::HTTPClient::URL agent_url, + tracing::Clock clock = tracing::default_clock); + + ~Telemetry(); + + private: Telemetry(FinalizedConfiguration configuration, tracing::TracerSignature tracer_signature, std::shared_ptr logger, @@ -86,15 +96,7 @@ class Telemetry final { tracing::HTTPClient::URL agent_url, tracing::Clock clock = tracing::default_clock); - /// Destructor - /// - /// Send last metrics snapshot and `app-closing` event. - ~Telemetry(); - - /// Move semantics. - Telemetry(Telemetry&& rhs); - Telemetry& operator=(Telemetry&&); - + public: /// Capture and report internal error message to Datadog. /// /// @param message The error message. @@ -111,6 +113,12 @@ class Telemetry final { void capture_configuration_change( const std::vector& new_configuration); + // Deterministic shutdown: cancels scheduled tasks, sends the app-closing + // payload, drains in-flight HTTP requests, and releases the HTTP client + // (joining the background thread if this is the last reference). + // After this call the Telemetry object is inert and safe to destroy. + void shutdown(); + /// Counter void increment_counter(const Counter& counter); void increment_counter(const Counter& counter, diff --git a/test/telemetry/test_telemetry.cpp b/test/telemetry/test_telemetry.cpp index 80db9e976..9119892c7 100644 --- a/test/telemetry/test_telemetry.cpp +++ b/test/telemetry/test_telemetry.cpp @@ -111,12 +111,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { SECTION("ctor send app-started message") { SECTION("Without a defined integration") { - Telemetry telemetry{*finalize_config(), - tracer_signature, - logger, - client, - scheduler, - *url}; + auto telemetry = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url); /// By default the integration is `datadog` with the tracer version. /// TODO: remove the default because these datadog are already part of the /// request header. @@ -136,12 +132,9 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { Configuration cfg; cfg.integration_name = "nginx"; cfg.integration_version = "1.25.2"; - Telemetry telemetry2{*finalize_config(cfg), - tracer_signature, - logger, - client, - scheduler, - *url}; + auto telemetry2 = + Telemetry::create(*finalize_config(cfg), tracer_signature, logger, + client, scheduler, *url); auto app_started = nlohmann::json::parse(client->request_body); REQUIRE(is_valid_telemetry_payload(app_started) == true); @@ -166,12 +159,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { ddtest::EnvGuard install_time_env("DD_INSTRUMENTATION_INSTALL_TIME", "1703188212"); - Telemetry telemetry4{*finalize_config(), - tracer_signature, - logger, - client, - scheduler, - *url}; + auto telemetry4 = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url); auto app_started = nlohmann::json::parse(client->request_body); REQUIRE(is_valid_telemetry_payload(app_started) == true); @@ -218,12 +207,9 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { Configuration cfg; cfg.products.emplace_back(std::move(product)); - Telemetry telemetry3{*finalize_config(cfg), - tracer_signature, - logger, - client, - scheduler, - *url}; + auto telemetry3 = + Telemetry::create(*finalize_config(cfg), tracer_signature, logger, + client, scheduler, *url); auto app_started = nlohmann::json::parse(client->request_body); REQUIRE(is_valid_telemetry_payload(app_started) == true); @@ -272,7 +258,7 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { SECTION("generates a configuration change event") { SECTION("empty configuration do not generate a valid payload") { client->clear(); - telemetry3.send_configuration_change(); + telemetry3->send_configuration_change(); CHECK(client->request_body.empty()); } @@ -285,8 +271,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { Error{Error::Code::OTHER, "empty field"}}}; client->clear(); - telemetry3.capture_configuration_change(new_config); - telemetry3.send_configuration_change(); + telemetry3->capture_configuration_change(new_config); + telemetry3->send_configuration_change(); auto updates = client->request_body; REQUIRE(!updates.empty()); @@ -338,7 +324,7 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { // No update -> no configuration update client->clear(); - telemetry3.send_configuration_change(); + telemetry3->send_configuration_change(); CHECK(client->request_body.empty()); } } @@ -347,12 +333,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { SECTION("dtor send app-closing message") { { - Telemetry telemetry{*finalize_config(), - tracer_signature, - logger, - client, - scheduler, - *url}; + auto telemetry = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url); client->clear(); } @@ -376,8 +358,8 @@ TELEMETRY_IMPLEMENTATION_TEST("session ID headers") { auto session_rid = RuntimeID::generate(); const TracerSignature tracer_signature(session_rid, "testsvc", "test"); - Telemetry telemetry{ - *finalize_config(), tracer_signature, logger, client, scheduler, *url}; + auto telemetry = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url); auto it = client->request_headers.items.find("DD-Session-ID"); REQUIRE(it != client->request_headers.items.end()); @@ -393,8 +375,8 @@ TELEMETRY_IMPLEMENTATION_TEST("session ID headers") { const TracerSignature tracer_signature(session_rid, root_rid.string(), "testsvc", "test"); - Telemetry telemetry{ - *finalize_config(), tracer_signature, logger, client, scheduler, *url}; + auto telemetry = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url); auto session_it = client->request_headers.items.find("DD-Session-ID"); REQUIRE(session_it != client->request_headers.items.end()); @@ -411,8 +393,8 @@ TELEMETRY_IMPLEMENTATION_TEST("session ID headers") { const TracerSignature tracer_signature(session_rid, root_rid.string(), "testsvc", "test"); - Telemetry telemetry{ - *finalize_config(), tracer_signature, logger, client, scheduler, *url}; + auto telemetry = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url); client->clear(); scheduler->trigger_heartbeat(); @@ -445,13 +427,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { auto url = HTTPClient::URL::parse("http://localhost:8000"); - Telemetry telemetry{*finalize_config(), - tracer_signature, - logger, - client, - scheduler, - *url, - clock}; + auto telemetry = Telemetry::create(*finalize_config(), tracer_signature, + logger, client, scheduler, *url, clock); SECTION("generates a heartbeat message") { client->clear(); @@ -483,12 +460,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { cfg.products.emplace_back(std::move(product)); auto scheduler2 = std::make_shared(); - Telemetry telemetry2{*finalize_config(cfg), - tracer_signature, - logger, - client, - scheduler2, - *url}; + auto telemetry2 = Telemetry::create(*finalize_config(cfg), tracer_signature, + logger, client, scheduler2, *url); client->clear(); scheduler2->trigger_extended_heartbeat(); @@ -528,18 +501,14 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { cfg.products.emplace_back(std::move(product)); auto scheduler2 = std::make_shared(); - Telemetry telemetry2{*finalize_config(cfg), - tracer_signature, - logger, - client, - scheduler2, - *url}; + auto telemetry2 = Telemetry::create(*finalize_config(cfg), tracer_signature, + logger, client, scheduler2, *url); // Simulate a remote config update overriding SERVICE_NAME - telemetry2.capture_configuration_change( + telemetry2->capture_configuration_change( {{ConfigName::SERVICE_NAME, "rc-service", ConfigMetadata::Origin::REMOTE_CONFIG}}); - telemetry2.send_configuration_change(); + telemetry2->send_configuration_change(); client->clear(); scheduler2->trigger_extended_heartbeat(); @@ -571,18 +540,18 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { /// - can't decrement below zero. -> is that a telemetry requirements? /// - rates or counter reset to zero after capture. const Counter my_counter{"my_counter", "counter-test", true}; - telemetry.increment_counter(my_counter); // = 1 - telemetry.increment_counter(my_counter); // = 2 - telemetry.increment_counter(my_counter); // = 3 - telemetry.decrement_counter(my_counter); // = 2 + telemetry->increment_counter(my_counter); // = 1 + telemetry->increment_counter(my_counter); // = 2 + telemetry->increment_counter(my_counter); // = 3 + telemetry->decrement_counter(my_counter); // = 2 scheduler->trigger_metrics_capture(); - telemetry.increment_counter(my_counter); // = 1 + telemetry->increment_counter(my_counter); // = 1 scheduler->trigger_metrics_capture(); - telemetry.set_counter(my_counter, 42); - telemetry.set_counter(my_counter, {"event:test"}, 100); - telemetry.decrement_counter(my_counter, {"event:test"}); + telemetry->set_counter(my_counter, 42); + telemetry->set_counter(my_counter, {"event:test"}, 100); + telemetry->decrement_counter(my_counter, {"event:test"}); scheduler->trigger_metrics_capture(); // Expect 2 series: @@ -654,9 +623,9 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { SECTION("counters can't go below zero") { client->clear(); const Counter positive_counter{"positive_counter", "counter-test2", true}; - telemetry.decrement_counter(positive_counter); // = 0 - telemetry.decrement_counter(positive_counter); // = 0 - telemetry.decrement_counter(positive_counter); // = 0 + telemetry->decrement_counter(positive_counter); // = 0 + telemetry->decrement_counter(positive_counter); // = 0 + telemetry->decrement_counter(positive_counter); // = 0 scheduler->trigger_metrics_capture(); scheduler->trigger_heartbeat(); @@ -696,13 +665,13 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { client->clear(); Rate rps{"request", "rate-test", true}; - telemetry.set_rate(rps, 1000); + telemetry->set_rate(rps, 1000); scheduler->trigger_metrics_capture(); - telemetry.set_rate(rps, 2000); - telemetry.set_rate(rps, 5000); - telemetry.set_rate(rps, {"status:2xx"}, 5000); + telemetry->set_rate(rps, 2000); + telemetry->set_rate(rps, 5000); + telemetry->set_rate(rps, {"status:2xx"}, 5000); scheduler->trigger_metrics_capture(); @@ -772,17 +741,17 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { client->clear(); Distribution response_time{"response_time", "dist-test", false}; - telemetry.add_datapoint(response_time, 128); - telemetry.add_datapoint(response_time, 42); - telemetry.add_datapoint(response_time, 3000); + telemetry->add_datapoint(response_time, 128); + telemetry->add_datapoint(response_time, 42); + telemetry->add_datapoint(response_time, 3000); // Add a tag, this will add a new serie to the distribution payload. - telemetry.add_datapoint(response_time, {"status:200", "method:GET"}, - 6530); + telemetry->add_datapoint(response_time, {"status:200", "method:GET"}, + 6530); Distribution request_size{"request_size", "dist-test-2", true}; - telemetry.add_datapoint(request_size, 1843); - telemetry.add_datapoint(request_size, 4135); + telemetry->add_datapoint(request_size, 1843); + telemetry->add_datapoint(request_size, 4135); // Expect 3 series: // - `response_time` without tags: 3 datapoint (128, 42, 3000). @@ -851,16 +820,12 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { const Rate rps{"request", "rate-test", true}; const Counter my_counter{"my_counter", "counter-test", true}; { - Telemetry tmp_telemetry{*finalize_config(), - tracer_signature, - logger, - client, - scheduler, - *url, - clock}; - tmp_telemetry.increment_counter(my_counter); // = 1 - tmp_telemetry.add_datapoint(response_time, 128); - tmp_telemetry.set_rate(rps, 1000); + auto tmp_telemetry = + Telemetry::create(*finalize_config(), tracer_signature, logger, + client, scheduler, *url, clock); + tmp_telemetry->increment_counter(my_counter); // = 1 + tmp_telemetry->add_datapoint(response_time, 128); + tmp_telemetry->set_rate(rps, 1000); client->clear(); } @@ -969,7 +934,7 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { CAPTURE(test_case.name); client->clear(); - test_case.apply(telemetry, test_case.input, test_case.stacktrace); + test_case.apply(*telemetry, test_case.input, test_case.stacktrace); scheduler->trigger_heartbeat(); auto message_batch = nlohmann::json::parse(client->request_body); @@ -1004,14 +969,10 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry API") { SECTION("dtor sends logs in `app-closing` message") { { - Telemetry tmp_telemetry{*finalize_config(), - tracer_signature, - logger, - client, - scheduler, - *url, - clock}; - tmp_telemetry.log_warning("Be careful!"); + auto tmp_telemetry = + Telemetry::create(*finalize_config(), tracer_signature, logger, + client, scheduler, *url, clock); + tmp_telemetry->log_warning("Be careful!"); client->clear(); } @@ -1056,8 +1017,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry configuration") { auto final_cfg = finalize_config(cfg); REQUIRE(final_cfg); - Telemetry telemetry(*final_cfg, tracer_signature, logger, client, scheduler, - *url); + auto telemetry = Telemetry::create(*final_cfg, tracer_signature, logger, + client, scheduler, *url); CHECK(scheduler->metrics_callback == nullptr); CHECK(scheduler->metrics_interval == nullopt); } @@ -1070,8 +1031,8 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry configuration") { auto final_cfg = finalize_config(cfg); REQUIRE(final_cfg); - Telemetry telemetry(*final_cfg, tracer_signature, logger, client, scheduler, - *url); + auto telemetry = Telemetry::create(*final_cfg, tracer_signature, logger, + client, scheduler, *url); CHECK(scheduler->metrics_callback != nullptr); CHECK(scheduler->metrics_interval == 500ms); @@ -1088,9 +1049,9 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry configuration") { auto final_cfg = finalize_config(cfg); REQUIRE(final_cfg); - Telemetry telemetry(*final_cfg, tracer_signature, logger, client, scheduler, - *url); - telemetry.log_error("error"); + auto telemetry = Telemetry::create(*final_cfg, tracer_signature, logger, + client, scheduler, *url); + telemetry->log_error("error"); // NOTE(@dmehala): logs are sent with an heartbeat. scheduler->trigger_heartbeat(); diff --git a/test/test_span.cpp b/test/test_span.cpp index 65a79c30c..4af524ed7 100644 --- a/test/test_span.cpp +++ b/test/test_span.cpp @@ -749,6 +749,11 @@ TEST_SPAN("injecting W3C tracestate header") { // If one of these test cases results in a local sampling decision, let it be // "drop." config.trace_sampler.sample_rate = 0.0; + // Disable telemetry so no real Curl HTTP client / background thread is + // created. Otherwise the telemetry "app_started" request to a (likely + // absent) agent fails and logs an error into the shared MockLogger, racing + // against the `error_count() == 0` assertion below. + config.telemetry.enabled = false; const auto logger = std::make_shared(); config.logger = logger; config.collector = std::make_shared(); From 77da245419aa359e57e8f3a0d020ddd36dcb9876 Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Thu, 11 Jun 2026 09:26:32 +0200 Subject: [PATCH 05/59] Use GitHub action instead of npm package for code coverage upload (#327) --- .github/workflows/dev.yml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 0c4622470..005797be1 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -123,7 +123,7 @@ jobs: matrix: arch: ["arm64", "amd64"] include: - - runner: windows-11-arm + - runner: windows-11-arm arch: arm64 - runner: windows-2022 arch: amd64 @@ -149,7 +149,7 @@ jobs: run: scoop install main/cmake@4.0.1 main/ninja - name: Build run: | - & 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1' -arch ${{ matrix.arch }} + & 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1' -arch ${{ matrix.arch }} cmake --preset=ci-msvc -B build -DCMAKE_BUILD_TYPE=Debug . cmake --build build -j $env:MAKE_JOB_COUNT -v - name: Test @@ -163,7 +163,7 @@ jobs: ./datadog-ci.exe junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp report.xml coverage: - needs: build-linux-cmake + needs: build-linux-cmake runs-on: ubuntu-22.04-arm container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-arm64 @@ -172,25 +172,24 @@ jobs: permissions: contents: read packages: read - env: - DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - run: bin/test --coverage --verbose - - name: Report Datadog coverage - run: | - curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-arm64" --output "/usr/local/bin/datadog-ci" && chmod +x /usr/local/bin/datadog-ci - cd .coverage - cp filtered.info lcov.info - datadog-ci coverage upload lcov.info + - name: Upload code coverage report to Datadog + # See https://github.com/DataDog/coverage-upload-github-action/releases + uses: DataDog/coverage-upload-github-action@2ba057033351887422f8eb0203d1990c3acbc8c5 # v1.0.4 + with: + api_key: ${{ secrets.DD_CI_VIS_API_KEY }} + files: .coverage/filtered.info + format: lcov build-system-tests-artifact: runs-on: ubuntu-22.04 steps: - - run: mkdir binaries + - run: mkdir binaries - run: echo "https://github.com/DataDog/dd-trace-cpp@${BRANCH_NAME}" > binaries/cpp-load-from-git env: - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} - name: Save artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: From 22ce7de4057cfec8cd5d51ecc36bd9bcc6d203e9 Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Tue, 16 Jun 2026 17:36:35 +0200 Subject: [PATCH 06/59] Capture proxy related environment variables at Curl client construction to avoid crash (#328) --- bin/check-environment-variables | 2 +- src/datadog/curl.cpp | 164 ++++++++++++++++++++++---------- src/datadog/curl.h | 17 ++-- test/test_curl.cpp | 92 ++++++++++++++++-- 4 files changed, 206 insertions(+), 69 deletions(-) diff --git a/bin/check-environment-variables b/bin/check-environment-variables index 07a7f27ce..9faae9137 100755 --- a/bin/check-environment-variables +++ b/bin/check-environment-variables @@ -1,5 +1,4 @@ #!/bin/sh -# TODO set -eu if grep -R -n \ @@ -10,6 +9,7 @@ if grep -R -n \ --include='*.h' \ --include='*.hpp' \ --exclude='environment.cpp' \ + --exclude='curl.cpp' \ 'std::getenv' include src; then echo "Check failed: std::getenv usage detected." exit 1 diff --git a/src/datadog/curl.cpp b/src/datadog/curl.cpp index e8f407836..10e5f8614 100644 --- a/src/datadog/curl.cpp +++ b/src/datadog/curl.cpp @@ -2,17 +2,10 @@ #include #include -#include #include -#include -#include -#include -#include #include -#include #include -#include #include #include #include @@ -21,14 +14,80 @@ #include "json.hpp" #include "string_util.h" -namespace datadog { -namespace tracing { +namespace datadog::tracing { + namespace { // `libcurl` is the default implementation: it calls `curl_*` functions under // the hood. CurlLibrary libcurl; +struct ProxyConfiguration { + Optional all_proxy; + Optional http_proxy; + Optional https_proxy; + Optional no_proxy; +}; + +Optional environment_variable(const char *name) { + const char *const value = std::getenv(name); + if (value == nullptr || *value == '\0') { + return nullopt; + } + return std::string{value}; +} + +ProxyConfiguration load_proxy_configuration() { + ProxyConfiguration config; + + config.all_proxy = environment_variable("all_proxy"); + if (!config.all_proxy) { + config.all_proxy = environment_variable("ALL_PROXY"); + } + + // Only the lowercase form for http, to avoid httpoxy (CVE-2016-5385). + config.http_proxy = environment_variable("http_proxy"); + + config.https_proxy = environment_variable("https_proxy"); + if (!config.https_proxy) { + config.https_proxy = environment_variable("HTTPS_PROXY"); + } + + config.no_proxy = environment_variable("no_proxy"); + if (!config.no_proxy) { + config.no_proxy = environment_variable("NO_PROXY"); + } + + return config; +} + +bool is_unix_socket(const HTTPClient::URL &url) { + return url.scheme == "unix" || url.scheme == "http+unix" || + url.scheme == "https+unix"; +} + +StringView resolve_proxy(const HTTPClient::URL &url, + const ProxyConfiguration &config) { + if (is_unix_socket(url)) { + return ""; + } + const Optional &scheme_proxy = + url.scheme == "https" ? config.https_proxy : config.http_proxy; + if (scheme_proxy) { + return *scheme_proxy; + } + if (config.all_proxy) { + return *config.all_proxy; + } + return ""; +} + +void throw_on_error(CURLcode result) { + if (result != CURLE_OK) { + throw result; + } +} + } // namespace CURL *CurlLibrary::easy_init() { return curl_easy_init(); } @@ -61,6 +120,10 @@ CURLcode CurlLibrary::easy_setopt_httpheader(CURL *handle, return curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); } +CURLcode CurlLibrary::easy_setopt_noproxy(CURL *handle, const char *no_proxy) { + return curl_easy_setopt(handle, CURLOPT_NOPROXY, no_proxy); +} + CURLcode CurlLibrary::easy_setopt_post(CURL *handle, long post) { return curl_easy_setopt(handle, CURLOPT_POST, post); } @@ -77,6 +140,10 @@ CURLcode CurlLibrary::easy_setopt_private(CURL *handle, void *pointer) { return curl_easy_setopt(handle, CURLOPT_PRIVATE, pointer); } +CURLcode CurlLibrary::easy_setopt_proxy(CURL *handle, const char *proxy) { + return curl_easy_setopt(handle, CURLOPT_PROXY, proxy); +} + CURLcode CurlLibrary::easy_setopt_unix_socket_path(CURL *handle, const char *path) { return curl_easy_setopt(handle, CURLOPT_UNIX_SOCKET_PATH, path); @@ -172,6 +239,7 @@ class CurlImpl { std::list new_handles_; bool shutting_down_; int num_active_handles_; + const ProxyConfiguration proxy_config_; std::condition_variable no_requests_; std::thread event_loop_; @@ -214,6 +282,7 @@ class CurlImpl { }; void run(); + void configure_handle(CURL *handle, Request &request, const URL &url); void handle_message(const CURLMsg &); CURLcode log_on_error(CURLcode result); CURLMcode log_on_error(CURLMcode result); @@ -238,16 +307,6 @@ class CurlImpl { void clear_requests(); }; -namespace { - -void throw_on_error(CURLcode result) { - if (result != CURLE_OK) { - throw result; - } -} - -} // namespace - Curl::Curl(const std::shared_ptr &logger, const Clock &clock) : Curl(logger, clock, libcurl) {} @@ -283,7 +342,8 @@ CurlImpl::CurlImpl(const std::shared_ptr &logger, const Clock &clock, logger_(logger), clock_(clock), shutting_down_(false), - num_active_handles_(0) { + num_active_handles_(0), + proxy_config_(load_proxy_configuration()) { curl_.global_init(CURL_GLOBAL_ALL); multi_handle_ = curl_.multi_init(); if (multi_handle_ == nullptr) { @@ -360,33 +420,7 @@ Expected CurlImpl::post( "unable to initialize a curl handle for request sending"}; } - throw_on_error( - curl_.easy_setopt_httpheader(handle.get(), request->request_headers)); - throw_on_error(curl_.easy_setopt_private(handle.get(), request.get())); - throw_on_error( - curl_.easy_setopt_errorbuffer(handle.get(), request->error_buffer)); - throw_on_error(curl_.easy_setopt_post(handle.get(), 1)); - throw_on_error(curl_.easy_setopt_postfieldsize( - handle.get(), static_cast(request->request_body.size()))); - throw_on_error( - curl_.easy_setopt_postfields(handle.get(), request->request_body.data())); - throw_on_error( - curl_.easy_setopt_headerfunction(handle.get(), &on_read_header)); - throw_on_error(curl_.easy_setopt_headerdata(handle.get(), request.get())); - throw_on_error(curl_.easy_setopt_writefunction(handle.get(), &on_read_body)); - throw_on_error(curl_.easy_setopt_writedata(handle.get(), request.get())); - if (url.scheme == "unix" || url.scheme == "http+unix" || - url.scheme == "https+unix") { - throw_on_error(curl_.easy_setopt_unix_socket_path(handle.get(), - url.authority.c_str())); - // The authority section of the URL is ignored when a unix domain socket is - // to be used. - throw_on_error(curl_.easy_setopt_url( - handle.get(), ("http://localhost" + url.path).c_str())); - } else { - throw_on_error(curl_.easy_setopt_url( - handle.get(), (url.scheme + "://" + url.authority + url.path).c_str())); - } + configure_handle(handle.get(), *request, url); { std::lock_guard lock(mutex_); @@ -403,6 +437,39 @@ Expected CurlImpl::post( return Error{Error::CURL_REQUEST_SETUP_FAILED, curl_.easy_strerror(error)}; } +void CurlImpl::configure_handle(CURL *handle, Request &request, + const URL &url) { + throw_on_error(curl_.easy_setopt_httpheader(handle, request.request_headers)); + throw_on_error(curl_.easy_setopt_private(handle, &request)); + throw_on_error(curl_.easy_setopt_errorbuffer(handle, request.error_buffer)); + throw_on_error(curl_.easy_setopt_post(handle, 1)); + throw_on_error(curl_.easy_setopt_postfieldsize( + handle, static_cast(request.request_body.size()))); + throw_on_error( + curl_.easy_setopt_postfields(handle, request.request_body.data())); + throw_on_error(curl_.easy_setopt_headerfunction(handle, &on_read_header)); + throw_on_error(curl_.easy_setopt_headerdata(handle, &request)); + throw_on_error(curl_.easy_setopt_writefunction(handle, &on_read_body)); + throw_on_error(curl_.easy_setopt_writedata(handle, &request)); + + throw_on_error(curl_.easy_setopt_noproxy( + handle, proxy_config_.no_proxy ? proxy_config_.no_proxy->c_str() : "")); + const StringView proxy = resolve_proxy(url, proxy_config_); + throw_on_error(curl_.easy_setopt_proxy(handle, proxy.data())); + + if (is_unix_socket(url)) { + throw_on_error( + curl_.easy_setopt_unix_socket_path(handle, url.authority.c_str())); + // The authority section of the URL is ignored when a unix domain socket is + // to be used. + throw_on_error( + curl_.easy_setopt_url(handle, ("http://localhost" + url.path).c_str())); + } else { + throw_on_error(curl_.easy_setopt_url( + handle, (url.scheme + "://" + url.authority + url.path).c_str())); + } +} + void CurlImpl::clear_requests() { for (const auto &handle : request_handles_) { char *user_data; @@ -650,5 +717,4 @@ void CurlImpl::HeaderReader::visit( } } -} // namespace tracing -} // namespace datadog +} // namespace datadog::tracing diff --git a/src/datadog/curl.h b/src/datadog/curl.h index bbaf380a9..3ff8e2398 100644 --- a/src/datadog/curl.h +++ b/src/datadog/curl.h @@ -1,26 +1,20 @@ #pragma once // This component provides a `class`, `Curl`, that implements the `HTTPClient` -// interface in terms of [libcurl][1]. `class Curl` manages a thread that is -// used as the event loop for libcurl. +// interface in terms of [libcurl](https://curl.se/libcurl)]. `class Curl` +// manages a thread that is used as the event loop for libcurl. // // If this library was built in a mode that does not include libcurl, then this // file and its implementation, `curl.cpp`, will not be included. -// -// [1]: https://curl.se/libcurl/ #include #include #include -#include -#include #include -#include #include -namespace datadog { -namespace tracing { +namespace datadog::tracing { // `class CurlLibrary` has one member function for every libcurl function used // in the implementation of this component. @@ -50,10 +44,12 @@ class CurlLibrary { virtual CURLcode easy_setopt_headerdata(CURL *handle, void *data); virtual CURLcode easy_setopt_headerfunction(CURL *handle, HeaderCallback); virtual CURLcode easy_setopt_httpheader(CURL *handle, curl_slist *headers); + virtual CURLcode easy_setopt_noproxy(CURL *handle, const char *no_proxy); virtual CURLcode easy_setopt_post(CURL *handle, long post); virtual CURLcode easy_setopt_postfields(CURL *handle, const char *data); virtual CURLcode easy_setopt_postfieldsize(CURL *handle, long size); virtual CURLcode easy_setopt_private(CURL *handle, void *pointer); + virtual CURLcode easy_setopt_proxy(CURL *handle, const char *proxy); virtual CURLcode easy_setopt_unix_socket_path(CURL *handle, const char *path); virtual CURLcode easy_setopt_url(CURL *handle, const char *url); virtual CURLcode easy_setopt_writedata(CURL *handle, void *data); @@ -104,5 +100,4 @@ class Curl : public HTTPClient { std::string config() const override; }; -} // namespace tracing -} // namespace datadog +} // namespace datadog::tracing diff --git a/test/test_curl.cpp b/test/test_curl.cpp index 3c88ef88a..e48a9690c 100644 --- a/test/test_curl.cpp +++ b/test/test_curl.cpp @@ -1,17 +1,11 @@ -#include #include -#include -#include -#include #include #include -#include -#include -#include +#include #include -#include "datadog/clock.h" +#include "common/environment.h" #include "mocks/loggers.h" #include "null_logger.h" #include "test.h" @@ -495,3 +489,85 @@ CURL_TEST("post() deadline exceeded before request start") { REQUIRE(error_delivered->code == Error::CURL_DEADLINE_EXCEEDED_BEFORE_REQUEST_START); } + +CURL_TEST("proxy is taken from the environment and forwarded to libcurl") { + using datadog::test::EnvGuard; + + class ProxyCapturingCurlLibrary : public SingleRequestMockCurlLibrary { + public: + Optional proxy_; + Optional no_proxy_; + + CURLcode easy_setopt_proxy(CURL *, const char *proxy) override { + proxy_ = proxy; + return CURLE_OK; + } + CURLcode easy_setopt_noproxy(CURL *, const char *no_proxy) override { + no_proxy_ = no_proxy; + return CURLE_OK; + } + }; + + std::list cleared; + for (const char *name : + {"http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY", "all_proxy", + "ALL_PROXY", "no_proxy", "NO_PROXY"}) { + cleared.emplace_back(name, ""); + } + + const auto clock = default_clock; + const auto logger = std::make_shared(); + ProxyCapturingCurlLibrary library; + + const auto post_to = [&](const std::string &scheme) { + Curl client{logger, clock, library}; + const HTTPClient::URL url{scheme, "agent:8126", "/", ""}; + REQUIRE( + client.post(url, ignore, "body", ignore, ignore, clock().tick + 10s)); + client.drain(clock().tick + 1s); + }; + + SECTION("http scheme uses http_proxy") { + EnvGuard env{"http_proxy", "http://proxy:8080"}; + post_to("http"); + REQUIRE(library.proxy_ == "http://proxy:8080"); + } + + SECTION("https scheme uses https_proxy") { + EnvGuard env{"https_proxy", "http://secure:8080"}; + post_to("https"); + REQUIRE(library.proxy_ == "http://secure:8080"); + } + + SECTION("scheme-specific proxy falls back to all_proxy") { + EnvGuard env{"all_proxy", "http://any:8080"}; + post_to("http"); + REQUIRE(library.proxy_ == "http://any:8080"); + } + + SECTION("no_proxy is forwarded") { + EnvGuard env{"no_proxy", "agent,localhost"}; + post_to("http"); + REQUIRE(library.no_proxy_ == "agent,localhost"); + } + +#ifndef _WIN32 // Windows environment variable names are case-insensitive + SECTION("uppercase HTTP_PROXY is ignored (httpoxy)") { + EnvGuard env{"HTTP_PROXY", "http://attacker:8080"}; + post_to("http"); + REQUIRE(library.proxy_ == ""); + } +#endif + + SECTION("absent proxy environment yields empty options") { + post_to("http"); + REQUIRE(library.proxy_ == ""); + REQUIRE(library.no_proxy_ == ""); + } + + SECTION("unix sockets are never proxied") { + EnvGuard env{"http_proxy", "http://proxy:8080"}; + post_to("unix"); + REQUIRE(library.proxy_ == ""); + } +} From d38a9d8973b255bd51520841c0f57cd7c06780db Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Fri, 19 Jun 2026 11:20:17 +0200 Subject: [PATCH 07/59] Bump version following delivery of v2.1.1 (#329) --- src/datadog/version.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datadog/version.cpp b/src/datadog/version.cpp index 7c5b4d29e..8b9710c64 100644 --- a/src/datadog/version.cpp +++ b/src/datadog/version.cpp @@ -2,7 +2,7 @@ namespace datadog::tracing { -#define DD_TRACE_VERSION "v2.1.1" +#define DD_TRACE_VERSION "v2.1.2" const char* const tracer_version = DD_TRACE_VERSION; const char* const tracer_version_string = From 227add0f355119c5a23f2bf809f3f1863ce335ce Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Thu, 2 Jul 2026 17:28:36 +0200 Subject: [PATCH 08/59] Reformat documentation. Cleaned deprecated typographic rules. (#331) --- CONTRIBUTING.md | 22 +- LICENSE.md => LICENSE | 0 README.md | 47 +- SECURITY.md | 14 +- benchmark/README.md | 37 +- benchmark/hasher.cpp | 6 +- bin/with-toolchain | 4 +- doc/README.md | 50 +- doc/decisions.md | 52 +- doc/maintainers.md | 882 ++++++++++++------------- examples/hasher/hasher.cpp | 6 +- examples/http-server/common/httplib.h | 2 +- examples/http-server/proxy/proxy.cpp | 2 +- examples/http-server/server/server.cpp | 4 +- fuzz/README.md | 21 +- fuzz/w3c-propagation/README.md | 36 +- include/datadog/cerr_logger.h | 2 +- include/datadog/clock.h | 2 +- include/datadog/collector.h | 6 +- include/datadog/datadog_agent_config.h | 10 +- include/datadog/dict_reader.h | 2 +- include/datadog/dict_writer.h | 4 +- include/datadog/environment.h | 2 +- include/datadog/error.h | 2 +- include/datadog/event_scheduler.h | 6 +- include/datadog/expected.h | 8 +- include/datadog/http_client.h | 12 +- include/datadog/optional.h | 8 +- include/datadog/propagation_style.h | 2 +- include/datadog/sampling_mechanism.h | 10 +- include/datadog/sampling_priority.h | 2 +- include/datadog/span.h | 34 +- include/datadog/string_view.h | 10 +- include/datadog/trace_segment.h | 14 +- include/datadog/tracer.h | 8 +- include/datadog/tracer_config.h | 32 +- src/datadog/common/hash.h | 14 +- src/datadog/curl.cpp | 6 +- src/datadog/curl.h | 4 +- src/datadog/datadog_agent.cpp | 8 +- src/datadog/datadog_agent.h | 2 +- src/datadog/datadog_agent_config.cpp | 2 +- src/datadog/glob.cpp | 4 +- src/datadog/glob.h | 2 +- src/datadog/http_client.cpp | 10 +- src/datadog/json.hpp | 12 +- src/datadog/json_serializer.h | 2 +- src/datadog/msgpack.h | 33 +- src/datadog/random.cpp | 2 +- src/datadog/sampling_util.h | 4 +- src/datadog/span_data.h | 4 +- src/datadog/span_sampler.h | 2 +- src/datadog/span_sampler_config.cpp | 10 +- src/datadog/tag_propagation.cpp | 12 +- src/datadog/tag_propagation.h | 2 +- src/datadog/trace_id.cpp | 2 +- src/datadog/trace_sampler.cpp | 4 +- src/datadog/trace_sampler.h | 20 +- src/datadog/trace_sampler_config.cpp | 4 +- src/datadog/trace_segment.cpp | 4 +- src/datadog/tracer.cpp | 8 +- src/datadog/tracer_config.cpp | 2 +- src/datadog/w3c_propagation.cpp | 2 +- test/README.md | 24 +- test/system-tests/utils.h | 2 +- test/test_cerr_logger.cpp | 2 +- test/test_curl.cpp | 2 +- test/test_span.cpp | 4 +- test/test_trace_sampler.cpp | 4 +- test/test_trace_segment.cpp | 2 +- test/test_tracer.cpp | 6 +- test/test_tracer_config.cpp | 4 +- 72 files changed, 763 insertions(+), 829 deletions(-) rename LICENSE.md => LICENSE (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 164f912cc..ef6af873f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,16 @@ -Contributing to dd-trace-cpp -============================ +# Contributing to dd-trace-cpp + Pull requests for bug fixes are welcome. Before submitting new features or changes to current functionality, [open an -issue](https://github.com/DataDog/dd-trace-cpp/issues/new) and discuss your -ideas or propose the changes you wish to make. After a resolution is reached, a -PR can be submitted for review. +issue](https://github.com/DataDog/dd-trace-cpp/issues/new) and discuss your ideas or propose the +changes you wish to make. After a resolution is reached, a PR can be submitted for review. + +## Code Style + +C++ code is formatted using `clang-format-14`. Before submitting code changes, run the following +command: -Code Style ----------- -C++ code is formatted using `clang-format-14`. Before submitting code changes, -run the following command: -```shell -$ bin/format +```shell +bin/format ``` diff --git a/LICENSE.md b/LICENSE similarity index 100% rename from LICENSE.md rename to LICENSE diff --git a/README.md b/README.md index dcf5adbb8..66cb32e5e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -Datadog C++ Tracing Library -=========================== +# Datadog C++ Tracing Library ```c++ #include @@ -37,26 +36,30 @@ int main() { std::this_thread::sleep_for(std::chrono::seconds(2)); } ``` + See the [examples](examples) directory for more extensive usage examples. ## Platform Support -The library has been tested and is compatible on the following CPU architecture, OS and compiler combinations: -- x86_64 and arm64 Linux with GCC 11.4. -- x86_64 and arm64 Linux with Clang 14. -- x86_64 Windows with MSVC 2022. -- arm64 macOS with Apple Clang 15. +The library has been tested and is compatible on the following CPU architecture, OS and compiler +combinations: + +- x86_64 and arm64 Linux with GCC 11.4; +- x86_64 and arm64 Linux with Clang 14; +- x86_64 Windows with MSVC 2022; +- arm64 macOS with Apple Clang 15. ## Building and Installation ### Requirements + `dd-trace-cpp` requires a [supported](#platform-support) C++17 compiler. -A recent version of CMake is required (`3.28`), which might not be in your -system's package manager. [bin/install-cmake](bin/install-cmake) is an installer -for a recent CMake, on Linux. +A recent version of CMake is required (`3.28`), which might not be in your system's package manager. +[bin/install-cmake](bin/install-cmake) is an installer for a recent CMake, on Linux. ### Building + Build this library from source using [CMake](https://cmake.org). ```shell @@ -74,6 +77,7 @@ cmake -B build -DBUILD_SHARED_LIBS=1 . ``` ### Installation + Installation places a shared library and public headers into the appropriate system directories (`/usr/local/[…]`), or to a specified installation prefix. Example: @@ -83,12 +87,13 @@ cmake --install build --prefix=.install ``` ### Optional: Linking to the shared library + In case you decided to build the shared library: -When building an executable that uses `dd-trace-cpp`, specify the path to -the installed headers using an appropriate `-I` option. If the library was -installed into the default system directories, then the `-I` option is not -needed. +When building an executable that uses `dd-trace-cpp`, specify the path to the installed headers +using an appropriate `-I` option. If the library was installed into the default system directories, +then the `-I` option is not needed. + ```shell c++ -I/path/to/dd-trace-cpp/.install/include -c -o my_app.o my_app.cpp ``` @@ -97,15 +102,17 @@ When linking an executable that uses `dd-trace-cpp`, specify linkage to the built library using the `-ldd_trace_cpp` option and an appropriate `-L` option. If the library was installed into the default system directories, then the `-L` options is not needed. The `-ldd_trace_cpp` option is always needed. + ```shell c++ -o my_app my_app.o -L/path/to/dd-trace-cpp/.install/lib -ldd_trace_cpp ``` -Test ----- +## Test + Pass `-DDD_TRACE_BUILD_TESTING=1` to `cmake` to include the unit tests in the build. The resulting unit test executable is `test/tests` within the build directory. + ```shell cmake -B build -DDD_TRACE_BUILD_TESTING=1 . cmake --build build -j @@ -114,7 +121,7 @@ cmake --build build -j Alternatively, [bin/test](bin/test) is provided for convenience. -Contributing ------------- -See the [contributing guidelines](CONTRIBUTING.md) and the [maintainer docs](doc/maintainers.md) -for information on the overall structure of the repository. +## Contributing + +See the [contributing guidelines](CONTRIBUTING.md) and the [maintainer docs](doc/maintainers.md) for +information on the overall structure of the repository. diff --git a/SECURITY.md b/SECURITY.md index 6177cd67f..bdd299333 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,15 +1,19 @@ # Security Policy -This document outlines the security policy for the Datadog C++ client library (aka C++ tracer) and what to do if you discover a security vulnerability in the project. -Most notably, please do not share the details in a public forum (such as in a discussion, issue, or pull request) but instead reach out to us with the details. -This gives us an opportunity to release a fix for others to benefit from by the time details are made public. +This document outlines the security policy for the Datadog C++ client library (a.k.a. C++ tracer) +and what to do if you discover a security vulnerability in the project. Most notably, please do not +share the details in a public forum (such as in a discussion, issue, or pull request) but instead +reach out to us with the details. This gives us an opportunity to release a fix for others to +benefit from by the time details are made public. ## Supported Versions -We accept vulnerability submissions for the [currently maintained release](https://github.com/DataDog/dd-trace-cpp/releases). +We accept vulnerability submissions for the [currently maintained +release](https://github.com/DataDog/dd-trace-cpp/releases). ## Reporting a Vulnerability -If you discover a vulnerability in the Datadog C++ client library (or any Datadog product for that matter) please submit details to the following email address: +If you discover a vulnerability in the Datadog C++ client library (or any Datadog product for that +matter) please submit details to the following email address: * [security@datadoghq.com](mailto:security@datadoghq.com) diff --git a/benchmark/README.md b/benchmark/README.md index e26f95dd1..6b16cb5e2 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -1,19 +1,18 @@ -Microbenchmarks -=============== -This directory contains the definition of a program that measures the timing and -resource consumption of a test tracing scenario. +# Microbenchmarks -The benchmark uses [Google Benchmark][1], whose source is included as a git -submodule under `./google-benchmark`. +This directory contains the definition of a program that measures the timing and resource +consumption of a test tracing scenario. -The scenario that's measured is similar to the [../examples/hasher][3] setup. A trace -is created whose structure reflects that of a particular file directory -structure. The directory structure, in this case, is the source tree of the -[Tiny C Compiler][4], whose source is included as a git submodule under -`./tinycc`. +The benchmark uses [Google Benchmark](https://github.com/google/benchmark), whose source is included +as a git submodule under `./google-benchmark`. -The scenario does not use the network, spawn any threads, or read/write -any files. The operations that are implicitly covered by the scenario are: +The scenario that's measured is similar to the [../examples/hasher](../examples/hasher) setup. A +trace is created whose structure reflects that of a particular file directory structure. The +directory structure, in this case, is the source tree of the [Tiny C +Compiler](https://bellard.org/tcc), whose source is included as a git submodule under `./tinycc`. + +The scenario does not use the network, spawn any threads, or read/write any files. The operations +that are implicitly covered by the scenario are: - configuring and initializing a tracer, - creating a trace, @@ -23,14 +22,8 @@ any files. The operations that are implicitly covered by the scenario are: - finalizing a trace and making a sampling decision, - serializing a trace as MessagePack. -[../bin/benchmark][6] is a script that builds dd-trace-cpp, this benchmark, and +[../bin/benchmark](../bin/benchmark) is a script that builds `dd-trace-cpp`, this benchmark, and then runs the benchmark. -This benchmark is intended to be driven by Datadog's internal benchmarking -platform. See [../.gitlab/benchmarks.yml][7]. - -[1]: https://github.com/google/benchmark -[3]: ../examples/hasher -[4]: https://bellard.org/tcc/ -[6]: ../bin/benchmark -[7]: ../.gitlab/benchmarks.yml +This benchmark is intended to be driven by Datadog's internal benchmarking platform. See +[../.gitlab/benchmarks.yml](../.gitlab/benchmarks.yml). diff --git a/benchmark/hasher.cpp b/benchmark/hasher.cpp index 548b522c0..c0a143e74 100644 --- a/benchmark/hasher.cpp +++ b/benchmark/hasher.cpp @@ -3,11 +3,11 @@ // If the path does not exist, print an error. // // If the path exists and is a regular file, print the SHA256 digest of the -// file's contents. Produce a single tracing span indicating the calculation. +// file's contents. Produce a single tracing span indicating the calculation. // // If the path exists and is a directory, calculate the SHA256 digest of the // directory from the names and digests of its children, combined in some -// canonical format. Produce a trace whose structure reflects the directory +// canonical format. Produce a trace whose structure reflects the directory // structure. // // Files that are neither regular files nor directories are ignored. @@ -47,7 +47,7 @@ std::string hex(const Digest &digest) { } // Store into the specified `digest` the SHA256 digest of the contents of the -// specified `file`. Return zero on success, or a nonzero value if an error +// specified `file`. Return zero on success, or a nonzero value if an error // occurs. int sha256(Digest &digest, const fs::path &file) { std::ifstream in(file); diff --git a/bin/with-toolchain b/bin/with-toolchain index 21af87625..5a6727776 100755 --- a/bin/with-toolchain +++ b/bin/with-toolchain @@ -9,7 +9,7 @@ usage: with-toolchain llvm [COMMAND ...] Execute COMMAND in an environment that uses either GNU's compilers (gcc and g++) or LLVM's compilers (clang and clang++). - + with-toolchain --help with-toolchain -h Print this message. @@ -33,7 +33,7 @@ case "$1" in llvm) toolchain=llvm ;; *) - >&2 echo "Invalid toolchain value \"$1\". Expected \"gnu\" or \"llvm\"." + >&2 echo "Invalid toolchain value \"$1\". Expected \"gnu\" or \"llvm\"." exit 2 ;; esac diff --git a/doc/README.md b/doc/README.md index 2376261d9..41963ae91 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,29 +1,28 @@ -Logical Component Relationships -------------------------------- +# Logical Component Relationships + - Vertices are components. -- Edges are ownership relationships between components. Each edge is labeled - by the kind of "smart pointer" that could implement that kind of - relationship. +- Edges are ownership relationships between components. Each edge is labeled by the kind of "smart + pointer" that could implement that kind of relationship. - Components containing a padlock are protected by a mutex. ![diagram](ownership.svg) -Objects -------- -- _Span_ has a beginning, end, and tags. It is associated with a _TraceSegment_. -- _TraceSegment_ is part of a trace. It makes sampling decisions, detects when - it is finished, and sends itself to the _Collector_. -- _Collector_ receives trace segments. It provides a callback to deliver - sampler modifications, if applicable. -- _Tracer_ is responsible for creating trace segments. It contains the - instances of, and configuration for, the _Collector_, _TraceSampler_, and - _SpanSampler_. A tracer is created from a _TracerConfig_. -- _TraceSampler_ is used by trace segments to decide when to keep or drop - themselves. -- _SpanSampler_ is used by trace segments to decide which spans to keep when - the segment is dropped. -- _TracerConfig_ contains all of the information needed to configure the collector, - trace sampler, and span sampler, as well as defaults for span properties. +## Objects + +- `Span` has a beginning, end, and tags. It is associated with a `TraceSegment`. +- `TraceSegment` is part of a trace. It makes sampling decisions, detects when it is finished, and + sends itself to the `Collector`. +- `Collector` receives trace segments. It provides a callback to deliver sampler modifications, if + applicable. +- `Tracer` is responsible for creating trace segments. It contains the instances of, and + configuration for, the `Collector`, `TraceSampler`, and `SpanSampler`. A tracer is created from a + `TracerConfig`. +- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. +- `SpanSampler` is used by trace segments to decide which spans to keep when the segment is dropped. +- `TracerConfig` contains all of the information needed to configure the collector, trace sampler, + and span sampler, as well as defaults for span properties. + +## Usage Intended usage is: @@ -32,11 +31,8 @@ Intended usage is: 3. Use the `Tracer` to create and/or extract local root `Span`s. 4. Use `Span` to create children and/or inject context. 5. Use a `Span`'s `TraceSegment` to perform trace-wide operations. -6. When all `Span`s in ` TraceSegment` are finished, the segment is sent to the +6. When all `Span`s in `TraceSegment` are finished, the segment is sent to the `Collector`. -Different instances of `Tracer` are independent of each other. If an -application wishes to reconfigure tracing at runtime, it can create another -`Tracer` using the new configuration. - -[1]: https://datadog.github.io/dd-trace-cpp/datadog +Different instances of `Tracer` are independent of each other. If an application wishes to +reconfigure tracing at runtime, it can create another `Tracer` using the new configuration. diff --git a/doc/decisions.md b/doc/decisions.md index 2a3ee0201..f9bea6fac 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -1,39 +1,39 @@ Here are some topics that were discussed during the design of this library. - Which version of C++ do we require? + - C++17 - Which C core libraries do we produce binaries for? - - glibc - - musl + - glibc + - musl - Which build systems do we support? - - CMake - - Bazel + - CMake + - Bazel - Which unit testing framework? - - Catch2 - - Google Test -- Integration tests? + - Catch2 + - Google Test - Error handling options: - - `std::variant` - - homebrew a `std::expected` - - `throw Error(...)` - - `RCode do_thing(T& output)` - - `struct Result { Error error; T value; }` + - `std::variant` + - homebrew a `std::expected` + - `throw Error(...)` + - `RCode do_thing(T& output)` + - `struct Result { Error error; T value; }` - Is a `Span` RAII with respect to start/finish? -- When we begin calculating trace metrics within the tracer, we'll need to hit - a `/stats` HTTP endpoint. - - Does it live on the same thread as the `Collector`? - - Do we invent a library-specific `HTTPClient` interface? +- When we begin calculating trace metrics within the tracer, we'll need to hit a `/stats` HTTP + endpoint. + - Does it live on the same thread as the `Collector`? + - Do we invent a library-specific `HTTPClient` interface? - Do we keep using cURL for the default `Collector`? - - In-tree C++ library instead? + - In-tree C++ library instead? - Naming conventions: - - `class TypeName;` - - `.member_function();` - - `free_function();` - - `f(int func_arg);` - - `int local_var;` - - `int private_member_;` - - `int public_member;` - - `enum Color { red, green, blue };` - - `which_one` + - `class TypeName;` + - `.member_function();` + - `free_function();` + - `f(int func_arg);` + - `int local_var;` + - `int private_member_;` + - `int public_member;` + - `enum Color { red, green, blue };` + - `which_one` - Can tracing be reconfigured at runtime? - Can multiple tracers share a collector? - Are rate limits per-tracer, per-process, or other? diff --git a/doc/maintainers.md b/doc/maintainers.md index 76cf4a6be..e8dd0e4e2 100644 --- a/doc/maintainers.md +++ b/doc/maintainers.md @@ -1,168 +1,159 @@ -Care and Feeding of Your New Tracing Library -============================================ +# Care and Feeding of Your New Tracing Library + Congratulations! You are now the proud owner of a distributed tracing library. -The primary purpose of this guide is to describe salient features of the -library's design. dd-trace-cpp differs considerably from its [older sibling][1] -and [peers][2]. +The primary purpose of this guide is to describe salient features of the library's design. +`dd-trace-cpp` differs considerably from its [older +sibling](https://github.com/DataDog/dd-opentracing-cpp) and +[peers](https://github.com/open-telemetry/opentelemetry-cpp). -This guide will also cover operations performed by maintainers of the library, -such as scooping the box, applying flea medication, and regular trips to the -vet. +This guide will also cover operations performed by maintainers of the library, such as scooping the +box, applying flea medication, and regular trips to the vet. -Design ------- +## Design ### Span -[class Span][3] is the component with which users will interact the most. + +[class Span](../include/datadog/span.h) is the component with which users will interact the most. Each span: - has an "ID," - is associated with a "trace ID," -- is associated with a "service," which has a "service type," a "version," and - an "environment," +- is associated with a "service," which has a "service type," a "version," and an "environment," - has a "name" (sometimes called the "operation name"), -- has a "resource name," which is a description of the thing that the span is - about, -- contains information about whether an error occurred during the represented - operation, including an error message, error type, and stack trace, +- has a "resource name," which is a description of the thing that the span is about, +- contains information about whether an error occurred during the represented operation, including + an error message, error type, and stack trace, - includes an arbitrary name/value mapping of strings, called "tags," - has a start time indicating when the represented operation began, - has a duration indicating how long the represented operation took to finish. -Aside from setting and retrieving its attributes, `Span` also has the following -operations: +Aside from setting and retrieving its attributes, `Span` also has the following operations: - `parent.create_child(...)` returns a new `Span` that is a child of `parent`. - `span.inject(writer)` writes trace propagation information to a - [DictWriter][11], which is an interface for setting a name/value mapping, e.g. - in HTTP request headers. + [DictWriter](../include/datadog/dict_writer.h), which is an interface for setting a name/value + mapping, e.g. in HTTP request headers. A `Span` does not own its data. `class Span` contains a raw pointer to a [class -SpanData][4], which contains the actual attributes of the span. The `SpanData` -is owned by a `TraceSegment`, which is described in the next section. The -`Span` holds a `shared_ptr` to its `TraceSegment`. - -By default, a span's start time is when it is created, and its end time (from -which its duration is calculated) is when it is destroyed. However, a span's -start time can be specified when it is created, via `SpanConfig::start` (see -[span_config.h][5]), and a span's end time can be overridden via -`Span::set_end_time`. - -When a span is destroyed, it is considered "finished" and notifies its -`TraceSegment`. There is no way to "finish" a span without destroying it. You -can override its end time throughout the lifetime of the `Span` object, but a -`TraceSegment` does not consider the span finished until the `Span` object is -destroyed. This allows us to avoid "finished" `Span` states. - -Along similar lines, `class Span` is move-only. Its copy constructor is deleted. -Functions that produce spans return them by value, but only one copy of a span -can exist at a time. In fact, `class Span` is even more strict than move-only: -its assignment operator is deleted, including the move-assignment operator. To -see why, consider the following (disallowed) example: +SpanData](../src/datadog/span_data.h), which contains the actual attributes of the span. The +`SpanData` is owned by a `TraceSegment`, which is described in the next section. The `Span` holds a +`shared_ptr` to its `TraceSegment`. + +By default, a span's start time is when it is created, and its end time (from which its duration is +calculated) is when it is destroyed. However, a span's start time can be specified when it is +created, via `SpanConfig::start` (see [span_config.h](../include/datadog/span_config.h)), and a +span's end time can be overridden via `Span::set_end_time`. + +When a span is destroyed, it is considered "finished" and notifies its `TraceSegment`. There is no +way to "finish" a span without destroying it. You can override its end time throughout the lifetime +of the `Span` object, but a `TraceSegment` does not consider the span finished until the `Span` +object is destroyed. This allows us to avoid "finished" `Span` states. + +Along similar lines, `class Span` is move-only. Its copy constructor is deleted. Functions that +produce spans return them by value, but only one copy of a span can exist at a time. In fact, `class +Span` is even more strict than move-only: its assignment operator is deleted, including the +move-assignment operator. To see why, consider the following (disallowed) example: + ```c++ Span span = tracer.create_span(); // ... // Let's reuse the variable `span`. span = tracer.create_span(); ``` -Move assignment begins with two objects and ends up with one object (and one -empty shell of an object). -Since destroying a `Span` has the side effect of finishing it, one sensible -definition of `Span::operator=(Span&& other)` would be equivalent to: +Move assignment begins with two objects and ends up with one object (and one empty shell of an +object). + +Since destroying a `Span` has the side effect of finishing it, one sensible definition of +`Span::operator=(Span&& other)` would be equivalent to: + ```c++ this->~Span(); new (this) Span(std::move(other)); return *this; ``` -This would have the potentially surprising feature of _finishing_ the first span -when you wish to replace it with another, i.e. there would always be two spans. - -This could be avoided if we could guarantee that the two `Span`s belong to the -same `TraceSegment`. Then move-assigning a `Span` could be defined as -move-assigning its `SpanData` and somehow annotating the moved-from `SpanData` -as being invalid. However, if the two `Span`s belong to different -`TraceSegment`s, then it could be that the moved-to `Span`'s `TraceSegment` -consists of only that one `Span`. Now we have to account for empty -`TraceSegment` states. This could all be dealt with, but no matter what we -decide, it would always be the case that `Span::operator=(Span&&)` has the -effect of making the original span (`this`) either finish implicitly or -_disappear entirely_, which is at odds with its otherwise [RAII][6] nature. + +This would have the potentially surprising feature of _finishing_ the first span when you wish to +replace it with another, i.e. there would always be two spans. + +This could be avoided if we could guarantee that the two `Span`s belong to the same `TraceSegment`. +Then move-assigning a `Span` could be defined as move-assigning its `SpanData` and somehow +annotating the moved-from `SpanData` as being invalid. However, if the two `Span`s belong to +different `TraceSegment`s, then it could be that the moved-to `Span`'s `TraceSegment` consists of +only that one `Span`. Now we have to account for empty `TraceSegment` states. This could all be +dealt with, but no matter what we decide, it would always be the case that `Span::operator=(Span&&)` +has the effect of making the original span (`this`) either finish implicitly or _disappear +entirely_, which is at odds with its otherwise +[RAII](https://en.cppreference.com/w/cpp/language/raii) nature. To avoid these issues, assignment to `Span` objects is disallowed. -Another opinionated property of `Span` is that it is not an interface, nor does -it implement an interface. Usually it is considered polite for a C++ library to -deal in handles (`unique_ptr` or `shared_ptr`) to interfaces, i.e. classes that -contain pure virtual functions. This way, a client of the library can substitute -an alternative implementation to the interface(s) for testing or for when the -behavior of the library is not desired. - -At the risk of being impolite, dd-trace-cpp takes a different approach. `Span` -is a concrete type whose behavior cannot be substituted. Instead, there are -other places in the library where dependency injection can be used to restrict -or alter the behavior of the library. The trade-off is that `Span` and related -components must always "go through the motions" of their definitions and cannot -be completely customized, but in exchange the indirection, pointer semantics, -and null states that accompany handle-to-interface are avoided. +Another opinionated property of `Span` is that it is not an interface, nor does it implement an +interface. Usually it is considered polite for a C++ library to deal in handles (`unique_ptr` or +`shared_ptr`) to interfaces, i.e. classes that contain pure virtual functions. This way, a client of +the library can substitute an alternative implementation to the interface(s) for testing or for when +the behavior of the library is not desired. + +At the risk of being impolite, dd-trace-cpp takes a different approach. `Span` is a concrete type +whose behavior cannot be substituted. Instead, there are other places in the library where +dependency injection can be used to restrict or alter the behavior of the library. The trade-off is +that `Span` and related components must always "go through the motions" of their definitions and +cannot be completely customized, but in exchange the indirection, pointer semantics, and null states +that accompany handle-to-interface are avoided. ### Trace Segment + A "trace" is the entire tree of spans having the same trace ID. -Within one process/worker/service, though, typically there is not an entire -trace but only part of the trace. Let's call the process/worker/service a -"tracer." +Within one process/worker/service, though, typically there is not an entire trace but only part of +the trace. Let's call the process/worker/service a "tracer." -One portion of a trace that's passing through the tracer is called a "trace -segment." A trace segment begins either at the trace's root span or at a span -extracted from trace context, e.g. a span created from the `X-Datadog-Trace-Id` -and `X-Datadog-Parent-Id` HTTP request headers. The trace segment includes all -local descendants of that span, and has as its "boundary" any descendant spans -without children or descendant spans that were used to inject trace context -out-of-tracer, e.g. in outgoing HTTP request headers. +One portion of a trace that's passing through the tracer is called a "trace segment." A trace +segment begins either at the trace's root span or at a span extracted from trace context, e.g. a +span created from the `X-Datadog-Trace-Id` and `X-Datadog-Parent-Id` HTTP request headers. The trace +segment includes all local descendants of that span, and has as its "boundary" any descendant spans +without children or descendant spans that were used to inject trace context out-of-tracer, e.g. in +outgoing HTTP request headers. -There might be more than one trace segment for the _same trace_ within a tracer -at the same time. Consider the diagram below. +There might be more than one trace segment for the _same trace_ within a tracer at the same time. +Consider the diagram below. flame graph -If our tracer is "service X," then this trace passes through the tracer twice. -We would have two concurrent trace segments for the same trace. +If our tracer is "service X," then this trace passes through the tracer twice. We would have two +concurrent trace segments for the same trace. -`class TraceSegment` is defined in [trace_segment.h][7]. `TraceSegment` objects -are managed internally by the library. That is to say, a user never creates a +`class TraceSegment` is defined in [trace_segment.h](../include/datadog/trace_segment.h). +`TraceSegment` objects are managed internally by the library. That is to say, a user never creates a `TraceSegment`. -The library creates a `TraceSegment` whenever a new trace is created or when -trace context is extracted. This is the job of `class Tracer`, described in the -next section. +The library creates a `TraceSegment` whenever a new trace is created or when trace context is +extracted. This is the job of `class Tracer`, described in the next section. -Primarily, `TraceSegment` is a bag of spans. It contains a -`vector>`. `Span` objects then refer to the `SpanData` -objects via raw pointers. Now that I think about it, `deque` would -work just as well. +Primarily, `TraceSegment` is a bag of spans. It contains a `vector>`. `Span` +objects then refer to the `SpanData` objects via raw pointers. Now that I think about it, +`deque` would work just as well. -When one of a trace segment's spans creates a child, the child is registered -with the trace segment. When a span is finished, the trace segment is notified. -The trace segment keeps track of how many spans it contains (the size of its -`vector`) and how many spans are finished. When the two numbers are equal, the -trace segment is finished. +When one of a trace segment's spans creates a child, the child is registered with the trace segment. +When a span is finished, the trace segment is notified. The trace segment keeps track of how many +spans it contains (the size of its `vector`) and how many spans are finished. When the two numbers +are equal, the trace segment is finished. -When a trace segment is finished, it performs some finalization logic in order -to prepare its spans for submission to the `Collector`. Then it moves its spans -into the collector via `Collector::send`, and a short time later the trace -segment is destroyed. See `TraceSegment::span_finished` in -[trace_segment.cpp][8]. `Collector` is described in a subsequent section. +When a trace segment is finished, it performs some finalization logic in order to prepare its spans +for submission to the `Collector`. Then it moves its spans into the collector via `Collector::send`, +and a short time later the trace segment is destroyed. See `TraceSegment::span_finished` in +[trace_segment.cpp](../src/datadog/trace_segment.cpp). `Collector` is described in a subsequent +section. -A `TraceSegment` contains `shared_ptr`s to everything that it needs in order to -do its job. Those objects are created by `class Tracer` when the tracer is -configured, and then shared with `TraceSegment` when the `TraceSegment` is -created. +A `TraceSegment` contains `shared_ptr`s to everything that it needs in order to do its job. Those +objects are created by `class Tracer` when the tracer is configured, and then shared with +`TraceSegment` when the `TraceSegment` is created. ### Tracer -`class Tracer` is what users configure, and it is how `Span`s are extracted from -trace context or created as a trace's root. See [tracer.h][9]. + +`class Tracer` is what users configure, and it is how `Span`s are extracted from trace context or +created as a trace's root. See [tracer.h](../include/datadog/tracer.h). `Tracer` has two member functions: @@ -173,196 +164,208 @@ and another that combines them: - `extract_or_create_span(...)`. -All of these result in the creation of a new `TraceSegment` (or otherwise return -an error). The `Tracer`'s data members, which were initialized based on the -tracer's configuration, are copied into the `TraceSegment` so that the -`TraceSegment` can operate independently. +All of these result in the creation of a new `TraceSegment` (or otherwise return an error). The +`Tracer`'s data members, which were initialized based on the tracer's configuration, are copied into +the `TraceSegment` so that the `TraceSegment` can operate independently. -Note how `create_span` never fails. This is a nice property. `extract_span` -_can_ fail. +Note how `create_span` never fails. This is a nice property. `extract_span` _can_ fail. -The bulk of `Tracer`'s implementation is `extract_span`. The other substantial -work is configuration, which is handled by `finalize_config(const -TracerConfig&)`, declared in [tracer_config.h][10]. Configuration will be -described in more depth in a subsequent section. +The bulk of `Tracer`'s implementation is `extract_span`. The other substantial work is +configuration, which is handled by `finalize_config(const TracerConfig&)`, declared in +[tracer_config.h](../include/datadog/tracer_config.h). Configuration will be described in more depth +in a subsequent section. ### Collector -`class Collector` is an interface for sending a `TraceSegment`'s spans somewhere -once they're all done. It's defined in [collector.h][12]. + +`class Collector` is an interface for sending a `TraceSegment`'s spans somewhere once they're all +done. It's defined in [collector.h](../include/datadog/collector.h). It's just one function: `send`. More of a callback than an interface. -A `Collector` is either created by `Tracer` or injected into its configuration. -The `Collector` instance is then shared with all `TraceSegment`s created by the -`Tracer`. The only thing that a `TraceSegment` does with the `Collector` is call -`send` once the segment is finished. +A `Collector` is either created by `Tracer` or injected into its configuration. The `Collector` +instance is then shared with all `TraceSegment`s created by the `Tracer`. The only thing that a +`TraceSegment` does with the `Collector` is call `send` once the segment is finished. -The default implementation is `DatadogAgent`, which is described in the next -section. +The default implementation is `DatadogAgent`, which is described in the next section. ### DatadogAgent -`class DatadogAgent` is the default implementation of `Collector`. It's defined -in [datadog_agent.h][13]. -`DatadogAgent` sends trace segments to the [Datadog Agent][14] in batches that -are flushed periodically. In order to do this, `DatadogAgent` needs a means to -make HTTP requests and a means to set a timer for the flush operation. So, -there are two interfaces: [HTTPClient][15] and [EventScheduler][16]. +`class DatadogAgent` is the default implementation of `Collector`. It's defined in +[datadog_agent.h](../src/datadog/datadog_agent.h). -The `HTTPClient` and `EventScheduler` can be injected as part of -`DatadogAgent`'s [configuration][17], which is usually specified via the `agent` -member of `Tracer`'s [configuration][10]. If they're not specified, then default -implementations are used: +`DatadogAgent` sends trace segments to the [Datadog Agent](../include/datadog/http_client.h) in +batches that are flushed periodically. In order to do this, `DatadogAgent` needs a means to make +HTTP requests and a means to set a timer for the flush operation. So, there are two interfaces: +[HTTPClient](../include/datadog/http_client.h) and +[EventScheduler](../include/datadog/event_scheduler.h). -- [class Curl : public HTTPClient][18], which uses libcurl's [multi - interface][20] together with a dedicated thread as an event loop. -- [class ThreadedEventScheduler : public EventScheduler][19], which uses a - dedicated thread for executing scheduled events at the correct time. +The `HTTPClient` and `EventScheduler` can be injected as part of `DatadogAgent`'s +[configuration](../include/datadog/datadog_agent_config.h), which is usually specified via the +`agent` member of `Tracer`'s [configuration](../include/datadog/tracer_config.h). If they're not +specified, then default implementations are used: -`DatadogAgent::flush` is periodically called by the event scheduler. `flush` -uses the HTTP client to send a POST request to the Datadog Agent's -[/v0.4/traces][21] endpoint. It's all callback-based. +- [class Curl : public HTTPClient](../src/datadog/curl.h), which uses libcurl's [multi + interface](https://curl.se/libcurl/c/libcurl-multi.html) together with a dedicated thread as an + event loop. +- [class ThreadedEventScheduler : public EventScheduler](../src/datadog/threaded_event_scheduler.h), +- which uses a dedicated thread for executing scheduled events at the correct time. + +`DatadogAgent::flush` is periodically called by the event scheduler. `flush` uses the HTTP client to +send a POST request to the Datadog Agent's +[/v0.4/traces](https://github.com/DataDog/datadog-agent/blob/9d57c10a9eeb3916e661d35dbd23c6e36395a99d/pkg/trace/api/version.go#L22) +endpoint. It's all callback-based. ### HTTPClient + `class HTTPClient` is an interface for sending HTTP requests. It's defined in -[http_client.h][15]. +[http_client.h](../include/datadog/http_client.h). + +The only kind of HTTP request that the library needs to make, currently, is a POST to the Datadog +Agent's traces endpoint. `HTTPClient` has one member function for each HTTP method needed — so, +currently just the one: -The only kind of HTTP request that the library needs to make, currently, is a -POST to the Datadog Agent's traces endpoint. `HTTPClient` has one member -function for each HTTP method needed — so, currently just the one: ```c++ virtual Expected post(const URL& url, HeadersSetter set_headers, std::string body, ResponseHandler on_response, ErrorHandler on_error) = 0; ``` -It's callback-based. `post` returns almost immediately. It invokes `set_headers` -before returning, in order to get the HTTP request headers. The request `body` -is moved elsewhere for later processing. One of `on_response` or `on_error` will -eventually be called, depending on whether a response was received or if an -error occurred before a response was received. If something goes wrong setting -up the request, then `post` returns an error. If `post` returns an error, then -neither of `on_response` nor `on_error` will be called. + +It's callback-based. `post` returns almost immediately. It invokes `set_headers` before returning, +in order to get the HTTP request headers. The request `body` is moved elsewhere for later +processing. One of `on_response` or `on_error` will eventually be called, depending on whether a +response was received or if an error occurred before a response was received. If something goes +wrong setting up the request, then `post` returns an error. If `post` returns an error, then neither +of `on_response` nor `on_error` will be called. `HTTPClient` also has another member function: + ```c++ virtual void drain(std::chrono::steady_clock::time_point deadline) = 0; ``` -`drain` waits for any in-flight requests to finish, blocking up until no later -than `deadline`. It's used to ensure "clean shutdown." Without it, on average -the last one second of traces would be lost on shutdown. Implementations of -`HTTPClient` that don't have a dedicated thread need not support `drain`; in -those cases, `drain` returns immediately. -The default implementation of `HTTPClient` is [class Curl : public -HTTPClient][18], which uses libcurl's [multi interface][20] together with a -dedicated thread as an event loop. +`drain` waits for any in-flight requests to finish, blocking up until no later than `deadline`. It's +used to ensure "clean shutdown." Without it, on average the last one second of traces would be lost +on shutdown. Implementations of `HTTPClient` that don't have a dedicated thread need not support +`drain`; in those cases, `drain` returns immediately. -`class Curl` is also used within NGINX in Datadog's NGINX module, -[nginx-datadog][22]. This is explicitly [discouraged][23] in NGINX's developer -documentation, but libcurl-with-a-thread is widely used within NGINX modules -regardless. One improvement that I am exploring is to use libcurl's -"[multi_socket][24]" mode, which allows libcurl to utilize someone else's event -loop, obviating the need for another thread. libcurl can then be made to use -NGINX's event loop, as is done in [an example library][25]. +The default implementation of `HTTPClient` is [class Curl : public +HTTPClient](../src/datadog/curl.h), which uses libcurl's [multi +interface](https://curl.se/libcurl/c/libcurl-multi.html) together with a dedicated thread as an +event loop. + +`class Curl` is also used within NGINX in Datadog's Nginx module, +[nginx-datadog](https://github.com/DataDog/nginx-datadog). This is explicitly +[discouraged](https://nginx.org/en/docs/dev/development_guide.html#http_requests_to_ext) in Nginx's +developer documentation, but libcurl-with-a-thread is widely used within NGINX modules regardless. +One improvement that I am exploring is to use libcurl's +"[multi_socket](https://curl.se/libcurl/c/curl_multi_socket_action.html)" mode, which allows libcurl +to utilize someone else's event loop, obviating the need for another thread. libcurl can then be +made to use NGINX's event loop, as is done in [an example +library](https://github.com/dgoffredo/nginx-curl). For now, though, nginx-datadog uses the threaded `class Curl`. -[Envoy's Datadog tracing integration][26] uses a different implementation, -[class AgentHTTPClient : public HTTPClient, ...][27], which uses Envoy's -built-in HTTP facilities. libcurl is not involved at all. +[Envoy's Datadog tracing +integration](https://github.com/envoyproxy/envoy/tree/main/source/extensions/tracers/datadog#datadog-tracer) +uses a different implementation, [class AgentHTTPClient : public HTTPClient, +...](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h), +which uses Envoy's built-in HTTP facilities. libcurl is not involved at all. ### EventScheduler -As of this writing, `class DatadogAgent` flushes batches of finished trace -segments to the Datadog Agent once every two second [by default][28]. -It does this by scheduling a recurring event with an `EventScheduler`, which is -an interface defined in [event_scheduler.h][16]. +As of this writing, `class DatadogAgent` flushes batches of finished trace segments to the Datadog +Agent once every two second [by +default](https://github.com/DataDog/dd-trace-cpp/blob/ca155b3da65c2dc235cf64a28f8e0d8fdab3700c/src/datadog/datadog_agent_config.h#L50-L51). + +It does this by scheduling a recurring event with an `EventScheduler`, which is an interface defined +in [event_scheduler.h](../include/datadog/event_scheduler.h). `EventScheduler` has one member function: + ```c++ virtual Cancel schedule_recurring_event( std::chrono::steady_clock::duration interval, std::function callback) = 0; ``` -Every `interval`, the scheduler will invoke `callback`, starting an initial -`interval` after `schedule_recurring_event` is called. The caller can invoke the -returned `Cancel` to prevent subsequent invocations of `callback`. -The default implementation of `EventScheduler` is [class ThreadedEventScheduler -: public EventScheduler][19], which uses a dedicated thread for executing -scheduled events at the correct time. It was a fun piece of code to write. +Every `interval`, the scheduler will invoke `callback`, starting an initial `interval` after +`schedule_recurring_event` is called. The caller can invoke the returned `Cancel` to prevent +subsequent invocations of `callback`. -Datadog's NGINX module, [nginx-datadog][22] uses a different implementation, -[class NgxEventScheduler : public EventScheduler][29], which uses NGINX's own -event loop instead of a dedicated thread. +The default implementation of `EventScheduler` is [class ThreadedEventScheduler : public +EventScheduler](../src/datadog/threaded_event_scheduler.h), which uses a dedicated thread for +executing scheduled events at the correct time. It was a fun piece of code to write. -[Envoy's Datadog tracing integration][26] also uses a different implementation, -[class EventScheduler : public EventScheduler][30], which uses Envoy's built-in -event dispatch facilities. +Datadog's Nginx module, [nginx-datadog](https://github.com/DataDog/nginx-datadog) uses a different +implementation, [class NgxEventScheduler : public +EventScheduler](https://github.com/DataDog/nginx-datadog/blob/master/src/ngx_event_scheduler.h), +which uses Nginx's own event loop instead of a dedicated thread. + +[Envoy's Datadog tracing +integration](https://github.com/envoyproxy/envoy/tree/main/source/extensions/tracers/datadog#datadog-tracer) +also uses a different implementation, [class EventScheduler : public +EventScheduler](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h), +which uses Envoy's built-in event dispatch facilities. ### Configuration -There's a good [blog post][32] by [Alexis King][31] where she makes the case for -encoding configuration validation into the type system. Forbid invalid states by -making configurable components accept a different type than that which is used -to specify configuration. - -This is not a new idea. It's been used, for example, to "taint" strings that -originate as program inputs. Then you can't accidentally pass user-influenced -inputs to, say, `std::system`, because `std::system` takes a `const char*`, not -a `class UserTaintedString`. There's still ample opportunity to cast away the -taint and sneak it into some string building operation, but at least `class -UserTaintedString` gives hope that a static analysis tool could be used to fill -in some gaps in human code review. - -This library adopts that approach for configuration. The configuration of `class -Tracer` is `class TracerConfig`, but in order to construct a `Tracer` you must -first convert the `TracerConfig` into a `FinalizedTracerConfig` by calling -`finalize_config`. If there is anything wrong with the `TracerConfig` or with -environment variables that would override it, `finalize_config` will return an -`Error` instead of a `FinalizedTracerConfig`. In that case, you can't create a -`Tracer` at all. + +There's a good [blog post](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) by +[Alexis King](https://lexi-lambda.github.io/about.html) where she makes the case for encoding +configuration validation into the type system. Forbid invalid states by making configurable +components accept a different type than that which is used to specify configuration. + +This is not a new idea. It's been used, for example, to "taint" strings that originate as program +inputs. Then you can't accidentally pass user-influenced inputs to, say, `std::system`, because +`std::system` takes a `const char*`, not a `class UserTaintedString`. There's still ample +opportunity to cast away the taint and sneak it into some string building operation, but at least +`class UserTaintedString` gives hope that a static analysis tool could be used to fill in some gaps +in human code review. + +This library adopts that approach for configuration. The configuration of `class Tracer` is `class +TracerConfig`, but in order to construct a `Tracer` you must first convert the `TracerConfig` into a +`FinalizedTracerConfig` by calling `finalize_config`. If there is anything wrong with the +`TracerConfig` or with environment variables that would override it, `finalize_config` will return +an `Error` instead of a `FinalizedTracerConfig`. In that case, you can't create a `Tracer` at all. This technique applies to multiple components: | Component | Unvalidated | Validated | Parser | | --------------- | ----------- | --------- | ----------------- | -| `Tracer` | `TracerConfig` | `FinalizedTracerConfig` | `finalize_config` in [tracer_config.h][10] | -| `DatadogAgent` | `DatadogAgentConfig` | `FinalizedDatadogAgentConfig` | `finalize_config` in [datadog_agent_config.h][17] | -| `TraceSampler` | `TraceSamplerConfig` | `FinalizedTraceSamplerConfig` | `finalize_config` in [trace_sampler_config.h][33] | -| `SpanSampler` | `SpanSamplerConfig` | `FinalizedSpanSamplerConfig` | `finalize_config` in [span_sampler_config.h][34] | -| multiple | `double` | `Rate` | `Rate::from` in [rate.h][35] | - -An alternative approach, that Caleb espouses, is to accept invalid configuration -quietly. When invalid configuration is detected, the library could substitute a -reasonable default and then send notice of the configuration issue to Datadog, -e.g. as a hidden span tag. That information would then be available to Support -should the customer raise an issue due to a difference in behavior between what -they see and what they think they configured. This approach is also resilient to -dynamic configuration changes. Rather than a "bad config update" causing tracing -to cease completely, instead tracing could continue to operate in the defaulted -mode. - -This library uses the stricter approach. The downside is that a user of the -library has to decide what to do when even the slightest part of the -configuration or environment is deemed invalid. - -One other convention of the library is that `FinalizedFooConfig` (for some -`Foo`) is never a data member of the configured component class. That is, -`FinalizedTracerConfig` is not stored in `Tracer`. Instead, a constructor might -individually copy the finalized config's data members. This is to prevent -eventual intermixing between the "configuration representation" and the "runtime -representation." In part, `finalize_config` already mitigates the problem. -Abstaining from storing the finalized config as a data member is a step further. +| `Tracer` | `TracerConfig` | `FinalizedTracerConfig` | `finalize_config` in [tracer_config.h](../include/datadog/tracer_config.h) | +| `DatadogAgent` | `DatadogAgentConfig` | `FinalizedDatadogAgentConfig` | `finalize_config` in [datadog_agent_config.h](../include/datadog/datadog_agent_config.h) | +| `TraceSampler` | `TraceSamplerConfig` | `FinalizedTraceSamplerConfig` | `finalize_config` in [trace_sampler_config.h](../include/datadog/trace_sampler_config.h) | +| `SpanSampler` | `SpanSamplerConfig` | `FinalizedSpanSamplerConfig` | `finalize_config` in [span_sampler_config.h](../include/datadog/span_sampler_config.h) | +| multiple | `double` | `Rate` | `Rate::from` in [rate.h](../include/datadog/rate.h) | + +An alternative approach, that Caleb espouses, is to accept invalid configuration quietly. When +invalid configuration is detected, the library could substitute a reasonable default and then send +notice of the configuration issue to Datadog, e.g. as a hidden span tag. That information would then +be available to Support should the customer raise an issue due to a difference in behavior between +what they see and what they think they configured. This approach is also resilient to dynamic +configuration changes. Rather than a "bad config update" causing tracing to cease completely, +instead tracing could continue to operate in the defaulted mode. + +This library uses the stricter approach. The downside is that a user of the library has to decide +what to do when even the slightest part of the configuration or environment is deemed invalid. + +One other convention of the library is that `FinalizedFooConfig` (for some `Foo`) is never a data +member of the configured component class. That is, `FinalizedTracerConfig` is not stored in +`Tracer`. Instead, a constructor might individually copy the finalized config's data members. This +is to prevent eventual intermixing between the "configuration representation" and the "runtime +representation." In part, `finalize_config` already mitigates the problem. Abstaining from storing +the finalized config as a data member is a step further. ### Error Handling -Most error scenarios within this library are individually enumerated by `enum -Error::Code`, defined in [error.h][36]. -As of this writing, some of the error codes are emitted in more than one place, -but most of them are emitted in only one place, as is illustrated by the -following incomprehensible command shell pipeline: -``` -david@ein:~/src/dd-trace-cpp/src/datadog$ sed -n 's/^\s*\(\w\+\)\s*=\s*[0-9]\+,\?\s*$/{Error::\1/p' error.h | paste -d '|' -s | xargs git grep -P | sed -n 's/.*Error::\(\w\+\),.*/\1/p' | sort | uniq -c | sort -rn +Most error scenarios within this library are individually enumerated by `enum Error::Code`, defined +in [error.h](../include/datadog/error.h). + +As of this writing, some of the error codes are emitted in more than one place, but most of them are +emitted in only one place, as is illustrated by the following incomprehensible command shell +pipeline: + +```bash +dd-trace-cpp/src/datadog$ sed -n 's/^\s*\(\w\+\)\s*=\s*[0-9]\+,\?\s*$/{Error::\1/p' error.h | paste -d '|' -s | xargs git grep -P | sed -n 's/.*Error::\(\w\+\),.*/\1/p' | sort | uniq -c | sort -rn 3 MESSAGEPACK_ENCODE_FAILURE 2 MAX_PER_SECOND_OUT_OF_RANGE 2 INVALID_INTEGER @@ -403,27 +406,26 @@ david@ein:~/src/dd-trace-cpp/src/datadog$ sed -n 's/^\s*\(\w\+\)\s*=\s*[0-9]\+,\ 1 CURL_HTTP_CLIENT_SETUP_FAILED 1 CURL_HTTP_CLIENT_NOT_RUNNING ``` -The integer values of the enumerated `Error::Code`s are intended to be -permanent. Given an error message from a log mentioning an error code 24, one -can look at the source code for the matching `Error::Code` -(`TAG_MISSING_SEPARATOR`) and then find all of the possible source origins for -that error. At first this seems like a poor substitute for including the source -file and line in the error message, but I suspect that this compromise is -better. - -In addition to an error code, each error condition is associated with a -contextual diagnostic message. The diagnostic is not only a description of the -error, but also contains runtime context that might help a user or a maintainer -identify the underlying issue. For example, a message for -`TAG_MISSING_SEPARATOR` might include the text that was being parsed, or mention -the name of the relevant environment variable. - -The `Error::Code code` and `std::string message` are combined in a `struct -Error`, which is the error type used by this library. - -`struct Error` has a convenience member function, `Error with_prefix(StringView) -const`, that allows context to be added to an error. It's analogous to -`catch`ing one exception and then `throw`ing another, e.g. + +The integer values of the enumerated `Error::Code`s are intended to be permanent. Given an error +message from a log mentioning an error code 24, one can look at the source code for the matching +`Error::Code` (`TAG_MISSING_SEPARATOR`) and then find all of the possible source origins for that +error. At first this seems like a poor substitute for including the source file and line in the +error message, but I suspect that this compromise is better. + +In addition to an error code, each error condition is associated with a contextual diagnostic +message. The diagnostic is not only a description of the error, but also contains runtime context +that might help a user or a maintainer identify the underlying issue. For example, a message for +`TAG_MISSING_SEPARATOR` might include the text that was being parsed, or mention the name of the +relevant environment variable. + +The `Error::Code code` and `std::string message` are combined in a `struct Error`, which is the +error type used by this library. + +`struct Error` has a convenience member function, `Error with_prefix(StringView) const`, that allows +context to be added to an error. It's analogous to `catch`ing one exception and then `throw`ing +another, e.g. + ```c++ Expected adopt_cat(AnimalShelter& shelter) { Expected result = shelter.adopt(Animals::CAT, 1); @@ -434,26 +436,27 @@ Expected adopt_cat(AnimalShelter& shelter) { } ``` -`struct Error` is most often used in conjunction with the `Expected` class -template, which is defined in [expected.h][37]. +`struct Error` is most often used in conjunction with the `Expected` class template, which is +defined in [expected.h](../include/datadog/expected.h). -`template class Expected` is either a `T` or an `Error`. It is a -wrapper around `std::variant`. It's inspired by C++23's -[std::expected][38], but the two are not compatible. +`template class Expected` is either a `T` or an `Error`. It is a wrapper around +`std::variant`. It's inspired by C++23's +[std::expected](https://en.cppreference.com/w/cpp/utility/expected), but the two are not compatible. -Functions in this library that intend to return a "`Value`," but that might -instead fail with an `Error`, return an `Expected`. +Functions in this library that intend to return a "`Value`," but that might instead fail with an +`Error`, return an `Expected`. -This library never reports errors by throwing an exception. However, the library -will allow exceptions, such as `std::bad_alloc` and `std::bad_variant_access`, -to pass through it, and does sometimes use exceptions internally. The intention -is that a client of this library does not need to write `catch`. An alternative -design would be to use exceptions for their intended purpose. We decided that, -for a tracing library embedded in proxies, the ergonomics of error values are a -better fit than exceptions. +This library never reports errors by throwing an exception. However, the library will allow +exceptions, such as `std::bad_alloc` and `std::bad_variant_access`, to pass through it, and does +sometimes use exceptions internally. The intention is that a client of this library does not need to +write `catch`. An alternative design would be to use exceptions for their intended purpose. We +decided that, for a tracing library embedded in proxies, the ergonomics of error values are a better +fit than exceptions. + +`Expected` supports two syntaxes of use. The first is +[std::get_if](https://en.cppreference.com/w/cpp/utility/variant/get_if)-style unpacking with the +`if_error` member function: -`Expected` supports two syntaxes of use. The first is [std::get_if][39]-style -unpacking with the `if_error` member function: ```c++ Expected lunch = go_buy_lunch(); if (Error *error = lunch.if_error()) { @@ -461,22 +464,21 @@ if (Error *error = lunch.if_error()) { } eat_salad(*lunch); // or, lunch.value() ``` -`if_error` returns a pointer to the `Error` if there is one, otherwise it -returns `nullptr`. The body of a conditional statement such as `if` or `while` -is allowed to contain a variable definition. If the conditional statement -contains a variable definition, then the truth value of the resulting variable -is used as the condition. So, if there is _not_ an error, then `if_error` -returns `nullptr`, and so the declared `Error*` is `nullptr`, which is false for -the purposes of conditionals, and so in that case the body (block) of the -conditional statement is skipped. - -`if_error` cannot be called on an [rvalue][40], because allowing this makes it -far too easy to obtain a pointer to a destroyed object. I wrote the component -and nonetheless made this mistake repeatedly. So, the rvalue-flavored overload -of `Expected::if_error` is `delete`d. - -The other syntax of use supported by `Expected` is the traditional -check-and-accessor pattern: + +`if_error` returns a pointer to the `Error` if there is one, otherwise it returns `nullptr`. The +body of a conditional statement such as `if` or `while` is allowed to contain a variable definition. +If the conditional statement contains a variable definition, then the truth value of the resulting +variable is used as the condition. So, if there is _not_ an error, then `if_error` returns +`nullptr`, and so the declared `Error*` is `nullptr`, which is false for the purposes of +conditionals, and so in that case the body (block) of the conditional statement is skipped. + +`if_error` cannot be called on an +[rvalue](https://en.cppreference.com/w/cpp/language/value_category), because allowing this makes it +far too easy to obtain a pointer to a destroyed object. I wrote the component and nonetheless made +this mistake repeatedly. So, the rvalue-flavored overload of `Expected::if_error` is `delete`d. + +The other syntax of use supported by `Expected` is the traditional check-and-accessor pattern: + ```c++ Expected lunch = go_buy_lunch(); if (!lunch) { @@ -485,195 +487,131 @@ if (!lunch) { eat_salad(*lunch); // or, lunch.value() ``` -`Expected` defines `explicit operator bool`, which is `true` if the `Expected` -contains a non-`Error`, and `false` if the `Expected` contains an `Error`. There -is also `has_value()`, which returns the same thing. +`Expected` defines `explicit operator bool`, which is `true` if the `Expected` contains a +non-`Error`, and `false` if the `Expected` contains an `Error`. There is also `has_value()`, which +returns the same thing. -Then the `Error` can be obtained via `error()`, or the non-`Error` can be -obtained via `value()` or `operator*()`. +Then the `Error` can be obtained via `error()`, or the non-`Error` can be obtained via `value()` or +`operator*()`. -Why bother with `if_error`? Because I like it! I'm a sucker for structured -bindings and pattern matching. +Why bother with `if_error`? Because I like it! I'm a sucker for structured bindings and pattern +matching. -`template class Expected` has one specialization: `Expected`. -`Expected` is "either an `Error` or nothing." It's used to convey the -result of an operation that might fail but that doesn't yield a value when it -succeeds. It behaves in the same way as `Expected`, except that `value()` and -`operator*()` are not defined. +`template class Expected` has one specialization: `Expected`. `Expected` is +"either an `Error` or nothing." It's used to convey the result of an operation that might fail but +that doesn't yield a value when it succeeds. It behaves in the same way as `Expected`, except +that `value()` and `operator*()` are not defined. -At first I instead used `std::optional` directly. The problem there was -that `explicit operator bool` has the opposite meaning as it does in -`Expected`. I wanted error handling code to be the same in the two cases, and -so I specialized `Expected`. `Expected` is implemented in terms of -`std::optional`, but inverts the value of `explicit operator bool`. +At first I instead used `std::optional` directly. The problem there was that `explicit +operator bool` has the opposite meaning as it does in `Expected`. I wanted error handling code to +be the same in the two cases, and so I specialized `Expected`. `Expected` is implemented +in terms of `std::optional`, but inverts the value of `explicit operator bool`. ### Logging -Can we write a tracing library that does not do any logging by itself? The -previous section describes how errors are reported by the library, and no -logging is involved there. Why not leave it up to the client to decide whether -to note error conditions in the log or to proceed silently? - -The problem is that the default implementations of [HTTPClient][15] ([Curl][18]) -and [EventScheduler][16] ([ThreadedEventScheduler][19]) do some of their work on -background threads, where error conditions may occur without having a "caller" -to notify, and where execution will proceed despite the error. In those cases, -should the library squelch the error? - -One option is for these async components to accept an `on_error(Error)` callback -that will be invoked whenever an error occurs on the background thread that -would not otherwise be reported to client code. What would a client library do -in `on_error`? I think that it would either do nothing or log the error. So, an -`on_error` callback for use in background threads is the same as a logging + +Can we write a tracing library that does not do any logging by itself? The previous section +describes how errors are reported by the library, and no logging is involved there. Why not leave it +up to the client to decide whether to note error conditions in the log or to proceed silently? + +The problem is that the default implementations of [HTTPClient](../include/datadog/http_client.h) +([Curl](../src/datadog/curl.h)) and [EventScheduler](../include/datadog/event_scheduler.h) +([ThreadedEventScheduler](../src/datadog/threaded_event_scheduler.h)) do some of their work on +background threads, where error conditions may occur without having a "caller" to notify, and where +execution will proceed despite the error. In those cases, should the library squelch the error? + +One option is for these async components to accept an `on_error(Error)` callback that will be +invoked whenever an error occurs on the background thread that would not otherwise be reported to +client code. What would a client library do in `on_error`? I think that it would either do nothing +or log the error. So, an `on_error` callback for use in background threads is the same as a logging interface. -It's tempting to omit a logging interface, leaving it to clients to decide -whether and how to log. Why have logging _and_ error reporting when you can have -just error reporting? - -We could do that. Here are three reasons why this library has a logging interface -anyway: - -1. Logging a `Tracer`'s configuration when it's initialized is a helpful - diagnostic tool. A logging interface allows `Tracer` to do this explicitly, - as opposed to counting on client code to log `Tracer::config_json()` itself. - A client library can still suppress the startup message in its implementation - of the logging interface, but this is more opt-out than opt-in. -2. Along the same lines, reporting errors that occur on a background thread by - invoking a logging interface allows for the library's default behavior to be - to print an error message to a log, as opposed to having an `on_error` - callback that a client library might choose to log within. -3. A logging interface allows warnings to be logged, notifying a user of a - potentially problematic, but valid, configuration. Sometimes these warnings - are a matter of taste, and sometimes they are required by the specification - of the feature being configured. Logging is not the only way to handle this — - imagine if the return value of `finalize_config` included a list of warnings. - But, as with the previous two points, a logging interface allows for the - default behavior to be a logged message. - -On the other hand, the primary clients of this library are NGINX and Envoy, -where Datadog engineers have a say in how the library is used. So, the -distinction is probably not so important. - -The logging interface is `class Logger`, defined in [logger.h][41]. +It's tempting to omit a logging interface, leaving it to clients to decide whether and how to log. +Why have logging _and_ error reporting when you can have just error reporting? + +We could do that. Here are three reasons why this library has a logging interface anyway: + +1. Logging a `Tracer`'s configuration when it's initialized is a helpful diagnostic tool. A logging + interface allows `Tracer` to do this explicitly, as opposed to counting on client code to log + `Tracer::config_json()` itself. A client library can still suppress the startup message in its + implementation of the logging interface, but this is more opt-out than opt-in. +2. Along the same lines, reporting errors that occur on a background thread by invoking a logging + interface allows for the library's default behavior to be to print an error message to a log, as + opposed to having an `on_error` callback that a client library might choose to log within. +3. A logging interface allows warnings to be logged, notifying a user of a potentially problematic, + but valid, configuration. Sometimes these warnings are a matter of taste, and sometimes they are + required by the specification of the feature being configured. Logging is not the only way to + handle this — imagine if the return value of `finalize_config` included a list of warnings. But, + as with the previous two points, a logging interface allows for the default behavior to be a + logged message. + +On the other hand, the primary clients of this library are Ngix and Envoy, where Datadog engineers +have a say in how the library is used. So, the distinction is probably not so important. + +The logging interface is `class Logger`, defined in [logger.h](../include/datadog/logger.h). The design of `class Logger` is informed by three constraints: -1. Most "warn," "info," "debug," and "trace" severity logging is noise. It is - more an artifact of feature development than it is a helpful event with which - issues can be diagnosed. The logger should have few severity levels, or - ideally only one. -2. Logging libraries that obscure a conditional branch via the use of - preprocessor macros are difficult to understand. Reverse engineering a - composition of preprocessor macros is hard, and is not justified by the - syntactic convenience that the macros provide. -3. When client code decides that a message will not be logged, the library - should minimize the amount of computation that is done — as close to nothing - as is feasible. +1. Most "warn," "info," "debug," and "trace" severity logging is noise. It is more an artifact of + feature development than it is a helpful event with which issues can be diagnosed. The logger + should have few severity levels, or ideally only one. +2. Logging libraries that obscure a conditional branch via the use of preprocessor macros are + difficult to understand. Reverse engineering a composition of preprocessor macros is hard, and is + not justified by the syntactic convenience that the macros provide. +3. When client code decides that a message will not be logged, the library should minimize the + amount of computation that is done — as close to nothing as is feasible. (1) and (3) work well together. -On account of (1), `Logger` has only two "severities": "error" and "startup." -`log_startup` is called once by a `Tracer` when it is initialized. `log_error` -is called in all other logging circumstances. +On account of (1), `Logger` has only two "severities": "error" and "startup." `log_startup` is +called once by a `Tracer` when it is initialized. `log_error` is called in all other logging +circumstances. -On account of (3), `Logger` must do as little work as possible when an -implementer decides that a logging function should not log. If this library were -to build diagnostic messages in all cases, and then pass them to the `Logger`, -then the cost of building the message would be paid even when the `Logger` -decides not to log. On account of (2), the library cannot define a `DD_LOG` -macro that hides an `if (logger.severity > ...)` branch. As a matter of taste, I -don't want the library to be littered with such branches explicitly. +On account of (3), `Logger` must do as little work as possible when an implementer decides that a +logging function should not log. If this library were to build diagnostic messages in all cases, and +then pass them to the `Logger`, then the cost of building the message would be paid even when the +`Logger` decides not to log. On account of (2), the library cannot define a `DD_LOG` macro that +hides an `if (logger.severity > ...)` branch. As a matter of taste, I don't want the library to be +littered with such branches explicitly. The compromise is to have `Logger::log_error` and `Logger::log_startup` accept a -[std::function][44] that, if invoked, does the work of building the diagnostic -message. When a `Logger` implementation decides not to log, the only cost paid -at the call site is the construction of the `std::function` and the underlying -capturing lambda expression with which it was likely initialized. The signature -of the `std::function`, aliased as `Logger::LogFunc`, is `void(std::ostream&)`. -I don't know whether this results in a real runtime savings in the not-logging -case, but it seems likely. - -`Logger` also has two convenience overloads of `log_error`: one that takes a -`const Error&` and one that takes a `StringView`. - -The `const Error&` overload reveals a contradiction in the design. If an `Error` -is produced in a context where its only destiny is to be passed to -`Logger::log_error(const Error&)`, then the cost of building `Error::message` -will always be paid, in violation of constraint (3). One way to avoid this would -be to have versions of the `Error`-returning operations that instead accept a -`Logger&` and use `Logger::log_error(Logger::LogFunc)` directly. I think that -the present state of things is acceptable and that such a change is not -warranted. +[std::function](https://en.cppreference.com/w/cpp/utility/functional/function) that, if invoked, +does the work of building the diagnostic message. When a `Logger` implementation decides not to log, +the only cost paid at the call site is the construction of the `std::function` and the underlying +capturing lambda expression with which it was likely initialized. The signature of the +`std::function`, aliased as `Logger::LogFunc`, is `void(std::ostream&)`. I don't know whether this +results in a real runtime savings in the not-logging case, but it seems likely. + +`Logger` also has two convenience overloads of `log_error`: one that takes a `const Error&` and one +that takes a `StringView`. + +The `const Error&` overload reveals a contradiction in the design. If an `Error` is produced in a +context where its only destiny is to be passed to `Logger::log_error(const Error&)`, then the cost +of building `Error::message` will always be paid, in violation of constraint (3). One way to avoid +this would be to have versions of the `Error`-returning operations that instead accept a `Logger&` +and use `Logger::log_error(Logger::LogFunc)` directly. I think that the present state of things is +acceptable and that such a change is not warranted. The default implementation of `Logger` is `NullLogger`, defined in -[null_logger.h][47]. `NullLogger` doesn't log anything. - -A client library might wish to install `CerrLogger` instead. `CerrLogger` is -defined in [cerr_logger.h][42] and logs to [std::cerr][43] in both `log_error` -and `log_startup`. - -The `Logger` used by a `Tracer` is configured via `std::shared_ptr -TracerConfig::logger`, defined in [tracer_config.h][10]. - -Finally, constraint (1) is still a matter of debate. Support representatives -have expressed frustration with this library's, and its predecessor's, lack of a -"debug mode" that logs the reason for every decision made throughout the -processing of a trace. This issue deserves revisiting. Here are some potential -approaches: - -- Introduce a "debug mode" that sends fine-grained internal information to - Datadog, rather than to a log, either as hidden tags on the trace or via a - different data channel, such as the [Telemetry API][45]. -- Introduce a "trace the tracer" mode that generates additional traces that - represent operations performed by the tracer. This technique was prototyped in - the [david.goffredo/traception][46] branch. -- Add a `Logger::log_debug` function that optionally prints fine-grained tracing - information to the log, in violation of constraint (1). - -[1]: https://github.com/DataDog/dd-opentracing-cpp -[2]: https://github.com/open-telemetry/opentelemetry-cpp -[3]: ../include/datadog/span.h -[4]: ../src/datadog/span_data.h -[5]: ../include/datadog/span_config.h -[6]: https://en.cppreference.com/w/cpp/language/raii -[7]: ../include/datadog/trace_segment.h -[8]: ../src/datadog/trace_segment.cpp -[9]: ../include/datadog/tracer.h -[10]: ../include/datadog/tracer_config.h -[11]: ../include/datadog/dict_writer.h -[12]: ../include/datadog/collector.h -[13]: ../src/datadog/datadog_agent.h -[14]: https://docs.datadoghq.com/agent/ -[15]: ../include/datadog/http_client.h -[16]: ../include/datadog/event_scheduler.h -[17]: ../include/datadog/datadog_agent_config.h -[18]: ../src/datadog/curl.h -[19]: ../src/datadog/threaded_event_scheduler.h -[20]: https://curl.se/libcurl/c/libcurl-multi.html -[21]: https://github.com/DataDog/datadog-agent/blob/9d57c10a9eeb3916e661d35dbd23c6e36395a99d/pkg/trace/api/version.go#L22 -[22]: https://github.com/DataDog/nginx-datadog -[23]: https://nginx.org/en/docs/dev/development_guide.html#http_requests_to_ext -[24]: https://curl.se/libcurl/c/curl_multi_socket_action.html -[25]: https://github.com/dgoffredo/nginx-curl -[26]: https://github.com/envoyproxy/envoy/tree/main/source/extensions/tracers/datadog#datadog-tracer -[27]: https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h -[28]: https://github.com/DataDog/dd-trace-cpp/blob/ca155b3da65c2dc235cf64a28f8e0d8fdab3700c/src/datadog/datadog_agent_config.h#L50-L51 -[29]: https://github.com/DataDog/nginx-datadog/blob/master/src/ngx_event_scheduler.h -[30]: https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h -[31]: https://lexi-lambda.github.io/about.html -[32]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ -[33]: ../include/datadog/trace_sampler_config.h -[34]: ../include/datadog/span_sampler_config.h -[35]: ../include/datadog/rate.h -[36]: ../include/datadog/error.h -[37]: ../include/datadog/expected.h -[38]: https://en.cppreference.com/w/cpp/utility/expected -[39]: https://en.cppreference.com/w/cpp/utility/variant/get_if -[40]: https://en.cppreference.com/w/cpp/language/value_category -[41]: ../include/datadog/logger.h -[42]: ../include/datadog/cerr_logger.h -[43]: https://en.cppreference.com/w/cpp/io/cerr -[44]: https://en.cppreference.com/w/cpp/utility/functional/function -[45]: https://github.com/DataDog/datadog-agent/blob/796ccb9e92326c85b51f519291e86eb5bc950180/pkg/trace/api/endpoints.go#L97 -[46]: https://github.com/DataDog/dd-trace-cpp/tree/david.goffredo/traception -[47]: ../src/datadog/null_logger.h +[null_logger.h](../src/datadog/null_logger.h). `NullLogger` doesn't log anything. + +A client library might wish to install `CerrLogger` instead. `CerrLogger` is defined in +[cerr_logger.h](../include/datadog/cerr_logger.h) and logs to +[std::cerr](https://en.cppreference.com/w/cpp/io/cerr) in both `log_error` and `log_startup`. + +The `Logger` used by a `Tracer` is configured via `std::shared_ptr TracerConfig::logger`, +defined in [tracer_config.h](../include/datadog/tracer_config.h). + +Finally, constraint (1) is still a matter of debate. Support representatives have expressed +frustration with this library's, and its predecessor's, lack of a "debug mode" that logs the reason +for every decision made throughout the processing of a trace. This issue deserves revisiting. Here +are some potential approaches: + +- Introduce a "debug mode" that sends fine-grained internal information to Datadog, rather than to a + log, either as hidden tags on the trace or via a different data channel, such as the [Telemetry + API](https://github.com/DataDog/datadog-agent/blob/796ccb9e92326c85b51f519291e86eb5bc950180/pkg/trace/api/endpoints.go#L97). +- Introduce a "trace the tracer" mode that generates additional traces that represent operations + performed by the tracer. This technique was prototyped in the + [david.goffredo/traception](https://github.com/DataDog/dd-trace-cpp/tree/david.goffredo/traception) + branch. +- Add a `Logger::log_debug` function that optionally prints fine-grained tracing information to the + log, in violation of constraint (1). diff --git a/examples/hasher/hasher.cpp b/examples/hasher/hasher.cpp index 4b71b7b87..efc3cb84e 100644 --- a/examples/hasher/hasher.cpp +++ b/examples/hasher/hasher.cpp @@ -3,11 +3,11 @@ // If the path does not exist, print an error. // // If the path exists and is a regular file, print the SHA256 digest of the -// file's contents. Produce a single tracing span indicating the calculation. +// file's contents. Produce a single tracing span indicating the calculation. // // If the path exists and is a directory, calculate the SHA256 digest of the // directory from the names and digests of its children, combined in some -// canonical format. Produce a trace whose structure reflects the directory +// canonical format. Produce a trace whose structure reflects the directory // structure. #include @@ -45,7 +45,7 @@ std::string hex(const Digest &digest) { } // Store into the specified `digest` the SHA256 digest of the contents of the -// specified `file`. Return zero on success, or a nonzero value if an error +// specified `file`. Return zero on success, or a nonzero value if an error // occurs. int sha256(Digest &digest, const fs::path &file) { std::ifstream in(file); diff --git a/examples/http-server/common/httplib.h b/examples/http-server/common/httplib.h index 88558dc4f..713613800 100644 --- a/examples/http-server/common/httplib.h +++ b/examples/http-server/common/httplib.h @@ -8713,7 +8713,7 @@ inline bool SSLClient::verify_host(X509 *server_cert) const { Certification Authorities are encouraged to use the dNSName instead. Matching is performed using the matching rules specified by - [RFC2459]. If more than one identity of a given type is present in + [RFC2459]. If more than one identity of a given type is present in the certificate (e.g., more than one dNSName name, a match in any one of the set is considered acceptable.) Names may contain the wildcard character * which is considered to match any single domain name diff --git a/examples/http-server/proxy/proxy.cpp b/examples/http-server/proxy/proxy.cpp index 3941e869c..cc7559fa1 100644 --- a/examples/http-server/proxy/proxy.cpp +++ b/examples/http-server/proxy/proxy.cpp @@ -24,7 +24,7 @@ namespace dd = datadog::tracing; void hard_stop(int /*signal*/) { std::exit(0); } int main() { - // Set up the Datadog tracer. See `src/datadog/tracer_config.h`. + // Set up the Datadog tracer. See `src/datadog/tracer_config.h`. dd::TracerConfig config; config.service = "dd-trace-cpp-http-server-example-proxy"; config.service_type = "proxy"; diff --git a/examples/http-server/server/server.cpp b/examples/http-server/server/server.cpp index 1b183ee2c..3b3f11a91 100644 --- a/examples/http-server/server/server.cpp +++ b/examples/http-server/server/server.cpp @@ -11,7 +11,7 @@ // array [created time, note], e.g. ["2023-05-12 12:38:25","here's a note"]. // // POST /notes -// Create a new note. The body of the request is the note content. +// Create a new note. The body of the request is the note content. // // GET /sleep?seconds= // @@ -107,7 +107,7 @@ void on_get_notes(const httplib::Request& request, httplib::Response& response); void on_post_notes(const httplib::Request& request, httplib::Response& response); int main() { - // Set up the Datadog tracer. See `src/datadog/tracer_config.h`. + // Set up the Datadog tracer. See `src/datadog/tracer_config.h`. dd::TracerConfig config; config.service = "dd-trace-cpp-http-server-example-server"; config.service_type = "server"; diff --git a/fuzz/README.md b/fuzz/README.md index 1929ebd7a..2264a5595 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -1,13 +1,15 @@ -Fuzzers -======= -Each subdirectory here contains the source of an executable that [fuzz tests][1] -some part of the library using [LLVM's libfuzzer][2]. +# Fuzzers -There is a toplevel CMake boolean option that adds all of the fuzzer -executables to the build: `BUILD_FUZZERS`. +Each subdirectory here contains the source of an executable that [fuzz +tests](https://en.wikipedia.org/wiki/Fuzzing) some part of the library using [LLVM's +libfuzzer](https://llvm.org/docs/LibFuzzer.html). -When building the fuzzers, the toolchain must be clang-based. For example: -```console +There is a toplevel CMake boolean option that adds all of the fuzzer executables to the build: +`BUILD_FUZZERS`. + +When building the fuzzers, the toolchain must be clang-based. For example: + +```shell $ rm -rf .build # if toolchain needs clearing $ bin/with-toolchain llvm bin/cmake-build -DDD_TRACE_BUILD_FUZZERS=1 $ .build/fuzz/w3c-propagation/w3c-propagation-fuzz @@ -16,6 +18,3 @@ $ .build/fuzz/w3c-propagation/w3c-propagation-fuzz ``` The fuzzer executables are named `.build/fuzz/*/*-fuzz` by convention. - -[1]: https://en.wikipedia.org/wiki/Fuzzing -[2]: https://llvm.org/docs/LibFuzzer.html diff --git a/fuzz/w3c-propagation/README.md b/fuzz/w3c-propagation/README.md index f803c278f..8aab9571d 100644 --- a/fuzz/w3c-propagation/README.md +++ b/fuzz/w3c-propagation/README.md @@ -1,11 +1,12 @@ -W3C Propagation Fuzzer -====================== -This directory defines an executable, `fuzz`, that fuzz tests extraction and -injection of the W3C tracing HTTP headers "traceparent" and "tracestate". - -Libfuzzer invokes the `LLVMFuzzerTestOneInput` function repeatedly with a binary -blob of varying size and contents. For each blob, [fuzz.cpp](./fuzz.cpp) runs -its test multiple times. The input blob is interpreted in the following way: +# W3C Propagation Fuzzer + +This directory defines an executable, `fuzz`, that fuzz tests extraction and injection of the W3C +tracing HTTP headers "traceparent" and "tracestate". + +Libfuzzer invokes the `LLVMFuzzerTestOneInput` function repeatedly with a binary blob of varying +size and contents. For each blob, [fuzz.cpp](./fuzz.cpp) runs its test multiple times. The input +blob is interpreted in the following way: + ```text blob: _ _ _ _ _ _ _ _ _ @@ -23,14 +24,15 @@ iteration 8: p p p p p p p p s iteration 9: p p p p p p p p p ``` - The `p`-labeled bytes are the "traceparent" header value, while the `s`-labeled - bytes are the "tracestate" header value. So, for an input blob of length `n`, - the `LLVMFuzzerTestOneInput` runs its test `n + 1` times, for the `n + 1` - possible divisions of the input between "traceparent" and "tracestate". - Each test uses a singleton[^1] `Tracer` to `extract_span` from a `DictReader` - containing the "traceparent" and "tracestate" headers. If that succeeds, then - the test `inject`s the resulting span into a no-op `DictWriter`. +The `p`-labeled bytes are the "traceparent" header value, while the `s`-labeled bytes are the +"tracestate" header value. So, for an input blob of length `n`, the `LLVMFuzzerTestOneInput` runs +its test `n + 1` times, for the `n + 1` possible divisions of the input between "traceparent" and +"tracestate". + +Each test uses a singleton[^1] `Tracer` to `extract_span` from a `DictReader` containing the +"traceparent" and "tracestate" headers. If that succeeds, then the test `inject`s the resulting span +into a no-op `DictWriter`. -[^1]: thread-local, actually, though it doesn't matter because even libfuzzer's - "worker" mode forks instead of threads +[^1]: thread-local, actually, though it doesn't matter because even libfuzzer's "worker" mode forks +instead of threads. diff --git a/include/datadog/cerr_logger.h b/include/datadog/cerr_logger.h index 63945ce0d..49497ad22 100644 --- a/include/datadog/cerr_logger.h +++ b/include/datadog/cerr_logger.h @@ -1,7 +1,7 @@ #pragma once // This component provides a class, `CerrLogger`, that implements the `Logger` -// interface from `logger.h`. `CerrLogger` prints to `std::cerr`, which is +// interface from `logger.h`. `CerrLogger` prints to `std::cerr`, which is // typically an unbuffered stream to the standard error file. #include diff --git a/include/datadog/clock.h b/include/datadog/clock.h index 84ef44f25..bc4bdcab9 100644 --- a/include/datadog/clock.h +++ b/include/datadog/clock.h @@ -5,7 +5,7 @@ // // Each `Span` has a start time and a duration. The start time ought to be // measured using a system clock, so that Network Time Protocol adjustments and -// other time settings are accurately reflected in the span start time. The +// other time settings are accurately reflected in the span start time. The // span's duration, however, is better measured using a steady (monotonic) clock // so that adjustments to the system clock made during the extent of the span do // not skew the span's measured duration. diff --git a/include/datadog/collector.h b/include/datadog/collector.h index 96f9e64d2..5198834ff 100644 --- a/include/datadog/collector.h +++ b/include/datadog/collector.h @@ -7,7 +7,7 @@ // serializing the spans and sending them to a Datadog Agent. // // As a result of `send`ing spans to a `Collector`, the `TraceSampler` might be -// adjusted to increase or decrease the rate at which traces are kept. See the +// adjusted to increase or decrease the rate at which traces are kept. See the // `response_handler` parameter to `Collector::send`. #include @@ -23,9 +23,9 @@ class TraceSampler; class Collector { public: - // Submit ownership of the specified `spans` to the collector. If the + // Submit ownership of the specified `spans` to the collector. If the // collector delivers a response relevant to trace sampling, reconfigure the - // sampler using the specified `response_handler`. Return an error if one + // sampler using the specified `response_handler`. Return an error if one // occurs. virtual Expected send( std::vector>&& spans, diff --git a/include/datadog/datadog_agent_config.h b/include/datadog/datadog_agent_config.h index a324f44f4..cb5334877 100644 --- a/include/datadog/datadog_agent_config.h +++ b/include/datadog/datadog_agent_config.h @@ -3,9 +3,9 @@ // This component provides facilities for configuring a `DatadogAgent`. // // `struct DatadogAgentConfig` contains fields that are used to configure -// `DatadogAgent`. The configuration must first be finalized before it can be -// used by `DatadogAgent`. The function `finalize_config` produces either an -// error or a `FinalizedDatadogAgentConfig`. The latter can be used by +// `DatadogAgent`. The configuration must first be finalized before it can be +// used by `DatadogAgent`. The function `finalize_config` produces either an +// error or a `FinalizedDatadogAgentConfig`. The latter can be used by // `DatadogAgent`. // // Typical usage of `DatadogAgentConfig` is implicit as part of `TracerConfig`. @@ -30,14 +30,14 @@ class EventScheduler; class Logger; struct DatadogAgentConfig { - // The `HTTPClient` used to submit traces to the Datadog Agent. If this + // The `HTTPClient` used to submit traces to the Datadog Agent. If this // library was built with libcurl (the default), then `http_client` is // optional: a `Curl` instance will be used if `http_client` is left null. // If this library was built without libcurl, then `http_client` is required // not to be null. std::shared_ptr http_client = nullptr; // The `EventScheduler` used to periodically submit batches of traces to the - // Datadog Agent. If `event_scheduler` is null, then a + // Datadog Agent. If `event_scheduler` is null, then a // `ThreadedEventScheduler` instance will be used instead. std::shared_ptr event_scheduler = nullptr; // A list of Remote Configuration listeners. diff --git a/include/datadog/dict_reader.h b/include/datadog/dict_reader.h index c6ee310f3..dfa6b1d19 100644 --- a/include/datadog/dict_reader.h +++ b/include/datadog/dict_reader.h @@ -1,7 +1,7 @@ #pragma once // This component provides an interface, `DictReader`, that represents a -// read-only key/value mapping of strings. It's used when extracting trace +// read-only key/value mapping of strings. It's used when extracting trace // context from externalized formats: HTTP headers, gRPC metadata, etc. #include diff --git a/include/datadog/dict_writer.h b/include/datadog/dict_writer.h index 89a4bfe30..34bb147d4 100644 --- a/include/datadog/dict_writer.h +++ b/include/datadog/dict_writer.h @@ -1,7 +1,7 @@ #pragma once // This component provides an interface, `DictWriter`, that represents a -// write-only key/value mapping of strings. It's used when injecting trace +// write-only key/value mapping of strings.It's used when injecting trace // context into externalized formats: HTTP headers, gRPC metadata, etc. // // Note that while the data structure modeled is a mapping, duplicate keys are @@ -17,7 +17,7 @@ class DictWriter { public: virtual ~DictWriter() {} - // Associate the specified `value` with the specified `key`. An + // Associate the specified `value` with the specified `key`. An // implementation may, but is not required to, overwrite any previous value at // `key`. virtual void set(StringView key, StringView value) = 0; diff --git a/include/datadog/environment.h b/include/datadog/environment.h index 824e4a3aa..6cfe231a1 100644 --- a/include/datadog/environment.h +++ b/include/datadog/environment.h @@ -3,7 +3,7 @@ // This component provides a registry of all environment variables that can be // used to configure this library. // -// Each `enum Variable` denotes an environment variable. The enum value names +// Each `enum Variable` denotes an environment variable. The enum value names // are the same as the names of the environment variables. // // `name` returns the name of a specified `Variable`. diff --git a/include/datadog/error.h b/include/datadog/error.h index af6825dc0..c7f9d7a94 100644 --- a/include/datadog/error.h +++ b/include/datadog/error.h @@ -7,7 +7,7 @@ // consistent across library versions, so integer values in error diagnostics // can always be looked up here. // -// `struct Error` is the error type used by the `Expected` class template. See +// `struct Error` is the error type used by the `Expected` class template. See // `expected.h`. #include diff --git a/include/datadog/event_scheduler.h b/include/datadog/event_scheduler.h index e8c7051a4..9a834dc8d 100644 --- a/include/datadog/event_scheduler.h +++ b/include/datadog/event_scheduler.h @@ -6,7 +6,7 @@ // `DatadogAgent` uses an `EventScheduler` to periodically send batches of // traces to the Datadog Agent. // -// The default implementation is `ThreadedEventScheduler`. See +// The default implementation is `ThreadedEventScheduler`. See // `threaded_event_scheduler.h`. #include @@ -21,8 +21,8 @@ class EventScheduler { using Cancel = std::function; // Invoke the specified `callback` repeatedly, with the specified `interval` - // elapsing between invocations. The first invocation is after an initial - // `interval`. Return a function-like object that can be invoked without + // elapsing between invocations. The first invocation is after an initial + // `interval`. Return a function-like object that can be invoked without // arguments to prevent subsequent invocations of `callback`. virtual Cancel schedule_recurring_event( std::chrono::steady_clock::duration interval, diff --git a/include/datadog/expected.h b/include/datadog/expected.h index 14cc5e0ed..84c582c03 100644 --- a/include/datadog/expected.h +++ b/include/datadog/expected.h @@ -1,7 +1,7 @@ #pragma once // This component provides a class template, `Expected`, that is either an -// instance of `T` or an instance of `Error`. `Expected` is either +// instance of `T` or an instance of `Error`. `Expected` is either // `nullopt` or an instance of `Error`. // // `Expected` is inspired by, but incompatible with, C++23's `std::expected`. @@ -66,7 +66,7 @@ class Expected { bool has_value() const noexcept; explicit operator bool() const noexcept; - // Return a reference to the `Value` held by this object. If this object is + // Return a reference to the `Value` held by this object. If this object is // an `Error`, throw a `std::bad_variant_access`. Value& value() &; const Value& value() const&; @@ -77,12 +77,12 @@ class Expected { Value&& operator*() &&; const Value&& operator*() const&&; - // Return a pointer to the `Value` held by this object. If this object is an + // Return a pointer to the `Value` held by this object. If this object is an // `Error`, throw a `std::bad_variant_access`. Value* operator->(); const Value* operator->() const; - // Return a reference to the `Error` held by this object. If this object is + // Return a reference to the `Error` held by this object. If this object is // not an `Error`, throw a `std::bad_variant_access`. Error& error() &; const Error& error() const&; diff --git a/include/datadog/http_client.h b/include/datadog/http_client.h index 7186acbe8..97e5abd9d 100644 --- a/include/datadog/http_client.h +++ b/include/datadog/http_client.h @@ -6,7 +6,7 @@ // `HTTPClient` is used by `DatadogAgent` to send traces to the Datadog Agent. // // If this library was built with support for libcurl, then `Curl` implements -// `HTTPClient` in terms of libcurl. See `curl.h`. +// `HTTPClient` in terms of libcurl. See `curl.h`. #include #include @@ -38,12 +38,12 @@ class HTTPClient { // error-indicating HTTP responses. using ErrorHandler = std::function; - // Send a POST request to the specified `url`. Set request headers by calling - // the specified `set_headers` callback. Include the specified `body` at the - // end of the request. Invoke the specified `on_response` callback if/when + // Send a POST request to the specified `url`. Set request headers by calling + // the specified `set_headers` callback. Include the specified `body` at the + // end of the request. Invoke the specified `on_response` callback if/when // a response is delivered (even if that response contains an error HTTP - // response status). Invoke the specified `on_error` if an error occurs - // outside of HTTP, such as a connection failure. If an error occurs while + // response status). Invoke the specified `on_error` if an error occurs + // outside of HTTP, such as a connection failure. If an error occurs while // preparing the request, return an `Error`. The behavior is undefined if // either of `on_response` or `on_error` throws an exception. virtual Expected post( diff --git a/include/datadog/optional.h b/include/datadog/optional.h index ae1deb7cc..e976203e8 100644 --- a/include/datadog/optional.h +++ b/include/datadog/optional.h @@ -3,7 +3,7 @@ // One of the clients of this library is Envoy, a service (HTTP) proxy. // // Envoy uses Abseil as its base C++ library, and additionally builds in C++17 -// mode. Abseil has a build option to forward its `std::string_view` and +// mode. Abseil has a build option to forward its `std::string_view` and // `std::optional` equivalents to the actual standard types when C++17 is // available. // @@ -17,9 +17,9 @@ // and `std::optional` in the exported interface, i.e. in header files. // // As a workaround, Bazel (the build tool used by Envoy) builds of this library -// will define the `DD_USE_ABSEIL_FOR_ENVOY` preprocessor macro. When this +// will define the `DD_USE_ABSEIL_FOR_ENVOY` preprocessor macro. When this // macro is defined, the library-specific `StringView` and `Optional` aliases -// will refer to the Abseil types. When the macro is not defined, the +// will refer to the Abseil types. When the macro is not defined, the // library-specific aliases will refer to the standard types. // // This file defines `datadog::tracing::Optional`, a type template that is an @@ -48,7 +48,7 @@ using Optional = std::optional; inline constexpr auto nullopt = std::nullopt; #endif // defined DD_USE_ABSEIL_FOR_ENVOY -// Return the first non-null argument value. The last argument must not be +// Return the first non-null argument value. The last argument must not be // `Optional`. template auto value_or(Value&& value) { diff --git a/include/datadog/propagation_style.h b/include/datadog/propagation_style.h index 075be1518..8b872c0a0 100644 --- a/include/datadog/propagation_style.h +++ b/include/datadog/propagation_style.h @@ -18,7 +18,7 @@ enum class PropagationStyle { B3, // W3C headers style, i.e. traceparent and tracestate W3C, - // The absence of propagation. If this is the only style set, then + // The absence of propagation. If this is the only style set, then // propagation is disabled in the relevant direction (extraction or // injection). NONE, diff --git a/include/datadog/sampling_mechanism.h b/include/datadog/sampling_mechanism.h index 07a65f1c7..b7376ec9d 100644 --- a/include/datadog/sampling_mechanism.h +++ b/include/datadog/sampling_mechanism.h @@ -1,7 +1,7 @@ #pragma once // This component provides an `enum class`, `SamplingMechanism`, describing a -// reason for a sampling decision. A sampler (or a user, with a manual +// reason for a sampling decision. A sampler (or a user, with a manual // override) decides whether to keep or to drop a trace, but it might do so for // various reasons. // @@ -9,9 +9,9 @@ // but `SamplingPriority` is inadequate for future expansion, for two reasons: // // - `SamplingPriority` conflates the keep/drop decision with the reason (e.g. -// `UserKeep` vs. `SamplerKeep`). Some engineers dislike this. +// `UserKeep` vs. `SamplerKeep`). Some engineers dislike this. // - Some tracer implementations do not decode `SamplingPriority` integer values -// outside of those enumerated in this library. This makes adding new values +// outside of those enumerated in this library. This makes adding new values // infeasible, as older versions of tracers propagating the `SamplingPriority` // along the trace will omit new integer values. // @@ -21,7 +21,7 @@ // Since `SamplingPriority` is already in use and has implications for sampling // behavior (both in its propagation along and trace and its interpretation by // the trace agent), the combination `{SamplingPriority, SamplingMechanism}` is -// used to completely describe a sampling decision. The `SamplingPriority` +// used to completely describe a sampling decision. The `SamplingPriority` // conveys the keep/drop decision, as well as the existing (and now redundant) // user vs. sampler distinction, while the `SamplingMechanism` conveys // precisely where the sampling decision came from, e.g. a user-specified @@ -30,7 +30,7 @@ // // To allow forward compatibility with future `SamplingMechanism` values, // sampling mechanism is treated as just an integer when being deserialized or -// serialized. `SamplingMechanism` enumerates integer values relevant to logic +// serialized. `SamplingMechanism` enumerates integer values relevant to logic // within the tracer. namespace datadog { diff --git a/include/datadog/sampling_priority.h b/include/datadog/sampling_priority.h index af6ae49f2..fb22d3e86 100644 --- a/include/datadog/sampling_priority.h +++ b/include/datadog/sampling_priority.h @@ -3,7 +3,7 @@ // This component defines an enumeration of "sampling priority" values. // // Sampling priority is a hybrid between a sampling decision ("keep" versus -// "drop") and a sampling reason ("user-specified rule"). Values less than or +// "drop") and a sampling reason ("user-specified rule"). Values less than or // equal to zero indicate a decision to "drop," while positive values indicate // a decision to "keep." // diff --git a/include/datadog/span.h b/include/datadog/span.h index 0018230f6..43be554c0 100644 --- a/include/datadog/span.h +++ b/include/datadog/span.h @@ -5,10 +5,10 @@ // query, calculation, etc. // // `Span` objects are created by calling member functions on `Tracer` or on -// another `Span` object. They are not instantiated directly. +// another `Span` object. They are not instantiated directly. // // A `Span` has a start time, an end time, and a name (sometimes called its -// "operation name"). A span is associated with a service, a resource (such as +// "operation name"). A span is associated with a service, a resource (such as // the URL endpoint in an HTTP request), and arbitrary key/value string pairs // known as tags. // @@ -19,25 +19,25 @@ // // For example, an HTTP server might create a `Span` for each request processed. // The `Span` begins when the server begins reading the request, and ends when -// the server has finished writing the response or reporting an error. The +// the server has finished writing the response or reporting an error. The // first child of the request span might represent the reading and parsing of -// the HTTP request's headers. The second child of the request span might +// the HTTP request's headers. The second child of the request span might // represent the dispatch of the request handling to an endpoint-specific -// handler. That child might itself have children, such as a database query or +// handler. That child might itself have children, such as a database query or // a request to an authentication service. // // The complete set of spans that are related to each other via the parent/child // relationship is called a trace. // // A trace can extend across processes and networks via trace context -// propagation. A `Span` can be _extracted_ from its external parent via +// propagation. A `Span` can be _extracted_ from its external parent via // `Tracer::extract_span`, and a `Span` can be _injected_ via `Span::inject` // into an outside context from which its external children might be extracted. // // If an error occurs during the operation that a span represents, the error can // be noted in the span via the `set_error` family of member functions. // -// A `Span` is finished when it is destroyed. The end time can be overridden +// A `Span` is finished when it is destroyed. The end time can be overridden // via the `set_end_time` member function prior to the span's destruction. #include @@ -81,18 +81,18 @@ class Span { Span& operator=(Span&&) = delete; Span& operator=(const Span&) = delete; - // Finish this span and submit it to the associated trace segment. If + // Finish this span and submit it to the associated trace segment. If // `set_end_time` has not been called on this span, then set this span's end // time to the current time. // If this span was moved-from, then the destructor has no effect aside from // destroying data members. ~Span(); - // Return a span that is a child of this span. Use the optionally specified - // `config` to determine the properties of the child span. If `config` is not + // Return a span that is a child of this span. Use the optionally specified + // `config` to determine the properties of the child span. If `config` is not // specified, then the child span's properties are determined by the // `SpanDefaults` that were used to configure the `Tracer` to which this span - // is related. The child span's start time is the current time unless + // is related. The child span's start time is the current time unless // overridden in `config`. Span create_child(const SpanConfig& config) const; Span create_child() const; @@ -148,19 +148,19 @@ class Span { // Set the name of the resource associated with the operation that this span // represents, e.g. "/api/v1/info" or "select count(*) from users". void set_resource_name(StringView); - // Set whether an error occurred during the extent of this span. If `false`, + // Set whether an error occurred during the extent of this span. If `false`, // then error-related tags will be removed from this span as well. void set_error(bool); // Associate a message with the error that occurred during the extent of this - // span. This also has the effect of calling `set_error(true)`. + // span. This also has the effect of calling `set_error(true)`. void set_error_message(StringView); // Associate an error type with the error that occurred during the extent of - // this span. This also has the effect of calling `set_error(true)`. + // this span. This also has the effect of calling `set_error(true)`. void set_error_type(StringView); // Associate a call stack with the error that occurred during the extent of - // this span. This also has the effect of calling `set_error(true)`. + // this span. This also has the effect of calling `set_error(true)`. void set_error_stack(StringView); - // Set end time of this span. Doing so will override the default behavior of + // Set end time of this span. Doing so will override the default behavior of // using the current time in the destructor. void set_end_time(std::chrono::steady_clock::time_point); // Specifies the product (AppSec, DBM) that created this span. @@ -171,7 +171,7 @@ class Span { void inject(DictWriter& writer) const; void inject(DictWriter& writer, const InjectionOptions& options) const; - // Return a reference to this span's trace segment. The trace segment has + // Return a reference to this span's trace segment. The trace segment has // member functions that affect the trace as a whole, such as // `TraceSegment::override_sampling_priority`. TraceSegment& trace_segment(); diff --git a/include/datadog/string_view.h b/include/datadog/string_view.h index 5e20c17ce..eb9cc5fa0 100644 --- a/include/datadog/string_view.h +++ b/include/datadog/string_view.h @@ -3,7 +3,7 @@ // One of the clients of this library is Envoy, a service (HTTP) proxy. // // Envoy uses Abseil as its base C++ library, and additionally builds in C++17 -// mode. Abseil has a build option to forward its `std::string_view` and +// mode. Abseil has a build option to forward its `std::string_view` and // `std::optional` equivalents to the actual standard types when C++17 is // available. // @@ -17,9 +17,9 @@ // and `std::optional` in the exported interface, i.e. in header files. // // As a workaround, Bazel (the build tool used by Envoy) builds of this library -// will define the `DD_USE_ABSEIL_FOR_ENVOY` preprocessor macro. When this +// will define the `DD_USE_ABSEIL_FOR_ENVOY` preprocessor macro. When this // macro is defined, the library-specific `StringView` and `Optional` aliases -// will refer to the Abseil types. When the macro is not defined, the +// will refer to the Abseil types. When the macro is not defined, the // library-specific aliases will refer to the standard types. // // This file defines `datadog::tracing::StringView`, a type that is an alias @@ -45,14 +45,14 @@ using StringView = std::string_view; #endif // defined DD_USE_ABSEIL_FOR_ENVOY // When `StringView` is not the same as `std::string_view`, -// `operator+=(string&, StringView)` isn't defined. To work around this, use +// `operator+=(string&, StringView)` isn't defined. To work around this, use // `append` everywhere. inline void append(std::string& destination, StringView text) { destination.append(text.data(), text.size()); } // When `StringView` is not the same as `std::string_view`, -// `operator=(string&, StringView)` isn't defined. To work around this, use +// `operator=(string&, StringView)` isn't defined. To work around this, use // `assign` everywhere. inline void assign(std::string& destination, StringView text) { destination.assign(text.data(), text.size()); diff --git a/include/datadog/trace_segment.h b/include/datadog/trace_segment.h index a9fcf171c..db32bf7ab 100644 --- a/include/datadog/trace_segment.h +++ b/include/datadog/trace_segment.h @@ -3,23 +3,23 @@ // This component provides a class, `TraceSegment`, that represents a portion of // a trace that is passing through this process. // -// `TraceSegment` is not instantiated directly. It is an implementation detail +// `TraceSegment` is not instantiated directly. It is an implementation detail // of this library. // // A trace might begin in this process, or it might have been propagated in from -// outside (see `Tracer::extract_span`). A trace might remain in this process, +// outside (see `Tracer::extract_span`). A trace might remain in this process, // or it might be propagated outward (see `Span::inject`) one or more times. // -// A trace might pass through this process twice or more. Consider an RPC +// A trace might pass through this process twice or more. Consider an RPC // server that receives a request, in handling that request makes a request to a // different service, and in the course of the other service handling its -// request, the original service is called again. Both "passes" through this +// request, the original service is called again. Both "passes" through this // process are part of the same trace, but each pass is a different _trace // segment_. // // `TraceSegment` stores context and configuration shared among all spans within -// the trace segment, and additionally owns the spans' data. When `Tracer` -// creates or extracts a span, it also creates a new `TraceSegment`. When a +// the trace segment, and additionally owns the spans' data. When `Tracer` +// creates or extracts a span, it also creates a new `TraceSegment`. When a // child `Span` is created from a `Span`, the child and the parent share the // same `TraceSegment`. // @@ -119,7 +119,7 @@ class TraceSegment { // Take ownership of the specified `span`. void register_span(std::unique_ptr span); - // Increment the number of finished spans. If that number is equal to the + // Increment the number of finished spans. If that number is equal to the // number of registered spans, send all of the spans to the `Collector`. void span_finished(); diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 6a032a133..891b972fd 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -7,7 +7,7 @@ // from a provided key/value source (see `extract_span`). // // `Tracer` is instantiated with a `FinalizedTracerConfig`, which can be -// obtained from a `TracerConfig` via the `finalize_config` function. See +// obtained from a `TracerConfig` via the `finalize_config` function. See // `tracer_config.h`. #include @@ -65,15 +65,15 @@ class Tracer { Tracer(const FinalizedTracerConfig& config, const std::shared_ptr& generator); - // Create a new trace and return the root span of the trace. Optionally + // Create a new trace and return the root span of the trace. Optionally // specify a `config` indicating the attributes of the root span. Span create_span(); Span create_span(const SpanConfig& config); // Return a span whose parent and other context is parsed from the specified // `reader`, and whose attributes are determined by the optionally specified - // `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 + // `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. Expected extract_span(const DictReader& reader); Expected extract_span(const DictReader& reader, diff --git a/include/datadog/tracer_config.h b/include/datadog/tracer_config.h index 4f9196dbd..5b464e64d 100644 --- a/include/datadog/tracer_config.h +++ b/include/datadog/tracer_config.h @@ -1,7 +1,7 @@ #pragma once // This component provides a struct, `TracerConfig`, used to configure a -// `Tracer`. `Tracer` is instantiated with a `FinalizedTracerConfig`, which +// `Tracer`. `Tracer` is instantiated with a `FinalizedTracerConfig`, which // must be obtained from the result of a call to `finalize_config`. #include @@ -59,19 +59,19 @@ struct TracerConfig { // Overriden by the `DD_TAGS` environment variable. Optional> tags; - // `agent` configures a `DatadogAgent` collector instance. See - // `datadog_agent_config.h`. Note that `agent` is ignored if `collector` is + // `agent` configures a `DatadogAgent` collector instance. See + // `datadog_agent_config.h`. Note that `agent` is ignored if `collector` is // set or if `report_traces` is `false`. DatadogAgentConfig agent; // `collector` is a `Collector` instance that the tracer will use to report - // traces to Datadog. If `collector` is null, then a `DatadogAgent` instance - // will be created using the `agent` configuration. Note that `collector` is + // traces to Datadog. If `collector` is null, then a `DatadogAgent` instance + // will be created using the `agent` configuration. Note that `collector` is // ignored if `report_traces` is `false`. std::shared_ptr collector; // `report_traces` indicates whether traces generated by the tracer will be - // sent to a collector (`true`) or discarded on completion (`false`). If + // sent to a collector (`true`) or discarded on completion (`false`). If // `report_traces` is `false`, then both `agent` and `collector` are ignored. // `report_traces` is overridden by the `DD_TRACE_ENABLED` environment // variable. @@ -81,13 +81,13 @@ struct TracerConfig { // `telemetry/configuration.h` By default, the telemetry module is enabled. telemetry::Configuration telemetry; - // `trace_sampler` configures trace sampling. Trace sampling determines which - // traces are sent to Datadog. See `trace_sampler_config.h`. + // `trace_sampler` configures trace sampling. Trace sampling determines which + // traces are sent to Datadog. See `trace_sampler_config.h`. TraceSamplerConfig trace_sampler; - // `span_sampler` configures span sampling. Span sampling allows specified + // `span_sampler` configures span sampling. Span sampling allows specified // spans to be sent to Datadog even when their enclosing trace is dropped by - // the trace sampler. See `span_sampler_config.h`. + // the trace sampler. See `span_sampler_config.h`. SpanSamplerConfig span_sampler; // `injection_styles` indicates with which tracing systems trace propagation @@ -113,12 +113,12 @@ struct TracerConfig { // `max_tags_header_size` is the maximum allowed size, in bytes, of the // serialized value of the "X-Datadog-Tags" header used when injecting trace - // context for propagation. If the serialized value of the header would + // context for propagation. If the serialized value of the header would // exceed `tags_header_size`, the header will be omitted instead. Optional max_tags_header_size; - // `logger` specifies how the tracer will issue diagnostic messages. If - // `logger` is null, then it defaults to no logging (`NullLogger`). See + // `logger` specifies how the tracer will issue diagnostic messages. If + // `logger` is null, then it defaults to no logging (`NullLogger`). See // `CerrLogger` for an alternative. std::shared_ptr logger; @@ -129,7 +129,7 @@ struct TracerConfig { Optional log_on_startup; // `trace_id_128_bit` indicates whether the tracer will generate 128-bit trace - // IDs. If true, the tracer will generate 128-bit trace IDs. If false, the + // IDs. If true, the tracer will generate 128-bit trace IDs. If false, the // tracer will generate 64-bit trace IDs. `trace_id_128_bit` is overridden by // the `DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED` environment variable. Optional generate_128bit_trace_ids; @@ -246,10 +246,10 @@ class FinalizedTracerConfig final { }; // Return a `FinalizedTracerConfig` from the specified `config` and from any -// relevant environment variables. If any configuration is invalid, return an +// relevant environment variables. If any configuration is invalid, return an // `Error`. // Optionally specify a `clock` used to calculate span start times, span -// durations, and timeouts. If `clock` is not specified, then `default_clock` +// durations, and timeouts. If `clock` is not specified, then `default_clock` // is used. Expected finalize_config(const TracerConfig& config); Expected finalize_config(const TracerConfig& config, diff --git a/src/datadog/common/hash.h b/src/datadog/common/hash.h index 3d2155d8c..4cf0bcbee 100644 --- a/src/datadog/common/hash.h +++ b/src/datadog/common/hash.h @@ -29,23 +29,23 @@ namespace details { // Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas // Feb 2 2012: production, same bits as beta // Feb 5 2012: adjusted definitions of uint* to be more portable -// Mar 30 2012: 3 bytes/cycle, not 4. Alpha was 4 but wasn't thorough enough. +// Mar 30 2012: 3 bytes/cycle, not 4. Alpha was 4 but wasn't thorough enough. // August 5 2012: SpookyV2 (different results) // -// Up to 3 bytes/cycle for long messages. Reasonably fast for short messages. +// Up to 3 bytes/cycle for long messages. Reasonably fast for short messages. // All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit. // // This was developed for and tested on 64-bit x86-compatible processors. -// It assumes the processor is little-endian. There is a macro +// It assumes the processor is little-endian. There is a macro // controlling whether unaligned reads are allowed (by default they are). // This should be an equally good hash on big-endian machines, but it will // compute different results on them than on little-endian machines. // // Google's CityHash has similar specs to SpookyHash, and CityHash is faster -// on new Intel boxes. MD4 and MD5 also have similar specs, but they are orders -// of magnitude slower. CRCs are two or more times slower, but unlike +// on new Intel boxes. MD4 and MD5 also have similar specs, but they are orders +// of magnitude slower. CRCs are two or more times slower, but unlike // SpookyHash, they have nice math for combining the CRCs of pieces to form -// the CRCs of wholes. There are also cryptographic hashes, but those are even +// the CRCs of wholes. There are also cryptographic hashes, but those are even // slower than MD5. // // Source: @@ -377,7 +377,7 @@ class SpookyHash { // // Short is used for messages under 192 bytes in length // Short has a low startup cost, the normal mode is good for long - // keys, the cost crossover is at about 192 bytes. The two modes were + // keys, the cost crossover is at about 192 bytes. The two modes were // held to the same quality bar. // static void Short( diff --git a/src/datadog/curl.cpp b/src/datadog/curl.cpp index 10e5f8614..c4228d731 100644 --- a/src/datadog/curl.cpp +++ b/src/datadog/curl.cpp @@ -505,7 +505,7 @@ std::size_t CurlImpl::on_read_header(char *data, std::size_t, // " Foo-Bar : thingy, thingy, thing \r\n" // -> {"foo-bar", "thingy, thingy, thing"} // - // There isn't always a colon. Inputs without a colon can be ignored: + // There isn't always a colon. Inputs without a colon can be ignored: // // > For an HTTP transfer, the status line and the blank line preceding the // > response body are both included as headers and passed to this @@ -646,8 +646,8 @@ void CurlImpl::handle_message(const CURLMsg &message) { } auto &request = *reinterpret_cast(user_data); - // `request` is done. If we got a response, then call the response - // handler. If an error occurred, then call the error handler. + // `request` is done. If we got a response, then call the response + // handler. If an error occurred, then call the error handler. const auto result = message.data.result; if (result != CURLE_OK) { std::string error_message; diff --git a/src/datadog/curl.h b/src/datadog/curl.h index 3ff8e2398..a9d85e681 100644 --- a/src/datadog/curl.h +++ b/src/datadog/curl.h @@ -1,7 +1,7 @@ #pragma once // This component provides a `class`, `Curl`, that implements the `HTTPClient` -// interface in terms of [libcurl](https://curl.se/libcurl)]. `class Curl` +// interface in terms of [libcurl](https://curl.se/libcurl)]. `class Curl` // manages a thread that is used as the event loop for libcurl. // // If this library was built in a mode that does not include libcurl, then this @@ -25,7 +25,7 @@ namespace datadog::tracing { // corresponding member functions -- one for each `CURLINFO` value or // `CURLoption` value, respectively. // -// The default implementations forward to their libcurl counterparts. Unit +// The default implementations forward to their libcurl counterparts. Unit // tests override some of the member functions. class CurlLibrary { public: diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index e761d8feb..fe1db1626 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -63,7 +63,7 @@ std::variant parse_agent_traces_response( if (type != "object") { std::string message; message += - "Parsing the Datadog Agent's response to traces we sent it failed. " + "Parsing the Datadog Agent's response to traces we sent it failed. " "The response is expected to be a JSON object, but instead it's a JSON " "value with type \""; append(message, type); @@ -83,7 +83,7 @@ std::variant parse_agent_traces_response( if (type != "object") { std::string message; message += - "Parsing the Datadog Agent's response to traces we sent it failed. " + "Parsing the Datadog Agent's response to traces we sent it failed. " "The \""; append(message, sample_rates_property); message += @@ -289,7 +289,7 @@ void DatadogAgent::flush() { } }; - // This is the callback for the HTTP response. It's invoked + // This is the callback for the HTTP response. It's invoked // asynchronously. auto on_response = [samplers = std::move(response_handlers), logger = logger_](int response_status, @@ -344,7 +344,7 @@ void DatadogAgent::flush() { }; // This is the callback for if something goes wrong sending the - // request or retrieving the response. It's invoked + // request or retrieving the response. It's invoked // asynchronously. auto on_error = [logger = logger_](Error error) { telemetry::counter::increment(metrics::tracer::api::errors, diff --git a/src/datadog/datadog_agent.h b/src/datadog/datadog_agent.h index fe016c462..993c11ee7 100644 --- a/src/datadog/datadog_agent.h +++ b/src/datadog/datadog_agent.h @@ -3,7 +3,7 @@ // This component provides a `class`, `DatadogAgent`, that implements the // `Collector` interface in terms of periodic HTTP requests to a Datadog Agent. // -// `DatadogAgent` is configured by `DatadogAgentConfig`. See +// `DatadogAgent` is configured by `DatadogAgentConfig`. See // `datadog_agent_config.h`. #include diff --git a/src/datadog/datadog_agent_config.cpp b/src/datadog/datadog_agent_config.cpp index 05b3b065f..20967db7e 100644 --- a/src/datadog/datadog_agent_config.cpp +++ b/src/datadog/datadog_agent_config.cpp @@ -63,7 +63,7 @@ Expected finalize_config( if (!user_config.http_client) { result.http_client = default_http_client(logger, clock); // `default_http_client` might return a `Curl` instance depending on how - // this library was built. If it returns `nullptr`, then there's no + // this library was built. If it returns `nullptr`, then there's no // built-in default, and so the user must provide a value. if (!result.http_client) { return Error{Error::DATADOG_AGENT_NULL_HTTP_CLIENT, diff --git a/src/datadog/glob.cpp b/src/datadog/glob.cpp index eaac66171..6484793f5 100644 --- a/src/datadog/glob.cpp +++ b/src/datadog/glob.cpp @@ -26,7 +26,7 @@ bool glob_match(StringView pattern, StringView subject) { const char pattern_char = pattern[p]; switch (pattern_char) { case '*': - // Try to match at `s`. If that doesn't work out, restart at + // Try to match at `s`. If that doesn't work out, restart at // `s + 1` next. next_p = p; next_s = s + 1; @@ -47,7 +47,7 @@ bool glob_match(StringView pattern, StringView subject) { } } } - // Mismatch. Maybe restart. + // Mismatch. Maybe restart. if (0 < next_s && next_s <= s_size) { p = next_p; s = next_s; diff --git a/src/datadog/glob.h b/src/datadog/glob.h index dbb5f396b..60f458e8c 100644 --- a/src/datadog/glob.h +++ b/src/datadog/glob.h @@ -17,7 +17,7 @@ namespace datadog { namespace tracing { // Return whether the specified `subject` matches the specified glob `pattern`, -// i.e. whether `subject` is a member of the set of strings represented by the +// i.e.whether `subject` is a member of the set of strings represented by the // glob `pattern`. bool glob_match(StringView pattern, StringView subject); diff --git a/src/datadog/http_client.cpp b/src/datadog/http_client.cpp index c8b4a95f2..bd4a422c3 100644 --- a/src/datadog/http_client.cpp +++ b/src/datadog/http_client.cpp @@ -39,11 +39,11 @@ Expected HTTPClient::URL::parse(StringView input) { const StringView authority_and_path = input.substr(after_scheme + k_scheme_separator.size()); // If the scheme is for unix domain sockets, then there's no way to - // distinguish the path-to-socket from the path-to-resource. Some + // distinguish the path-to-socket from the path-to-resource. Some // implementations require that the forward slashes in the path-to-socket - // are URL-encoded. However, URLs that we will be parsing designate the + // are URL-encoded. However, URLs that we will be parsing designate the // location of the Datadog Agent service, and so do not have a resource - // location. Thus, if the scheme is for a unix domain socket, assume that + // location. Thus, if the scheme is for a unix domain socket, assume that // the entire part after the "://" is the path to the socket, and that // there is no resource path. if (scheme == "unix" || scheme == "http+unix" || scheme == "https+unix") { @@ -64,11 +64,11 @@ Expected HTTPClient::URL::parse(StringView input) { "", ""}; } - // The scheme is either "http" or "https". This means that the part after + // The scheme is either "http" or "https". This means that the part after // the "://" could be /, e.g. "localhost:8080/api/v1". // Again, though, we're only parsing URLs that designate the location of // the Datadog Agent service, and so they will not have a resource - // location. Still, let's parse it properly. + // location. Still, let's parse it properly. const auto after_authority = authority_and_path.find('/'); std::string path; diff --git a/src/datadog/json.hpp b/src/datadog/json.hpp index 82d69f7c5..c2cd0b198 100644 --- a/src/datadog/json.hpp +++ b/src/datadog/json.hpp @@ -1118,7 +1118,7 @@ NLOHMANN_JSON_NAMESPACE_END #endif /* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif @@ -2082,7 +2082,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_REQUIRE_CONSTEXPR #endif /* JSON_HEDLEY_IS_CONSTEXPR_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_IS_CONSTEXPR_) #undef JSON_HEDLEY_IS_CONSTEXPR_ #endif @@ -6533,7 +6533,7 @@ Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at beginning of input. Does not support changing the underlying std::streambuf in mid-input. Maintains underlying std::istream and std::streambuf to support subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the +characters following those used in parsing the JSON input. Clears the std::istream flags; any input errors (e.g., EOF) will be detected by the first subsequent call for input from the std::istream. */ @@ -8355,7 +8355,7 @@ class lexer : public lexer_base This function provides the interface to the used input adapter. It does not throw in case the input reached EOF, but returns a - `char_traits::eof()` in that case. Stores the scanned characters + `char_traits::eof()` in that case. Stores the scanned characters for use in error messages. @return character read from the input @@ -8473,9 +8473,9 @@ class lexer : public lexer_base return position; } - /// return the last read token (for errors only). Will never contain EOF + /// return the last read token (for errors only). Will never contain EOF /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. + /// 255 may legitimately occur. May contain NUL, which should be escaped. std::string get_token_string() const { // escape control characters diff --git a/src/datadog/json_serializer.h b/src/datadog/json_serializer.h index 014dd6809..9d23bf7a2 100644 --- a/src/datadog/json_serializer.h +++ b/src/datadog/json_serializer.h @@ -85,7 +85,7 @@ inline Expected from_json(const nlohmann::json& json) { } } else { // Unknown properties are OK. `SpanMatcher` is used as a base class for - // trace sampling rules and span sampling rules. Those derived types + // trace sampling rules and span sampling rules. Those derived types // will have additional properties in their JSON representations. } } diff --git a/src/datadog/msgpack.h b/src/datadog/msgpack.h index 4a8447cff..b8cb74300 100644 --- a/src/datadog/msgpack.h +++ b/src/datadog/msgpack.h @@ -1,15 +1,14 @@ #pragma once -// This component provides encoding routines for [MessagePack][1]. +// This component provides encoding routines for +// [MessagePack](https://msgpack.org/index.html). // // Each function is in `namespace msgpack` and appends a specified value to a -// `std::string`. For example, `msgpack::pack_integer(destination, -42)` +// `std::string`. For example, `msgpack::pack_integer(destination, -42)` // MessagePack encodes the number `-42` and appends the result to `destination`. // // Only encoding is provided, and only for the types required by `SpanData` and // `DatadogAgent`. -// -// [1]: https://msgpack.org/index.html #include #include @@ -37,11 +36,11 @@ Expected pack_array(std::string& buffer, std::size_t size); // Append to the specified `buffer` a MessagePack encoded array having the // specified `values`, where for each element of `values` the specified -// `pack_value` function appends the value. `pack_value` is invoked with two +// `pack_value` function appends the value. `pack_value` is invoked with two // arguments: the first is a reference to `buffer`, and the second is a -// reference to the current value. `pack_value` returns an `Expected`. If +// reference to the current value. `pack_value` returns an `Expected`. If // the return value is an error, then iteration is halted and the error is -// returned. If some other error occurs, then an error is returned. Otherwise, +// returned. If some other error occurs, then an error is returned. Otherwise, // the non-error value is returned. template Expected pack_array(std::string& buffer, Iterable&& values, @@ -54,23 +53,23 @@ Expected pack_map(std::string& buffer, std::size_t size); // map element, and the second element of each pair is some value that is // MessagePack encoded by the specified `pack_value` function. `pack_value` is // invoked with two arguments: the first is a reference to `buffer`, and the -// second is a reference to the current value. `pack_value` returns an +// second is a reference to the current value. `pack_value` returns an // `Expected`. If the return value is an error, then iteration is halted -// and the error is returned. If some other error occurs, then an error is -// returned. Otherwise, the non-error value is returned. +// and the error is returned. If some other error occurs, then an error is +// returned. Otherwise, the non-error value is returned. template Expected pack_map(std::string& buffer, const PairIterable& pairs, PackValue&& pack_value); // Append to the specified `buffer` a MessagePack encoded map consisting of the -// specified key value pairs. After the `buffer` argument, `pack_map` accepts -// an even number of arguments. First in each pair of arguments is `key`, the -// key name of the corresponding map item. Second in each pair of arguments is -// `pack_value`, a function that encodes the corresponding value. `pack_value` +// specified key value pairs. After the `buffer` argument, `pack_map` accepts +// an even number of arguments. First in each pair of arguments is `key`, the +// key name of the corresponding map item. Second in each pair of arguments is +// `pack_value`, a function that encodes the corresponding value. `pack_value` // is invoked with one argument: a reference to `buffer`. `pack_value` returns -// an `Expected`. If the return value is an error, then iteration is -// halted and the error is returned. If some other error occurs, then an error -// is returned. Otherwise, the non-error value is returned. +// an `Expected`. If the return value is an error, then iteration is +// halted and the error is returned. If some other error occurs, then an error +// is returned. Otherwise, the non-error value is returned. template Expected pack_map(std::string& buffer, StringView key, PackValue&& pack_value, Rest&&... rest); diff --git a/src/datadog/random.cpp b/src/datadog/random.cpp index 48138af2e..78f52e65f 100644 --- a/src/datadog/random.cpp +++ b/src/datadog/random.cpp @@ -44,7 +44,7 @@ std::uint64_t random_uint64() { return thread_local_generator(); } std::string uuid() { // clang-format off - // It's not all random. From most significant to least significant, the + // It's not all random. From most significant to least significant, the // bits look like this: // // xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 0100xxxx xxxxxxxx 10xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx diff --git a/src/datadog/sampling_util.h b/src/datadog/sampling_util.h index 1c74d8acc..19f424f45 100644 --- a/src/datadog/sampling_util.h +++ b/src/datadog/sampling_util.h @@ -1,6 +1,6 @@ #pragma once -// This component provides sampling-related miscellanea. It's used by both +// This component provides sampling-related miscellanea. It's used by both // `TraceSampler` and `SpanSampler`. #include @@ -11,7 +11,7 @@ namespace datadog { namespace tracing { -// Return a hash value for the specified `value`. `value` is one of the +// Return a hash value for the specified `value`. `value` is one of the // following: // // - a 64-bit span ID diff --git a/src/datadog/span_data.h b/src/datadog/span_data.h index 9413e173b..36950427d 100644 --- a/src/datadog/span_data.h +++ b/src/datadog/span_data.h @@ -38,7 +38,7 @@ struct SpanData { Optional version() const; // Modify the properties of this object to honor the specified `config` and - // `defaults`. The properties of `config`, if set, override the properties of + // `defaults`. The properties of `config`, if set, override the properties of // `defaults`. Use the specified `clock` to provide a start none of none is // specified in `config`. void apply_config(const SpanDefaults& defaults, const SpanConfig& config, @@ -50,7 +50,7 @@ struct SpanData { Expected msgpack_encode(std::string& destination, const SpanData& span); // Append to the specified `destination` the MessagePack representation of an -// array containing each of the specified `spans`. The behavior is undefined +// array containing each of the specified `spans`. The behavior is undefined // if any span is `nullptr`. Expected msgpack_encode( std::string& destination, diff --git a/src/datadog/span_sampler.h b/src/datadog/span_sampler.h index 0d4f09a2d..a6615afba 100644 --- a/src/datadog/span_sampler.h +++ b/src/datadog/span_sampler.h @@ -11,7 +11,7 @@ // is dropped. // // As with the `TraceSampler`, spans are matched by rules that indicate the -// sample rate at which the spans will be sent to Datadog. Each rule is +// sample rate at which the spans will be sent to Datadog. Each rule is // additionally associated with an optional limiter that prevents the sent // volume of spans from exceeding a specified number of spans per second. // diff --git a/src/datadog/span_sampler_config.cpp b/src/datadog/span_sampler_config.cpp index cf1b60fb8..28d5c4ef3 100644 --- a/src/datadog/span_sampler_config.cpp +++ b/src/datadog/span_sampler_config.cpp @@ -29,7 +29,7 @@ std::string to_string(const std::vector &rules) { } // `env_var` is the name of the environment variable from which `rules_raw` was -// obtained. It's used for error messages. +// obtained. It's used for error messages. Expected> parse_rules(StringView rules_raw, StringView env_var) { std::vector rules; @@ -86,7 +86,7 @@ Expected> parse_rules(StringView rules_raw, append(message, env_var); message += " JSON "; append(message, rules_raw); - message += ". The \"sample_rate\" property of the rule "; + message += ". The \"sample_rate\" property of the rule "; message += json_rule.dump(); message += " is not a number, but instead has type \""; message += type; @@ -106,7 +106,7 @@ Expected> parse_rules(StringView rules_raw, append(message, env_var); message += " JSON "; append(message, rules_raw); - message += ". The \"max_per_second\" property of the rule "; + message += ". The \"max_per_second\" property of the rule "; message += json_rule.dump(); message += " is not a number, but instead has type \""; message += type; @@ -129,7 +129,7 @@ Expected> parse_rules(StringView rules_raw, message += value.dump(); message += " in trace sampling rule "; message += json_rule.dump(); - message += ". Error occurred while parsing from "; + message += ". Error occurred while parsing from "; append(message, env_var); message += ": "; append(message, rules_raw); @@ -165,7 +165,7 @@ Expected load_span_sampler_env_config(Logger &logger) { append(message, rules_file_name); message += " is overridden by "; append(message, rules_name); - message += ". Since both are set, "; + message += ". Since both are set, "; append(message, rules_name); message += " takes precedence, and "; append(message, rules_file_name); diff --git a/src/datadog/tag_propagation.cpp b/src/datadog/tag_propagation.cpp index 2c790742d..46ead2d57 100644 --- a/src/datadog/tag_propagation.cpp +++ b/src/datadog/tag_propagation.cpp @@ -11,8 +11,11 @@ namespace datadog { namespace tracing { -// The following [eBNF][1] grammar describes the tag propagation encoding. -// The grammar was copied from [an internal design document][2]. +// The following +// [eBNF](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form) +// grammar describes the tag propagation encoding. The grammar was copied from +// [an internal design +// document](https://docs.google.com/document/d/1zeO6LGnvxk5XweObHAwJbK3SfK23z7jQzp7ozWJTa2A/edit#heading=h.yp07yuixga36). // // tagset = ( tag, { ",", tag } ) | ""; // tag = ( identifier - space or equal ), "=", identifier; @@ -24,14 +27,11 @@ namespace tracing { // // See `tag_propagation_test.cpp` for examples. // -// [1]: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form -// [2]: -// https://docs.google.com/document/d/1zeO6LGnvxk5XweObHAwJbK3SfK23z7jQzp7ozWJTa2A/edit#heading=h.yp07yuixga36 namespace { // Insert into the specified `destination` a tag decoded from the specified -// `entry`. Return an `Error` if an error occurs. +// `entry`. Return an `Error` if an error occurs. Expected decode_tag( std::vector>& destination, StringView entry) { diff --git a/src/datadog/tag_propagation.h b/src/datadog/tag_propagation.h index 21169139f..7c9d0703c 100644 --- a/src/datadog/tag_propagation.h +++ b/src/datadog/tag_propagation.h @@ -1,7 +1,7 @@ #pragma once // Some span tags are associated with the entire local trace, rather than just -// a single span within the trace. These tags are added to the local root span +// a single span within the trace. These tags are added to the local root span // before the trace is flushed. // // Among these root span tags, some are also propagated as trace context. diff --git a/src/datadog/trace_id.cpp b/src/datadog/trace_id.cpp index 4eaff241c..ee61c481f 100644 --- a/src/datadog/trace_id.cpp +++ b/src/datadog/trace_id.cpp @@ -38,7 +38,7 @@ Expected TraceID::parse_hex(StringView input) { return result; }; - // A 64-bit integer is at most 16 hex characters. If the input is no + // A 64-bit integer is at most 16 hex characters. If the input is no // longer than that, then it will all fit in `TraceID::low`. if (input.size() <= 16) { auto result = parse_hex_piece(input); diff --git a/src/datadog/trace_sampler.cpp b/src/datadog/trace_sampler.cpp index 1831581f5..d455b9c42 100644 --- a/src/datadog/trace_sampler.cpp +++ b/src/datadog/trace_sampler.cpp @@ -71,7 +71,7 @@ SamplingDecision TraceSampler::decide(const SpanData& span) { return decision; } - // No sampling rule matched. Find the appropriate collector-controlled + // No sampling rule matched. Find the appropriate collector-controlled // sample rate. auto found_rate = collector_sample_rates_.find( CollectorResponse::key(span.service, span.environment().value_or(""))); @@ -83,7 +83,7 @@ SamplingDecision TraceSampler::decide(const SpanData& span) { decision.configured_rate = *collector_default_sample_rate_; decision.mechanism = int(SamplingMechanism::AGENT_RATE); } else { - // We have yet to receive a default rate from the collector. This + // We have yet to receive a default rate from the collector. This // corresponds to the `DEFAULT` sampling mechanism. decision.configured_rate = Rate::one(); decision.mechanism = int(SamplingMechanism::DEFAULT); diff --git a/src/datadog/trace_sampler.h b/src/datadog/trace_sampler.h index 78b27cd7b..640a4219b 100644 --- a/src/datadog/trace_sampler.h +++ b/src/datadog/trace_sampler.h @@ -8,11 +8,11 @@ // // When a span is extracted from an outside context (i.e. // `Tracer::extract_span`), then the trace sampling decision is included in the -// extracted information. In order to ensure that all parts of a trace are +// extracted information. In order to ensure that all parts of a trace are // sampled consistently, such sampling decisions are honored. // // However, when this process is the first service in a distributed trace (i.e. -// `Tracer::create_span`), it makes the trace sampling decision. The +// `Tracer::create_span`), it makes the trace sampling decision. The // `TraceSampler` determines how the decision is made. // // There are three levels of configuration, in order of increasing specificity, @@ -24,8 +24,8 @@ // sample rates. // // The Datadog Agent has a configured target number of traces per second to send -// to Datadog. It chases this target by adjusting the sample rates of services -// that send it traces. The target traces per second can be configured in the +// to Datadog. It chases this target by adjusting the sample rates of services +// that send it traces. The target traces per second can be configured in the // Datadog Agent via the environment variable `DD_APM_MAX_TPS` or the // corresponding YAML configuration option `max_traces_per_second`. // @@ -36,16 +36,16 @@ // --------------------- // If `TraceSamplerConfig::sample_rate` is given a value, or if the // `DD_TRACE_SAMPLE_RATE` environment variable has a value, then the rate at -// which traces are kept is overridden to be the configured value. The Datadog +// which traces are kept is overridden to be the configured value. The Datadog // Agent provided rate is no longer used. // // For example, if `TracerSamplerConfig::sample_rate` is `0.1`, then 10% of -// traces that originate with this tracer will be sent to Datadog. The +// traces that originate with this tracer will be sent to Datadog. The // remaining 90% will be sent to the Datadog Agent, but will not be sent to // Datadog's backend and will not be visible in the Datadog UI. // // The volume of traces kept on account of the global sample rate is limited by -// the same setting as for trace sampling rules. See the description of +// the same setting as for trace sampling rules. See the description of // `TraceSamplerConfig::max_per_second` and `DD_TRACE_RATE_LIMIT` at the end of // the following section. // @@ -57,7 +57,7 @@ // Trace sampling rules are configured via `TraceSamplerConfig::rules` or the // `DD_TRACE_SAMPLING_RULES` environment variable. // -// A trace sampling rule associates a span pattern with a sample rate. If the +// A trace sampling rule associates a span pattern with a sample rate. If the // root span of a new trace created by the tracer matches the span pattern, // then the associated sample rate is applied. // @@ -75,11 +75,11 @@ // matching rule is used. // // The global rate (section 2, above) is implemented as a sampling rule that -// matches any span and is appended to any configured sampling rules. Thus, +// matches any span and is appended to any configured sampling rules. Thus, // sampling rules override the global sample rate for matching root spans. // // The volume of traces kept by sampling rules (including the global sample -// rate) is limited by a configurable number of traces-per-second. The limit is +// rate) is limited by a configurable number of traces-per-second. The limit is // configured via `TraceSamplerConfig::max_per_second` or the // `DD_TRACE_RATE_LIMIT` environment variable. diff --git a/src/datadog/trace_sampler_config.cpp b/src/datadog/trace_sampler_config.cpp index 698731db3..b573bae8c 100644 --- a/src/datadog/trace_sampler_config.cpp +++ b/src/datadog/trace_sampler_config.cpp @@ -72,7 +72,7 @@ Expected load_trace_sampler_env_config() { append(message, name(environment::DD_TRACE_SAMPLING_RULES)); message += " value "; append(message, *rules_env); - message += ". The \"sample_rate\" property of the rule "; + message += ". The \"sample_rate\" property of the rule "; message += json_rule.dump(); message += " is not a number, but instead has type \""; message += type; @@ -95,7 +95,7 @@ Expected load_trace_sampler_env_config() { message += value.dump(); message += " in trace sampling rule "; message += json_rule.dump(); - message += ". Error occurred while parsing "; + message += ". Error occurred while parsing "; append(message, name(environment::DD_TRACE_SAMPLING_RULES)); message += ": "; append(message, *rules_env); diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index ea14aeb4c..4a7181b05 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -69,7 +69,7 @@ void inject_trace_tags( if (encoded_trace_tags.size() > tags_header_max_size) { std::string message; message += - "Serialized x-datadog-tags header value is too large. The configured " + "Serialized x-datadog-tags header value is too large. The configured " "maximum size is "; message += std::to_string(tags_header_max_size); message += " bytes, but the encoded value is "; @@ -227,7 +227,7 @@ void TraceSegment::span_finished() { telemetry::counter::increment(metrics::tracer::trace_chunks_enqueued); - // We don't need the lock anymore. There's nobody left to call our methods. + // We don't need the lock anymore. There's nobody left to call our methods. // On the other hand, there's nobody left to contend for the mutex, so it // doesn't make any difference. make_sampling_decision_if_null(); diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 4209ac228..d1de11f89 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -172,7 +172,7 @@ void Tracer::store_config( // clang-format off msgpack::pack_map( - buffer, + buffer, "schema_version", [&](auto& buffer) { msgpack::pack_integer(buffer, std::uint64_t(2)); return Expected{}; }, "runtime_id", [&](auto& buffer) { return msgpack::pack_string(buffer, runtime_id_.string()); }, "tracer_version", [&](auto& buffer) { return msgpack::pack_string(buffer, signature_.library_version); }, @@ -343,7 +343,7 @@ Expected Tracer::extract_span(const DictReader& reader, } if (!merged_context.parent_id) { - // We have a trace ID, but not parent ID. We're meant to be the root, and + // We have a trace ID, but not parent ID. We're meant to be the root, and // whoever called us already created a trace ID for us (to correlate with // whatever they're doing). merged_context.parent_id = 0; @@ -359,7 +359,7 @@ Expected Tracer::extract_span(const DictReader& reader, merged_context.headers_examined)); } - // We're done extracting fields. Now create the span. + // We're done extracting fields. Now create the span. // This is similar to what we do in `create_span`. span_data->apply_config(*config_manager_->span_defaults(), config, clock_); span_data->span_id = generator_->span_id(); @@ -425,7 +425,7 @@ Expected Tracer::extract_span(const DictReader& reader, if (tracing_enabled_ && merged_context.sampling_priority) { SamplingDecision decision; decision.priority = *merged_context.sampling_priority; - // `decision.mechanism` is null. We might be able to infer it once we + // `decision.mechanism` is null. We might be able to infer it once we // extract `trace_tags`, but we would have no use for it, so we won't. decision.origin = SamplingDecision::Origin::EXTRACTED; diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 1383ce478..7b2b1aca9 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -53,7 +53,7 @@ Expected> parse_propagation_styles( message += "\" in list \""; append(message, input); message += - "\". The following styles are supported: Datadog, B3, tracecontext."; + "\". The following styles are supported: Datadog, B3, tracecontext."; return Error{Error::UNKNOWN_PROPAGATION_STYLE, std::move(message)}; } diff --git a/src/datadog/w3c_propagation.cpp b/src/datadog/w3c_propagation.cpp index f6e1eb46e..b8174577b 100644 --- a/src/datadog/w3c_propagation.cpp +++ b/src/datadog/w3c_propagation.cpp @@ -251,7 +251,7 @@ void parse_datadog_tracestate(ExtractedData& result, StringView datadog_value) { const auto tag_suffix = key.substr(2); std::string tag_name = "_dd.p."; append(tag_name, tag_suffix); - // The tag value was encoded with all '=' replaced by '~'. Undo that + // The tag value was encoded with all '=' replaced by '~'. Undo that // transformation. std::string decoded_value{value}; std::replace(decoded_value.begin(), decoded_value.end(), '~', '='); diff --git a/test/README.md b/test/README.md index b866aa5c2..98a07a018 100644 --- a/test/README.md +++ b/test/README.md @@ -1,25 +1,21 @@ -Unit Tests -========== -This directory contains the unit tests for dd-trace-cpp. +# Unit Tests -The testing library used is [Catch2][1], vendored here as a single header, -[catch.hpp](catch.hpp) (see the [Makefile](Makefile)). +This directory contains the unit tests for `dd-trace-cpp`. + +The testing library used is [Catch2](https://github.com/catchorg/Catch2/tree/v2.x), vendored here as +a single header, [catch.hpp](catch.hpp) (see the [Makefile](Makefile)). [../bin/test](../bin/test) builds and runs the unit tests. -Code Layout ------------ +## Code Layout + Test-specific implementations of interfaces are defined in [mocks/](mocks). [test.h](test.h) is a wrapper around [catch.hpp](catch.hpp). -[matchers.h](matchers.h) defines extensions to Catch2 that are convenient in -test assertions. +[matchers.h](matchers.h) defines extensions to Catch2 that are convenient in test assertions. [main.cpp](main.cpp) is the test driver (executable). -All other translation units in this directory are the tests themselves. For -example, [test_span.cpp](test_span.cpp) contains the tests for the `Span` class -and associated behavior. - -[1]: https://github.com/catchorg/Catch2/tree/v2.x +All other translation units in this directory are the tests themselves. For example, +[test_span.cpp](test_span.cpp) contains the tests for the `Span` class and associated behavior. diff --git a/test/system-tests/utils.h b/test/system-tests/utils.h index dd4a5c84d..850e77fd6 100644 --- a/test/system-tests/utils.h +++ b/test/system-tests/utils.h @@ -61,7 +61,7 @@ class HeaderWriter final : public dd::DictWriter { HeaderWriter(nlohmann::json& headers) : j_(headers){}; ~HeaderWriter() = default; - // Associate the specified `value` with the specified `key`. An + // Associate the specified `value` with the specified `key`. An // implementation may, but is not required to, overwrite any previous value at // `key`. void set(dd::StringView key, dd::StringView value) override { diff --git a/test/test_cerr_logger.cpp b/test/test_cerr_logger.cpp index 472ae60bf..174455506 100644 --- a/test/test_cerr_logger.cpp +++ b/test/test_cerr_logger.cpp @@ -13,7 +13,7 @@ using namespace datadog::tracing; namespace { // Replace the `streambuf` associated with a specified `std::ios` for the -// lifetime of this object. Restore the previous `streambuf` afterward. +// lifetime of this object. Restore the previous `streambuf` afterward. class StreambufGuard { std::ios *stream_; std::streambuf *buffer_; diff --git a/test/test_curl.cpp b/test/test_curl.cpp index e48a9690c..9f2668bae 100644 --- a/test/test_curl.cpp +++ b/test/test_curl.cpp @@ -282,7 +282,7 @@ CURL_TEST("fail to allocate request handle") { CURL_TEST("setopt failures") { // Each call to `Curl::post` allocates a new "easy handle" and sets various - // options on it. Any of those setters can fail. When one does, `post` + // options on it. Any of those setters can fail. When one does, `post` // immediately returns an error. class MockCurlLibrary : public CurlLibrary { public: diff --git a/test/test_span.cpp b/test/test_span.cpp index 4af524ed7..237c9cf1e 100644 --- a/test/test_span.cpp +++ b/test/test_span.cpp @@ -1,5 +1,5 @@ -// These are tests for `Span`. `Span` is a container for labels associated with -// an extent in time. `Span` is also responsible for injecting trace context +// These are tests for `Span`. `Span` is a container for labels associated with +// an extent in time. `Span` is also responsible for injecting trace context // for propagation. #include diff --git a/test/test_trace_sampler.cpp b/test/test_trace_sampler.cpp index de10f3522..c1f889380 100644 --- a/test/test_trace_sampler.cpp +++ b/test/test_trace_sampler.cpp @@ -103,7 +103,7 @@ TEST_CASE("trace sampling rule sample rate") { // priority 2 ("user keep"), but no other values. REQUIRE(priority_counts.size() <= 2); // I assume that there have been enough trials that not _all_ traces are kept - // or dropped purely due to chance. That could happen only if the sample rate + // or dropped purely due to chance. That could happen only if the sample rate // were 0% or 100%, respectively. REQUIRE((test_case.sample_rate == 0.0 || priority_counts.count(int(SamplingPriority::USER_KEEP)))); @@ -162,7 +162,7 @@ TEST_CASE("trace sampling rate limiter") { test_case.expected_kept_count); // Now verify that there is a "cooldown period" of one second, after which - // the limiter will permit some more traces. How many it permits depends + // the limiter will permit some more traces. How many it permits depends // on how "over budget" it was, but it will allow at least one. collector->sampling_priority_count.clear(); current_time += std::chrono::seconds(1); diff --git a/test/test_trace_segment.cpp b/test/test_trace_segment.cpp index b1ac3a38e..37f8f94ad 100644 --- a/test/test_trace_segment.cpp +++ b/test/test_trace_segment.cpp @@ -376,7 +376,7 @@ TEST_CASE("TraceSegment finalization of spans") { SECTION("rules (implicit and explicit)") { // When sample rate is 100%, the sampler will consult the limiter. - // When sample rate is 0%, it won't. We test both cases. + // When sample rate is 0%, it won't.We test both cases. auto sample_rate = GENERATE(0.0, 1.0); SECTION("global sample rate") { diff --git a/test/test_tracer.cpp b/test/test_tracer.cpp index 72231115f..598901d50 100644 --- a/test/test_tracer.cpp +++ b/test/test_tracer.cpp @@ -1,4 +1,4 @@ -// These are tests for `Tracer`. `Tracer` is responsible for creating root +// These are tests for `Tracer`. `Tracer` is responsible for creating root // spans and for extracting spans from propagated trace context. #include @@ -748,7 +748,7 @@ TEST_TRACER("span extraction") { {__LINE__, "invalid: trailing characters when version is zero", "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-foo", // traceparent "malformed_traceparent"}, // expected_error_tag_value - + {__LINE__, "invalid: non hex trace ID", "00-abcdefghijklmnopqrstuvxyzabcdefg-00f067aa0ba902b7-00", // traceparent "malformed_traceid"}, // expected_error_tag_value @@ -792,7 +792,7 @@ TEST_TRACER("span extraction") { MockDictReader reader{headers}; // We can't `span->lookup(tags::internal::w3c_extraction_error)`, because - // that tag is internal and will not be returned by `lookup`. Instead, we + // that tag is internal and will not be returned by `lookup`. Instead, we // finish (destroy) the span to send it to a collector, and then inspect the // `SpanData` at the collector. Optional decision; diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index b6407f72d..5f6aad8ac 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -509,7 +509,7 @@ TRACER_CONFIG_TEST("TracerConfig::agent") { {"override port with default host", nullopt, "8080", nullopt, "http", "localhost:8080"}, // A bogus port number will cause an error in the TCPClient, not - // during configuration. For the purposes of configuration, any + // during configuration. For the purposes of configuration, any // value is accepted. {"we don't parse port", nullopt, "bogus", nullopt, "http", "localhost:bogus"}, @@ -1232,7 +1232,7 @@ TRACER_CONFIG_TEST("TracerConfig propagation styles") { } // It's the same as for injection styles, so let's omit most of the - // section. Keep only an example where parsing fails, so we cover the + // section. Keep only an example where parsing fails, so we cover the // error handling code in `TracerConfig`. SECTION("parsing failure") { const EnvGuard guard{"DD_PROPAGATION_STYLE_EXTRACT", "b3,,datadog"}; From 6979721c4674baad486725e349f538be62c6ddce Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Fri, 3 Jul 2026 11:40:36 +0200 Subject: [PATCH 09/59] Redo diagrams with Mermaid (#334) --- doc/Makefile | 5 -- doc/README.md | 21 ++++++-- doc/maintainers.md | 25 ++++++---- doc/ownership.dot | 25 ---------- doc/ownership.svg | 122 --------------------------------------------- doc/segments.jpg | Bin 629629 -> 0 bytes 6 files changed, 32 insertions(+), 166 deletions(-) delete mode 100644 doc/Makefile delete mode 100644 doc/ownership.dot delete mode 100644 doc/ownership.svg delete mode 100644 doc/segments.jpg diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index e30fc0381..000000000 --- a/doc/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -.PHONY: all -all: ownership.svg - -%.svg: %.dot - dot -Grankdir=LR -Tsvg -o $@ $< diff --git a/doc/README.md b/doc/README.md index 41963ae91..a85736de6 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,11 +1,22 @@ # Logical Component Relationships - Vertices are components. -- Edges are ownership relationships between components. Each edge is labeled by the kind of "smart - pointer" that could implement that kind of relationship. -- Components containing a padlock are protected by a mutex. - -![diagram](ownership.svg) +- Edges are ownership relationships between components. Each edge is labeled by the kind of pointer + that is used to implement the relationship. +- Components with a padlock are protected by a mutex. + +```mermaid +--- +title: Components Relationships +config: + layout: elk +--- +graph LR; + Tracer(Tracer) & TraceSegment("TraceSegment 🔒")-- shared -->Collector("Collector 🔒") & SpanSampler("SpanSampler 🔒") & TraceSampler("TraceSampler 🔒") + TraceSegment-- "`**unique**`" -->SpanData(SpanData) + Span(Span)-- shared -->TraceSegment + Span-- "`**raw**`" -->SpanData +``` ## Objects diff --git a/doc/maintainers.md b/doc/maintainers.md index e8dd0e4e2..3247e5614 100644 --- a/doc/maintainers.md +++ b/doc/maintainers.md @@ -106,8 +106,8 @@ that accompany handle-to-interface are avoided. A "trace" is the entire tree of spans having the same trace ID. -Within one process/worker/service, though, typically there is not an entire trace but only part of -the trace. Let's call the process/worker/service a "tracer." +Within one process / worker / service, though, typically there is not an entire trace but only part +of the trace. Let's call the process / worker / service a "tracer." One portion of a trace that's passing through the tracer is called a "trace segment." A trace segment begins either at the trace's root span or at a span extracted from trace context, e.g. a @@ -116,13 +116,20 @@ segment includes all local descendants of that span, and has as its "boundary" a without children or descendant spans that were used to inject trace context out-of-tracer, e.g. in outgoing HTTP request headers. -There might be more than one trace segment for the _same trace_ within a tracer at the same time. -Consider the diagram below. - -flame graph - -If our tracer is "service X," then this trace passes through the tracer twice. We would have two -concurrent trace segments for the same trace. +There might be more than one trace segment for the _same trace_ within a tracer. For example, in the +diagram below, the trace passes through the "Service A" tracer twice. So for this trace, this tracer +has two trace segments: + +```mermaid +block + columns 8 + a["root"]:8 + space b["Service A - Trace segment A1 - Span A1"]:6 space + space:2 c["Service A - Trace segment A1 - Span A2"] d["Service A - Trace segment A1 - Span A3"]:4 space + space:3 e["Service B"]:3 space:2 + space:4 f["Service A - Trace segment A2 - Span A4"]:2 space:2 + space:4 g["Service A - Trace segment A2 - Span A5"] h["Service A - Trace segment A2 - Span A6"] space:2 +``` `class TraceSegment` is defined in [trace_segment.h](../include/datadog/trace_segment.h). `TraceSegment` objects are managed internally by the library. That is to say, a user never creates a diff --git a/doc/ownership.dot b/doc/ownership.dot deleted file mode 100644 index 3889c67d5..000000000 --- a/doc/ownership.dot +++ /dev/null @@ -1,25 +0,0 @@ -# This describes the object ownership relationships among the components -# in the tracer library. -# -# Each vertex (node) is a component, while each edge is a relationship. -# Edges are labeled by the kind of "smart pointer" that describes the -# relationship, e.g. "Tracer holds a shared_ptr to SpanSampler," or -# "Span holds a raw pointer to SpanData." -# -# Vertices labeled with a 🔒 are protected by a mutex. -# -digraph { - rankdir=LR; - - Tracer -> "Collector 🔒" [label=" shared", fontsize=8]; - Tracer -> "SpanSampler 🔒" [label=" shared", fontsize=8]; - Tracer -> "TraceSampler 🔒" [label=" shared", fontsize=8]; - - Span -> "TraceSegment 🔒" [label=" shared", fontsize=8]; - Span -> SpanData [label=< raw >, fontsize=8]; - - "TraceSegment 🔒" -> SpanData [label=< unique >, fontsize=8]; - "TraceSegment 🔒" -> "Collector 🔒" [label=" shared", fontsize=8]; - "TraceSegment 🔒" -> "SpanSampler 🔒" [label=" shared", fontsize=8]; - "TraceSegment 🔒" -> "TraceSampler 🔒" [label=" shared", fontsize=8]; -} diff --git a/doc/ownership.svg b/doc/ownership.svg deleted file mode 100644 index e39c39dea..000000000 --- a/doc/ownership.svg +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - -%3 - - - -Tracer - -Tracer - - - -Collector 🔒 - -Collector 🔒 - - - -Tracer->Collector 🔒 - - - shared - - - -SpanSampler 🔒 - -SpanSampler 🔒 - - - -Tracer->SpanSampler 🔒 - - - shared - - - -TraceSampler 🔒 - -TraceSampler 🔒 - - - -Tracer->TraceSampler 🔒 - - - shared - - - -Span - -Span - - - -TraceSegment 🔒 - -TraceSegment 🔒 - - - -Span->TraceSegment 🔒 - - - shared - - - -SpanData - -SpanData - - - -Span->SpanData - - - - raw - - - - -TraceSegment 🔒->Collector 🔒 - - - shared - - - -TraceSegment 🔒->SpanSampler 🔒 - - - shared - - - -TraceSegment 🔒->TraceSampler 🔒 - - - shared - - - -TraceSegment 🔒->SpanData - - - - unique - - - - diff --git a/doc/segments.jpg b/doc/segments.jpg deleted file mode 100644 index b893799815d77f62db6fb5fca84b306256d07e70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 629629 zcmeFYcUV(R*Dt*35EKCc0YM=2&_ifJq=w!hNLNS#gx(b_fQmu@=`HjQp(wowVx<@9 zf`uFD&4!}%vr+Hoxxe?k=e@r3{rf$`wfFq?%$hZ8t?8M?(d(nX07iXnJ#B!Dj115P z|A3=8uB)i4cozWB(}MxD001xn3}oa08HkRx@z!sRdq8n>{@_<2hDQC?=2!~h zKbRJjK>8o)@TlL?9n$~_Gyo+Sfr3a=B>cASYmg7+AG`r#vc%ssWXG0Dg8bGJD4-5} zQT!Pn)ZjPuKQQYbd`w41{+mw=_(A>$H?xBoV4(f=cl6IueOx(My zrJ7GJ}y4^|8+Qe0x;16X=I?XP=K6?jDm^m=mo$7%1H&z zLC4e3p8$4mN-Am^S~>_lNYKc5Y$*zIN(w3}N^pdb-8k<4luT62d@}0Pr_G#bpnfdy zh{OU~evR6vtmY%11!SH5Z_z>6&aiWE3JM8}h{6zZ@(PMdNKGx2wvMizzJ(>)>Y}xc zEe4BoadpGH2LuKMU%46*dize~-Fs2dgrww@)U@=BOk!bCaY<=ec?GGizM-+Hxuv!3 z+4C1KySjUN`$oscCnl#}PtVMKm|s|2T3%UQ`|@?`+xP7sKX-PI^*Yw`@9hMHO3jK<0DG!z~|%c7B3Q2UgQU)KCHtF!+IgiQc3 zC-~)9wO^Y3zfF!yG#N5HGd3n4GA&_UkpR9*CYNBdqSuXqYECyy=Qo z=#EPnGL#sYnF!OaVI<5W|`_rfP5R&jx0o0(-bmHao} zU06A=V0EATpq#;`r5y1o7F}RKRJk?Wnzg-G|08g^lg;b^Z#1#PBXRda9b`l?ACilE z9W48Jq~i1uaL(^k)$D=$C1p#FBS7=s;Smt_y;75FtfC@>Dz#M;K=Bcv zA7bRNYvjQ*LLX*kD?AfnWIXI-J-8=HGErE$kP!c+gsrXo2*|kOx=wQhI5w=XI*#?& zm*N{Hj8ARf!Ms*K0;b9i@+>G~R^lg59riWo6`eO<#?)pwPju^T>K*|#*f3l5bB*t> zUE2F=vJ@q$W9weD!ByTjT@^pyq#DgLnw_vtdHn|?#RlDBYUxRlb(5LL{U6UjWl>F4 zCJMD=o9En7bsa}Q8u5166Ml-Fr3M{+S)z962-|R1ADZCTp zVWq;st$Oa%x6 z04)XAa;dhve0|O)cI$iuw2R5?)XCe~*$1%Fyuz4DMCQU%&&0TQvS0&0PsC(`B0uiz zYG`Lm7k-b}^rm=HwYre^v6kcDq``K%Z1bSuu1hV?^Duc#l4?SXb`b9d&5lY<#o zUZYS2Bk}L$PrlGRw0*Fww_P5#ObVMtr?nwOj{xaCmwl7(rAAIHx(*FdnQFbSwcYf| zK5>5dI(vAH_Xvo9TzKcHy4W7};}ywtmDAycD0D{4>1U4 zA`G;YgfoJh}OW3Dco5?ojF3PAcSUouny)UAkyGm3SXSLs66a5c_AU}(V2Fs z?a6GK{Tn(vquc?;oBn01$>uR}ufnzgXPnUZd;J~{gN z)b3y7@{NoXY*Y7M+jai5x+@w?upilAbGbTM#1lFR=KpXvt5Gw)Fnr|*2>*1*nh%sf zM7MMv+N7MdZg$i+R{TUC7U}A^o;EC4S!k?pD7%-&?XRM;UI0yY&c;Gm3frhM&&)7T z^Cf@j{y7@5IYXyv@}*+e6d$1Tuxc;$a70+OCHdPCz|U|+tfhC?)|3h16X@|qOJlvcd261WaX>#NJ1KgVyQVAAP7VvYc>=);hrB-H_~;o1i+=D8?b z7;cEBzvA744`n+9|JRQBiW5Srp9*;vs3cKuCHL46Z^g~EkSH;cbGILSFJ1SKYVfGj zJzFFqyY}|fGTKZ0qn9MkEVK?0w{*dhVs-3uUZ?v}!q`^K*<^GdLYfCeUn<(yOSu|Ky{6}CaKL~WNK({=vN)7>wodUI*6ZVV%X~ zZxyX~_2rGO)=kKBc>&nE^CE-Ltv1AtiQg0Mb(Q^ngc}g;coHQ+9N|kFmFEplPnL%qGkJ!GG;whFJ+j=spZi_IXWQWm@1Bq(WfEr|>~CMi%*ZL@T!~@NQgR6i#Fm4OCH7tnpJ$zlk^k9A=MzsIoW<(@ULYlB&}gc}s=y z7>kFk^KajuGCpa41Z-Dt`?g*A@HIgdg_tW}i|m{qdV9)5UL))qL?w2Q=Dg8ol$7n$ z!?E%7njEGhAlT)wLSN2HD`-snMyVpWO5yi7wi&Jx<=M4cqWtPCBEB#05?f4I@0A)| z+3wHu&SxslfHBs8RXkj&R+22T&dC~3V@Y~*>fEM}SrwJ}(p3n@LDGQW@vTJlCgXo!E%p_);UPurqPhOE$z9iiN}qa9 zw_a>+ndR5pn_N^ANQ~GCuH5!1Z%r&=E5S>?stX_RWsRWuiujRvd8;(Zv#Vt%?9mah z{-I(hHgFLg{r>8$1dZ?fJVO=Fsa`eWq+9)+lb2QoT6&IvZWJVo0qfRO!R5OX&qdOE zqR}Z+>Dwb5E$E28i^4cmzPDFL?0P=nx*RXXo1J^$XPYo|z2GoL{IV}g#FPD#!bb6# zEJ4!Ft+D)GXLtl!xM_ZLmd)GxX(eja=95`ohLrGpT5Ju;PpIUPQ0I9@^K0eSg)ueI#cD_Q+;?8^Agv~&oezy54A{xF zcD8K^X1S+A*ffConZ~gV(TJ%&nfWiMcQbvx&>MbB$i8h0S7iUDC}GFJH5*$qf569~Q^g5xkdn5u6Oj==XbyHqSUz3G6$Bb)_z_Y2MGF`y_R+ z@AIX+vvz)qzUl{W?tA=`eb}W7M?fR-rfk^vitC$dK@E3~fJX{Hs}T#FCm!1HCtbxR z7Qa3ML_J;EE9(*$H{E_zGM4z|o-}JP7~bS4AyN^9QL9255BFhWeyrw}+blW!k=7@}$U=(TrfRj^Yd->2~+qE=F7)DW_py)zP=V zQdG?u{=PI^8b3Y*^e`D50V;34vK#?Imv%nRCRFG^Q#e(M7%Vjx`hVxp;%E-8-PGKN zT_4FF*<|;J^0Aa1+BGkTd=)$bayNG%DO~1D=?zYOQFq`+!0_`!&3)19nI`+qK0RTP z`kX0T7TdA*QI#siN!pr5{FiSxsx9+G>Q)H(x+E(OzvG#+SniNeb$_172ve?^lMPp9 zrPxIyMmK7Rda-_w9$g>!Tp@4>Z3K7OgL3HV+ld@9_+Wos-P`!sTe7qiDpB*Sp?u0k zZ1~gM6jV!9w+BU`_s|a)w6XBMH?hr$iMjHZ53gH59|>vO)O;}c7 zrp;A;d*kD&-5phv&t6nVVwJp_&-r`je<8GAcv)xq=Mi8deDK|TnZ!Ar`r~rEL1PWx*ys)^iYj{ zn-)I!>~_ZESB{kiL7s5^)dpL-fAh@LUJ^JnW=oDA0hD<^o>pv+Zc+voe%=r>Xr-A+ z{*{@&i9eV==IFUySNp7gBBJnBO0MVNDP|n{qC|NHLhTfDVgJv%haxiE-_d zC(J%}2de^yHWeSO(2tr4!q)RR&$!mrSaUrme|xxN-Cu#PX-P{_HVLOo>+{oQ>?_Gj zwY)o8L;S+l{bCKUn~5G{cWvjvI1*=q39z;<2%MwhlqYRs9fK+G_Q;{XeiN_Q^p1k zs&3v)=-q+z5^d&NGv^=$Z>baSYRqXXviciLG&e*HmNkebmcV>{r;*}Z#+@Rb1 z;N8>8+j@Eg$Q&YW6j~es;>TNbix0^xzj9&Zq9`l2ii1_KZ|O^1-1{0f>yldZ_DZ_* zkQ*z_^zVfDx(EB;(!owxeY`0Ww;(-iq&T$wwNo?mR9!Ca{4rgWrt<9ThV_SZ@_e@E zJU77}JbI83HmnD-HTjig@=}Vu{K61O4esko_N2Ra!A@DP^K0|xNnsEUWAgqxPl0Fs zxaXEH#``|nFp4nqIRf;)e(4&V-gjf0|9zIW#IYFHh9rIDP293Di}!Qb=6&2km^mED z3lZnmC`=PBbNW_sVa)dkSld{js7<^TKPFVU#`I1zz-vKYzwafal|TD*_Wc|cSmnF- z#r?FA{X38CZtlfDdUPMQ1D%{3*gF%rQZt|Qmwi`M>|V0R$G^UBi0OEHAP0$yXZ>=8 zwP*SU-`7;}d;^E-T0xh>#QjeX!(oO`n#E<~)x_Xp%SlVF_eD#cg9}BTMRNC^53m)Q z6wX+(q2GLZ_7U2zK$DrLc2J^z8#Ya|raU1??|tS*co<%<$KdL{A{op9%pj~eIy~pH zOu|j9F#l&c*NqnNcZ<5PS~ru zyaAh?j^FDGv9_LdL+Q>ePN{yvy?(wt8b4LfNv>5pZ7h%bdaT@DXrf`EZxznmpG^GtqwH z(gn}3?pClXMT+G5?EDq>sX(VbY>Xk$W*E^*dVjrh>&X!?tC3;^o>EnRyegXRT)l@B zA0s_DKDPSotynxB5drP~>*RWK5X>64P)!@j$%?+LxJh)K0TLbU|Cq zpM$_U{J{P&m9GUizfpG+K#Md)4iL6ai%%&yItG8FWG;4%4;^{Rimq|dZ5GU~3TuPh z-d`1LZDn#1(-;l5@-5opsPOfQ&t$Wb7Q)N+0+`X_UXp3Az_osLA%|wB7A`J^>^;j) zx3HZb2{-xo-2z_+K)c-5(fg}1gY6l+4}OmBd_A>u<@ybspQGFU41pF&EKS)B1z7C_ z?&VK>!m)cUq|8r041CKx1vVXCKUoF{jS?y5(KLzvm7@KT>16TC<}W!2^06-wiOC7^ z4UxNH-`5?Ds0QwGe3U5G%JR4;Aa-Ag;(Yv*akh)6LOfi&KUgJM4@~nsALA)tb@|GF zgC^xwUyIU-Vsh0>hVfn5302zMX`{T+`lMSe-DS4+L>joL%Esq6D&ukIrY_g=&2!Bs zTQ$6i_I7ef$3IU!k;5Juzco|PGWu7}sonDhx4kv2r8PI`o>W>L0d549x=P*m`LOtY zM2-rA0c#{%Wmez%th~3%&YGFN6aFQ*>qYz7;lA9Wb=%~RxomOOvotMEiN;hjj7fI& z5$_0FT9-#@1gy=v8`+l%WsPRub$%+)Tj~p21dmaVBTc~W!~=(oj1t6zOp6kY3kiVz z2#O`#{zE##%#bSI48?m!r6OR4AR4}5HVVG;M{g5E@~PhGixj3lkZ+5kl#Hab6gU*F`Z{4eaDlweI9I&43iQ*XPAD%Ps{*|!XC!Up ztBG^N>xTN{EJBSfF`*t9B`j3+0`K{&$g5tyUbsLf-m6}o-T}y~D$rldksv-!mV)yB zA_??Rfm(xCeVRW0I9`M#LQ+}+ya)}3LqQ(?SQn(Zmi8YG;Fk*YkEmC!T#>vYE9v9! zDkY<&q$DK`mx9A3KnjU~5br>zs}kM;{C{)M!UbUb@xFn0A8+1cj!w=#L4hhzu>RkI zdHEU{{fqH`YXdK@V`+a;2Lz&m!NUKO#R4otd~s6dxB#CZe+&*4jPnlU|GPLA^RKeL zLH?e<6u@GnaGp3XkSqYSxXiz*I=%t@7xl5iu6QrsUnM}x{)-C4|04Qtg+Hzu)DWrV zg9$pWL{Ccvddvxl^}*n=$X`&&Sw7fy@Rg) zNwvg#;Vc53jx8r6uLM_Al2L-oD=Nv$%l}=@3g;gH_LpN;ziyy^36IqD$2oy_*p@y% zo+{9PT~HtQv)?Ax#Rq`dA%A+V1NiLy%yBPNfd)7Q_i5NF0Z&w^R zp1?N!O@{w(OspuQfRL5LDoMz~rLkZWArvGO6{Hm|6;M_B&3TbGxRMj)l7p;DmyQpZE) zw<=QqRm)#_{}^6>lY?XS82)PtxWN0L@E;5O#{&Pcz<(_89}E1)0{{QBz`qX>IB#&L za|Jvi9DN{vsHdrU$<*9LTh9;$x@R3bsd-|&0w_U;KQHeH)D?fEq(am?#~&;K7&PGZ5s0_f+&3sR|JeEkDKd>O>@ zR|0*HaR!K4zzrMdX+~BBVsU>^KoGw^PIvx|H;%FEFAVw(g4o~ETocso*k_a1^&i;z z9~k52?*-BzKpFw8mp90t-1;}h9^>oB*vm5rlkmR0Xl#lU<8-~ zynr(h1mFQrAP|rMV{b4e05AvhHU1CfIe(Qm1xq=DrSJd-ETIMX0A7I8ukyfg8-O%m z__u8XTx8+DlE_YIfR2FgkB+tk!8@5`060iEI@&8ZIyxu>UF+Tgz!UF(m-opB0LAZM zdcwcc1oA-l);j>u^y1%X&glTqd=CKFr+uCLoqp8=I^F@~E}(<#*D?S&X#={fz5*Qr z?S9)0%sb8pilzX-610`!AOK_%0YJzVZ3osV*Z7E3_}db0iP&Ih_-f(~M!=i9L;@|I;DvIRCd( z+|eJ$GDZr}rIKtr@9Dvrj4o)TzJR89pa%k}rstI6YLxdYP3m5bi&lhiE{8VPSC*!L4vec z1{OhoG{OV1ZfaO>D#Gdpm`7D2gd|fbQKy-iO5phL58;7$a*>Q6jT7a%cr~?rl9>5Q zv{f`ZMGehcPD9z+)nsHEPRE{>I#yS%!7q+$Xfrc1UXb z%MkJg#u5)X#!-~TX=rbZ{*3q_y*ag7IvQ(T9mHtKuxJzOk<)NuwV3rw$0s3jGFE+Z zjM2Fg>n9|wmo8m&&K$O}kyNPwsfrwG%TBJM#h0Q>S12M{yrziKkjyW1Iw7Kt9erT< z0v_9)R3cE4j&dMf6i2P0l3i{WKuz6Jt*fdz1jo!Qwal2D1kmGF(He!agEWQQOit#E zqfdZ*0YtJXd!m7uX0(=LEb*a0RAN`6Jic&*cA!$A5|RZ=m2uP5qvtMe(7Nl{SAaL4 zw_f`KoqNIJVKc?n66|$`y-N!}tPqEL)%bx+S*~`{Ocg$s8u=cfdfrj2N$?od{nf{&b2+ihRjmt@K28sRxma)ymJ2gJ1s)!sssq_KjC#$K|5y4ChMG8e1Z4Kh#kdx7U7jFuS> zTU3nMDdHz{A_>Z|E%J*)bA!`MUx=fM8(+UGDaQv?ze#p)UhrR=`J~iwsVwW$4IWji z#=!-QUBGCXX|wgbO`)0jCc;SDBT}r4E3ztIED@n4Vp(c&Lce5&rOGeJyg;&!Z}GG- zg#WC&KJruMnn0~Bl$SJ~WS&o@39z^sLW-+dBbk_A>qV3|K#LR$tHm!fTB2ypl^vk> zESv>KW$)>i$7bBtyU#JqYs-&l#0oMb%4>LN=a0f`x#h5~qedCHNZ+dNfRgdQys!W8 z47yNbFZs5GyS8UNx2wNp$=bv-gizP35S_1ai&hu<0Q+%JQZAsx`SQ9W}uSuo@07c&g~7v_0% zV=NNzQVO}PHtn(NaSmP`lF?4rJl}Up3fbs5zt#64-(TY%Yg=1pKbJ75u_~&kyDHQ0NJDYbr!tecnwHuCo1ez^=Cs=> z+67J?Vt&j9e(9(jyzfxx=w;Doc}G_}DS<5Ke*Vdl7IcOlr(04nl_(ZHY85pwbCE&N zT%-{F;<=7#J*(kLi<{vf+9q4E+K9X^zlEOGd|XryTO1_HnQAIh=T0V@R$$fS5`lCh zWQ*LY?$ZVDvBV>7ldG6e%sZY`+bo(PKra0GpZPw+Go9}5Zo+ZE`%NZP+m~sA*?QmBBVhYL(c7x7G2JE9@4NKK9l!aEDVE#Sc8g;Vh-)($tF`4_ZA%Y5N{05lm8TRQ5;qu@ zIp_O(1||&`-^ixQzOj4r06D$v+n>-_`Lf^sqK&tQnG|!&ZqRqqb>zWaslpGz*WWcs zwl-2Rjt&Mg&5WjbAZuTeQO}_H&$C^G!2l+?hqO^8qCnAU{0cCky+WKRpT#GKw> zIigIr{Fbvsxh*wkX0mg0LUzfhcu0zi1ItL&!lHjwiDPL48as!}bcWI6$YY{km1#vK zN?354rHCY}N3o_PxH_2VEJ&3f=*@LHJx6kiGP>b8!k-z==}&0XdvR0Sw5ea#V!6fZ z-^Mgr3@NN;dQqKB$7PnQ=fIhOwsFn7k(WK7a6x$X`4aLmPfc4^r}Ogjhpy@An4zyS zfiZ1KYo34ksGx=o+5ppZB`WaBX?5gs$9-wx(L2 z#JGhiDF!Pap4)A6V-1UshmjkyAy+#}xdzsA{R3)r6l4_=IaxUug&IzLNacz|Y4(nw zOCzvk)f%ttIJB+1YB3N$T{XQ>s{#u1%oveK$&Qh!E zmK8MeL=-EDQwyzCLL7Zqa>Cc8aiBOUJP_^8QV<)MI96<_DCk5SfA3(HCZV1zDB>p{ z9xJHsWh#)x*;WaGTH%5)8diE%F3AqTv+;*Hp#5%K;xO~b*DtU!@0WHHA5l*k!r5sV zKqUm6OIYfYAxVMd&f?BYLbsUAq#3P}^{ZS_W4Xah^GCp?dq$7GsFdY|IzF9SpX_~l zU$HPK`xCsG?aK7z&)FdEF77l}8sy`PF+*;=&F--;S@irLF`j1S14u74CYZZ0a%ILf&%*NqpYSWny1<@# zkqbH}Z6;L(jy6!&Uamp&m%@B0W%@P%SqCvmLZQDtl_4|UjlAx%B%1soV|dbS6i$tC zLWA)MU7Y9y9$`~rn8X@rna)a!83H{gjqSfW_c9Kq6h2{qT2Yi?g!S1YQP3AQTG&N% zt7MnZ9PhmQ2fGL8`8Iy?Nzvi)>so_XYoEg;D$84SB^$o6GjGU z3#h$AYz0MQ>7ws?lrs<*^94OJ)gqHQMe{DpYLizj?h7$FwNNC|H8o<6I;>HsHOvqW8O z8xM5JDnFY=VJ}|uf=^m29BY30di=#j&?#$p`^>Vke=SL}Zya{H&q6TNClcS(cbFua>aj{oTr$G>dDK#Sl^b(jp^Jjf)zrmXiMOSe|m~w^XyH8Yc!8 zoY0K*HSHt8^8KKQkt7FXB8v>8nO4MQatK}6>j`Mmz6#`~$-}1T(e!^GUNq?(-oCi3>@#d-HBpt)O;3B*f$xNtx+r#ng1N0`>$K+>uIu*=V!D4 z8UPcDnHp1=iCb|S#f_5RAs3;&$7C!wqQPn!B?J?t3S50wF7UblJ?Ug;9$S|I#b;XC z-qhY+|8_4+71N{63fyWC)?i`^&@yBSy``8zAhA9zz(KeuDELxLX%oo@DqwNX65=Q= z6?OEwi!X1C$U0`#gbCb?$=iq@+MbG=6w_(1<}!Wg%UBowL^D!P1SSXzI^R4UFTHyj z^izNKK2xs3S)@&b9saFg{FQlyHBMR!tEK{vD|}g0D2!r8qx&L>m0BG_^&)Q!pAzk@@6-6hbbt=F|XOO}mhtSti9eHi;g= zFCasUA%DRKxHqU-rRbGEp$7QWsbJ+$O2;JY0m(7_zv>UH)F#<8{zVvd(tr@%7f1**(;jwa>V_zDW?sA+QjVTmCW61uIPaeB zv+`Er{I|TgPR+d6dGuw<1JQx?#z~0zp0VrIt}NsRktjk5P{=htom&=pfQrexO$NS_jUkj3Sc+tz z`bvgaEDfpLyp@4L_a`XU_BL(p+cF&aU5b`0GG-_y=?{8xOlo}L(Q@n@cRlKDXBXNPxO$qiKs{k1yo-r3(uU9p zyVkhLwOkNVf?8mJ@!1yC+fu4SV315_+tyG(rqXaw4I<5f8Of|#YM^YR)=o5D!oQ?W zrPLeQ+2yb*E*^Wk@3qTySpTy_IZPyG9Px8j`}&#Hxr^_wZ-z<{4;U;TE!@)$*6Xe* z9GVwPyL0*GwcU_is_j#$LHAKL=;Wa|*wVU&X&uR+#LzscDk76j1XFQ`(W2DNEHgzs zYD}kURo65IUH+|*4|QiO_PJ>Ey^AI8%8bsHo)IjL^*J@YF))GK>L*Zc1oBmjvGduw zA4vCTwO#In&rJaNT}3ui`oh|3Y?P-&$?sBfMyaXwm+1npIz;H$S#`6s$%TZ@r8!1r zL{*FH(;>KF5hd;-=A+}_|BxkWjGWk?-JBYm-gvC|)pri1RcTu40Cmy~r>qxiwRHz{ zsYHtONiX~wBq)@fZMm4K{a1BkSd*#TkiJ7P!y{PhjVHOuUlmqrcRT04ZCtO88B;MC z%(GBQzgYNFYB-O|@6CLeUi$mF_PmpmHy%sjPg#7}*zfpW|M8sBHJahEv{=lR>*Vsv z^&cy<@I~&zPvQ#(R;&Iij2|5uQuQby{^Qw?Qjbc%ou#NJP{NHA>W&NKylqlZq2>{p?PSL9x9SWg7GrW5rn7 z<$LAb`OxrzLKG*hS%n~>oC7e9?NibA^SeS1;WNa*$fNBy>*8(ozeacIQ@!=L<_+@qXP6L_LyZx~9*BUqSPn1aW#xCL?{wHaPwADk`)=akz#H8)QgyV7^47;fyRe)s#7>u``x zw13#L=324kP(Rmc!Xq>4Q@LC8;ZtJv&ns=$kAUi%9xI1-YmZfEo(B#u`&8fm@ZKl# z>xIhQyoGPO_mSgOsb-c>iX%sRYtd+z7qzt7;ZOo3kX&EJyhOrfk@NKijV{e8WKxin zDH*eyHa@FBAe_3yU3?8*7c(kH6c3M%4abPo-i@V(g&G=RIOQtEA?Iu)czL;CngVrd zbttqgGhY%_GJ{A0yBnuDFX&l@>^_Tc_5^v_|PUvsJt5YEPTklJ3w%i4~6t|mSr~& zA97&je0vLmdg0R8gH{l5;3JZ~3fVO_cNp+`{&qj{N5JmzUx6DT4jbYzs{994*My0? zdG{=9YL=_lRaI|D-VFK{u&cB5scX0JlJl19*Z8sA?{iZRuSzXSVGmS4bd*XhJ}8L4 z^TVWd@#a|XgW4^R(fw-+IG3c``lLdUfm+&vF{qFbH}bM|Ly)<4zAXHS2B8#w2Y$J) zItG@>%a<-110~lM6Z1>VD)r>_kyASn#SaZnnnRCR*-*S<#HU>hf+Jp;NgFxzlM71M zBxxitFup*JR%MtrIGKpvk!Di28y%Bjk)d>ufqx5SG?2;la`%jY#z7H*_aGVOcPi{n z*KYM_Q?Hia{_#P$~Dz!E%uWal=Ecc^=&}OeIl0u2lUgn9>xOf-a zlMzqiVOQA2{hJ-#xnH4!?u+JW4iP1E%te}Tf&jG|Rx%AG&Fx`R>~0FAjWC-Dy$J82 z4eVp04u_V++AsxcaXN^JCoa9(XuB<|;XE&M8ZmOeZ?uaXMhLG6N8J|^$X_(i$!oQ=AM1EaLPDSa>ZSY3T~g zSth1VjLAb~ge~-mQC08wGz8I+*1eJX6`?$mZ;{om$oaLKMh6V4*4IydRkRHk>pr}H zUU_5q^=$U)>%TTa^Ukc~a)TYtVqsISdoqmw2K|d&_5-S~KUN*NJu|&;p5NU$i1?~t z|7qT*F@7rVY?;%uuaLX;bx6++a4N2M5y2S=_SWQ8?cd(@ zJgoVtyn6(|K4Mpthxb~_i>mafN-z5! zW=>!mU@BovwO(NnkBSPawS`Gq_cFI~1U9@H!!e7%618z;kT@rc+Eg^O$%yi z2$cE6pxP^{BFIqO@WA2Q8&WEJSCTwfSsBn`cf+Yz3e>dpd`VOuwW%qb03+K7!kR^& z()&9DZkYK*g)^mhKgvu_r9%I6*a8jpi_&fjkXtrq*_PI-70n_zaztF zlfrtnfviHVfI^g657Lchc}QKLcdjr$dqg84LiZNb!+8Ub=o^X6j&!co;*_-13+|P} zXY{4M&>)Zy;{?%2H-7ffZvN3Y1YK%*oPZ{Uv^b?ziW#C}BFc%dT7&ax6gK3G zAsvLncfU+J+>HMs7pEUv;F1(wA^_81kxL+V*0#!gsmV>J^}LZ|?4f}8xE92=r$PiD zlxtaT%d%ej`N{~nUagO6(uK(|-Tik5JULbNm14~UVjayJ#i2cVPuq3|n~V>Q#<)#} zb6c0wFQGD5xjt3;`R`2dq#c$?AP)Gy?gpOCdF*p7rZkXc;Kf+kWofHqtw!>tG(IMV zD0+M{w5) z!hK2M1L~*IsAQqOjcVJf3YMx{3!}nvPt!shT^e(l=mib*MVU!C!@}E`-VUD$RoUxR zMvW|nB!Q%IX47b9<0y?=Hc8EbXKk5Wu_ z1LT5w_J54jMhjbToAh3~lDB#)tFz>5gOJ@|8@68_ZG9R=4qI}USSwk)2pufAJil;o z72J}@&W5}@xK=haJGJw}Js~E#a0x=*T?nMD()v;Ro}e$ZF~SRQJjI<6cX>zLU_ zh^9)MDTdMokYZPbMiQcm^&uYv@zdSb^%XT7TW5o|y@M)Bmthm!cZCDn4EmI?pOkZM z_%U64@n%5j+ed!|WACkN$?ZSnI9=)`6(2|*!6Be4YjYKKp(&gj?Se5wE5$bYGANwTW(C5QPV=f!-j zW{4f3*zdcN&A1JdLA&2~Iftqbk}aJkKl4Tuvn2S<><_iUWkLJ;`#h5mX4(n*{O)Gx zS5zY|ewOBj6AX>5HY6VVeOLSx55DW`&c{|_D|ox5M+JFC>Vo%K+ngY}q*}nl(Y9%N zEKwBJQ}VD4tHBIhW4ieBMnaLaJ>;TbW!>D}%;}ESVg}ucv{9HR385!gyvinl2-ht{ z+mx2F84>#G=(Htd1yVh_;q~!GMq02~#cnCjz&O|77TbW+1V2oqO@E392ASI$n!Pap zcCr+ieeLGe4^n5jTQX+eEDv>?ZN!%uoBMswIa5RYuvK~H=9LHi5yC!AyV-9-RScKX zd{lE=IfhSbW!EGdCqGzuTRkL^WuWN9-dkNOj4QjrvG{HDyMrrD$Va)<_H`e}VUw&W zjBS4!&cT6xzVW>|z%4l%>5*l)r%I^OFZ{c7c5W<9-gX47^0I=9N%=fU^YIq*0% z$Apda1lrA-P>-x;N)nkNS>wFYb+s04Ca_vU{wo=hu6osMnAV>9rh($o(%vz<+za>ihj`!~&&DZTe8RlGK=l+!HNy0F;fYT;!)(=XnrgzuhwbYfizc`&z~(=mM7 zz%^+yEwJf(<78<~q6Jp?Z(Du-tDho9ZtqLY4PK&bB9l-!$z*hBqxlxaAdd~Ui`Kj^4@#aWC>q$W4P$vghzVV8#(8?vG{;k=j_sl<1SWK z^^KFwiiyI^trj+RqWEs!r;?7Gp6#J?Qy1g>0;bBBXXjh?;K`Epkz=ab%hT)WBj4xg zytG|;bng0f59M@J2iXm*!0y?->nSbou;86(6oS7T!dH{L3!5|kz96r^s8bn-29wr5O$nqB_x8Lv2y=oTJ z?>4w(Fo5h(7Jpmh=Gb!L5YU12Xt ze4SS1!~%;d?`t3k6eMe*m^`xYRO9r;uta_idztZR-&NfKSvPkZaIav}Ut`>;!+j&9 zeRX*5@l7tf^Pg6Ie|BDyl&T+oV7Mi|sLe6OHvOu`5SPwv>CZ2ugns6zG9{&e`p^xP z8))~4i|O|fAJRYnNUvrpcgK3xuiMV`dhBE6`aI0r1rHVZFFF348+8jW7l)QZ>>r59 z)r|Dk-*4yYb9`WPEuyQ5zQOR@kg>*ROvm!Ip({?^qE?uRP^;?RFK?zs=H6`uzs`;_ zC@~Gs7)YwJ4Px`#+?*F_m~8oy-7E#`PpQ;RS3e{8MuuE=Rgts9;ksny`1d@qtSr44 z`^-daIn;R!NvhZI5}+fD#g#qx`pV56Jm%^hw39YvNB!1tHtfs$?z>HquDot&Dj5qg zeL_X7U`U&3lx997EWDzU-DLo6#wb<>WpS*e&;?hk0y}eE>hQbNL`J>*x@s%A*k{vB zC}1E-gS8sb$S=T`q*x?UqE^dl9Px}G%l=m>RF|osa#^*m?BQPqBXx0$O4pBUTT8mc?=-pU7Vkeq7GtoR=KvUs(@hkv=+A}hvyqG!_S z46~Jqm?^1RU%-Ib-NmrYvgfRpkv@I-;uAr$Mq8xYMm6$W{j;0*mE68x%XaL~T9FCt zawaajq8+?_P!1B2MxODuXrxx7Fh@p}fVM61O_Tlgb?^s;(4p5}XEE2a*PHLp%BDHy z5Wc5A{3_;wL_KSncw*cv)9t|B(=d{&P3)i6UoRWGT}ESEWSl+`Jn`2H7mxIkkXc;U zw;A6b=cgXMYriEVfrf6LQOxyX{N`QMWD`WvXe*7|k5v%mt0@ z>v6-Gvb=zBb9o3dpP$y3y#MtE)3GE$>Y&CXjOLKX|lD*gNyN8Cy^aP!9J6I#CfY^N2ATW)9-J_?I5e% zi_}vKs%r0OHHc(*1Xj7NkShB12S}n+c(v%E2ZB(cSG9?P3`y@qAW{5+w&u0q{?I^{ z7}6&2M$}gNoURKl%1pjby;iOoEkKB@$`+wwfvFjoBiuB($YYm^+bUD@1>J|TAOm!1 z&L6%(1$E0S`OO1UhB|p~C8N9n&{+d{*%s>za)P3<&5;j@+Dc;B=q|2g-KX}V!Qw!4Ii zu=Qp1^vB{e2CnF3{tyjHGj~Y}JGZqk?``gV3xUqZW?;%4>eh__5hMTV4?Y;a9?sSD zXm(=WMo2g!UEr!W1<%Q+3{HfcEW4!MH>IcyHEj>SYG!o-Z5HjDq?CljIw?CbXJezS zz8VLBkU>C8rOA_OJBM&WE4_KgLmtQV0!TC4MP}nxIaVfHx>MSa~hZ z8mif-CpQ6Ri6a1PZb2m^cH?>$k&-?lT^$&MoXox?VvNoftuscTAm+BmW0(2_M2GM` zgx(JZL(*E&N?scL7?K+UW5@Uz8Pl`tc- zth2U}mA~G94RaoA<)?4#k*~X^4OZ71R(<{-SKH%hxAVo(3sQ>dJRl5GPa2<*b3=1* zh`%XLJ&uOw!wIo@XGVx_tAWoj2#h(;k$2SDkEY1R;;o@%_!hJ-5*=LksA*C&%u{Is&f{5;uQN57Qa5R=+7E?+BkZt5& zIly(xxJ`u_fNF9)iocLW#oEYml2qKeCIISrRx|wBQ)oDwqGR)tYea$7LXC50pKg|B zrWei?iE3zCFfTDr)@iyoUkLj%x!=AybEyAc$lH*p;N@|7Z&t7%ffq$?9pkC3gF}o3 zYi3<-yprL}hO42bz}fU={ zj3z%C7Dw-ndT99mr$FSbdwFum+9$NOA}qH~AucdRoLU~2ss>iTNm#L`L-=MyMR0Pw z#|)?qA4 zDFCt{z+{yoj4z3pa%_+DNGS_tq+b$FW?QP4&6u0$Q4wGps*JJAG zzJeE2Tm_~p>X4vw6R;DV^j`B2O_P5OXPOXvakA@>Ahff_vQOIPGtN+ zo8?<1ncb9h-X6MAs##pd1bR}lxJ1ZU7KJC4Z_@GvkdSRGuCPAclf=Cw&7FtiTmZpU zR8Q9zq4nIQ2w0XmZ;nr$x#cCkz-cAA)iguY{RWW1pNC>?09AAqD;HTRD7yPbU}oSP zT!Y<+Ei(U<8u?Rp_TkxvnLBMc8TeLY9p<#rD?WS7%jIs^uBOVVl*nVrcLLew7PGnG@Ik9y9-1wn&cwxA^`=AcD@alwI znV6teqDUFxn1~+WwQu{KGNL;FL`wE^r(#+ncX1i`_9L%)>sF7vA(OazZCv=c1bDEs!Hw&etiiEbBy?q3QD$0UMRi3T z+$z&KNbaf^g#Hc{M_Rw^B&bYn%AC2FyU#ap{%`mEq&;ACcD%?PsrD z{uz01w}vOG8NzD4fKf|mTl`elFx##1=76S5AWS0wmZFdZQ5P<0DS1AclTUufVu7Lx z0g^mlz!U9a5~>o|v&NfpSG)3&*65vm88F?wR5NA6szRE5&em6&bnW7Mqr%ASqu21= z!KKc`fa{k4WsJn@T5C<|0^lSz{1P~kr2>F8o^(qEwX}=#JAkxpmoWpSa75l6;1;-{O9BopOoEF@=&s-bMXpIz^SJRr>uF5Grd3h zcI*6=s5sbP?{XP~-Vr}0nNWQjd|=ox{P4!%&jmdLS{&XyIG)P{PNniA&R8gw^F6;{ zl|-OM^>Vp22bWE$#3c5|*diPR>Iax4DX}amIc-}JcfPt`|$0S>>b7u(f zutoAjl|_R|*;+z*V>$w%uyiX_zGn-#34IJFkT;{8?>VfL5hV&a3OMw;Qnp%&>h4y1RueU}L{up&&s>dAb_a^%Rp6LZ~-5B2MsZUBK;8+Y=+dPsFchj)qmAR7ae3D5X>*3!#m@4lEJnN#lhw5ov4%V;#^_!KYzmR(b*< zFO-slS70U8?j-UNw?dStnNoZvBnGBhitKB~vf>GZk77rXh_4VPl2N1ll8?+qa_syn zS8In=5ShHoCy8o0Al68m!D{E9zxxOOx_(`4TMVv=hqR>B;ma#+2wX&48_4XS4mT$b zcM6o`Numg3QsmsvFEpE)%Gm9$c2#ABU)V6>>&#JS15~Th&6|9Y|9!HSmEG*FHWc5Z z(7~EYg|ss1s3BGDQSgSXdhlzTfzwiODgr5j?e~(f@emd=cH*(U1Ugq=q?Y4UO~|2F zix_h$ab6>*cDK8Jgcncl5=j9f3f?NuLTWTq#n6!dVyF1Bjq%Y~W*Qj8n^zzZye63> zG;8&iN9Po;demrPl1>NSTPcZ|q?rmHw&V+Jq(I1&NuU*XGy{wlmL~C1Bwv+gc*a7K zERZrY$jp57?w@cXxZ?Pc`tQYuFLTE+fh&f!_x#@tY&MLAP8GMPN;k&zaIRY9kW$p| zXJT!`N6C*Zvuipz47aV)w|2vE`OsJ=F~(X_f#>{wNdRa z?5;*S9UiP)T(^Jh4?87r&gQxgR)I3aD=$niseHunjMKZBX?0AVF%^fk>>)gnWKYvg zTxbp=DSXmd1e`LshLY2gF78g9L{O~;s#ed?f1mbu`DQ`2vP$IvReLnCf~^+Hki5fz zA5KzTwa_*SNBOdRC~C#q>J)qrfs({ftGv{>4h&NvpxD(Q5I=r4JB7yLbx|54DhqS~ zGOa0-nRYi*nA*veIAp$*iU1MZ3(Ny&k^%yDJ3BT~z-7}JieQ%n5&?SrLR^Hwz3n#x zTe2fRK4lS0bF_gKrC&ISffeDd`BPG*>}F^SrL{Ceh)^N-YG%#bnA_$$250#QHNW=T ze$WVcxVUY9}yw1)x7tSf=ybvlN5HoNjMGq775T208qxH|o<~>AbZCBe$Rj4$1QLf~Bfpd+ATaq# zG`2&k98nTVO3M( z8}@Pa1DU>Q@-uz?D~qXnpRN0I#v(9*ET!e)YAMFrZ9fg`p}wV|+D5TQ*`pI3L@E+o zdr~U@3DCiPzR1wO;*bB2uz!``LiQeud2{I>z4DB-Hdz z9~!up*VXQQ_BWDc-VB5mwr@fE*M3Xs!U`n|VQgkSJTM5<(OP_aQva5nOD8idyeOhX z`(2NruFkK7<(kuFvRNtwy>H@)0|nddK0^@<+`4~YD$7#pDjeDl?l1oUh%TS7oU$- z7|rI)=R-w`8MBzo8}xRl=WbFqriA z=}51;7Y8m%MF1i7Z4L_|-PHMm(HF0WBDY7uM~5#8;q0|{+qT122iLVf2F?adFI-TB zEiXnGd~&$vJay*5PP4vNYLM62jpj(VO@^Dm&!M#!_xx+WX@))heg$0MdQJ0#CM@Ej zKd33tp1KLU{p|Pn1-sY7oG&RgHtHdP8W-*jX-x~-ZY`K^_IuqY*64-3uxlR9lF?2x z9X#nzSXh7B%*b<^Lf*UVLVH{L*5%eJGQjPwek?d7bzC8?Jc;l!?zzZCkW0m=PA+(< z>Wo81cG~4O>Gt~2&{o|mV&nnYu-P6$u6Xb)WO~LQwrm?%dH6^7hr;qGH>TdE&P6o& z?d}Wct03{)q)Hm=`9pR@=fZ~i;5*Bd$yxGUXeEtOxia^zu&p+>MPOq{S;+v;u$MF8vX+{6z%8F>y|7dZg^1fl={?tmx=I7u3Yp|W4_E(ZY z_j4*;+Oo&mJ7tahGd{nMD+-YT>9pPh?tIujV`sa*_P{Ib-cGnja+RKHF>dUF>&2nf zD(ct=d~xOKUWDFv?fPf5O`WG*Aze!0Vrfr(pgZRdH$EX}-fYS~EIv2?(Za^1vGY&E zQLv%Nz|8pG!PTrPN{C*LYthX)v!b2mhV0c(39p;Ry0)j5fBRb`XPt#Fe{cWvD(tUo z>)h=ZIU&SR--rbN3zwIVAfbc!F1yW@-KngVJ@xI6f3NBLWd!NUXmdgaBB1XNepa+s zREq92)?+(952(z}whxw$&NFLoF4>Y@G|Xo#PA6yDY7|_qE7#X_gvPjZriF*zxqG>) z;IhAZvUv9N+-1^7zobr8FH=N2)nH0PoB5hhkA!8B+h>h!$La!`EAsJ8^Uvnj!4OK0 zQvYxbZC;t_Yj-mAC<)TQ*OtT~Qfk>%BwIVQ1n=x@*qKiUTI7rZZE~hfqs9$F9Q8&` zOPi|3djG68ZN5JpItXYaA@C9?s;>O(ecD2i(!)Wz`OB z4$&}h(SA1CetmI30zey(-c;UjVC~tpwQSt_Z`dkFh+x>UcMlH_xJn?3;eoY%(2M%?y}by_Dd>g_dc?ISVFr%Cdaj< zDD5`G_J;JV2>niA=;ta~2Q{@TY3)V6J3%43u0eBmR|nrezG&?wUO!Y%>uQrgUUXQi zzen(Qt%3zTUv(KSQl~Br_oiXFTCHpU2MG{ zX?yQ~TvY-~%MGEQIgS3{7@T`)9<4N%tIduEFejVGM@s`O^VlrWclbDCW%HPs%o|G! zbdB^zhe|Jg2(KTGJ~`Fo{?arR_&Nrf=z=-&kDc@#ekyMweAP=IUv(lVpFQiRUYb~b z`}|5+(D$0rDRtX3ncJ^a@Q4nQ7RqyElLWnRB~y6{**C_E$Yl=DHM5a7R7%%-q~~pP zkL!g<;`p-20hL)tvwa*!%pp^gi}keBw5hgbtV^xRNMibjCh>j2rbDYA(wn#RI0lBf zA0_5aTrP^-ow{4t4%sZuuYYd!T4~Wb?R(!kWJ*8$z)#}I*mK~@&_LS|?9)40=+MF& z5;nFmL!!E6x7#{3X#U2JKdSNh91zj8NvYfca#Cf=LV_S}qIjg{qHJuixcb4TwVt__ zbYzSqBb2OY4SKHtNOi(zugxG^-6>eCDxoxKXwaG(6@RP}Sct!wh)jKO0=fLJ;81O- zi1Zw*0+?RB9eMLm>PLz4Z+pY~^S8i{3s%APeK_$au`1=T;2H8;@0qNerzGGJzzZ*< zjh+OZ!kL(9>u5+1-C;&ea+HNBm9P$K^?>*~Li%XvFaH=xUzNg(C3oedangk*mDtc+ z1^e9h-~HFBzWS%$w^yH?;TB$W;$jU>1Xq_j5VgH3JGDZC{ku711!WU@L5iw zGvM`uL{)GOr3#ruX&P{|pE;OYJ1UZ9kS7krSd`q&X$7!6Qj)V3-0}d0U5yhOmCWwB~C-a9dw>> z+-9t`0@4B}=R*g_hMGUO{8`Pw}-y1yIT-_gkJvSLv6XP>%F?y$s z^k##?PcS!;mUi_MrQbA_;yLG5W64kz1E9f6P`4~;l&Q9rGPm?2rFKCPxmxwIY2xRV zbxV;PaK2{+9$)B?aKQ+Mnu9;*qlN@vc(DR<>vxTS|KcM*{rcIm+ZqF^Mx%`J>Gi^V zY4rd-VvfEXmYI868-tg-tTK#=JFT=(rEsL`qc34+mcXWOM7$k1>jciNgNJM5-ruhw zcbqA0&Ps3co(U~5@vxHY7cZ_l6h}OKt;BSZMop>86 zbuB6Q+r|kScU;s13@JR*kGygiGeL(eJdKJs6_5#YU=$qHgJ>!tAf`gyVsY(QQz&_KD%c>*%kItXvBKus#kP`>Y>AM z9hV;-Y#PTa2=+HH%=+H& zar}!>ZvFdVO`o2lsB&K8M0HZSuY3lPPacpjepGgTqBplAO8CD7TaqMG0s+Sp`Wz&C zis_A*+Rc^UMv%Xb8~!<44_2Xr71_~YCVqLGTZxK=aqEM2;^meqBe*nV*|l94Y6uKAeM^4arN}UW5kd=0sbDM zGXj<8^WVSPp9xQbW~788?S6WFIkbOx@Z;cpUu``X%*eno2CvNZ4lP=r$ zm-}_BhOA5TVsell@3~%By!N8x%|o?_PkEjQZez=L+1%=7VnB?qt-PoYSG)_{&Z>2i z!_#ZL6Ii2W%xh8yyi__yO&jGB+Se?yMNpp~$gYhC|F90~^MK91m+CitsUl|Dz}yE;+|g{OfhGE>Z*5+vQ%$=NftK#wM*Kj7wQ5kmwXIhfBWWQlN$MlAacjoK_VcR-ghlRKMQ4&=K-` zZtZctCb4ozeHbl80IcKN&GVPhX;74}xI921k%rnMfsR<7TY1aMwY}NRD*77M(l&DV zM$8ZckN3IdiNKi$xN`%v5`FtK7|HgMYljaEe_r59=>hOXA+kh8*{)2diN^d{ue8JF z-t~yb8FR~@T=tZIJQV8mvjKCbcp+BT79s2NAIJuoOsh*^)>@osD!;1q7k&+ql#HAs z0>oOuWuf&lJ%djwTP2_}Q>%xfW-f0|RpypIiQ@ROwdp+9HET@@1UUPWqDZZ)+9ehX z4bLCHIV#Hl?W4UogMJFhWDN<0deTrTY-iTAYQ}LmW)kwjHOo^Pbtz6m-5Am)lW3}* zk*&oQb=)qh59d`J9<&@e8kv5O>s{f^XjN1%;>Ms)6a+^kT=5&5ZgZbzi;!Z?Lkiuf z6%e-4eE?;pGh4p-OhkGIcz z2F>Oh6v0ly9vhh`%ZE;*(CKux!9*5X2%{#+X0<^dnbxXbH)#~EOotyC2|_^R>^LrI zVU>KF_p>1rLPvBdulX%CNX)2uNIoJHGG=fo!OB(4iV~%ix~kDF6EPpzazNWQcv=?J z3g%LW^IylHkrbJ8;fRe{aSAnWiA1x5)+ht0S-!~!tuuds$S6f&2oMZ@svlp z%t|{;dMy;lb;r)tUzkTq4-FUQt_;r)DM{}ddx&}Pd#}qmOnBF&3Dv8`ZB7#EIp>xF zPi%^TQ2eY5D&(Y$FL6mhgI!o$$_$Y=y%1wuF#E!VDrD_Hr^BrMw)n07uTa#2xvM9P zpnb}~VzS}R?yA8XV6n%C&;MRTzBp)Vl!8aYF?37Fla~5ZofR{ouWeeLjX6!DwG%~4 zhGs3_KHc9`+Os>uTA2muz6*TvEb+gUt=o@u;%v|%*nVEqN2aVw?J2!ec2ydrFYb&n zrO)e^Lv=fV8a;StxhVJ+C;Y;SEVHD`KJ4KAT>5AsKLl4HKVUsjA(sskI0v!hrio>? zT18pNjU3_HTp~bbu+k`2M^sRT1@w+16F{-TE;X0yT`Mx3PE%4^M3;}>oU(Agh^#j( z$%&ZSv&j5=1+<)>sZwoBI%$hw1dlIvv;NAiL=2=iJ?m_yk;IY4a&pJvwggi-56Ra` zt}uB%r(wy2awSiO6E58;Dl;Ap4Nm1(DJ)%w*$*4}$ubOxhY!WuBuVgI>1kmtX{q6X z)?><%UOzu|Jofl*`N~X_UfJ=&;P<5A#rk`$+H+e)H>#}t^|O0E+Ltt}Up)8wv?IKf zP8hY^SLil6tO(ydJk}SI6eodDgnj$heAL!YMLO?0o#@$mxAIpU)ZVdyZxGiPC`|Wk zVX?{|Gk4Dxb8kKPWHBRKX6VhL)(R=hH;pCMh_2GUVC*OtO`pAsgd8@!d8qg9yRW4XY9UdC zX9BWb!v17+_~8DT7@tgjtqQb)`pHen*dU;{r$lFH;{V09pjpV6&R*f(dFmD}*#fikctlh027d({MPZ*~K>Ar(B zFTo53S`Lb*RwFbypUhVEYsWTISC=t6%gZ-jP5)Z?mz=fz%$(0*$m+|Zs|G)x_x){{ zF4pVTgQpdN|GeHiYBgmZpWQcT=={}CuwPR0m!q+*`@(rR;!NR}#hq2>L;KXP2Q>=M zW(KPWvU=?Y32R-uH8Y*|kJt52J8(MNMvgwH_dk{EjTc`lzBXAb*kz}9d8P^5i%DOTi?Wye+-nTS5^n9(FURB`NyO;lNn zG#8;L8zqvizG-S&Up>OAk(W#m5Fylt!jD(_&OLU1qs&i948~V2jh7pl-`n4tuZ$Hc zGmS^*AL9t^8^I#P|CW>+y4>kelqT_;#{2NWvM6rEED0S^EW zDAwcraSZF*dvPZF(9XZ6@9?x{sEAm4Qzg#0%&hLXH{6S>r8&86W&8eS`?$yMs6c|X z{pHOE)|-oa+hbjUFN~01BlQ-qHV95NIP6}_o&P2Ck>!;&Y@pdTqwB}%%vf~2yqf$W zGTKUWbvM`5=hL-PT`w2iA2wOC8GpCkvSvD``u|Fl&HTNv8xrPSPdr(;CF*N;5qXfc zx%lxx$Kq~Sf>+zUqGD)0P(+ACDx5>GKi)tJRPu6CPs`7 zH_<{LH6E6YzBnsuM^lV^rj4+tgM#{TGpnafQUKvNyTUtac^$oMr;KQH2;;hXs?u=K z>whT+B@TPz19;+TLSJL1ak7f>ae1mBxDpmpnZadt;eyQzVeadA`m`}$im6;vycYii z*PY7z%8Ct>0;7`1iecj4GrPC~1T`x$?iR)tY-Ym^nPTgAPJJrj{5$JXa$<7v-|*Yr zuJYxQ8_A!pm(gtn;*lC8DgdG?K}^$5N|U&{4k$~`z21M2;IjYX;)`Dwv-ZLzt}Hj${f`SD);ONh z@~2^aZtdem`pR?O-re&JV}=JmAOV5Rd)Jb$-B{(YX-yfK?GUt^-o`j#&#U84eID|^ z;@ZEb&p%)3aGy3%AElo=G8b}Z$>38SnP+L^tRyRw^JFOF5NLhye_MH$T&G6Pk z|H3Z^$j8NN-ya9>KNRokPF=eGEggd~^p9fGefK&9=;<%>^64ve-X|f>R9=?p%Q|bg zf;X!U%u>*1#7!?Xg^T@^8`eBmJaa4liv4|*qYmSfS zhHdf5z4H&ZO6t4x+}}N8tBEVDRaTgey)SE~jZhQABu4eo#am0u}Qq}~Fe(v;1r9KbF+;5AD=^c_AxmQoh1=vjDo z(TgihS$h)d`|nC}U(9XV+wJ;o8_X`;elY&@p}}wH;m=jOMc_hIk=MS|Zp?03V(*n`a@W-R0|p?4+lV-m<>d7B*hn(*@R%3r*dRnqre9@{v#@qXe87T_xH{R2MRF8sC?~XTp zN-Y`FRBMICY5cwJr(xTZB}_xZsw~TyJEN1r8~n!<6;#EXbBPj4=F_QLazkcRvRfTe zn$-&)4sft*bEvO>p_>}?WoxswZ%NXpzaBY0>}ggTM24mrFOQAXXxRA4*i-hpArZ(! z$5##5Z?2St%+cxz9Zz`~Q2q09r9aJk7i(m_#;*=s{-Zih%<;(~s0LdBz0oZ5{Aj&a zTLJf+a)XvyCbeSDF6^$&A-40c?uUy@U&m(*ng{L2ik}}^_b&x?jEZ{%>=r=}9OfEk zi`D-c0al(dAzMc3_jkXD{V< z%YrlEF0JmY#8}+%JIh(ROFUi}B5!RuYs$(Dp$1T}Rev7D&mv^U{ftBp?1tXp2-l_kt~TRY6pz>x@v3r1Q+?j*8C2!8)}r@n4i%C-wE zUhqCw{lZXN)v`ZdWkLROm#j$@(lxon+Fx$VM$f;g{+j+w{Z(n-2VF(@2DS37gKKlw z6t)Y()Hx=>sseGMx%!5({$t&k2cPcm|9cSLQ2e*8_{aSI+eLeb!r{|Kg7tbXT&y8EstF8%Z_X3v(Q@yITE>CZ6uKZ|zp1

A?y8VFl%~@oyo%Q6(|*Gr;6FEo9aA5kk3-st@5UUI5+`VB);~H z97rnAVKzZE2VEJjj^7HU#V$Zx1O3kBgd7y#e+b_k9S?d7acZxDAf68;LsHe!I)@vQ zHV(f2BpYt(y)P_e+1;GQcn4@YxYW)w5}%8jH-S1}?>;!BwL8_M2Iap~ug6K_IwMR; zUJfbS(A1Fvnsq#3HgoOyjlSl_Dc0=$V=`X#`l{seyE%9EL#XvTBxrAXTBNgu_-g)b z$vLes68UZ1aFZ{{4`v0eE7(BC*FQDSC-nNSwr^K`Uf=y_IBv4Fw3k+_0o6)-@T>}3 z)G{+_I~Mxwt6tdr>(*wNt!rTltN50MYY}cecIJJIe?Tn_nbhnWss9c1JgoSdzi!Xd zvWjI?^WCwhekU7r!vAIHcNH6&Jy3TWg3Rhc#@^84HL9e9f`@Z&D|NKKx$)jNU|Tt; z(yoZa@N)CI@^W7tiHUwiVXGX8jhi*Kh1d@jX5`NzJd~1yPRl{lzC2z556DafFj|LTp+^j}#Ns!Hcuztvc#19}l=h1Isf3 zaT2t$IGm!h;YDqNm)0=B_R^F!I3ux%!Fh=+f`%ydXLx9qW~m73OqvITF&Zu~Exjq{ z5MI(i8YNXHJ2(~}E$*X{ZxzqkLrCxXZiCuSV$1r3sc=`QQuM77 zWKK%VO_2*{9Io1Fkb)+|k4Ay_R;|}M_Yad-_U3X5$q(ipggvY|8*|rsPgkUH;#vQN zBRgBdMW{gjrJQohM^@FeG415q8hAL_B%cM#@UXt(quHA4R823>uu^)LU#OVCJWyNf zCj9zPtR@}bk1lMbaoHg5;g(kR$jDKwD={E(wI(T9kv(F=6s%UVCI@4+#Pw_6>E?LezVc)5Jr~Or>xIJ zU9_I=oO_FvOPpnO;uNBqRl&-)$!0;H)}n#(9^e@PjOsaCr753t2J^{aVQHWZjit`w zl?MvQO^>yrDAlM0?h|4`X4EX7qm%~<%Tk4btc$~xYxzES9QL{R?LhOn>J^#L52qXS zojw&jYVTdwA6#(WJ=@*ZWq$M$A$w8o2OYF+dd=u|6{Lhca}Q_@Yj4(^rS9JR9-?-7 zQ~C=;+~b(iBI!+k$g3-EmwkL^L+YTH*Sy3W(_%Ky$E`#>mhd=BV2)8&=G(*x?x1WJ z9C~u^ZoaqER+D!oDeow6h)gZ^wRvsa!G92(pvJ?br&c8f<3nNr`R9rL8 zT4jnUP86dOyhS$#ry}?K(G%3aN4IQ zsiuM?)z`PiQYaJD5Y$$w6RAwsz9g#4NGv^tC#%9JT`XrAJoAmCDN88SGfo57Lce@Q4qiIsEnGu6y9vS_}2 zOn5fT#}r9R7gW_z@}oVMaf&e>wg;_;*Im1_J2=|x04am7qv%7EG$&u2d9cgqgY7D# z^sdDpSJ*GQQ^SO@R>sCY{mr`r-B7Aue${L(?hgzd`P*qr*-uo@Keob) zdKCnif%1}Np7mvk*xcOSWA3%AAbiyZmcm?byH=8-%VgQwcgbg_uydxQGovrrBu8I z4z#NGRgmoEvI|yTZ>1h3C#yZlWZifP7@+e&5YlU6*~^XyQ-7wS$_RasOE_~ttpbJS z&v@gwV)v7?yf_uLSDh#3x3XCgsBJC9Dt%WydzV={Aq`G zYxYeEJ-ioU^1$ee-w%nQ!md-=zAC1mqWCI{Yng^ce;@9;e7QV|_hL?M{i@pX+8-F3 zo4YrQCOtM+^@Ic{QHds|ICx8kIoTsl;%PKegz!Xu179J01Y2C0Slas}cvFWkO8-hw zc4)|M8~u6p`FKc9nKVAfr$$64S{fCLv$g^Y0@LzTkO-&5QH5RsV>`lZ%MgF~Nf@=9 zAp}8LgArH&NqTK^=1pAos0zP~eA>!}+-#)<$rJ;BP5=tC8CDQl^|Mp_#~>}0*UihP zmJMD=U$V;1*}%PZm*Nx85GxRtw`#=$)+Bq5>CT*k`&A1feT^scB=Ic?{A0iw?Fz&# zLbgg0#*W67q(Y88Bc0gcc%@4Aa`~-y0O4qz=@`1Q)#=t*EBOsCPsfq{NWb4#_Q(6E zuZhcM2@a>}ryu9f|LNZI|8gb|(%Cw7)vNyf&Y8F4>yJws>c7`AU5PM8;go9BaV>5f zwwF(;=g8NQLN_M)sUaNPls8{IwE0~%-f@Gz5j89#f9>St%K6cM@dr&iv)rd!CxMp1 zOL9*{Xtfh%K)Y-=3aA#|A0=F-Zdp1-JQ>BJ)toOE7*`X@B18w9X{&p%Y9O!r%|NXD zykP+Fc)>8$s;nHCsKP+qDClgHK7$Yw_VH-eMyVg1xngzhn25W22+%VYt7woPTmwnv z^(#ffUu&PEfdX2|u8koO;9VUwurwacTVRgrBXR(pVZjzmGr3Y>amgvlwB;U~U|Yur z9-`XBy1OK6)~}58l{Y~R^=o$9rsg&urq|zskX9Xo3c+B%|2oFUyS9$zGT)cA>dc$_ z-hVHdD`9kA`TD>wXE}IXP<2#Up*B=YwCqW%WRn1AWTY27Tc{PM`<%w)_zgx#ujzZu z{|j#nKH?-&VusW=T0VdM>7tfufkh%{ap1xjXo0XQZ72?C54YuViaT8maaT}b)hX~R zs2NX(;L&+z@$K)-ICM+Ok!e!znB*B_^Dr11yZ(l7i2+0qRAH{*9w>E~B#=@u$XTA@ z7cle~pFECfDP2GvC1!zSR62O&dn&Y~ahRbg8I{E9XLU-)j7Q2`KKNS3YDJ?jCDWs5 zi8ggAOj@q7h?bv^}_b)Li0oU zUkXf_-~%etQ3}!>jW*fU4LaKm(fjrf4pOy4;>BIlwWKjATVbtKpyd!|%@-q`=A)V+y+zh>9y0_AE`BsA;N2 z^)?s4Qh~0vDlL)BUn*~U46zi0qdNqO* zYmm25tx2ySl`%mv!l!W#1)-{HIEG4edc3zh|9o%lBa>uvFE`TUa^#0d`oTeQxPp6& zXG&A1X|g&?XRLW@G5n}AIQ#p=vaQ~gAzM^_#-u~ltB`vMZP%FpBKNlLnn1vg_DWXbv?IAa_4hTFq4P~0 ziV9Q*f>$f1cL5vh*q{5-72>rOGfH(TGNNoD^3p)M@Q@_HxKEnjlZyrEtS0iV0dzde zePa@%bF@Wc?QGrLfo{2&W8#D~8JsOf>AF?pkw~CmLVO~;lYY@MMy|=eWRa-`QdU+P znZj)FhCS=i`QpFfh6mlcjRZwnbE1 z(htu2(zxZou6bv5vb!$Q`RUTEO5;=ow^#nw(%-|#(p~qm-Rb);Weoz-&Sne`hyB?3d1!TAGBD=kmTLj_E;N5d@HoR*lB9S@}m9S>f0 zw4zHEqR8BGhP^Qau#uZdf+h*e>J3=dR-W`nsbC?4(YNzdrF|}aK26D3lASX$s4gy%tyu=hPCVlCAViBmz zqGspuOi4=@^b=))9FwtbiN7CmKN5Z@{WorRckH$CsZ&Nu_ubx)u0@JJN)Rc4Y6V+~ z2}`q8N~IGeD&13WW!I^yjGmIJt5Fv9a%3i0EX$Th&W-%+E(%Sq@aCb{8Om1t+4@wq z*?svg<&m5*K8jyGluNzZ799Y3im$wDlgady(;ZU{Zl_FSx?j&BxpUQ2TtwGg#AoQJ7Rcxy+PUPt$H6*om>C6QJ}W9p#1 z(*k#OU|FW#oN7wSPN{abG^~*|>M@<2;e*R5QG9!Fe{=kutmwFSyG`ka=w8RbZ6k|C z`|^glk}Fr|pb`jtN!E+;8>?5(zAUp6;IXC)lY3w>r_4P(hZ*>2)uIlkeeHS!k@!N& z(wyQ2Q7^{y`l8!hN@(QRue!z>6=6IKSG=0FwRw+PP+J26*PO2yb@9CFsRJUUgME`B ztoAyAw?Witl1;YhkR~m$R4!40oUIk74|Gi|oM+6_jvgYHHjn8J@||65y9q;RBHPC^ zky+)Wth{!VEiTwfsTi%HG%9H*;G5!2pT#V$wy%rBMLY#q{pl)n=BaW;Wyj`O<0R@z zvq6p35Dw$2p6Qbfxs=$!BEW)gyQcI`XZE7?+!CjdY+hb!5pPazbvzd^EiN$S+p}~@ ziV``$&Uji>;W7>u_OtA>k%LiPq-Kfu6SE5PRp`_ySZcT8UyaC@2kl$BNw)_aIFS)Q z4U@%Y9%xunn2wfX&o1zEv@VDzh5!0+&+%$R(M5~1w&X@8R4>&>WVqbU z|ETA94c^KBe~QjLD#`rq!|o|rqXwo^Y=kClW03Er~dBmLW}=Bniz-~5o!2Sw6eHp7RAuSWMnr#d-{Ph5sj{z zCi+6u_wGlE#fV%+M-zqTAH3RLtyk93FcyOAF<{~j_AJl6#sR1njArGF2!n>NHgfx07ot!!l$-VQlb{E zR8$?b$^e%_GV+EQd6SSnuXKO+;zFpl7Nd)oTS90%L8MeOO^kTv8aPf}4u%h`)7Al* zXJd6M&LG;X4 z`qDIg?`G1qHzva1@s!Qp+S0@^?k^-+E5F;aVv`$6R2aUq#!QI0&V#t~t3(X32S` zGo4JAy!bL(f%JC1L<&cZm4=`&L4p9K7~<{Kc8`6wcgo+T-L4Keb~?IpaO{~Oc<@=T z$8Y-Icm8v8ICU4J>xNrMEq&$czV}yYJ>Pe_DlNWRvuQ3Q0^_l=K8U6PHq!0Uow{mu zb;B&x>6MmbHSF+61G?3yFP0MhyHPX_PoM}@n#Oo!H`e7!8UV;OBX_$RN(V`G_bg*Tj6l8)~e7i~}PLCBb%6+8e zG0^c`xb^`q)-hTwwaF+`RwFK+i6+}r1VC4Nb3DcD^ZhqP$| zJYN6>>XLk-O_l^UjrkyRevE`;6$Zj!0p_Png#@`Y3y+sH##E9S{}nY=e&~7eQ>Vw6 zbZ5ruAt;R5=vUSpm+0RugzRc%JdHnvbLaq7yg{F?sxA$LA=++mda*OHlg`-JYfk=U zWPL|*KDn!r=Q(Co1}k9?NG+sgK=viK4qKrPJ_Or_=dCmBxWygO5vn6rS(9g7O73nk zCF^Cg#@HV^QU}q2n0;UYFn~gBL#vNbsQ%^rm3Dlbb7&jMIvhrg{%yZgJZ`!eKM_RN zz`qNR-DgQXNioJAr8tJ9_4jKBD&nF|!yTvBWXmC&zq%HJrZ=i}kKgzbcYQr9k#tMu3mE_?jEl3xX}9`| zFKaY|TRwmal^zL18OOfmgq|x8y+B%8Z6sN~ebU&pr(u7gT|@O+;!Bzs z`;xS}b!Y4NH~yQol-qp}a62=?w{rmUT>kV}Q`*|EKjTUfGAo2P)s{bI-4X)I#tHmh zGlm3(ai_c@`EN#7${W+^UANxLpN-!fXZ^J+mlRi(kgv()eQt?u-{$`?$kZ8wZ||bb z=HEk73KO@x$F@tjj~wYU4>4lw)T)hpPMy9WmO`&vwnBavbn9^?GazlNPkDE zj#D$F?2hD*AvshtXdB*2ax5SwPuM4scUjpjA!(>=E9nqrGU)d=e{XC)vJ*MBu{&#S zS~SKdkBR&E{CVf_X9MkiGF(?Tl_bLs%B6Nxfi<-RRQvpn;-T|;Qe_f0mvNJw9>sf8 z?lH`QP=ewu`0zQmM`tQ~##);+TLyS>4yI1O^Q!Zk9psBCXpsquRYoiSqkq6$Gcd5r zt@>hxVwl%Zc{U^f(wKYM1a7#k2t7$t7D?IbspBoTy337DAF^0m{@XMo-+8I( zXh#G!M&F@1mTpXU_3tRH5`_h!Fyw$J!~&tmuFhJ*U1+ZH!JX05l;(40u3!R*x{_!I z8xE;Q*p-_S;CHP>>5GMNG<%{P#r0m6Q8iKn$ z15Q@O!jel?A9DL+zgm#wF9^7@4)ZCpUeA!!=*yWp)fIuQcizxiN1>gRTPoncLbh%3 zBMkBCSfB#5y=*MeU^P&}c5B8;u7?z^GYnZn&)i4)yIfr;Hh+gT<^G6%xd(8eR}S~o zgE@+)tBTyL4<~NWOMoXacn3Y^$s!}r4if{QyxG(Z6D43{c7#lm=@R3%(*dJH+$dF7 zP)qLH>ky|fEuXjoQ@0AhWgN9A&&L%ZYCfz1g-Z)932Oo`Z4K!_(Dsrn9E4&B5TJJ+ zB@2OZd(4+!ZtT$KQYarpSFl)UWL6^*%pnhy=~hM?lyRd#_0#Djm}0M$u5)^k7+tih z4OxW<)|PEG)kBeX0oMk##a24f>Ezv@$(fC-0{4INEeKPU@Dgp2LS>A}6OkmlPhGD^ zNvJ7?XTBnv6Xy&U8L8)^gNnYLFFY4?_2SKk&Tgg4Df?$W#<`8z4V3lOhRwWO{p!$> z2q)uxQQ65<@D{u_HOmgBr(MyI z?txQKOV%;rW&~+gz14QYT~k&)LO&`>Dt(_dWNn3)7r)_IV>G#OjaYCerWYTqVQwD4 zQMIctmVcqPlKV`UQE2wK@reekaCI`G!1|*1n5@|#DfBubmC6;i6|`!!kbD(TZD6*l zS-V!eHYV2gu%DPl28CR~sbyGk!7**UL<^~pAD-jgI+X)wyyw`oS+CY9TcWOq&*t<# z*?iV`Pgegljqw}zS{}mV(9Wwn3=J_g{%L2K1KmIF?dy0*OKyV&4yDiUe(^3n`rXcr zBiv_69cN@i-ygNzTyY)0n9>1-ch_J}og1<-uudx681JjMckUX0VKuh}5V}3<5n}4q zk9W)6abLHTTsXqNllL6aZ4l0w2@p!#Lp-sV5&qhU0;NyRb>8xSswCEE14hzZ1EA=&%VIX`>4iLO{67E>NCSi}Fh9e_@*1I#+ zcg5PzGHQ&&u!~$zLldr_AP?D@hlJ z5b$Wdb(4Sh`K~y~vx3Q>@+)eghv zsFQaAcOlRyUCuHsPmS)w$WcJZG_-|M)C9G~OR+|*CJny{^{rfdb;y4=w^2elNSv#c z!3Sx0qIB4ju9DBn2c$$;MlH0HR(C`_A$mH@D1>F5R_J07QiO4iRlGPww0yn8Q4Vn9V$LDMD z>%YEj%oU|RuV%lyQtlX#c>bT~+l!_GZCs{>Nolm|duQ86ZWo1WrTks9??L+6kN;CS zv~NExR#L81KX`ftQ3Kew@&*AcNg<3Ayck<2F;=&{ZJLo`ew0LU^dw7`CVX|8*`vBc zNM|t+t8&TKy1Zd(#Jx;W&~U)qSpgf)#Znz}AZZe&2EYhLQx9~o^d)LtQnZ{P8!91e z_-v;GAf8j?!oSIiTt-OQkWUIlmPrg^00Nt#;MEz9ZfS5< zuOE}JBSc^RjuXBvFl8>dK<|~Gh{pK z7HKK3K^=0vTOrG1U*9TW3CG}+2%uM8i*PA_2+CF&*Q(H+$g{?vCxb8so{BXL#To{^ zWO39Q-H|ke5g-4?SzIQ{4tprRo_b4ZpX2w0R6-0CHymAO@ehj>kKng z_56dsnqX|}{+oM$@3L&|;;uU~Jfbd-@D`PrC0zkDJW7mv>*jvt$^FSaZU<9Et?#S| zeWi~1VU*{6CbV#UeSm2&37%kH+W9!&XhjIifLk|EnF4_u!&REC40$VEpwK*_I3sEy zLr20Y$OcD9bhnDOUviu7?z4cksyuk)R_v_qZIErY*C$xFVW$JgL|@abqF91=+kGHU z>TPVV$MlOd6R<25!=8~6_ERmLRH!6!r~5T$9e;pLw14$1T`Wy$dD5#3?=DH4ecbK~ zAnFbOP8w9+Jo-VN5Awtqq`J{I|rWGFv8KwkZL%=1{guLEA7ntq_nMU&4h7hC4| z)Sh0w4|@44^Y5tPjHj&XYClaf*KbR`1+B(y`<1Q#oZdJ+b{SGKBN`FrMdX)pcQCq3 z15E&G5dsPkO%MRcophQeXa^qAhzXg_piKaKpax}_B-!EnTInuskI;wUBlP4I8*9u?YfoV`w8FU=GHu2K4fX=_%lTyQMth?IC&v-u3|R$bC%;70 z&D1;QC&+ZLD99@i4r)f|hYPR~`Nj^!5GIBjncWW3VQfXTk~`6Tv=F=+LM=lRgw)E_ z*>tz-M#}dii+hk!Gc9S_R%)UNjr`qgG-|v|Cq$*YKG=s10Qn;mV_Xmq zgj+;9wpOvyUPXRh5TlB)75*g-XGKkZXc-Wq%Q4B*QM#Pyey!-g^iMwVBovtGK!v^v z6vPREY(HREca}`F_s-E)KDG%DMo*l-@1dXKMbYIL7`NN;i-y#)W3(_OM3gGsf!wc# zl!r4MInz(4cYy)Yx(cpAj>*Yv%?#nIJXSreo0o~1F>c_~l&~%q7tc~!ZKTbngFXR` z`XtF2XE;C~l5-kT$&V70m>HL3@Pn53Fzy!o*0|0nWcHURdooWA>qQ-0UYXdiz3}|L z=&}o@7mGIIT@5KVK_$j2T9&+Frw@_xh_l?J}5QWtwPvI{M%k^uP2uA(Y~?bPy{^jC@kV;jQqmp?zlO}o(-Ooc82O^8s1ii(NIO+j8w2)vuuK6LT1~*o2V0Ztmdi#uQ7m?Wn>z~(;^>ewqS1-Fdy&%*O~V{}z087D zH8VYn9l&r_3eoju2*=BrXqA`NOcYonarA8rz8Zu>G?*5*R+<>+O(4rf+SR}r1N!gO z6CTRL=*GPLhihj)zr}6?0E6{lHgT1(Rw6`p1o_qd_{*QCKR>GN7*?7=l)&Rm{SbS# zyu5M@_Nz7_S32D2MvQ~@s|NG?BMcNYFhU=a5x{dGUZ?f__~aJpkcx1ChK>>$etaa`f& zMYO5eo*0LPb?W7swWG>i2(NYdSy|Krro2293?!vGa!9tx#vHVEonC(!>j6qz)6Y9M zOkE$64Gc)3T6jINK)DYj*DK)vh28SC5aO!)B$aIIXggs zWOW*cC1r`ti7NdXc@dU$gBV8*Y+*9M*iu`Fm$fBY_!0-AF8i;Ko$6s2mj` zw_dUfD-^L^H}`NC(3as3pl;ahFBT^Y^~ydh=i5d zfXV<-P*m^)SsbH=6OfyoRK?e;EQ{kXb#=Tg0q73%;P)rgjr26Ng+uz@P>x2JIZ%V$ z_CT79?)SD8>8nUAe5^w*!3Ls+1%@3sYiG=1zs)_;%_H5v3O1i?idXi#Z98`7!Q13; zS?|;Z*Tl0%XVV8x-06Hz|EPYX;@PG0&i}q0Dhyruomx~AKqe~d&2e76Xug387Cl`> zY6t}m@4~*;I|Vbtta8Axa1h! z8D3PVzr2Ep3N)h~*tR=E!=Mrj&MW-K8X!+#d!-};Mx^=KG}mKd?Nx#*pbTKBgT@5U zs7CQM8by@_7PdT!9y3thraPts6rA}G!BHg*LFLLt-r}`-mzS4U{@nFFz-BoDt}qgY zoB>hpJVBCo`YCj2L%x_P5ne?#M{m_@r=FV8>XVRYUGboTOCWpgv@Ny{QAbxPU7EJ-T0tc>AUN49PwcsJ`$|D}P`+M4Rop-({f z;8|vwm3&GL>=A?v%yolhpZ|q42x$P(=y}vIFg-2K4qar9rzE5rP(WyWub23ejiFD8 zhmV=zsq@ds6h*=01ok~q8A+4@2!WZ1;DRw(7@lTvUB;G|h=4`_L|f1SgfS^M6NQ)O zGYwXw@~n46lGXDK$U>oK8bN_5>Aae^F}}V%6{|3olL3XG{u9UQB|=1-7-1MUMk@`O zSpi;eE60L;+Ue!+iE>#^l`1=w;^8Z%*eEyMWyQIULWB=pR^ySG570O1c0EVUP<`Ofjwy$K6yKvgUxQ=;>t| zdKaq{k=|}DNbK0$n(vRYW(+e$=+dL!(lLG|h2N9i5l$cWm4`BejAq-3@;78Ae?63z zIV5TrA^Cd-BIOH|@EsOqO|iI1HRvQY;${k()x67J>k`GxIyKMS?s@;vsf1>K+FtX- zMn1Y!GsK{Eq_zkPfu^o@<>)R2Tbsb?>UMu=8ep)5$P)B87aeT$`w~Q%jmsUP1j-kWu0h9LZtg$r95QnWQIZJ^ zmoG~i+f!%Bb0*RFo`8T(UaNWXVUYe{YtQtZm+q3}Fx%IA5wBYZ3(K!W@1fOT=oDIm z4|(EF?Ck!c-PHx4M8xa1PGr~H(06d3grV}%D*j!URAmA*(d2rSKRv11zqM*G5&leyImR7pO|&wF=B|L|HvaI^O@99i+N-s=q?XgBnv0G5 zU3Z8Vx>Cw5LLXE1S>K$*^>!@~O*$Qyw;57+H~4qLUPIcCM*CQAODZkBxhFXN&J)Hl zM3q{&wBbo=A5nV7f8kC1!1O$k@$R%)-yh0a$6xeQO#acFQ=#ogn?MIG4s4z}SbJaT zu}IzTQ6BIoWv=|JoFiTS{W1N^^Uihm^pro|4bHeNuiXCp-9Pf~*y1vN6pC6lm5wgF z3wRk<&ac1xyG{GK;KC$%{mBmk+mXV=@EO|dY2}H0*Bp4P;mt^7D5vqsj8V=V`NRD= za^`K_FCkNI?W}lTP{mMTVaO-rPU7dVrvB7(dw8E9k7tREapksKJf+tER_JitR?x_unT5sCt~1zu)J6HTa-$%ps=W{*P$?L(?WvTiiz8$2s ztT4{!HjP~>(cTS%t+|XTD#{R?UWH(#Un* zVkM14l}0<#?NYc$b=+VbRsJ_hoILX-&$dO&pKmUFY(IA|#kVe~Gmqb@Q^xiJ@MKZxP?XYrUAidF*5YLXU3uUHk0z)nR*v(FtjeSfv_ zU_fV2T^@gY7c)dV#>bv^BS$le#9ljNLw_pH$ls+tR%nM2L{5NVB*$D$QZ86p3d0b! z;&W7WXoRAoILm~Zst~yq%|1h{ppY8~TT0gKzvdIUg2(f$A{W_spqsU#n-kegKv|!wYD5h%t#7Rvlg^2wI|T(u8&5 z^5&c6M{PeH;{SYDW%Q|oDJC`tn4gJyl?(O+_;wnPpuJ6TB3H0JwcQbZ zcQ+$KVC-uziM<&A?fCWSugdc7VwzP&S8U5bY<@{S5-jtNx)Dh-XBmCC**Yf9*(;J#vF|Vv$H7rMNQ=CZ;=o+J4{w9OL#R#@d}Tl! z1X@9)H0B(z46%%BwxNb|qlEEO^eC2PNr6K004uS|hN-o1Tq5lT#n33*9-(6ncapzj zrzBltI16C{=1v9-_?Z{S_-C!+8=@ZWX3{u{lxH1!yfZd^0PS=Cls%u7^JjQt2r>U?k4cfNhr7o3|J%vCiFv+P7h*U4NY%n%SteS~>Tq_9Y0YCNFJyzOwNioOmgx zN&R%q^yW{Ob5}iNA8OB@&YznbVXocj99>GAEwPYN+_(!R)xL_ z&UV_ddZ3Tys;ghXNnb`QpNU#>OFdw!ueu$0fNp1&sF-wiyRD{WSaPTAW~61Yw2?z6 z%Qzix!Nap&K*B(mCB6*+t*|wJV#NZgKywmJ?71gqF{1hzp%%#oS{ZXYxWP&a^WjP; z#x@a;a@YR8pY-*3X6US=j@jqa0e>F)xkbErjXA^_Z5e(!7dU?N;8|JO9pm&D(fLid zoA2k#FWwwc(kJ@e#L1++&{h$3%a(u!GiIYrMFS`C3aAr0mSmt;qYTN=Q4MvyjhH@LQ@ElO z-*7u2Z#R4qGtEYG19C}EU?mE?nF6xIE5aOs*6d){8>dl;6fKRI=2PV2t>Y61nKT9aHF?eQws608!kOU^ z>`|UCBZ4`lhIVA>0YP5G?M8!6rWRhkO4z+2p+l?`J~fRu*+5eql!r-xrB>8Q&tVx@ zXt%V18rlvyRov)D=%qkOITRWKgGSl$N{AQ(bHHDaqncXE4vE9y{f)?{)psbt@=aHY#a!=d3yDD@cJX%7vxy% z8*SzI;c@37#E)w&Nmt|E#v@EJbn#ZkWtw__T#Zk+OWOE1)Li%O1JZMBpNXou(3mWY z2sZ&?{Pc!FZUO_sR=gHf38}fcadzkavb^<+-})~cQSA2nR()E%;lIU?bE|(s4ncmL zzW@1ZO8@!Zy9ZAT6S+0|HNJ;jpS(3~-S}g!?aVx6p9N%FD3NH>Wfzv|-BBod$KhXv(z!m@QP80Y8~eFQ`O=9fl|c>spm79T+XQL;(6V}t59)GuOR+*foa~KiOMYkKOSj^PfEJ#X z;xpvg40Y&e;gRC^|Jr>zy^dQFH0ziZ-gp0TZ9b_s|7{%d%xeP&73%(j`_}H%+)a9T z%4kFnzj)g;Q(f)IzSWEU2i}i`=kb-)o-qz9i_t8rqj8!~X zJNy4Un)JrwzmHsews=2o=tc-yIwmNN3wZ+7ieX5VjTZ_F){o7Ypi~kvW9kh!+9&Ld z%^YL@mOmd}NMKNem&|Q}_BXI4Pxd#i+kyL&N2azBVGE zF%zxwMm%gjOA%>g4mw$iTfNoHm&DB&5fcmp5;jJ_5WBVpNeX?3i06>0TC#t#l81Bf zmb716`FtPq?a;x~l^uU=bu_$Md9QHeW8mZ+f2%oUrXEF`QuC<%`!(;`ABQp<$-#Yy zH~DxeCVmJwez2%R`<69`9*b_b)_@8xYvo{bkCCwb;Ee7Hm2{_&5??uI@1vAIcHTVR z=$+|No+`;{d zpONdIs`uf}e!Q2a%n-)yck&8k%}fOwDni(PV<&my2=?p8?>!w1VdiS0YStN2SF1{{ zx@EIv^buzqVTWo1yisKW#*01Lg`Q%mt~~-SL&WgHgq~T^M-qng1!xmZ4~T`?l&3VgpHX=5T>JW;H;;?|tKJyeb3pOS`TK#N z=UxxYeZK12RCxB?cbk!snDjHr{~j#wb352_By8csrn~R$1rMhecOFUC=Xoza+wp(8 zF7cC&*(!UF3W1?0!`KVxEaxn02NH99Vh-WE=|WiE;A=hB_3rcMadSyYTzR(D}H9D{2&2 zM)K&0(sj%F;C}SQ{i#EC%$y$nBp{~W+?$E&A~XA@2D?3)IQ^LtYeW!W9=>`ZX|!5g zl8qBH!Fyp+CANumSGQf;#+yh9bn?AQSWdAg~YLNVGY zj07u!w!dG84Zlu^2D3-hHZXJ!YMb83URxENHsm4b1)J|qW#5lLmn0E1qg>z`VzajE zzuOyMzyDZtej{J)6UEva&JKb9Lv;X6f4elRp9T_ONgj zBEAePbp%Uh8~J2pmtL*|5S&suHSpukv&n1X*EOduCbe|eKK;4>)uTA4nbpmAH;+uY zr@iA($)3IHKKQ#VuJ-cXXU!kZ{8W8?+;L?6QQZ8HA0IC+}0cC}aOVWygaI4HS5Vl?cy3mv?%Rp0)E z@YR#j?Zkw_Z+3%|3%w2*2Ii{~Dkd8BG4Rp0eCUbj(&kvS=8o+Zb&W(HG#daX2~T25 zRB%3Ai%ULGf&uj^_qOJRO5M^ZiKw9-m*?U+y0M ztGP8s`Cs8qpw;a%uI*aAcKhI!S{nIlrKo9V;QFK1r~ll0{l#`M0*%V%fAp%XY*pp) zR>(|-Vy1yuO|%zoVB#EY@13oGYqs)Z_3C(-+c`U@Z@bn-7gOg0BF-&ChBhBf9z1gQ z6Y{{V@0V^Kv3>FF5Mp5G@W$HyKQWu_!~MLiU>$}vrHq7SL1KkCxCRBvKsk+|zE)1M z1u=!%D%oz+MEi{EQ|@(ZCMSg>ss+xBd^2SZs#9t9!mNVPai{Emv)QJvWJ?Y`%*re^ z?DC$z3+Mc{SELfCC&>U7^@AgLR9|S;1F!A!L4c8J6bi&7`$cJS$$^9A8YhCY@=_d{ zt@l!*Otgx})6dV$&qQl?NprbTOt-7$zY6~ucY5#M$7+i|aTEapg(SpXoBHeS)FY46 zkN>Bl9@^skv8=iVt*)Z?Kq+l~xAfurc%m%5FxsuqeXis4>2qJVjGrD}EtM$i1m_!T zFUTg+lX_MLNJUe2SDoM8=u?_T*LTcqcDc{RjRMz)iKf2fidO@ogQ z_*4A`Y`4ho>U$fOk8QT;d?q@gVz2p3jxpCqKK%@RqYb-Eff zO*td9fnBV98=c;)w~c`p+K}7w8HT)%col)RIEP?k993jWVD}RGaRN0bS5-k7m;RVY zD~ILzP*W^t`)|5vM^dbRL+4yQF!`ot-^#edA}NF08nNoW<=M5{i&t;In%eLFoV~HO zu<0>hHkEnP|L*x49QoG^HAm7u9N+(^;9eX?f@rYUj}RaBsRNrhQqpt&e{Z>e#^bpB z>mHy()W1dTkGjW8MXQ}j{rB$ge>c_T`sC5}V|8yf61rVdHw^!~g8QD-qg2xWj*;vj z?%ZLMeZ{v6k*w<(^~Ze6&*S@_CzJ!@@Wo?rs=r?}a@OwaqtSX7&Z6ErBM2nHfh}A0 zIuMbWjNX_inPn@ty)n1gK_P`TI_)M0XG9vYeJsS!b|Im$IJ}TwCNM<%#pFeHv|S<= zSSpOI@{KrB?q9m%VSX48E!$-X7%Z5EOQkxz_a)l^di@OZMf?oAtjajWvA}*TId9TD z!YNGA!HeNf0EE?2Z1z?rO!3Yo#flY(kaY0}>c9M%_I>Ws`J+y%Yqp~|KHm>}wY$FO zeD(Rp&M%#lv58&xUVVsMwOFCQZ+jDTue)T z*&IBYw0@-NxD1lKc-6l9%c=4E4L@%E@H_U7`{U(KE+jT;k|9k6_9^3^pufr177r?Ra$Kl8myV~r5R>C!~wMbiZf^eAx1$i+teafN@O+v_B zudN|0&PM`Ig0TzM)c0v%ZkFEOcw{^>NMNPf-s*m|bcpdwefC4!#-H2oU32};9{-<; z-N@bo*9N^nqlbIThSz4Ju3z$Pi-Dr2gmfH0M8O|1YO;?Yb@%#dEr4wE7-cqm8HhD&aRV*>G-s9k<8 zm7tsSK(IbaKiLYN1-8OOWi_Nyz#X@;*nP09VHIeWh1Y}$-SjYp5%3$b%qp#N=>@e6 zh`p>wM#^B1^Pwp?;7~|$1F14=1`c6O5mzRCYeDgkFNf@~5Rau(%re+Ayj@@15K1yE z2BgNIfl`r|rURQG)*(6khBt+?&a7S5-wJ4^r@0jEgMJ2gS}!zgX7hPbVPZjY@?JSi>de;jBM$L;a! zU0wG$UjD205IOBy(c${P=VlX<+T<&}m7xvR`~2bc*2Gjd4*3B|N&>|Wjm8<1I$&#~ z6Ph-z`e`N(T(pIQ)he<2I?>s@83=`8GoHY*bc|kGmd1q?O#AAmID&nl{SPL51#D2-O6F8BFIBQ=N8&v~5fg zX{281;ZymwnGu`mqdhD^}l!gj6h!&gW5YirJHinHEa&!hzJv{TC z8jMy3XUz!ALkpZpLi@J&GBD(6#yHY%%7kt+9a7OhgP)`WP;Fn&C_~8~|Er~*a`5au z<!FTmHCsT6i(GR{} zwRoCZ)o=SX^uT|g3Z_;rZcE>H%>CE%<9_|urR#BSGP~C4aha_Z(~Tn+Q(>&}@ry`q zLgTT*KhCS${e;R>uA zM=Y%7qMkqVJGp>lqnVagYbzz)fAJ_3lZP`(a_er^C|o|~C|_%y+)Gi5uIJx*He?>P z79wGc$|Ce1vu;uzAot6cw%WJShm(5{4gsX)*phZBPXU+U422=so9aCmo$!6E`1n(dD`S=a62w$C-dZ+IESixq4zG>DM>6MYU7jkkXZ*=Q ztF9iK9|z-ucs`EfZvTBNeX?{uJ?-1Yi?82*{tiidUuwrp{E~DdT%?BjWEs4JF866w zF0lPe-Jee}<;a?ov`&1O5WAoM)~9l2S{XW-<|<%@ryS9VksQP#XkX;Mz>pyus)@H{ zCun(l~A%I;@Vo2bsQ}Ta=9gC@OqfRBXj@W z{uF-Fs%TgH4ilSceGLL^7uiO$Dmu_7)H=98I}6t&@y^dOg(c+y_8?%l z6VgCj*9eX{c{^TTgmVK18nuV=ebqA}8iiX=3KaU3WILJ+#yNGs=!17QSv9H`qZz>J zXdPamzpw#6dUSF0-{pH3QlnRoYjssrEr?Rx-?^-PtsU(W+U)mZhpjWJk0np8xlw#d zx;r?44zVP-8BW3UjX1)ekkkG=%=)qXZl8K7M@du_N_iYQ7i8lYf)at7!wqf5Fg|om zbDmbzLuHgRaJmqJ8}H07&{lR!dozaGL=4Ph+cn3-HoF)2q%3)e92sk81Ej_*!0w9+KAKa=k69B11TgnjrUxM;T?WGQDVp=jVMl?kpAi+J6~@ zeFd3g*Jkkf`64f9YXpL2**(}@EY0GPqM%a5upKI<-6hy|b zAJ7BMg8erBvu5e@`+MhFPVt`S(@haTaEOt&sTWfjr&F_fg;+SFO_H~d#2dVm=u@g= z-ST5edS*Gt^0Ftr3ShyxhS*6N{<`$0OXA>cC#**;Q7ENLF=l3JWw=JQONWEZ+Cdl_ z1F@s9hlX&1YFS3AK11|Kr4a3O|B~RkTuwD6|!Q0=eo8~v077vLo%#X?c{`X~zW8(Xts_UKq{PJyqjftL$ zOdTGJWTr(OR%pH!xr0?>FlqIyv#4#vB$2Ek0k%uP8UT_0|1Z~qXbgFyF-ki5IFHL0 z7(~^Xkhzrxli>lCO7}tqC33pta#eNR$m-4*Ie4{)e);X7O4A_0?@|>21~8C0%$FPdoeHr zjtUTq=(UvIHViD`ciZ?gtTPI-*dm)QVbyuDwMKi^)D6=Gr>80NEs;3ZY z+ibU&<-&%yzH+kKh9;O(6CCVq;I~cH^=zzCe>V%vqm^mETMZcPCFL#xnkeHkj2Hg2 zkVpwGXrm9)l%;5NP~iNb>U&Lxfao)C)6Hhdj&`>&ut6$q3Wk#fHhR z8W4E1qDcs_1u;QE>EK1FB&8B=ym(mO3J6m(WzzN9z(d(#gE&tnQ7N5@UbsfR+qDsb+c$S zdjqXjHr5O0Wy=@mYg3rd6@w3*vx?uLnHE+uD^)q0mwqm7i<8b+DPEd=2A^Y#*G2O6 zLn6!gD%tv!-)nu}KdRcec;(A@YM@=*Wb)NYkEzD5#|eMmNB{SX?(ZU~SDYx8g6wUa zcQ(q{Z{B26OK@Ui{`P^0kbGWSRxcUrMX7I$yp(~E1>-EBI%*OHbPH%l_A;9KcGc#v z_^tah<4OY0*Awc~T1;4r&4-udBTO8rU{RFS_8NPoECCme&1-!eY@k^r1WU(DoBuu? zaNl>cZL?aaFyRE=T$qplxo!Ds;Bpb=*tU-sFzJV@4prYh@I!t#dWg>pTwiWKe(X`x ze?OVymB%t3fR$cUH6w$xN3t-@djm^7<2Q!=tpi<6Du)om!b*Jy9>veck{*9klM}Vv(+2k z!Umc{vB5jIj$Kc&s;8Ph(&UU=^!h%@+MV^4YW~3B*ZVd18oql!KX~E$pSFuh1b?yv zKXi!5v2RXwOA~H%5>UgUR1-HXC-CLQdN6D^jSnC69ux%$Fz|*tVWxLRca{(x<|be% zKUyZ5gtjORG-hh~I^^p#^z#{w1)v)RrPmW|H*Be`+@?Lxo+%>8^mJ9|24>R&j)`1> z&Y*l){<()%9#@d4ym+R`AA9SM6?S`Af(L+7)pV4vyxu{$l7%(+Gc=ozepui zLjHUqJ+4hDo+p~un9m5yoqUT4SwR%>10}?);Cf^94qI+yofcWd!>SCyBO8<_{4}s6 zr?||c8szu^>Ugs3+#mbmFZ}iGc@i=G{LQo3U*}h^DC;IK@4UTm2)mg!9&o3<{_W5I z1LZ&(zcb#vHutiLH72Hl=~4g?z>tcE zS5gHL6&6e=Qafs$A=0EG#WW?@giL8fDRWteTI(TTNkBlw1WN5>(j;btfXXaF0!k=l z=)^%e1ewOP>DgMJD<4lH{ zBtaR1v{#|+x3E=(p@_i?1%J$xOr{VSyQDmGA zJfqP(!_xg*^Y1U1$pM*19P*y;3-;f-<9|eWX7EYJPoL{}b@m+ZFEX>JH7ckesenXS zwIghL&mi{C3-wRZ{vCP;jaj;3QoPUrqd|_s%?UClQd`uNM@ck8iOQmh(x|3cnIi}T zDwRtH);T5^#Z_8V)RZbzz>q9~7EsF(M3a&%WaJQCKOcUZz@ZdoP!doURRmJWk`U@C)82gk>+kcOGi_*`o}%3IPWPzkeTRlv ztewxvp1z-_{P^i3!+P}nKjg+(RD7pL=I@~WdGimL&81)h5XJ=;qz=WVx;Y~yl~SiG z&6r?jGQg6|%K|`>N+_X>c21`Qv&}nSFx~ckc>7*9#47Rs07K`!S@&-{&br?`>3vVl zJQvY@ug^K0u35e{)%t^j%dGWS+C1Z|@Qt13A0sUr}z4NNyW-qZ6>zHQcfAB$gY<#Kba zaJOVF( zl74vf@AW5wMiU(--;_R${fYBuFOu_8(O^gtF_Kn+LaVaHB)}lGX1GLwV-X_~w4n?{ z6fmHwcO@++Q>W4%3+Q(~ zy~ccA@0o93r#@`vVN&S3nZ|KLGYTw?%y&OE`{&!~&gVR_uhG6)+)KU{inDUfqKl>! z5RX!c2yh0JbTdi}rzy))t2nBf(u%BtAdK?Tu8@ZpD^|{QX>`dnASj|HC@D}`1p!8c z6avZ@Kxg z(eC~}_v`h~mp@hIjQp+Ne({X`pD6VBo39k<*Yv-ij+qk4=AGw-eJlFA#m|wO@*8-M zqo?YRmp8?!URqLwND>rlFQdjiQ|5iM-~MrB;=YU3SLi=9&iGzV8LpwZ=Us-c+2fzdTkst(#QGj}>Au0`dXF6bVfE{cm(cT{M<-F) z@x68WQ^55<1=d@N03dZ$o<%zft5IT$2+m2Ctg0o>IcFF^NXn%Qm?aC+P%BLtg4T6i z%B;gjyuH3Xe?Il;`gfl%oz?PxL-a?QUJ5EcI^PTH)AZk)pC>dXt5e~-JO|gm)jmFb zBK}eO8vTpo&ohkB{G-=@ptGN>04Y{|MNU~v7RKYB&O++-1 zBuCHl(}x69R6wH1(9?4ggeu(g?VvDutC8nG2cgtIQW ztjq)}I2|+5_1D((k)1fuNp@bR!ulR3(|v0_guiy5S2NPJ^?aPGI$buGsHT_E)bzi9 z<#(QYrfU*dktnuhm1xk^jXpZ>=%#xpd8!scS0%Zs%T#L!!hoby5{5+xvb7~4THRK& zooB4|yLr!B>p7X88Q*=L^L+0p^==ug7EH#!C3frjmyUZ(O#+Qhr?mXj>*@M)%a4QG z!TtC3UxPiD7M1y5rvCs#XFoy8Gvc>=m%jf1LwUJvjZC~-KP-J&#Oz#IN4)tbq4_t- z=6Ta9C}2dm8d$ZSH)rKveEkWT_8vyLu(Mr0v*F&G$IbcdzfWoe-8z@UW_8d9gG(S~$lX=PH-vDAW4fF`FV6!c<7A)vHr5S2(^ z3QMga83CZm5TO98LRl58!pcgu*>y1C)l(+Plqj*&NrO}!imOn`0@x!FF+~MBGR`$p zScWj(V@Fgtkd4PtbK~9L6TN!|C)o0r8N!-LwxY>Y%aNsNYYd($T4VrG5iqL9wQ2d2 zw*LS|^UpUjdD@JksiPR8s3fBzjcOw@r6rI8taU)Dor_b0so;K>$@(woeow8=aF3Ym z{L|>Z&&kE-eT&VT=GIjmZJ(9B9Y0X;oz^80QAYFmBiGaPtmooAZ^-)R=^Va#%~{n$s)Z~W6kU&V z%6(JHz0>siB?+VlO@xKA2pj9GD<2-6*(Qd zX*DGZCJ1)cqg4R1b)}M37E;P7Q7}qnL8?-!v7;;nkq(qqNXin@qN>D^Duq-bMI)v( zLsS{EBCAUlK{V{Ds)=GK*2EQNc7<5Sp^~bEBT*6~N>yPQ;YgH}mab!Lbou?ysuouO z#uh!Yu$Hh;OEQJjWp&4kG}5VxCKM=P1v5A)j;B*DlkyjBU*?I zz_Ut|D5FT@t;JaC#sgKTwCZcXy)G}J_Swf{T{+ZrzbD#$i{X4*FVTK^+wo|-`g^ZMU>|bFVwg zlJQh&ohV>TIcn64P}KRp^T@q#N##D%h2JZHG)7?tM53XPNwPrVs#=`I6;eFDa>81W zv@%PQ;)yiTYRP0miZ0fOilEBJpuNKh6@tyz>jnFhK^N=c;@|`fp&<)m#%rVLKP7rPey8J(b`J{_ zO*jSuhOlFm*y@&OlVBne(zr%N#+rtX$GJM0ZuEM5=C#&VyT>f_3{N3nE6({G@32Yf zoTb9e%+{FF@sz{|{@SSVxaQy+wX^~HL zzbj}^v{0pJw5>%^Rk*dBwWpUOFv`h>MoFqJT#qzU9uBe zrx|vIRhF6~6Ow2~N?Xk(A`V_gtFs$5FkVb&rfJJnQBhKBl|hT0O)ECJyzhK#DQZ|W zPCllVSgU578fUDPX%w+*HOQ*-s7^%IR#da8X=`yZU9f(1^yl|0c;jb~vTYmJ)YYdlTn^z1RJ#nU&36Rh5)+7~sJ z8%<`LuL(4*B(f7@g{bu3k6E&ErXxnZT7PZ#?VzV})_G*DZMQs@mu@aSNnGwoPQ2 z+h`g>mt3>1PHu*J1~_)#nEPgIV^f%+<)I)|U6E=o+aknXq^pxW+JP31O0-9#$z?K> zS$5hYRcc(K-m=mR3WY7pYc^h@xtnfDQpUFknQbnaN|I`oWQiutB>;nDQkkeK%7_+~ zRW3I+2`grF&18D283@**2UkKm#>55I!Vz_fR0A{3*dvc_JryNx;i=PWA73;jpB$ZB z*EZ*zbg}fupU127*434ky4OuLq~9@{MRQt_EJ`Hi)L9yU$$=`;$h5;dFG8-xO&w`1 z>PDukQJi6xYjJeZu7p+;GX}Q1o0_R;%Hpk|8Of@;n#N4^DGGur?+|ZJOqzEj2Q!%H_OJ#uYmXA{FLD15|DTNi8K=Mkax4swBz?VVfFimo$lz za_PBrdDb#4jIJ3VR+mb}MY;eCn4pM&bi#xv0Yw!oiY#_btsMd#GGHcKtEof~lC84I zAZD`6F^G|bRb~+}t)e366eI=n!P-O0;#gn%TpaqGBTSLWh)$K}yPmPHU^FrzJzF)G9<#rCQlE z>p0Jx8YH@;RZ$e`Wuz6Ots?@hEYM0wDyL!*Qbej6vb0jvD0VYSivma|D-f$?T9UL7 zWD`!6L2)n&Gq$WKiUQ*-h=WAds-q@mG25yt&RL;bB-BHN5~|H9SVEVf&emDxytbs1 z4Kps``_l&n+!>6bi=*sH-w4(om9$)>Wl3WTQB{Y9^d84MLG=OEBsRvCvQ%jvP8rLjuJ} zDUO;^3Pl$yCWxX7BCAeBVoYNSDxFaB00^ZPjZ^}vvl(`!6}Xc#O%UR3w5n?vPG*Zk zrDKfBln{y#6irlBIzow{su4gE&P4?ZCY-vHVL<5-Au5Ve$}dQ==$2$9P{l=5L`bUW zq5@7-ajJ4aP#P>lv7%5ZA{4DiRWd}bQA?e4q=CoIg>{{mW><|lEg3=5NS%Y6+AT|GZ}RQmVjds zF)>u^Q4)~oAdJ?mE_9$oofdTx)B~}IArxi+09jO}lnWT41T#%#Q=*EY1Sp^$YEck| zO4Ss>8WM_C5;J6qQoz8XVZo7|D=NoR0PdAi0}$*~07HVEQC1ZZLWo-^vOon0EMTmW zkXE3Tqs7f!Fik00Fr}kg61auBb}}F-8mU=!NCY*pSgeYuLd~j43sAIaMtL=2QZuWu z(IHe&29y<5A(B&2jiN{qP!1pmn#t6Ns?cSSB9#oy5w#;c*8z1Su?|)W>}jQBL`K(WH1pGRI;TYt3rxHhgL}el9kdkiHlOkL?vP_i<*h3It*@wDrZ_z z0vO>$1yG|x?TKX71OS-M9daz1tw&EpIGlmh&0b89qyQsJRfusVLaQ>C^)(O@1&qv` zo+Fmp&rnMMRIaYcmpH9L#acu|80zXmBt=$)h_DDEVUDXp3Ss~!Qk7&7StWoBWt0S! zRba7{jMS4djRqoskq*a5jGD0wT2e^zr3nEAX;T7Kj70$y#wabT2$)LIh+rd3p{N9u zs#U1s3bvJ!W|fm6Q6nrutt3lAH4538tmVc~WEZH?t#&OcA{j72S_?M-mIXve61x>g86E}b>bR|`wInt4Lp zl}M@~Dux=BNMsIaMp3*X^_DVdtpF=JlCp52(M*FtEL6*cDs?d9F`F4hnbpOq43q~> zq_F_W0`x*JDW+o^l4Mvzr)5~mB$8z%^d%>~$5Lkg+}W+I29%5zC7m=QEZ*s79Br)Zg~L^7pT zXt!Zl6d3}IDHgDZc~e1jfisa7X;Re1SnO2A0YD+bnnaeDsE4DLWdb0$x-M7>ooFh$ zl0^az(QdXtLMjnCP1O|51w;)| zdI(5DG$e+gs;iLDg`0GdB*w6oZj_a6SxJiNL;yjkk=Wv@=ouww1Vl)(dNVN;Q9>Am zQD!Ei86t>^9MXlA)R$C~VO635MMSOG>W5JjP#K7^fD1slP!b`5VgRK9BN)zupHDjS zeGg;ze9bJ#Krw+N6i~)yStN)6#$H{PK!z|iIJhipi)TBeDztf6w9YChz|cm9WdW2D z!KS1PqfuCsIJSfB(b)GY|j)0|NvB1OfsB0RRI4 z0s{d60uciQ1qKijAu$IN6+sjt7BUwgLL($4CNMK6H8%g+00;pA009L81wtE4s6?I0 zY8@ZAL4Z4oh$IE}M1jz8{hj3>DD=4n;dxyITA>+0DKbB?3OfZJk?nFb_E8dIHl8V< zF9;ovNO@mo0tyiCfBGI=PTyq`ntL98&q`3+t%Rxlp&r+i)%Kj|Q~HzHK}aa}5Q&}T zNk`Aw=}Mi7o`UT-pzWLrF7KCf-zh|(B?%7gO6C!8YLIsS0Hr8-B@K+O)XE2LASviU zAonU|c|=O$p?9>xB}!~T^B|QfVNTKkc#M zOS|NxAf^nU;G_d7?&73LcWrX!i;yE}f=cBsAZ{fmi}!Zjr}F^ z4B_%LQOVMut-@-UGJ@{BEeH*|*r6LrfaTj%gduoefAu}`*neW2;JHbeG7*FbK*=Q@*W8u& z<6+X|?m+fm`wt_;$|NFJCCNx#M6NMxBYIYqc6Clc!AriTFDT1!A#I#b^7_y(Mag8q3__h4Q6$4sgc+=N7nze?i$2slPxab;! z$$a&Lo^v)y`jZ&Hm|_}6tH!wU>^Z5ng%~KEgwiEMA6Bl}x=*zERL}w-0l2 z^|>6i&`!;m`HF!vEq3EmCwDK&*QSO}>3p@r$jVlAcV5<$d2$1vep+hXHMaHcO0Qnw z#lM{7D&5a3n0xL}{HK@Ed2`uu$#TGb-lWFHF;LEyK}}i;f-yD%Yh{{quTpFs_?%28RA@jenXN2f3Sm*@gyVt zflddLQ6MAQa1%XGP?~mWNBemu5IwiGKet;-`(6)II}s$36rtMirbMIQ83UpBFcgI= zlp+Z~MbL?SeG<8M?f@o7AXn6PJdt}slpeVi%2y;z4p8G!2T28Tl_ehs`xG2X22-9I z4aGJSeQ(OPZpPWJ)%dnP<6dFtH~fc(H0%1KkE2?rs#fiH`C^G5hNYVwb5niqEU+9x98d>#SW)jJ0Ze^N1Z1HDYe(?itkF-`R! z81+kD;$qiY;x32sd}lA7v3tH^&3v_?PRrVW?7b#AxtdiR{JkLm0GMl2voxB1W{6JC z+VdH^cfaQ7$Ia3A8=R)f!#2kwoM>M*=YgDZsj0&iEc@%0XN!-`JD1M;f}UEZCuSPD|Tu&_U@qkyY63=aqd;9_OZ3DE7WyskVR^>oZE-Cqb@Ev z3(KO7-CkcKQGjHe6K|jGU1q7}@M-o|Nv!zp0Gej(0z#me|n=Nt=K?}uWmiRR;j z{RSko3^60&L0=Nars3L~il)aLWikdSu}c;I0I9@N37E@vFO8;9#j}yIq*vfjDcJf% z{B;6Nl@=yg&?iSQr(3bZ@o6JTu3pm$bp|

2FyN3_+*I7}c!^6o*{c|`us9gU}95zqE6AxfAt&{B%+87}uA z&u(8q7ekA?p2?HhUvPmur@2I-+nhgRDpyKEad2Fhk`#q7xdcaZDopY~v?o0S1NwkV zk?4~GmFsF&a^xUZ{atVq?rF4p)LaF6Y4;6jZNp^Mrd{qeRINn{^vi`-6Zura7gS{2 z(_fiHr(`X{si~}4bNrscm8xqjOGwtZmHhJ;HTC{7nm(jrfA3V(6P-@ zsBqZ|^y+EMo2oxd-_v*TT%fsjm(1~gkCD*!w+++0)ONFkds@qz6vgT=PIrfoXMUD;a(>kDVmrLHW+|&DqyD@J6(;m+Mxtnb#ttuC?8>E*q^I zacp(PN&@#)-mqP2oYlTSYF}|bRo3@etgkBF-fC>9uR}3)&6%9NOoJbmxxJ@|&0o6T zPHH0TW`fN77T%aLqinr5#amVWF^i^|fycEBMT=9h7D?D!Cn|Uhdt7n0tKw|aaW+gp zg=`43p*6Ae>a<~~%W<}dW31Rsg}ar;E}d%Q7illUW1UghJbUVVJ%}vC*fHOQK%bAc z=5f>j78Dg+Wut?zwl8H(KaZ%Z=`2;#GT0kDUK1?Zl4YBHFYn&$JOl2uA91qR%5g=_YUI?{fQ?#w zTUJ*vxi&rKv@)+G>Vd1?0ivT^z4nA|T2ZKlMig!XPrt~EppDHCnQ|UY)HvM<_uD4= zi9eG~ep7i1>L}dORWcM9zdqIBx712){U!O#CAm5hax?;dMu|;|kt}B&YYlvyBuQ0S#Z&C1!Wj|AJylZ-;il*=KrYnOzOTn_WPgX3LpX%El z`rfM5FR$t@PQ5q!g{W$Z+VfISG<`_ab?bkSH5E5g^+NocpHZ{aYByi!i2i?@b4Iz% zII~@5Dpaqoav>j4uX&GBFX}2f_VeAo)_FRQy1aE-kIG-yG^%8)D{O8~prxhrl>pKi z+SJa5%a+)BbABq+^ycpM)}ETM+_Te`J+!?(x93wwTT67^Hle2puTu#n+JB2#gQnN~ zD_8Nhnx7CLVkx15qSf%Wo|9@1OD-tacc!=8ho)EdwcqK^UbSmaPI6Xc=qs#sR{CF&FR$rE z#o2$R`69o^*;WR6d7h@N^bTx_o|)vHj*84Sm+`FiHa|+|oT+Inr5f(RYBdxi9je^QEG*$>CO*4D^a1KFjlr0w!i{V zP`<~K)LYY3Z7{rSc8#O6*@P2>C=0Lk8%E|(P#4njxXL{)K%clr%J6m#P`Iy?t{lv@ zR~Fy9pUu18`D(uIxYjjsqd@Chtj(*kwIF6{IJ+}l9Lw6BoU9r%l}hM{X-Ur2cI|C_YU(a_yr{+vX7{U|XOtCAr^wf*S3RF~Q+t-aRPZ^Pmw(4H^wSyWeklUudJ(z3U@`RSGRoPATT%$pY7|3V>@*+7 zrXTD8y|9BgpxJM?0io&4n2sXCU5Bvd%ypwfXwYGRNC8BW7a2TJ3$lwrC5SLCJ@H&j z@lX&5FS3Y5plkw#2qEAFI~|A%?Q|4M;Q`GEuqf^jYT}_m3KwcSE$=f))iGLzi~j%@ zN4eE-h!xTzQ=0?;3y4G^*3hH5+9bKX{SBk`@^<^*&i(=Ny4Zr`LK_b&vZG=Vouh8l z!U_WTu}J)D6j1`T~?fxgNVGcast%RZ6+1$ z&;(MT*LzmZ4yR41)2B6R+0j*VSbjH}pBYB2U1^LJ8>^_%bM=E+RO{YG>snVef0+SI z+N!PEtDn?vZ{=q$-pqD(s~v{RIGk2|(5G*xL++iOpz0c*F-%eQ1KKB8+|a81XOy~q z48DEC-qaz~>@^)n(#C4KOWV{>r|?>d%{UEIMGZNqE?ZAV=4%${YubX3rq!GWrq>?T z4^6qWdTVWJ8|l@z7HDj3Hn&CNxYN>DMZHzErB$q^jWxusFr)T_ zS|qe6J4Zxy_r%O1)e0fqE-S(iijas3JC4fWB(9<$u03&FR~7Bci#v|YA^}6B5C%yh zeZX8o?h8~XM0R}lBqud^UtCmnKnN(>H-!><PDwWJbry8_!GY+k|Pg z%&(-bu5R-BA?r}-d%G6dP^)>VDSCYNRLJ^r?q9&K@xs0b!g1lGJv#?#gQr z_vdw8CsfSp%dr~5wHE1YtMXgBKFJMZK^YQ78c2o!TH3$6yzNoFzg67lRU@^K(ibI|_Pq zqDqCpsD<~j^S4TNjkzh?!f;TE8x`bz#O)A|m^0e)yI)YDcwcMi_}DKyL7pW-A$^^r zZ@;+MsRTj-KhisxM0U9T#So!&v0h9lD~X7K3OfN6E9@u%1UH2QsX_`UC!pC}VL~HtCuX7I6WCU?p-QF;0@|+Dl$v-xh{8pv_L@;(<-~;wJA^_lah89XU73iASO3Kh5x)4CPT# zx^6xk1sixpPx`_#1VV-374(OQPK5|UK1flw*@^N(jiX`NP#2ZpNRD5ymG%>mD4m>S zr~pFb8oB|fj@}lsYd!-_TgI}7apTdMgAj{lIgpEZpKYtcraSDITuVs{{+tl=_CZ6j zw@c356nuf-l;PP59EQ;<0*;ZD3OgVof{>yYgzqp>^Tl-s%qa*#LuYg&zL(l;Cl%BP zP4K>#F8nS^dpklV9N+%{vCZYTg$ex?1wsZ9P3(>Pl?cM^0l8mZQAc9#%I;h$z{;u1KPzzR~mCqJsL4zLz9SChf=*;T84@kJYYSYyt?CDoNU5 z7Zed+T`5jIeQb6rRP1(uiZG=W8y?Z|*4{wrNZ7-Krxke4R#}Qv>C)1Fz7TjW=qN{i z_aw!t5zT0EqpbM=f5)zX7IC zv#a=-0RW*uMRZe}*=UGf9RWyDI}i@gp+Y?c+IHD|oeXWJmDP57jgm={5D<*7DikB& z6aK%nj*&)Y0v-ojId+cSqvb;T?RJQiKU4@S&fW@e64mwl7kF~$6AF4Wx8G~R`%Ya1 zN+?PzwxU-`cKSsDx0S_xlvk8gA~%ly$Wgc2?3nDYE8AaEohWz%w{!?Zci|9RqjC@n z?{5lGYL0?(1D3@efhGY(87IjU{{Uk$M6Ww?L&@>Cgy4^8gmx?Mv`XnuM5Evykx+{8 zr=|3|MiF1PCG+ugrNYh z0PV_Gl>rbphLzeqE{I2Xgh`3y3`eOqKGr|c%ewa2WBNEJBhuvy?`Tq-dhxU`0Fr{` z3+_~>cA&03LWJi9Jx@}+rw)pV9uPZ(=;R1dD5nsCmHz-e&kl$iIekJQId;3BE4Too z+K!wM={IL|x=;!cE5hnYUJ;3&%aA)bFYUM9(2t(Vh}e>W>`L;E(FiCAm|hU=c;D~B z@Oocm7(>qRj{PZKP)A~RApo37L3X~pCik)LXi%WXY6|-z2^%}5^rR_Ys+mR?gg?`y z7a3mHakxXviYfaYjFsVCw7$zw`;=_7O+!-vJQPOYC|(nQDi>+p6X6#qN6GT#^$7m} zq1Xjb1?3)w)CXpOunMs}28cttf;VI<0vC?39#h>%BK6vA?7`bR3P$({x6Sp9YB1)c#L!?uX?GXS0M*EF)8l3Q@aj+0!2mzBsAdH^BdFDQs#Q`cw(3L!hBW05LT zmr^$GVkL3gwCREUTjS`XD993b@`B>vrWZ@K^ilH&`1&Lw3h<9>!6YbAvDu@4u!!jp zNC3c<@hk7__KKDEPwdmu3y*!H;3C;joTp>B3#8|8CEfUQ zy!|8EgSXe6iC^Df5&r-{ybrEh_YEbey%ph4Y0JW%{HTqLLX)$G{{TTjD5yXbFP#F?Z45QTBY5! zJsW2k4^F65ZTF{FmJX$TsqC9$sxKBhD9hS+c_v!2uD-CPUmcaV$kOG}J!?Ft#$qXD zGgWdr7t|_utPT}hJ;){RXg;spvYtcJDqhB&=D^R)V}l$c%85{5lHH+9F3!+^QwXUW zA0(mJL@&2_`h-+2D~j;Ep%6+h4KC>zaA<^A*K5KjZ?a)|UuqFiAoRHar)NMby^E1V z!sMhBT7n))mBI<~SJ*{3$`QwJwJFmBq)9~*kDspRy@CozM9GOjLM9OLEAC(iDJbvS zZLf1zvy3Um}qufK8^IY6f_lrJhJ5L6@M@9WD-lmssV3=a~C*`d)?cSebWY*_zY_Jykt5;UYGS^F8UE{Q_ ztjKBW{7zPuLeA#mof=-DYP(CUXQi0xSsT4~qHeKOy*}1MEp7HggK|2q&c^4|Jk_3W zA*Ovmvcur6eN%NxRduect6xf8KIaJ61v0+eB{QWeB}Z;*?GCn;0eJ)?(Cv6#DcW{~ zHXtJhW76$?luw z-U{&4?$@cbs{C$^$Wf)Nskpg{5a@kK38qn9Plt1b&81Go6%wKpFFQN51nd+q0HUNW zV`6un{GwnZDo9+U74&xRXb_6}+1(&}5S$@h{??fnfBLIu`<7wF1SF!_KBF?F9Ji-+ zd18Qsdt7@U0ex~UE%gp^mZiVXI-M+rj>XWShS$0#?#k!W4P#o~>s)21*yF3)+|;M( zCO6u!ytAc{w9nAE(i(?L<|$`!d4hifQdnJG-@cou8xKz3cV%Pgg$E3NgtD@!MvXck zc|jBbMi7{Sr)bzIDX8q@$9~{{X@x3NB&R?F!~mR7UrXuh>E2YrJ(49)M43f-QiKvz zLImwUtjZn_OYHQ36Ve?oxlo5m+Y_;!oKa3i0oR22fWD`t5+XKu5PWz9@*Wr2M5*hg z(&gLxQi?u%P&e_hJtGoGN3k11DcvGe@8Nv_fE!602}Mehh!e>YzLDBtN(FZc6ev(p zFc(_{3M=dB5B~s%>&g;e#uJ1u39gjlr@30nnXQBsKMuY!ufJ<4suVA5C;%vgLWw+K zctEugDD)--sZgOt$6|T}lhP^034l=&peJly(U|Q>2pQO!Uqm8?(X=M+M_g2=m0SM+ z=*wICy0XojEkT9I$0hC%yz)EvpX#%X;uMzU8%NMJ%Vc zQ&?kL{{X;EYzXUT0$0%}?HxcwB8cufDteNqXA!?hpi4+hbRvjE@l70&=psr8p|B{3 z17e#Xz;c94Z0`Vw@`xakLi!_a&}m*5*VO*1N-ijG0Ivw4yN<-EA$@nT@Cqe)6S0ke z+lm1d*2MMNDi_z+mE59?uK4jP7fIU=kCh#AQofrAo}xh|G>~VYRG?8scO9qp8`21s zJucIwf5`|nctv)0p1iN5U9_*ExlIW8=@e9j2&n-T?jTUu1v@*j#3+%gA?wm-aML`b zf6KaGU8qN~+;|XzDaWyM6a(16jvoHrP7_Jk_evEucNn(ij^p%=gJF|DN;6+=OW^o z<*eyG>oMrv(W`|W53eFR9Vt@_%6Eg{IZBxc-KQBlIv3J2u{|)U?72DIkcBE!yw1Rc zNI>+tB1#CJN_q+-akRpeN(e6qqY+WFM_VvAEvFyuVNTGUPnv5#e^KmBj&IV5{yfrl zKh^CO8R`~}yQgu0)cT(aAD-0r&%x-s+so@5bt@`9rePV7wbI&(<4I@ibq$tAmEL~V zfYqAbt^55u(v7sMGV7@{wOJN%+U74_EVrR4%4uvbBH zmC`VR;=C`YP5oCT5{mx-m_kAYbc%zw(C`z`D5jWGE)7I3B?(S2ye@+J9c}iDkcH9( z6*0H!6p3=4k4Tod?J$RGAQvybK%?We$rTC8VE90yc9i5nDYGDKKrJ8!${n}st~1uf z6$WFY#R7sojigT{Do}hWYMz6amG)e_2)aNbIU@5dQi_0v#eGV5XocYfV{VY`IEZX) z6O1lFa_f;Rmrrywzp0Q9T!CDIl_;+QRH^B*iBlUD3)CwI+2y?;x%^Af+UW%{36&~j z2tK}{V>9wb2t zt`2WWfT9;=aZX)0dXY<(pwh(u03RFqJt zHl0RO;(!r#ZASLnSbBN?0HqB(sI1#|bpO+Bxogs-`TJn}^}{-zMQ^Ptsp-e2o~N!zy?eb+Qwx&i3!4ydgAqy- z;YyyRatoMyNnE-m0uf$7=}Im{r#c%ekqePhisvb=E7cahr7RvorYl!k*AJsj&4S{C z`8Imw0OryiSRqxZ^%&MRs~#Uwp?lQOtxT`Tq`xYeZ{*WL>Y8=M6zbHMyuyvcKsRhn zxuo=J(PK^3I5%{Yujqu^*75loQZHEzzNGW{RA=*Pb9L=CQu^Exlc66WZV$;(Ejb!K z*ve99eo2rrbkp+I;C!_v2V~g|$kUIMqK;0RQOp1nLF~TJayfP;_amOI%(HHJ`fD+GgKP(vkotiCpDRQsn+66)WgFu0xO4QP5vpf&?!pu0XH( zZ}kWiT)B56V!8@ZaDe1MaBD+QDpx2{(2JKPDi=*f&>CeQ6A8VqpdohxpmOaJ2ndu2 zB=}!#@=6Xt+?Rtgr58$+NN^i4ub^ZS6s|}WC?3FUH4lHS6Ud^8X~gP}>|(v>iY1oH2ggIF}V>y(a60rwQxjlghiR-srytk`|c zqf4_G>NLi#!_C&Y!CH#mtl%kzdasIU{{Spm5l_{7n)M&*wOVzLs-Dvu>fSk9`muwp zRQip9Yk$aCA}Q;*I2M_HO?Z19IvZ(RNY6_OG?)E z9-~pdqW=I=@!rt&D-l%F^#;k~`Q?aU*Orx$*0$e}%~Nj`wQaKx^9l)?(#Q|z_}Q%d;YlO4^Qt5Y5tJ`KCD>J;8} z3sKLqntpskGnDE&rl6q3uW#w)aW&dQ>~&2S*fTqEQLN0?gP5-Oza>?~-(0qvau*fL zukPOe0L;5_ZEL5m%eY|o?wwEa?$s-sfW6zwuXS6#G~Zd&fxHZPx}?!tAmGPemY5Nu(*p%OP9u0dAP<`s^N{P z0QOx0u9Yi{BHq15X{mXm>NVPKoQ=Gx3PJ=TozfktQj4K~arM%Wzp(pphV)TG#PqqW z)|Ifzy30jcG1k_Ww!&1e>d9T8_(B3dvhG(lf?l~UOOiDcT_BY!nsJmi)}eguoIg?9OSL_#T~ku`FOb)G_p18V*|ccu++hb?*cQ87S_aki0@Nn@lWgTz)hh}k{E6GWL$|00 zs5B|kKC9cdyM0))sOS2dXGx6pR}M(^62;25sJ0a9pHQuwo$A%SD%Jf@x^TJG`l{hm zcA~vwsAL>+IO}USTUb%Fq48Cms%gxDS4#6u zx|1%kucvQQ7eVVEYjH_466#c~TkPFdYi=8VfwOZc%7sq_miM2BykCKorXTp!Y1X@|b8Pc{G_iMCC0g3r#ZjQhyT&%){8a}~p=oVw zF^^>%%iQ&?XIo_)ZSk6v+ETsA*Y{{-IMveO;7Yss8}mF9AzbY2Sin7@cTz7~Z1T`<#N(3_2EKN)Ti zv8LC2eKH0riwmt-P_dv<$5V1R`e1xu=lFC27OY=`OPAtNkHer-t!cdrDm)!((v6)Y zZD^JFbQ5gYzXqHODnUBdlp9b3Y}&saoJGAR2GU?mqQbp~CtFfN&Vn}d%Y_$M9r`Y71Nwmkd#3^wE5-HOF@d#FG_gYh41G#{`<~Y8kHxE)B@7?-cn5TEA1>*vx zcSNsvN4~<=*I+*IUhN`{c7^XWFLeun%im!>{V+cwh+mUTp;@FGrg3d{L#`;6w&s`= z?*U(s)}dXC@>m>hsf6pgP;M!qdqgkHV^ePFf%&vcMdb&flBAA8fL|v?#o1aERmQEy zQmD;aW?6BpEGY|3Sz~z7nYJtCZCvq_qMewcz|6HOZ~1zBYi63-Zp~Z6bC$0|H%HuV zdV+3t-W{K}2x=Nr^YmPqpP;H|sWnp1)2N-EY`aj>W80{jLv!T2`4hQS&lnm0G|r*+ z6SY8NYUkM$|p^-Ai@Q}tY22l}CM6TMKpppU3oI<~*$oULJR>Mlc_Ur@465A_!(Nq>-XaZl7o z@ulh=UUhv!V+B7@t`)zi4yZqz(JG#}r}=fYr3-tz%}rX}w;J>R03og{>N(ojIURJz zGLEmk%x3#YAV{F$})>!tYYAaeU z%4oo@a$(6X>3(7{AU&r(%6na#xZ5C(|Do|mc+xfej&o1k;64r z(m2YA`YROl{Q-(J>UwcuSi95OTt9$O_V2wp_vyRR>MFmcuHjQcU;b6MrWKt_9qDxh zeL1tGO6$`LN;GmcZP|C}UW_%UiXb4x!4<_2SCrSQP0+)2HM=56WF^&R&NvenGFM^V4qIhxgJQ_Q_p%Duv_ zX0PM?^O(MRs0TmA$5EP%Zlw-w9ZvVA=d09ZEZs-5<(}r8!@Za0Y6U|x$<_4-5&V&? zbM*@%mY}BR9ZBt)xvzD6<7w3XMAwUrOG1LBswq=0)l{8KYTh-!pVRkWu5Q4|YO9Qk zAIhytK#@*`d!=J_l(0t*TUb);9&r)z?+3 zRn-@dsc)$=Z&w+7!Lj`Nzs4C{wZ%V{&CsFpc{b3anafwBZL2QJYwC;ky0)ymi+x__ zQ>U$NS}JP`ij`Zd>Neu*R^3onI;qu~-CcW0pUW;{rmMLu`D@3~x658Nmf8F2b!ue; zs`9T?i@T#rrb_<0W!>vVcjRtWTVY84747Y7Y*t#c?KB2X^;>#W@Gbo?bs{|}wyN4b zm0GnQODzij02tXdKhrj^@l_WapGAb~yc6h9%hBf#MhC-E&pT8BZbhb(L{{V(&iKnEsOWf@>sInAKr}@_^ zI&)Ohwtk$|wHkD8bvs36*ehx6MMCD|50|;7>^@Gxx47J$T6Wm{gKAx2IMi(cV|8^+ z^>4J^kIr9IvGmMwXQwtTP4xc&88q}pE}EsKF?7W}If@1N9A!i_{w1lnd}~+3W1OFh zuyrA)@rjs=CJ%?lknKH+sPlovmHcZK<4+HariGoO5Vxbt+M_0w2eew-p>JhX zt)6f6*}SPsOxQ3C9yz1ovF&?oZ576r$K9+}Cf^rA7Z25-H27RlYK7r9V438x0Rmet zZ+jE~KsiB00n{!E9)m*SxCIM}gc`>?f`Pw91qc~MrAJU#VRpEP;8D z4BkH5(!6y#))@P2U8o%ZnmI4HQP5#e*eI29dn=>;8m zDt8`yDH~MeP+^WJjiabUz@CZ>HUpLd0$MaPD4ar*tk{HR@CY0%*~ZQ=9lk7Sl)51sq3c=bk;nxE9uRR#l{~;*x1@rz}QnQqfLX`AP&<< zAVK8*OSQ=p`pAI5M;4ad<7r;Dz5^d#=9Rs*Hnz%$H1XDKUflp4LeQ#IEgJIMI*)hb zAyU>qCeSa*piq4$yOjmPin zvbmvcM%Xnwz-z({ba8ncKtZdC38Rwm8bqe}4JAaLE00`P7*+2q?OUDKxa?}F>R_hY z-l<$LTl%Y5)T`=iXo}vhQUaf;mp2U_qGw-R`ma^AzsfbKWvnk5lC)s`c=g2YWi>*D z2m}{^3Uie5O;I2OKwMCT#1S2FP`HIEP#po$@EV~&MXTsSow$O7R3H#4ckL4k=>UjO zix+^_mBt3m=|LTgZJ;=H1vM_yNz9XU0Uew@|q_U881^#h5Z$@c#MM%pozO*O=Y5Qu=$ zBY-10e#}jdL)8kF_3eF9Wp;m)9NL!Nr&yLz^&K-ChaJKb&-`i)ac)E$+r{RF7>V}+qDEfhib+s>4 zur*y*)Z7gs&r@{!nM2hKEz7I=m4u+f>h3Tv^3A1H{#9V6Jy!SE`9nK$KgpSYVuz@D zj*F`Lg_xmAkE)qCcdHfs$NIYZR+fIOpKZRaQTEyDi|W;Xs@INty-mqhYxTBvyK;H$ zMU}RrX_u#NY2N!I-lx*-%g$eRxC6%Vh=Sa_z2^N}ar(q!Ipyz(J-If`T1y=W(}a zBRc}22QEbq3Ogt+(DKw*h0#!;rvtYhpp*iDjWNUmoW*%=U1^%gWG&xw$b znWuHE3)_3D9?Dnxos6ZC)nL@V)b{DQomgFQlh!S9$!h{>|cMW42%W9oGWVz54_ zIOEV8vg(k!ZqF=qiwaOE~DsYvDXY{Le=eMdQMHK!isN(fbbjw>RKf6gy2v+ zf7B)!1vPnI6chxyAxbd-bfc*2jBG)H3)CArmGs`FCY`=B)2g=?zvFv`I{yIE+sbaK zp>O!JN8}4Xg=CAUXuRNQ(7Btsl>IcwRC_%uyXR@?gIP|WrZ!DK<2weg@xCSW+v)Bc zHJ+d1n!m?*a4F~vO(HaI9kkh_F+fz&n3~OIh{iO35W}?%C5uhd*uXvm8XHFojipcH zEdn^37crPjYf-{uNp_vZp{B6vrj*1zRna)gjiaD(!kte{u+7a;F!YrT4}zrHT5AzWt<%_` zzmMX8ewM>MKS^PpPLIPCQ%2z&&+*0#G2WYET&a3xhNSv>4+hgqMq-$$X{<|K{C5r; z@Hoci2S{u@ZP7pkWdkU#_=$~#z%YT^=qTujL;ZN8()#QnD23Vq zN(do44v}6*QymZ2Z#zjY4S+%bBjS3U=b!|15JX17ab6U!px!EWa9&pwQ3y40jk`Ml zgeZj7^&LzmcDxdZl?o7Q{Z~Yh-w>bUU)eI#Gw7ozUD>xEWK(h0MV}pLzCO+3jyBn; znA=c}I?sp4+j1DoCYIxD+S87;a5&pw1)UbPmh_kf8bNS#n{$e#cHiSz?gLHZTFRPB z9Z=k8TPn}K^!A??`hD)vccpZyQnvKE*_4N;t~BcUaBC-eUus=<>0b($8W&Mps`$-$ zVku>{g|N5Qxwbx!sF|pv>Mi3dGt{Ovto1&@?z8nC$;}?2SQLFkv8I{o1~u*f03zX9 z_iM`lsOwB+)jArY#^F=U+EhmN--|D()D+hv0$`$0L;8S-M07kj7VSG`Xtv`Mt4Mx3 zMbs7a%X~hY91XQTBGT2#mNtwu?dUZcG=gJT(bJa^1Ca<75`!c{jkvBTH9nl6Isokh zjBXStK?DL4p>f-UD1>C7I|;+6ba7q4YL1aW5`f$80t2dy=7V4Y6fXo9J@Pr_MMR5*IE3Llz+qLu*^&qH~>g~52r=hGK<2g%2jwy?YKq3P0 zn=8WXpf`o|7=ua;gU5)3>PXXG+$IAM|=sgex}WLL!4)pzmiYIc>z@u{Nm zHJmg)JB>{TWyRi}+eKeaaqn&Sr1llG|D4%DBycl*e4)vh;HnC$!Vl^~O+Y9WG;H5JR!V5ef-y(?9r{@|$V9(}Dj0<(Sl3 zfb1@c@Jy8np$^eU!ihix2Eh%wI}blj2m**s0vZTWx8K?dH*Z@;zyu13L&wq!jHuiW^H};hd|tM*ss@z07gz?AJcKxf1v!R8VGXBY+CE`4 zC|(EBCV`1)YZ}lr3`C-Mo~elpo(uuN;`%1Dtkr>GK5U+3J@K35L|nM zFr@?ElzLF)Jo>p){{XY}R^9ZS#PV$JCS?>Cf#gDsp%gk@Lx2EuXZ?8X_7@e!8Bj{_ zxcB2=xXOjtL$kp|CkE6{u(YTu>1!I*FZ50}>}y>n>{Z{SI+ga-fbE~wI{NK-L3Ocm zp1dO)R3G{4%YSOWrogvK1GJezLWvQuQl!Le0tyjnA-)h?WkDNp5Z?>y>3w)!7fK;{ z+w62yE|<^}yeR4vC{TlCLWSiP&i+)+;Wa`%><0e;do#|xq|0^bJ@C8IU2+W3^ znveT^ef@x=v_h2MJT?i+HUp;ixzUI#@J$#Ha#FrcR&ZF-e>`}RYBhY6}fVlO=abBWBvKkZ*cln^9HBMRXK$o72zcxT z<6xw~?RZnL3K0lx_x5M~&t_l};-Dk`f@C0%Wps(!dipR&YET_0+3$d68!}J! zB*Z3&+rk7L$4XSMI|1KYO7gsH5MBY4B?h9>xUU-&B>Va zfJdd$`yDRPUtI<2U7!{HI?5eCo@j2v$XryJj=(!dU4&&Bp4vT1Z@-+;_U6-1uyg`} zE6N@|qi?XIV1~oYLXXxL&_lG?T}kP5x=mkSeIeR~;U3q83KvK(v$IEipb#kb8`3N3 zceJ3PeQnYxD1;|-+JJ!T>Pqz*&9re^RJ8cFo_k zLK}mz3&@4{;IBJ$q#@*l*^bo0nMHP{5IaKfgGvoVbnT^iKyBQi-ri9_C`}TgP(X#& z-bj|A<#qmmqZfg1VIR%A*2)9`soinh2?gkefGOSG;bS(7tkdFrWZ&qm)jjH zkqS_m)>to^#b+6HWmipJw;_ZGp$H(GumuLn0UnW+c>Wf;mZPrqZZV;_*3Tac&ixRF zp9)uLrFFM^kbs3d4Z!`nT`#%r6vBiTONl6Xh%%awNxlKw>@GzP(DG!U-r*MY9sdBQ z&=R3>?mKV@Ozl7D3Oj2&d$L#@t?O}F+dGfTwoODq3+uQW5<+SUS45q;bYz*_J98xu zF$e=Bf1uluQom_I!cTiO1=!ex-nIY~Lizyj$`EiXpIxrXga+O=`ucQ~Ke6*DAPmp! zA#}c!qJ+s!5WCnf`u_l+gzP&icAxbISA{Z!&fi1A=h*i*1|R&jk`i1uP44-hTZKO z1O%vGaj@+OURJxuhGab~ymi)>1x%2KTX;in2o=h9)z?3diKO4j^#azJrEcDrl_{z_ zg4HsJM_|8X-u9m7{XFduf^rD1w);VOUt_f>f2iG~vC=3nvJgOai&{U|$_wklmE?HX zJGpcr3&I{sg>^{QwA9wmqeDPlzW)GCf1p4CvF!-hcu=BHUumO%uu&phfZUNI%YSqi zgV8Xg0$jU61VU>2JNQi<@=}CA@x)A`*<3pSE-;APxHS(bmB^``+GWTT;+l(gE9!Uq zo`N1=C>sP|CiS;#=mhBq4!}StL?RFy{T1O5f(!5Lge0OG4@En?yE zI$XNnT~aM`2F)w(SJx01*x?QHw`;Zb3i|J1EB=~Pf`>=-p3ociNZYc4j`t=5TxYf3 z{{UmjL&)>5TSA6+(aXMeO>!P~0Y_t`3txA=&q1P zN-UHB3BEY*$`Ej$2AkmPR*E;Ck<^_UI^V*cl%1n-(s%Xc`vgH#-;`U)0PVU!IFq-P z5RaHm3yN@o2&RtXxm5UsVNS!PJ@`<&E4_;8N(8B1P&+k0paSh4(14uf%2Y~Vg*~o7 zE@mbdAu<%s@`{L1oFN{NU(|)*N(lKubP<1Gr%C~I7c>l#qEnFn07*eg1{WnD?m#<9 zQl$qY(uKrwTKv>*FHh2qS!mGPb{>J+dzIRi_f!~a2d<}PsGWf`J8?}22tZE3LLOb_ zb}~>XIzV)~Wb$8Qr3z3z^oxY`v=<+>>OHjwRrH_#0I$>y1QF&D=@0BmF6?&TJ703W zNxI`{qV0{&t!t&dgbF{h1k9jOaBIH&7I^_5BeN1uo{9)<_xJmAkiOTHW_#RtkcooQ ziBf~tl`48Jgjb!XxSfI9%ALOc(b@?^wJ3jLycH2d_7~juDpaYIQB9X1N+b3IxkgavY*Z4O08oI9{3-0dRIeok9g!Oy ziJgep9fz0rlu$jc=gJ!iMS0jG9Jch;H05$|V zK&eAv+JINrNJ0)$5%Vfnl-NVdR3>@rf3w;P%7jahQ`&Cbpm`_}A{zy9hfnMG;Rs)A z%Jm-FrOq2ma>nb){rX>JHc;oFS7e>KDi1EuCzPp$Cz6Oid`VrQ(lS$5OR}MTkeZy;0XJe4A>Q6l2=s~GS41w5 z;(+gt$8QUwh*1JW1qq|S)@O<`fC%{mXgdvpCQuNd6cK4F>>^i{39^U~M1|JE7a$ac z>Qm!1uN}+w1TI;(eG~Mvbu%O zaynv{FTb<|4$}!!-mak9_z_;UuA{fB&fkzl6%cy}ZY2N}R|XGKaz^5>qPG6!PDpa( z-#=~Xbc`c1-bF`e`v)mgwaG9UgC)p39jTCWqr!>f)Kg2%b$FuPSe?OMFsl;n-Sp^();`S zUt@02=ru~uv^x{3s&QtNy*HR3dp+$age6MuN|mg$4#r|~buT^NN;Msh9*rGah_0w! zT3!xgmmrPEXcd@^YADoX(|CaHkDiy;G#+43AWUSo3 zKF%MLv*a(W<@sEDUtd$=EuB}?ELA0O>ee-`rRuH~>-?dFB8RG2N~yl6Vk=x+dYg{7 z6unx+In}*Twri^Tr(LyeySh2dk5llpPx*Hk<3rUeNFJurCdbtrebS@q797)OsCX9^YwQ%$*H|tmU0|Y~ zt-=~(RblwIS79E1lVS_CW9~XD7$BWW%hyMx>5oK z2PvI{fm7byAXn6YJSMq0(wcj7f*Zo{6rmP+kxsXRx^$1<(ws+3rEjLF=Do%aY~UJ&D>xgWQ?&;^Mk~=zH12US~{BBJ!tAfH)z)lNnizCK|!p# z)b^BE-D_aie=@ODwOxys^4l10uCjXmQIBY;ta0?;{M#DAPh8?^xtg~azn5d&=IR?K z25MVUhM=`WJ8VzSSpxj^n_M%tjdQd14MQ(!QNJy2*9?Ux7Tho&afnt0d$OA8JpTY- zocM4gB4r+vd)vzUUgQ}QGNn1txkBW%HNm#T=58NT5$S#Lxzm7>LMWB?P&=0|Q|#{Y zSo*kZ&DE=LHm24fu=OW9Xj$rJp{nZo_flNbp{#XnHU3Y{gK_FscHNf# zuU^wM{aJTZy8PgspW$Qs+nq3+v=uvs-fzhR8_0$7NcWn z`l*~x^*1kBwRQHQeM@aqtS+fl$ZD#!DBf!_^ODrn9bYAwrAeBDJ#kj)`O5Ugwoa+H z(|U@n7kXorxD-7nuT}p5;(GLI*YvXg0EG`vvefPFbRM9%H9a)RUS3-IV|e3N(`<)7 z@c|dOITb*3fxIT-MUr z-^&>5n>X6yuWD9iE#{RiEt02a{8KpUbZ}WJc5cAmwf7i1%auz<>WZ$Tq_sU)()7nW z$)2BTDunubt3@lF2dOFBUEwtyy~&}IZB}9R3i$m?ZpK(%HEeQUpO47n z@rx;5olIAxwvV&Yt#O%>yFsA`et;A|WF>ZhGyecZ;R0YL

U9O>`y^5`%(qQoUG@!^%+nESqohA+5^i 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

yG$PbVk&=_t=(_Y(1*~oX7 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

LkEBx*=`WSgy4-4CKsYsBl34JIq3zJ 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 YSsmPWP!)`(C{RcF9?6kf7=54r*;|lwlmGw# From c6d07085e6db0c71b2b04000732149d0463af5b7 Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Fri, 3 Jul 2026 16:09:18 +0200 Subject: [PATCH 10/59] Reorganize the documentation (#335) --- CONTRIBUTING.md | 13 ++---- README.md | 30 ++++++------- SECURITY.md | 18 ++++---- doc/README.md | 49 --------------------- docs/README.md | 6 +++ {doc => docs}/decisions.md | 0 doc/maintainers.md => docs/design.md | 66 +++++++++++++++++++++++----- docs/development.md | 24 ++++++++++ 8 files changed, 111 insertions(+), 95 deletions(-) delete mode 100644 doc/README.md create mode 100644 docs/README.md rename {doc => docs}/decisions.md (100%) rename doc/maintainers.md => docs/design.md (93%) create mode 100644 docs/development.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ef6af873f..4cebc1356 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to dd-trace-cpp +# Contributing to the Datadog C++ Tracer Pull requests for bug fixes are welcome. @@ -6,11 +6,6 @@ Before submitting new features or changes to current functionality, [open an issue](https://github.com/DataDog/dd-trace-cpp/issues/new) and discuss your ideas or propose the changes you wish to make. After a resolution is reached, a PR can be submitted for review. -## Code Style - -C++ code is formatted using `clang-format-14`. Before submitting code changes, run the following -command: - -```shell -bin/format -``` +Please refer to the [documentation](docs) to learn about the architecture of the Datadog of C++ Tracing +Library and the development processes, notably testing and code formatting, which are mandatory before +submitting code changes. diff --git a/README.md b/README.md index 66cb32e5e..9778eeaa5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ -# Datadog C++ Tracing Library +# Datadog C++ Tracer + +This `dd-trace-cpp` repository contains the Datadog C++ Tracer, which is the [Datadog Application +Performance Monitoring (APM)](https://docs.datadoghq.com/tracing) C++ client library. + +## Usage Example ```c++ #include @@ -37,7 +42,7 @@ int main() { } ``` -See the [examples](examples) directory for more extensive usage examples. +See the [examples](examples) for more extensive usage examples. ## Platform Support @@ -107,21 +112,12 @@ options is not needed. The `-ldd_trace_cpp` option is always needed. c++ -o my_app my_app.o -L/path/to/dd-trace-cpp/.install/lib -ldd_trace_cpp ``` -## Test - -Pass `-DDD_TRACE_BUILD_TESTING=1` to `cmake` to include the unit tests in the build. - -The resulting unit test executable is `test/tests` within the build directory. - -```shell -cmake -B build -DDD_TRACE_BUILD_TESTING=1 . -cmake --build build -j -./build/test/tests -``` +## Contributing -Alternatively, [bin/test](bin/test) is provided for convenience. +See the [contributing guidelines](CONTRIBUTING.md) if you would like to contribute to the Datadog +C++ Tracer. -## Contributing +## Security -See the [contributing guidelines](CONTRIBUTING.md) and the [maintainer docs](doc/maintainers.md) for -information on the overall structure of the repository. +If you discover a security vulnerablity in the Datadog C++ Tracer, please refer to the [Security +Policy](SECURITY.md). diff --git a/SECURITY.md b/SECURITY.md index bdd299333..4bdea8c31 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,10 +1,10 @@ -# Security Policy +# Datadog C++ Tracer Security Policy -This document outlines the security policy for the Datadog C++ client library (a.k.a. C++ tracer) -and what to do if you discover a security vulnerability in the project. Most notably, please do not -share the details in a public forum (such as in a discussion, issue, or pull request) but instead -reach out to us with the details. This gives us an opportunity to release a fix for others to -benefit from by the time details are made public. +This document outlines the security policy for the Datadog C++ Tracer and what to do if you discover +a security vulnerability in the project. Most notably, please do not share the details in a public +forum (such as in a discussion, issue, or pull request) but instead reach out to us with the +details. This gives us an opportunity to release a fix for others to benefit from by the time +details are made public. ## Supported Versions @@ -13,7 +13,5 @@ release](https://github.com/DataDog/dd-trace-cpp/releases). ## Reporting a Vulnerability -If you discover a vulnerability in the Datadog C++ client library (or any Datadog product for that -matter) please submit details to the following email address: - -* [security@datadoghq.com](mailto:security@datadoghq.com) +If you discover a vulnerability in the Datadog C++ Tracer (or any Datadog product for that matter) +please submit details to the [security@datadoghq.com](mailto:security@datadoghq.com) email address. diff --git a/doc/README.md b/doc/README.md deleted file mode 100644 index a85736de6..000000000 --- a/doc/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Logical Component Relationships - -- Vertices are components. -- Edges are ownership relationships between components. Each edge is labeled by the kind of pointer - that is used to implement the relationship. -- Components with a padlock are protected by a mutex. - -```mermaid ---- -title: Components Relationships -config: - layout: elk ---- -graph LR; - Tracer(Tracer) & TraceSegment("TraceSegment 🔒")-- shared -->Collector("Collector 🔒") & SpanSampler("SpanSampler 🔒") & TraceSampler("TraceSampler 🔒") - TraceSegment-- "`**unique**`" -->SpanData(SpanData) - Span(Span)-- shared -->TraceSegment - Span-- "`**raw**`" -->SpanData -``` - -## Objects - -- `Span` has a beginning, end, and tags. It is associated with a `TraceSegment`. -- `TraceSegment` is part of a trace. It makes sampling decisions, detects when it is finished, and - sends itself to the `Collector`. -- `Collector` receives trace segments. It provides a callback to deliver sampler modifications, if - applicable. -- `Tracer` is responsible for creating trace segments. It contains the instances of, and - configuration for, the `Collector`, `TraceSampler`, and `SpanSampler`. A tracer is created from a - `TracerConfig`. -- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. -- `SpanSampler` is used by trace segments to decide which spans to keep when the segment is dropped. -- `TracerConfig` contains all of the information needed to configure the collector, trace sampler, - and span sampler, as well as defaults for span properties. - -## Usage - -Intended usage is: - -1. Create a `TracerConfig`. -2. Use the `TracerConfig` to create a `Tracer`. -3. Use the `Tracer` to create and/or extract local root `Span`s. -4. Use `Span` to create children and/or inject context. -5. Use a `Span`'s `TraceSegment` to perform trace-wide operations. -6. When all `Span`s in `TraceSegment` are finished, the segment is sent to the - `Collector`. - -Different instances of `Tracer` are independent of each other. If an application wishes to -reconfigure tracing at runtime, it can create another `Tracer` using the new configuration. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..41d91c187 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,6 @@ +# Datadog C++ Tracer Documentation + +This directory contains documentation of the Datadog C++ Tracer, including: + +- [Design](design.md) +- [Development Processes](development.md) diff --git a/doc/decisions.md b/docs/decisions.md similarity index 100% rename from doc/decisions.md rename to docs/decisions.md diff --git a/doc/maintainers.md b/docs/design.md similarity index 93% rename from doc/maintainers.md rename to docs/design.md index 3247e5614..8dfd8b801 100644 --- a/doc/maintainers.md +++ b/docs/design.md @@ -1,16 +1,14 @@ -# Care and Feeding of Your New Tracing Library +# Datadog C++ Tracer Design -Congratulations! You are now the proud owner of a distributed tracing library. - -The primary purpose of this guide is to describe salient features of the library's design. -`dd-trace-cpp` differs considerably from its [older +The primary purpose of this guide is to describe salient features of the Datadog C++ Tracer's +design. It differs considerably from its [older sibling](https://github.com/DataDog/dd-opentracing-cpp) and [peers](https://github.com/open-telemetry/opentelemetry-cpp). This guide will also cover operations performed by maintainers of the library, such as scooping the box, applying flea medication, and regular trips to the vet. -## Design +## Architecture ### Span @@ -278,7 +276,55 @@ uses a different implementation, [class AgentHTTPClient : public HTTPClient, ...](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h), which uses Envoy's built-in HTTP facilities. libcurl is not involved at all. -### EventScheduler +### Logical Component Relationships + +- Vertices are components. +- Edges are ownership relationships between components. Each edge is labeled by the kind of pointer + that is used to implement the relationship. +- Components with a padlock are protected by a mutex. + +```mermaid +--- +title: Components Relationships +config: + layout: elk +--- +graph LR; + Tracer(Tracer) & TraceSegment("TraceSegment 🔒")-- shared -->Collector("Collector 🔒") & SpanSampler("SpanSampler 🔒") & TraceSampler("TraceSampler 🔒") + TraceSegment-- "`**unique**`" -->SpanData(SpanData) + Span(Span)-- shared -->TraceSegment + Span-- "`**raw**`" -->SpanData +``` + +Objects: + +- `Span` has a beginning, end, and tags. It is associated with a `TraceSegment`. +- `TraceSegment` is part of a trace. It makes sampling decisions, detects when it is finished, and + sends itself to the `Collector`. +- `Collector` receives trace segments. It provides a callback to deliver sampler modifications, if + applicable. +- `Tracer` is responsible for creating trace segments. It contains the instances of, and + configuration for, the `Collector`, `TraceSampler`, and `SpanSampler`. A tracer is created from a + `TracerConfig`. +- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. +- `SpanSampler` is used by trace segments to decide which spans to keep when the segment is dropped. +- `TracerConfig` contains all of the information needed to configure the collector, trace sampler, + and span sampler, as well as defaults for span properties. + +Intended usage is: + +1. Create a `TracerConfig`. +2. Use the `TracerConfig` to create a `Tracer`. +3. Use the `Tracer` to create and/or extract local root `Span`s. +4. Use `Span` to create children and/or inject context. +5. Use a `Span`'s `TraceSegment` to perform trace-wide operations. +6. When all `Span`s in `TraceSegment` are finished, the segment is sent to the + `Collector`. + +Different instances of `Tracer` are independent of each other. If an application wishes to +reconfigure tracing at runtime, it can create another `Tracer` using the new configuration. + +## EventScheduler As of this writing, `class DatadogAgent` flushes batches of finished trace segments to the Datadog Agent once every two second [by @@ -314,7 +360,7 @@ also uses a different implementation, [class EventScheduler : public EventScheduler](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h), which uses Envoy's built-in event dispatch facilities. -### Configuration +## Configuration There's a good [blog post](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) by [Alexis King](https://lexi-lambda.github.io/about.html) where she makes the case for encoding @@ -362,7 +408,7 @@ is to prevent eventual intermixing between the "configuration representation" an representation." In part, `finalize_config` already mitigates the problem. Abstaining from storing the finalized config as a data member is a step further. -### Error Handling +## Error Handling Most error scenarios within this library are individually enumerated by `enum Error::Code`, defined in [error.h](../include/datadog/error.h). @@ -514,7 +560,7 @@ operator bool` has the opposite meaning as it does in `Expected`. I wanted er be the same in the two cases, and so I specialized `Expected`. `Expected` is implemented in terms of `std::optional`, but inverts the value of `explicit operator bool`. -### Logging +## Logging Can we write a tracing library that does not do any logging by itself? The previous section describes how errors are reported by the library, and no logging is involved there. Why not leave it diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 000000000..17191469d --- /dev/null +++ b/docs/development.md @@ -0,0 +1,24 @@ +# Datadog C++ Tracer Development Processes + +## Test + +Pass `-DDD_TRACE_BUILD_TESTING=1` to `cmake` to include the unit tests in the build. + +The resulting unit test executable is `test/tests` within the build directory. + +```shell +cmake -B build -DDD_TRACE_BUILD_TESTING=1 . +cmake --build build -j +./build/test/tests +``` + +Alternatively, [bin/test](../bin/test) is provided for convenience. + +## Code Style + +C++ code is formatted using `clang-format-14`. Before submitting code changes, run the following +command: + +```shell +bin/format +``` From e128a5b9e4419b48472ba9ecfc5e4170b82cf59b Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Mon, 6 Jul 2026 19:25:24 +0200 Subject: [PATCH 11/59] Create Conventions & Rationale documentation from the Decisions one (#336) --- MODULE.bazel | 2 +- docs/README.md | 1 + docs/conventions.md | 50 +++++++++++++++++++++++++++++++++++++ docs/decisions.md | 41 ------------------------------ docs/design.md | 17 +++++++++---- include/datadog/collector.h | 15 ++++++----- 6 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 docs/conventions.md delete mode 100644 docs/decisions.md diff --git a/MODULE.bazel b/MODULE.bazel index ca9af3fdd..3b4551359 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "dd-trace-cpp", - version = "2.0.1", + version = "2.1.2", ) bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "com_google_absl") diff --git a/docs/README.md b/docs/README.md index 41d91c187..99adaf433 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,4 +3,5 @@ This directory contains documentation of the Datadog C++ Tracer, including: - [Design](design.md) +- [Conventions and Rationale](conventions.md) - [Development Processes](development.md) diff --git a/docs/conventions.md b/docs/conventions.md new file mode 100644 index 000000000..353954a9d --- /dev/null +++ b/docs/conventions.md @@ -0,0 +1,50 @@ +# Datadog C++ Tracer Conventions and Rationale + +## C++ Version + +We use **C++17** to ensure maximum compatibility. + +## Build Systems + +**CMake** is the primary build system supported, as documented in [the main Readme](../README.md). It is +how downstreams consumers, such as the Datadog Nginx module, embed the library (see +[nginx-datadog/CMakeLists.txt](https://github.com/DataDog/nginx-datadog/blob/c29a57f/CMakeLists.txt#L121)). + +**Bazel** is used internally for CI and by the Envoy integration (see +[envoy/source/extensions/tracers/datadog/BUILD](https://github.com/envoyproxy/envoy/blob/9d47ea91cc/source/extensions/tracers/datadog/BUILD#L52)). + +## C Standard Libaries + +We support **glibc** (GUN C Library) and [**musl**](https://en.wikipedia.org/wiki/Musl) (notably used by Alpine Linux). + +## C++ Standard Library vs Abseil + +Envoy uses [**Abseil**](https://abseil.io) instead of the C++ `std` types. It builds `dd-trace-cpp` +with the [-DDD_USE_ABSEIL_FOR_ENVOY +flag](https://github.com/envoyproxy/envoy/blob/9d47ea91cc/source/extensions/tracers/datadog/BUILD#L35-L38), +which is used in +[optional.h](https://github.com/DataDog/dd-trace-cpp/blob/v2.1.1/include/datadog/optional.h#L28-L49) +and +[string_view.h](https://github.com/DataDog/dd-trace-cpp/blob/v2.1.1/include/datadog/string_view.h#L30-L45). + +## Header Files Organization + +We separate public and private APIs. Public headers live in `include/datadog` and are the only ones exported. Internal headers live in `src` and are not installed. + +## Testing Frameworks + +**Catch2** is used for unit tests. + +**Google Benchmark** is used for performance benchmarks. + +## Naming Conventions + +- `class TypeName;` +- `.member_function();` +- `free_function();` +- `f(int func_arg);` +- `int local_var;` +- `int private_member_;` +- `int public_member;` +- `enum Color { red, green, blue };` +- `which_one` diff --git a/docs/decisions.md b/docs/decisions.md deleted file mode 100644 index f9bea6fac..000000000 --- a/docs/decisions.md +++ /dev/null @@ -1,41 +0,0 @@ -Here are some topics that were discussed during the design of this library. - -- Which version of C++ do we require? - - C++17 -- Which C core libraries do we produce binaries for? - - glibc - - musl -- Which build systems do we support? - - CMake - - Bazel -- Which unit testing framework? - - Catch2 - - Google Test -- Error handling options: - - `std::variant` - - homebrew a `std::expected` - - `throw Error(...)` - - `RCode do_thing(T& output)` - - `struct Result { Error error; T value; }` -- Is a `Span` RAII with respect to start/finish? -- When we begin calculating trace metrics within the tracer, we'll need to hit a `/stats` HTTP - endpoint. - - Does it live on the same thread as the `Collector`? - - Do we invent a library-specific `HTTPClient` interface? -- Do we keep using cURL for the default `Collector`? - - In-tree C++ library instead? -- Naming conventions: - - `class TypeName;` - - `.member_function();` - - `free_function();` - - `f(int func_arg);` - - `int local_var;` - - `int private_member_;` - - `int public_member;` - - `enum Color { red, green, blue };` - - `which_one` -- Can tracing be reconfigured at runtime? -- Can multiple tracers share a collector? -- Are rate limits per-tracer, per-process, or other? -- Which clang-format version and configuration do we use? -- Do we separate "public" and "private" APIs, or do we export all headers? diff --git a/docs/design.md b/docs/design.md index 8dfd8b801..6a15556af 100644 --- a/docs/design.md +++ b/docs/design.md @@ -185,11 +185,13 @@ in a subsequent section. `class Collector` is an interface for sending a `TraceSegment`'s spans somewhere once they're all done. It's defined in [collector.h](../include/datadog/collector.h). -It's just one function: `send`. More of a callback than an interface. +It's just one function: `send()`. More of a callback than an interface. A `Collector` is either created by `Tracer` or injected into its configuration. The `Collector` instance is then shared with all `TraceSegment`s created by the `Tracer`. The only thing that a -`TraceSegment` does with the `Collector` is call `send` once the segment is finished. +`TraceSegment` does with the `Collector` is call `send()` once the segment is finished. + +A `Collector` can also be shared by several `Tracer`s. The default implementation is `DatadogAgent`, which is described in the next section. @@ -306,8 +308,10 @@ Objects: - `Tracer` is responsible for creating trace segments. It contains the instances of, and configuration for, the `Collector`, `TraceSampler`, and `SpanSampler`. A tracer is created from a `TracerConfig`. -- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. +- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. It is owned + exclusively by one `Tracer`. - `SpanSampler` is used by trace segments to decide which spans to keep when the segment is dropped. + It is owned exclusively by one `Tracer`. - `TracerConfig` contains all of the information needed to configure the collector, trace sampler, and span sampler, as well as defaults for span properties. @@ -321,8 +325,11 @@ Intended usage is: 6. When all `Span`s in `TraceSegment` are finished, the segment is sent to the `Collector`. -Different instances of `Tracer` are independent of each other. If an application wishes to -reconfigure tracing at runtime, it can create another `Tracer` using the new configuration. +Different instances of `Tracer` are independent of each other. + +If an application wishes to reconfigure tracing at runtime, it can create another `Tracer` using the +new configuration. Some behavior (sampling rate / rules, trace reporting, tags) is reconfigurable at +runtime via Remote Config, through `ConfigManager`. ## EventScheduler diff --git a/include/datadog/collector.h b/include/datadog/collector.h index 5198834ff..72ba27237 100644 --- a/include/datadog/collector.h +++ b/include/datadog/collector.h @@ -15,18 +15,18 @@ #include "expected.h" -namespace datadog { -namespace tracing { +namespace datadog::tracing { struct SpanData; class TraceSampler; class Collector { public: - // Submit ownership of the specified `spans` to the collector. If the - // collector delivers a response relevant to trace sampling, reconfigure the - // sampler using the specified `response_handler`. Return an error if one - // occurs. + // Submit ownership of the specified `spans` to the collector. + // If the collector delivers a response relevant to trace sampling, + // reconfigure the sampler using the specified `response_handler`. Return an + // error if one occurs. This must be safe to call from multiple threads + // concurrently. virtual Expected send( std::vector>&& spans, const std::shared_ptr& response_handler) = 0; @@ -43,5 +43,4 @@ class Collector { virtual ~Collector() {} }; -} // namespace tracing -} // namespace datadog +} // namespace datadog::tracing From cfeb95292b3a94686fd4f5ba408197dadfb854c7 Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Mon, 13 Jul 2026 11:27:44 +0200 Subject: [PATCH 12/59] Huge update of the Design documentation (#338) --- docs/design.md | 675 ++++++++----------------- include/datadog/collector.h | 11 +- include/datadog/datadog_agent_config.h | 2 +- include/datadog/error.h | 6 +- include/datadog/event_scheduler.h | 15 +- include/datadog/expected.h | 6 +- include/datadog/http_client.h | 15 +- include/datadog/logger.h | 4 +- include/datadog/rate.h | 4 +- include/datadog/span.h | 19 +- include/datadog/span_sampler_config.h | 6 +- include/datadog/trace_sampler_config.h | 6 +- include/datadog/trace_segment.h | 20 +- include/datadog/tracer.h | 16 +- include/datadog/tracer_config.h | 8 +- src/datadog/datadog_agent.h | 4 +- src/datadog/threaded_event_scheduler.h | 7 +- 17 files changed, 295 insertions(+), 529 deletions(-) diff --git a/docs/design.md b/docs/design.md index 6a15556af..17ff38af6 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,99 +1,66 @@ # Datadog C++ Tracer Design The primary purpose of this guide is to describe salient features of the Datadog C++ Tracer's -design. It differs considerably from its [older -sibling](https://github.com/DataDog/dd-opentracing-cpp) and -[peers](https://github.com/open-telemetry/opentelemetry-cpp). - -This guide will also cover operations performed by maintainers of the library, such as scooping the -box, applying flea medication, and regular trips to the vet. +design. ## Architecture ### Span -[class Span](../include/datadog/span.h) is the component with which users will interact the most. -Each span: +[Span](../include/datadog/span.h) is the component with which users will interact the most. Each +span: -- has an "ID," -- is associated with a "trace ID," -- is associated with a "service," which has a "service type," a "version," and an "environment," +- has an "ID", +- is associated with a "trace ID", +- is associated with a "service", which has a "version", and an "environment", - has a "name" (sometimes called the "operation name"), -- has a "resource name," which is a description of the thing that the span is about, +- has a "resource name", which is a description of the thing that the span is about, - contains information about whether an error occurred during the represented operation, including an error message, error type, and stack trace, -- includes an arbitrary name/value mapping of strings, called "tags," -- has a start time indicating when the represented operation began, -- has a duration indicating how long the represented operation took to finish. +- includes an arbitrary name/value mapping of strings, called "tags", +- includes an arbitrary name/value mapping of numbers, called "metrics" (we may change this to a map + of primitives, as in [OpenTelemetry span + attributes](https://opentelemetry.io/docs/specs/otel/common/#attribute-collections)), +- has a "start time" indicating when the represented operation began, +- has a "duration", known only once it finishes, indicating how long the represented operation took. Aside from setting and retrieving its attributes, `Span` also has the following operations: -- `parent.create_child(...)` returns a new `Span` that is a child of `parent`. -- `span.inject(writer)` writes trace propagation information to a +- `Span::create_child()` returns a new `Span` that is a child of this `Span`. +- `Span::inject(writer)` writes trace propagation information to a [DictWriter](../include/datadog/dict_writer.h), which is an interface for setting a name/value mapping, e.g. in HTTP request headers. -A `Span` does not own its data. `class Span` contains a raw pointer to a [class -SpanData](../src/datadog/span_data.h), which contains the actual attributes of the span. The +A `Span` does not own its data. `Span` contains a raw pointer to a +[SpanData](../src/datadog/span_data.h), which contains the actual attributes of the `Span`. The `SpanData` is owned by a `TraceSegment`, which is described in the next section. The `Span` holds a -`shared_ptr` to its `TraceSegment`. +`shared_ptr` to its `TraceSegment`, retrievable via `Span::trace_segment()`. -By default, a span's start time is when it is created, and its end time (from which its duration is -calculated) is when it is destroyed. However, a span's start time can be specified when it is +By default, a `Span`'s start time is when it is created, and its end time (from which its duration +is calculated) is when it is destroyed. However, a `Span`'s start time can be specified when it is created, via `SpanConfig::start` (see [span_config.h](../include/datadog/span_config.h)), and a -span's end time can be overridden via `Span::set_end_time`. - -When a span is destroyed, it is considered "finished" and notifies its `TraceSegment`. There is no -way to "finish" a span without destroying it. You can override its end time throughout the lifetime -of the `Span` object, but a `TraceSegment` does not consider the span finished until the `Span` -object is destroyed. This allows us to avoid "finished" `Span` states. +span's end time can be overridden via `Span::set_end_time()`. -Along similar lines, `class Span` is move-only. Its copy constructor is deleted. Functions that -produce spans return them by value, but only one copy of a span can exist at a time. In fact, `class -Span` is even more strict than move-only: its assignment operator is deleted, including the -move-assignment operator. To see why, consider the following (disallowed) example: +When a `Span` is destroyed, it is considered "finished" and notifies its `TraceSegment`. There is no +way to "finish" a `Span` without destroying it. You can override its end time throughout the +lifetime of the `Span` object, but a `TraceSegment` does not consider the `Span` finished until the +`Span` object is destroyed. This allows us to avoid "finished" `Span` states. -```c++ -Span span = tracer.create_span(); -// ... -// Let's reuse the variable `span`. -span = tracer.create_span(); -``` +Along similar lines, `Span` is move-only. Its copy constructor is deleted. Functions that produce +`Span`s return them by value, but only one copy of a `Span` can exist at a time. -Move assignment begins with two objects and ends up with one object (and one empty shell of an -object). - -Since destroying a `Span` has the side effect of finishing it, one sensible definition of -`Span::operator=(Span&& other)` would be equivalent to: - -```c++ -this->~Span(); -new (this) Span(std::move(other)); -return *this; -``` - -This would have the potentially surprising feature of _finishing_ the first span when you wish to -replace it with another, i.e. there would always be two spans. - -This could be avoided if we could guarantee that the two `Span`s belong to the same `TraceSegment`. -Then move-assigning a `Span` could be defined as move-assigning its `SpanData` and somehow -annotating the moved-from `SpanData` as being invalid. However, if the two `Span`s belong to -different `TraceSegment`s, then it could be that the moved-to `Span`'s `TraceSegment` consists of -only that one `Span`. Now we have to account for empty `TraceSegment` states. This could all be -dealt with, but no matter what we decide, it would always be the case that `Span::operator=(Span&&)` -has the effect of making the original span (`this`) either finish implicitly or _disappear -entirely_, which is at odds with its otherwise -[RAII](https://en.cppreference.com/w/cpp/language/raii) nature. - -To avoid these issues, assignment to `Span` objects is disallowed. +`Span` is even stricter than move-only: its assignment operator is deleted too, including +move-assignment. Since destroying a `Span` finishes it, move-assignment would have to either finish +the original `Span` early or leave two `Span`s referring to one finished state, both at odds with +its otherwise [RAII](https://en.cppreference.com/w/cpp/language/raii) nature. Another opinionated property of `Span` is that it is not an interface, nor does it implement an interface. Usually it is considered polite for a C++ library to deal in handles (`unique_ptr` or `shared_ptr`) to interfaces, i.e. classes that contain pure virtual functions. This way, a client of -the library can substitute an alternative implementation to the interface(s) for testing or for when -the behavior of the library is not desired. +the library can substitute an alternative implementation for the interface(s) for testing or for +when the behavior of the library is not desired. -At the risk of being impolite, dd-trace-cpp takes a different approach. `Span` is a concrete type +At the risk of being impolite, `dd-trace-cpp` takes a different approach. `Span` is a concrete type whose behavior cannot be substituted. Instead, there are other places in the library where dependency injection can be used to restrict or alter the behavior of the library. The trade-off is that `Span` and related components must always "go through the motions" of their definitions and @@ -104,15 +71,15 @@ that accompany handle-to-interface are avoided. A "trace" is the entire tree of spans having the same trace ID. -Within one process / worker / service, though, typically there is not an entire trace but only part -of the trace. Let's call the process / worker / service a "tracer." +Within one process/worker/service, though, typically there is not an entire trace but only part +of the trace. Let's call the process/worker/service a "tracer". -One portion of a trace that's passing through the tracer is called a "trace segment." A trace -segment begins either at the trace's root span or at a span extracted from trace context, e.g. a -span created from the `X-Datadog-Trace-Id` and `X-Datadog-Parent-Id` HTTP request headers. The trace -segment includes all local descendants of that span, and has as its "boundary" any descendant spans -without children or descendant spans that were used to inject trace context out-of-tracer, e.g. in -outgoing HTTP request headers. +One portion of a trace that's passing through the tracer is called a "trace segment". This is a +Datadog-specific concept. A trace segment begins either at the trace's root span or at a span +extracted from trace context, e.g. a span created from the `X-Datadog-Trace-Id` and +`X-Datadog-Parent-Id` HTTP request headers. The trace segment includes all local descendants of that +span, and has as its "boundary" any descendant spans without children or descendant spans that were +used to inject trace context out-of-tracer (described in a subsequent section). There might be more than one trace segment for the _same trace_ within a tracer. For example, in the diagram below, the trace passes through the "Service A" tracer twice. So for this trace, this tracer @@ -129,78 +96,115 @@ block space:4 g["Service A - Trace segment A2 - Span A5"] h["Service A - Trace segment A2 - Span A6"] space:2 ``` -`class TraceSegment` is defined in [trace_segment.h](../include/datadog/trace_segment.h). -`TraceSegment` objects are managed internally by the library. That is to say, a user never creates a +`TraceSegment` is defined in [trace_segment.h](../include/datadog/trace_segment.h). `TraceSegment` +objects are managed internally by the library. That is to say, a user never creates a `TraceSegment`. The library creates a `TraceSegment` whenever a new trace is created or when trace context is -extracted. This is the job of `class Tracer`, described in the next section. +extracted. This is the job of `Tracer`, described in the next section. -Primarily, `TraceSegment` is a bag of spans. It contains a `vector>`. `Span` -objects then refer to the `SpanData` objects via raw pointers. Now that I think about it, -`deque` would work just as well. +Primarily, `TraceSegment` is a bag of `Span`s. It contains a `vector>`. `Span` +objects then refer to the `SpanData`s via raw pointers. -When one of a trace segment's spans creates a child, the child is registered with the trace segment. -When a span is finished, the trace segment is notified. The trace segment keeps track of how many -spans it contains (the size of its `vector`) and how many spans are finished. When the two numbers -are equal, the trace segment is finished. +When one of a `TraceSegment`'s `Span`s creates a child, the child is registered with the +`TraceSegment`. When a `Span` is finished, the `TraceSegment` is notified. The `TraceSegment` keeps +track of how many `Span`s it contains (the size of its `vector`) and how many `Span`s are finished. +When the two numbers are equal, the `TraceSegment` is finished. -When a trace segment is finished, it performs some finalization logic in order to prepare its spans -for submission to the `Collector`. Then it moves its spans into the collector via `Collector::send`, -and a short time later the trace segment is destroyed. See `TraceSegment::span_finished` in -[trace_segment.cpp](../src/datadog/trace_segment.cpp). `Collector` is described in a subsequent -section. +When a `TraceSegment` is finished, it uses a `TraceSampler` to decide whether to keep or drop +itself, and, if it is dropped, a `SpanSampler` to decide which `Span`s to keep anyway. It then +performs finalization logic in order to prepare its `Span`s for submission to the `Collector`. Then +it moves its `Span`s into the `Collector` via `Collector::send()`, and a short time later the +`TraceSegment` is destroyed. See `TraceSegment::span_finished()`. `Collector` is described in a +subsequent section. -A `TraceSegment` contains `shared_ptr`s to everything that it needs in order to do its job. Those -objects are created by `class Tracer` when the tracer is configured, and then shared with -`TraceSegment` when the `TraceSegment` is created. +A `TraceSegment` contains `shared_ptr`s to the main objects it needs in order to do its job. Those +objects are created by `Tracer` when it is configured, and then shared with `TraceSegment` when the +`TraceSegment` is created. ### Tracer -`class Tracer` is what users configure, and it is how `Span`s are extracted from trace context or -created as a trace's root. See [tracer.h](../include/datadog/tracer.h). +`Tracer` is what users configure, and it is how `Span`s are extracted from trace context or created +as a trace's root. See [tracer.h](../include/datadog/tracer.h). -`Tracer` has two member functions: +A `Tracer` owns a `Collector`, a `SpanSampler`, and a `ConfigManager`. `SpanSampler` and +`ConfigManager` are owned exclusively by one `Tracer`. `ConfigManager` in turn owns a +`TraceSampler`. -- `create_span(...)` -- `extract_span(...)` +Different `Tracer` instances are independent of each other, even if they share a `Collector`. -and another that combines them: +A `Tracer` is constructed from a `TracerConfig`, which configures these objects and many other +aspects of a `Tracer`'s behavior (span defaults, propagation styles, telemetry, and more; see +[tracer_config.h](../include/datadog/tracer_config.h)). To change most of a `Tracer`'s behavior, an +application constructs a new `Tracer` from a new `TracerConfig`. -- `extract_or_create_span(...)`. +`Tracer` has two main member functions: `Tracer::create_span()` and `Tracer::extract_span()`, and +another that combines them: `Tracer::extract_or_create_span()`. All of these result in the creation of a new `TraceSegment` (or otherwise return an error). The -`Tracer`'s data members, which were initialized based on the tracer's configuration, are copied into +`Tracer`'s data members, which were initialized based on the tracer's configuration, are passed to the `TraceSegment` so that the `TraceSegment` can operate independently. -Note how `create_span` never fails. This is a nice property. `extract_span` _can_ fail. +Note how `Tracer::create_span()` never fails, whereas `Tracer::extract_span()` can fail. -The bulk of `Tracer`'s implementation is `extract_span`. The other substantial work is +The bulk of `Tracer`'s implementation is `Tracer::extract_span()`. The other substantial work is configuration, which is handled by `finalize_config(const TracerConfig&)`, declared in [tracer_config.h](../include/datadog/tracer_config.h). Configuration will be described in more depth in a subsequent section. -### Collector +### Trace Context Propagation + +Trace context propagation is how spans in different tracers become part of the same trace. When a +trace crosses a tracer boundary (e.g. an outgoing HTTP request), the trace ID, the ID of the span +that initiated the request, and the trace's sampling decision must travel with it, so that the +receiving tracer can create spans belonging to the same trace. -`class Collector` is an interface for sending a `TraceSegment`'s spans somewhere once they're all -done. It's defined in [collector.h](../include/datadog/collector.h). +There are two directions: -It's just one function: `send()`. More of a callback than an interface. +- Extraction: `Tracer::extract_span()` reads trace context from a carrier (e.g. incoming HTTP + headers), and uses it to create a `Span` that continues the trace. +- Injection: `Span::inject()` writes the current trace context into a carrier (e.g. outgoing HTTP + headers). -A `Collector` is either created by `Tracer` or injected into its configuration. The `Collector` -instance is then shared with all `TraceSegment`s created by the `Tracer`. The only thing that a -`TraceSegment` does with the `Collector` is call `send()` once the segment is finished. +Several wire formats, "propagation styles", are supported. A `Tracer` can be configured with +multiple styles for both injection and extraction. -A `Collector` can also be shared by several `Tracer`s. +A trace's sampling decision, once made, is part of what gets propagated: every tracer the trace +passes through agrees on whether it's kept or dropped, rather than deciding independently. + +Propagation can also be suppressed: if tracing is disabled for a trace and no other product depends +on it continuing, context is not injected at all. + +`Tracer` can also propagate W3C `Baggage`, a key/value store for application data that is not +inherently part of a distributed trace, but is propagated across services alongside it. It is +defined in [baggage.h](../src/datadog/baggage.h). It is enabled by a trace context propagation +style, and it uses the same carrier abstraction. `Tracer::create_baggage()` creates one, +`Tracer::extract_baggage()` / `Tracer::extract_or_create_baggage()` read one from a carrier, and +`Tracer::inject()` writes one to a carrier. + +### Collector + +`Collector` is an interface for sending a `TraceSegment`'s spans somewhere once they're all done. +It's defined in [collector.h](../include/datadog/collector.h). + +It has one main function: `Collector::send()`. More of a callback than an interface. `send()` also +takes a `TraceSampler` as a `response_handler`, which an implementation may use to update the trace +sampling rates based on the response it gets back when delivering spans (e.g. from the Datadog +Agent). + +A `Collector` is either created by `Tracer` or injected into its configuration. A `Collector` can be +shared by several `Tracer`s. The `Collector` is then shared with all `TraceSegment`s created by the +`Tracer`. The only thing that a `TraceSegment` does with the `Collector` is call `Collector::send()` +once the segment is finished. The default implementation is `DatadogAgent`, which is described in the next section. ### DatadogAgent -`class DatadogAgent` is the default implementation of `Collector`. It's defined in +`DatadogAgent` is the default implementation of `Collector`. It's defined in [datadog_agent.h](../src/datadog/datadog_agent.h). -`DatadogAgent` sends trace segments to the [Datadog Agent](../include/datadog/http_client.h) in +`DatadogAgent` sends trace segments to the [Datadog Agent](https://docs.datadoghq.com/agent) in batches that are flushed periodically. In order to do this, `DatadogAgent` needs a means to make HTTP requests and a means to set a timer for the flush operation. So, there are two interfaces: [HTTPClient](../include/datadog/http_client.h) and @@ -209,73 +213,50 @@ HTTP requests and a means to set a timer for the flush operation. So, there are The `HTTPClient` and `EventScheduler` can be injected as part of `DatadogAgent`'s [configuration](../include/datadog/datadog_agent_config.h), which is usually specified via the `agent` member of `Tracer`'s [configuration](../include/datadog/tracer_config.h). If they're not -specified, then default implementations are used: +specified, then default implementations are used: `Curl` and `ThreadedEventScheduler` (described in +subsequent sections). -- [class Curl : public HTTPClient](../src/datadog/curl.h), which uses libcurl's [multi - interface](https://curl.se/libcurl/c/libcurl-multi.html) together with a dedicated thread as an - event loop. -- [class ThreadedEventScheduler : public EventScheduler](../src/datadog/threaded_event_scheduler.h), -- which uses a dedicated thread for executing scheduled events at the correct time. +`DatadogAgent::flush()` is periodically called by an `EventScheduler`. `flush()` uses the HTTP +client to send a `POST` request to the Datadog Agent's `/v0.4/traces` endpoint. It's all +callback-based. -`DatadogAgent::flush` is periodically called by the event scheduler. `flush` uses the HTTP client to -send a POST request to the Datadog Agent's -[/v0.4/traces](https://github.com/DataDog/datadog-agent/blob/9d57c10a9eeb3916e661d35dbd23c6e36395a99d/pkg/trace/api/version.go#L22) -endpoint. It's all callback-based. +`DatadogAgent` also periodically polls the Agent's `/v0.7/config` endpoint for Remote Configuration +updates, via `EventScheduler`. Responses are dispatched to registered `remote_config::Listener`s, +including `ConfigManager`, which is how sampling rate/rules, trace reporting, and tags can be +reconfigured at runtime (without creating a new `Tracer`). ### HTTPClient -`class HTTPClient` is an interface for sending HTTP requests. It's defined in +`HTTPClient` is an interface for sending HTTP requests. It's defined in [http_client.h](../include/datadog/http_client.h). -The only kind of HTTP request that the library needs to make, currently, is a POST to the Datadog -Agent's traces endpoint. `HTTPClient` has one member function for each HTTP method needed — so, -currently just the one: +The only needed HTTP method is `POST` (for requests to the Datadog Agent's endpoints). `HTTPClient` +has one member function for each HTTP method needed, so, currently just `HTTPClient::post()`. It's +callback-based and returns almost immediately. -```c++ -virtual Expected post(const URL& url, HeadersSetter set_headers, - std::string body, ResponseHandler on_response, - ErrorHandler on_error) = 0; -``` - -It's callback-based. `post` returns almost immediately. It invokes `set_headers` before returning, -in order to get the HTTP request headers. The request `body` is moved elsewhere for later -processing. One of `on_response` or `on_error` will eventually be called, depending on whether a -response was received or if an error occurred before a response was received. If something goes -wrong setting up the request, then `post` returns an error. If `post` returns an error, then neither -of `on_response` nor `on_error` will be called. +`HTTPClient` also has another method, `HTTPClient::drain()`, which waits for any in-flight requests +to finish. It's used to ensure "clean shutdown". Without it, on average the last one second of +traces would be lost on shutdown. Implementations of `HTTPClient` that don't have a dedicated thread +need not support `drain()`; in those cases, `drain()` returns immediately. -`HTTPClient` also has another member function: - -```c++ -virtual void drain(std::chrono::steady_clock::time_point deadline) = 0; -``` +The default implementation of `HTTPClient` is `Curl`, defined in [curl.h](../src/datadog/curl.h), +which uses libcurl's [multi interface](https://curl.se/libcurl/c/libcurl-multi.html) together with a +dedicated thread as an event loop. -`drain` waits for any in-flight requests to finish, blocking up until no later than `deadline`. It's -used to ensure "clean shutdown." Without it, on average the last one second of traces would be lost -on shutdown. Implementations of `HTTPClient` that don't have a dedicated thread need not support -`drain`; in those cases, `drain` returns immediately. - -The default implementation of `HTTPClient` is [class Curl : public -HTTPClient](../src/datadog/curl.h), which uses libcurl's [multi -interface](https://curl.se/libcurl/c/libcurl-multi.html) together with a dedicated thread as an -event loop. - -`class Curl` is also used within NGINX in Datadog's Nginx module, +`Curl` is also used in Datadog's Nginx module, [nginx-datadog](https://github.com/DataDog/nginx-datadog). This is explicitly [discouraged](https://nginx.org/en/docs/dev/development_guide.html#http_requests_to_ext) in Nginx's -developer documentation, but libcurl-with-a-thread is widely used within NGINX modules regardless. -One improvement that I am exploring is to use libcurl's +developer documentation, but libcurl-with-a-thread is widely used within Nginx modules regardless. +One possible improvement would be using libcurl's "[multi_socket](https://curl.se/libcurl/c/curl_multi_socket_action.html)" mode, which allows libcurl to utilize someone else's event loop, obviating the need for another thread. libcurl can then be -made to use NGINX's event loop, as is done in [an example +made to use Nginx's event loop, as is done in [an example library](https://github.com/dgoffredo/nginx-curl). -For now, though, nginx-datadog uses the threaded `class Curl`. - [Envoy's Datadog tracing integration](https://github.com/envoyproxy/envoy/tree/main/source/extensions/tracers/datadog#datadog-tracer) -uses a different implementation, [class AgentHTTPClient : public HTTPClient, -...](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h), +uses a different implementation, +[AgentHTTPClient](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h), which uses Envoy's built-in HTTP facilities. libcurl is not involved at all. ### Logical Component Relationships @@ -292,29 +273,14 @@ config: layout: elk --- graph LR; - Tracer(Tracer) & TraceSegment("TraceSegment 🔒")-- shared -->Collector("Collector 🔒") & SpanSampler("SpanSampler 🔒") & TraceSampler("TraceSampler 🔒") + Tracer(Tracer) & TraceSegment("TraceSegment 🔒")-- shared -->Collector("Collector 🔒") & SpanSampler("SpanSampler 🔒") + Tracer & TraceSegment-- shared -->ConfigManager("ConfigManager 🔒") + ConfigManager & TraceSegment-- shared -->TraceSampler("TraceSampler 🔒") TraceSegment-- "`**unique**`" -->SpanData(SpanData) Span(Span)-- shared -->TraceSegment Span-- "`**raw**`" -->SpanData ``` -Objects: - -- `Span` has a beginning, end, and tags. It is associated with a `TraceSegment`. -- `TraceSegment` is part of a trace. It makes sampling decisions, detects when it is finished, and - sends itself to the `Collector`. -- `Collector` receives trace segments. It provides a callback to deliver sampler modifications, if - applicable. -- `Tracer` is responsible for creating trace segments. It contains the instances of, and - configuration for, the `Collector`, `TraceSampler`, and `SpanSampler`. A tracer is created from a - `TracerConfig`. -- `TraceSampler` is used by trace segments to decide when to keep or drop themselves. It is owned - exclusively by one `Tracer`. -- `SpanSampler` is used by trace segments to decide which spans to keep when the segment is dropped. - It is owned exclusively by one `Tracer`. -- `TracerConfig` contains all of the information needed to configure the collector, trace sampler, - and span sampler, as well as defaults for span properties. - Intended usage is: 1. Create a `TracerConfig`. @@ -322,220 +288,109 @@ Intended usage is: 3. Use the `Tracer` to create and/or extract local root `Span`s. 4. Use `Span` to create children and/or inject context. 5. Use a `Span`'s `TraceSegment` to perform trace-wide operations. -6. When all `Span`s in `TraceSegment` are finished, the segment is sent to the - `Collector`. - -Different instances of `Tracer` are independent of each other. - -If an application wishes to reconfigure tracing at runtime, it can create another `Tracer` using the -new configuration. Some behavior (sampling rate / rules, trace reporting, tags) is reconfigurable at -runtime via Remote Config, through `ConfigManager`. +6. When all `Span`s in a `TraceSegment` are finished, the segment is sent to the `Collector`. ## EventScheduler -As of this writing, `class DatadogAgent` flushes batches of finished trace segments to the Datadog -Agent once every two second [by -default](https://github.com/DataDog/dd-trace-cpp/blob/ca155b3da65c2dc235cf64a28f8e0d8fdab3700c/src/datadog/datadog_agent_config.h#L50-L51). +`DatadogAgent` uses an `EventScheduler` to schedule its recurring work, at fixed intervals. -It does this by scheduling a recurring event with an `EventScheduler`, which is an interface defined -in [event_scheduler.h](../include/datadog/event_scheduler.h). +`EventScheduler` is an interface defined in +[event_scheduler.h](../include/datadog/event_scheduler.h). It has one main member function, +`EventScheduler::schedule_recurring_event()`, which registers a callback to be invoked repeatedly. -`EventScheduler` has one member function: +The default implementation of `EventScheduler` is `ThreadedEventScheduler`, defined in +[threaded_event_scheduler.h](../src/datadog/threaded_event_scheduler.h), which uses a dedicated +thread for executing scheduled events at the correct time. -```c++ -virtual Cancel schedule_recurring_event( - std::chrono::steady_clock::duration interval, - std::function callback) = 0; -``` - -Every `interval`, the scheduler will invoke `callback`, starting an initial `interval` after -`schedule_recurring_event` is called. The caller can invoke the returned `Cancel` to prevent -subsequent invocations of `callback`. - -The default implementation of `EventScheduler` is [class ThreadedEventScheduler : public -EventScheduler](../src/datadog/threaded_event_scheduler.h), which uses a dedicated thread for -executing scheduled events at the correct time. It was a fun piece of code to write. - -Datadog's Nginx module, [nginx-datadog](https://github.com/DataDog/nginx-datadog) uses a different -implementation, [class NgxEventScheduler : public -EventScheduler](https://github.com/DataDog/nginx-datadog/blob/master/src/ngx_event_scheduler.h), +[Datadog Nginx module](https://github.com/DataDog/nginx-datadog) uses a different implementation, +[NgxEventScheduler](https://github.com/DataDog/nginx-datadog/blob/master/src/ngx_event_scheduler.h), which uses Nginx's own event loop instead of a dedicated thread. [Envoy's Datadog tracing integration](https://github.com/envoyproxy/envoy/tree/main/source/extensions/tracers/datadog#datadog-tracer) -also uses a different implementation, [class EventScheduler : public -EventScheduler](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h), +also uses a different implementation, +[EventScheduler](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h), which uses Envoy's built-in event dispatch facilities. ## Configuration -There's a good [blog post](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) by -[Alexis King](https://lexi-lambda.github.io/about.html) where she makes the case for encoding -configuration validation into the type system. Forbid invalid states by making configurable -components accept a different type than that which is used to specify configuration. - -This is not a new idea. It's been used, for example, to "taint" strings that originate as program -inputs. Then you can't accidentally pass user-influenced inputs to, say, `std::system`, because -`std::system` takes a `const char*`, not a `class UserTaintedString`. There's still ample -opportunity to cast away the taint and sneak it into some string building operation, but at least -`class UserTaintedString` gives hope that a static analysis tool could be used to fill in some gaps -in human code review. +This library encodes configuration validation into the type system (see ["Parse, don't validate" by +Alexis King](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate)). Invalid states +are forbidden by making configurable components accept a different, validated type than the one used +to specify configuration. -This library adopts that approach for configuration. The configuration of `class Tracer` is `class -TracerConfig`, but in order to construct a `Tracer` you must first convert the `TracerConfig` into a -`FinalizedTracerConfig` by calling `finalize_config`. If there is anything wrong with the -`TracerConfig` or with environment variables that would override it, `finalize_config` will return -an `Error` instead of a `FinalizedTracerConfig`. In that case, you can't create a `Tracer` at all. +The configuration of `Tracer` is `TracerConfig`, but in order to construct a `Tracer` you must first +convert the `TracerConfig` into a `FinalizedTracerConfig` by calling `finalize_config()`. If there +is anything wrong with the `TracerConfig` or with environment variables that would override it, +`finalize_config()` will return an `Error` instead of a `FinalizedTracerConfig`. In that case, you +can't create a `Tracer` at all. This technique applies to multiple components: | Component | Unvalidated | Validated | Parser | -| --------------- | ----------- | --------- | ----------------- | -| `Tracer` | `TracerConfig` | `FinalizedTracerConfig` | `finalize_config` in [tracer_config.h](../include/datadog/tracer_config.h) | -| `DatadogAgent` | `DatadogAgentConfig` | `FinalizedDatadogAgentConfig` | `finalize_config` in [datadog_agent_config.h](../include/datadog/datadog_agent_config.h) | -| `TraceSampler` | `TraceSamplerConfig` | `FinalizedTraceSamplerConfig` | `finalize_config` in [trace_sampler_config.h](../include/datadog/trace_sampler_config.h) | -| `SpanSampler` | `SpanSamplerConfig` | `FinalizedSpanSamplerConfig` | `finalize_config` in [span_sampler_config.h](../include/datadog/span_sampler_config.h) | -| multiple | `double` | `Rate` | `Rate::from` in [rate.h](../include/datadog/rate.h) | - -An alternative approach, that Caleb espouses, is to accept invalid configuration quietly. When -invalid configuration is detected, the library could substitute a reasonable default and then send -notice of the configuration issue to Datadog, e.g. as a hidden span tag. That information would then -be available to Support should the customer raise an issue due to a difference in behavior between -what they see and what they think they configured. This approach is also resilient to dynamic -configuration changes. Rather than a "bad config update" causing tracing to cease completely, -instead tracing could continue to operate in the defaulted mode. - -This library uses the stricter approach. The downside is that a user of the library has to decide -what to do when even the slightest part of the configuration or environment is deemed invalid. +| --------- | ----------- | --------- | ------ | +| `Tracer` | `TracerConfig` | `FinalizedTracerConfig` | `finalize_config()` in [tracer_config.h](../include/datadog/tracer_config.h) | +| `DatadogAgent` | `DatadogAgentConfig` | `FinalizedDatadogAgentConfig` | `finalize_config()` in [datadog_agent_config.h](../include/datadog/datadog_agent_config.h) | +| `TraceSampler` | `TraceSamplerConfig` | `FinalizedTraceSamplerConfig` | `finalize_config()` in [trace_sampler_config.h](../include/datadog/trace_sampler_config.h) | +| `SpanSampler` | `SpanSamplerConfig` | `FinalizedSpanSamplerConfig` | `finalize_config()` in [span_sampler_config.h](../include/datadog/span_sampler_config.h) | +| multiple | `double` | `Rate` | `Rate::from()` in [rate.h](../include/datadog/rate.h) | One other convention of the library is that `FinalizedFooConfig` (for some `Foo`) is never a data member of the configured component class. That is, `FinalizedTracerConfig` is not stored in `Tracer`. Instead, a constructor might individually copy the finalized config's data members. This is to prevent eventual intermixing between the "configuration representation" and the "runtime -representation." In part, `finalize_config` already mitigates the problem. Abstaining from storing +representation". In part, `finalize_config()` already mitigates the problem. Abstaining from storing the finalized config as a data member is a step further. -## Error Handling +This static validation happens once, at construction. `ConfigManager`, which is a `Tracer` member, +separately allows some configuration to change afterward, via a Remote Configuration update, rather +than through `finalize_config()`. This path is also validated, by a different parser. -Most error scenarios within this library are individually enumerated by `enum Error::Code`, defined -in [error.h](../include/datadog/error.h). - -As of this writing, some of the error codes are emitted in more than one place, but most of them are -emitted in only one place, as is illustrated by the following incomprehensible command shell -pipeline: - -```bash -dd-trace-cpp/src/datadog$ sed -n 's/^\s*\(\w\+\)\s*=\s*[0-9]\+,\?\s*$/{Error::\1/p' error.h | paste -d '|' -s | xargs git grep -P | sed -n 's/.*Error::\(\w\+\),.*/\1/p' | sort | uniq -c | sort -rn - 3 MESSAGEPACK_ENCODE_FAILURE - 2 MAX_PER_SECOND_OUT_OF_RANGE - 2 INVALID_INTEGER - 2 INVALID_DOUBLE - 2 CURL_REQUEST_SETUP_FAILED - 2 CURL_HTTP_CLIENT_ERROR - 1 ZERO_TRACE_ID - 1 URL_UNSUPPORTED_SCHEME - 1 URL_UNIX_DOMAIN_SOCKET_PATH_NOT_ABSOLUTE - 1 URL_MISSING_SEPARATOR - 1 UNKNOWN_PROPAGATION_STYLE - 1 TRACE_SAMPLING_RULES_WRONG_TYPE - 1 TRACE_SAMPLING_RULES_UNKNOWN_PROPERTY - 1 TRACE_SAMPLING_RULES_SAMPLE_RATE_WRONG_TYPE - 1 TRACE_SAMPLING_RULES_INVALID_JSON - 1 TAG_MISSING_SEPARATOR - 1 SPAN_SAMPLING_RULES_WRONG_TYPE - 1 SPAN_SAMPLING_RULES_UNKNOWN_PROPERTY - 1 SPAN_SAMPLING_RULES_SAMPLE_RATE_WRONG_TYPE - 1 SPAN_SAMPLING_RULES_MAX_PER_SECOND_WRONG_TYPE - 1 SPAN_SAMPLING_RULES_INVALID_JSON - 1 SPAN_SAMPLING_RULES_FILE_IO - 1 RULE_WRONG_TYPE - 1 RULE_TAG_WRONG_TYPE - 1 RULE_PROPERTY_WRONG_TYPE - 1 RATE_OUT_OF_RANGE - 1 OUT_OF_RANGE_INTEGER - 1 NO_SPAN_TO_EXTRACT - 1 MISSING_TRACE_ID - 1 MISSING_SPAN_INJECTION_STYLE - 1 MISSING_SPAN_EXTRACTION_STYLE - 1 MISSING_PARENT_SPAN_ID - 1 MALFORMED_TRACE_TAGS - 1 DUPLICATE_PROPAGATION_STYLE - 1 DATADOG_AGENT_NULL_HTTP_CLIENT - 1 DATADOG_AGENT_INVALID_FLUSH_INTERVAL - 1 CURL_REQUEST_FAILURE - 1 CURL_HTTP_CLIENT_SETUP_FAILED - 1 CURL_HTTP_CLIENT_NOT_RUNNING -``` +## Error Handling -The integer values of the enumerated `Error::Code`s are intended to be permanent. Given an error -message from a log mentioning an error code 24, one can look at the source code for the matching -`Error::Code` (`TAG_MISSING_SEPARATOR`) and then find all of the possible source origins for that -error. At first this seems like a poor substitute for including the source file and line in the -error message, but I suspect that this compromise is better. +Most error scenarios within this library are enumerated by `enum Error::Code`, defined in +[error.h](../include/datadog/error.h). The integer values of the enumerated `Error::Code`s are +intended to be permanent. In addition to an error code, each error condition is associated with a contextual diagnostic message. The diagnostic is not only a description of the error, but also contains runtime context -that might help a user or a maintainer identify the underlying issue. For example, a message for -`TAG_MISSING_SEPARATOR` might include the text that was being parsed, or mention the name of the -relevant environment variable. +that might help a user or a maintainer identify the underlying issue. The `Error::Code code` and `std::string message` are combined in a `struct Error`, which is the error type used by this library. -`struct Error` has a convenience member function, `Error with_prefix(StringView) const`, that allows -context to be added to an error. It's analogous to `catch`ing one exception and then `throw`ing -another, e.g. - -```c++ -Expected adopt_cat(AnimalShelter& shelter) { - Expected result = shelter.adopt(Animals::CAT, 1); - if (Error *error = result.if_error()) { - return error->with_prefix("While trying to adopt from AnimalShelter: "); - } - return result; -} -``` - -`struct Error` is most often used in conjunction with the `Expected` class template, which is -defined in [expected.h](../include/datadog/expected.h). +`Error` has a convenience member function, `Error::with_prefix()`, that allows context to be added +to an error. It's analogous to `catch`ing one exception and then `throw`ing another. -`template class Expected` is either a `T` or an `Error`. It is a wrapper around -`std::variant`. It's inspired by C++23's +`Error` is most often used in conjunction with the `Expected` class template, which is defined in +[expected.h](../include/datadog/expected.h). `template class Expected` is either a `T` or +an `Error`. It is a wrapper around `std::variant`. It's inspired by C++23's [std::expected](https://en.cppreference.com/w/cpp/utility/expected), but the two are not compatible. -Functions in this library that intend to return a "`Value`," but that might instead fail with an +Functions in this library that intend to return a `Value`, but that might instead fail with an `Error`, return an `Expected`. This library never reports errors by throwing an exception. However, the library will allow exceptions, such as `std::bad_alloc` and `std::bad_variant_access`, to pass through it, and does sometimes use exceptions internally. The intention is that a client of this library does not need to -write `catch`. An alternative design would be to use exceptions for their intended purpose. We -decided that, for a tracing library embedded in proxies, the ergonomics of error values are a better -fit than exceptions. +write `catch`. For a tracing library embedded in proxies, the ergonomics of error values are a +better fit than exceptions. `Expected` supports two syntaxes of use. The first is -[std::get_if](https://en.cppreference.com/w/cpp/utility/variant/get_if)-style unpacking with the -`if_error` member function: +[std::get_if()](https://en.cppreference.com/w/cpp/utility/variant/get_if)-style unpacking with the +`if_error()` member function: ```c++ Expected lunch = go_buy_lunch(); if (Error *error = lunch.if_error()) { return error->with_prefix("Probably getting a hotdog instead: "); } -eat_salad(*lunch); // or, lunch.value() +eat_salad(*lunch); // or, lunch.value() ``` -`if_error` returns a pointer to the `Error` if there is one, otherwise it returns `nullptr`. The -body of a conditional statement such as `if` or `while` is allowed to contain a variable definition. -If the conditional statement contains a variable definition, then the truth value of the resulting -variable is used as the condition. So, if there is _not_ an error, then `if_error` returns -`nullptr`, and so the declared `Error*` is `nullptr`, which is false for the purposes of -conditionals, and so in that case the body (block) of the conditional statement is skipped. - -`if_error` cannot be called on an +`if_error()` cannot be called on an [rvalue](https://en.cppreference.com/w/cpp/language/value_category), because allowing this makes it -far too easy to obtain a pointer to a destroyed object. I wrote the component and nonetheless made -this mistake repeatedly. So, the rvalue-flavored overload of `Expected::if_error` is `delete`d. +far too easy to obtain a pointer to a destroyed object. The other syntax of use supported by `Expected` is the traditional check-and-accessor pattern: @@ -544,112 +399,42 @@ Expected lunch = go_buy_lunch(); if (!lunch) { return lunch.error().with_prefix("Probably getting halal instead: "); } -eat_salad(*lunch); // or, lunch.value() +eat_salad(*lunch); // or, lunch.value() ``` `Expected` defines `explicit operator bool`, which is `true` if the `Expected` contains a non-`Error`, and `false` if the `Expected` contains an `Error`. There is also `has_value()`, which -returns the same thing. +returns the same thing. Then the `Error` can be obtained via `error()`, or the non-`Error` can be +obtained via `value()`, `operator*()`, or `operator->()`. + +`template class Expected` has one specialization: `Expected`, which is "either an `Error` +or nothing". It's used to convey the result of an operation that might fail but that doesn't yield a +value when it succeeds. It behaves in the same way as `Expected`, except that `value()` and +`operator*()` are not defined. `Expected` is implemented in terms of `std::optional`, +but inverts the value of `explicit operator bool`. -Then the `Error` can be obtained via `error()`, or the non-`Error` can be obtained via `value()` or -`operator*()`. +## Logging -Why bother with `if_error`? Because I like it! I'm a sucker for structured bindings and pattern -matching. +This library has a logging interface alongside its `Expected`/`Error` reporting, because the default +`HTTPClient`/`EventScheduler` implementations do work on background threads where errors can occur +with no caller to hand them to. A logging interface lets those errors, startup diagnostics and +configuration warnings be logged by default, rather than requiring client code to opt in via an +`on_error` callback. -`template class Expected` has one specialization: `Expected`. `Expected` is -"either an `Error` or nothing." It's used to convey the result of an operation that might fail but -that doesn't yield a value when it succeeds. It behaves in the same way as `Expected`, except -that `value()` and `operator*()` are not defined. +The logging interface is `Logger`, defined in [logger.h](../include/datadog/logger.h). -At first I instead used `std::optional` directly. The problem there was that `explicit -operator bool` has the opposite meaning as it does in `Expected`. I wanted error handling code to -be the same in the two cases, and so I specialized `Expected`. `Expected` is implemented -in terms of `std::optional`, but inverts the value of `explicit operator bool`. +`Logger` has only two severities, "error" and "startup": -## Logging +- `Logger::log_startup()` is called once by `Tracer` at initialization; +- `Logger::log_error()` handles every other case. + +To avoid paying the cost of building a diagnostic message when it won't be logged, both accept a +`std::function` (`Logger::LogFunc`) that builds the message only if the implementation actually +chooses to log. -Can we write a tracing library that does not do any logging by itself? The previous section -describes how errors are reported by the library, and no logging is involved there. Why not leave it -up to the client to decide whether to note error conditions in the log or to proceed silently? - -The problem is that the default implementations of [HTTPClient](../include/datadog/http_client.h) -([Curl](../src/datadog/curl.h)) and [EventScheduler](../include/datadog/event_scheduler.h) -([ThreadedEventScheduler](../src/datadog/threaded_event_scheduler.h)) do some of their work on -background threads, where error conditions may occur without having a "caller" to notify, and where -execution will proceed despite the error. In those cases, should the library squelch the error? - -One option is for these async components to accept an `on_error(Error)` callback that will be -invoked whenever an error occurs on the background thread that would not otherwise be reported to -client code. What would a client library do in `on_error`? I think that it would either do nothing -or log the error. So, an `on_error` callback for use in background threads is the same as a logging -interface. - -It's tempting to omit a logging interface, leaving it to clients to decide whether and how to log. -Why have logging _and_ error reporting when you can have just error reporting? - -We could do that. Here are three reasons why this library has a logging interface anyway: - -1. Logging a `Tracer`'s configuration when it's initialized is a helpful diagnostic tool. A logging - interface allows `Tracer` to do this explicitly, as opposed to counting on client code to log - `Tracer::config_json()` itself. A client library can still suppress the startup message in its - implementation of the logging interface, but this is more opt-out than opt-in. -2. Along the same lines, reporting errors that occur on a background thread by invoking a logging - interface allows for the library's default behavior to be to print an error message to a log, as - opposed to having an `on_error` callback that a client library might choose to log within. -3. A logging interface allows warnings to be logged, notifying a user of a potentially problematic, - but valid, configuration. Sometimes these warnings are a matter of taste, and sometimes they are - required by the specification of the feature being configured. Logging is not the only way to - handle this — imagine if the return value of `finalize_config` included a list of warnings. But, - as with the previous two points, a logging interface allows for the default behavior to be a - logged message. - -On the other hand, the primary clients of this library are Ngix and Envoy, where Datadog engineers -have a say in how the library is used. So, the distinction is probably not so important. - -The logging interface is `class Logger`, defined in [logger.h](../include/datadog/logger.h). - -The design of `class Logger` is informed by three constraints: - -1. Most "warn," "info," "debug," and "trace" severity logging is noise. It is more an artifact of - feature development than it is a helpful event with which issues can be diagnosed. The logger - should have few severity levels, or ideally only one. -2. Logging libraries that obscure a conditional branch via the use of preprocessor macros are - difficult to understand. Reverse engineering a composition of preprocessor macros is hard, and is - not justified by the syntactic convenience that the macros provide. -3. When client code decides that a message will not be logged, the library should minimize the - amount of computation that is done — as close to nothing as is feasible. - -(1) and (3) work well together. - -On account of (1), `Logger` has only two "severities": "error" and "startup." `log_startup` is -called once by a `Tracer` when it is initialized. `log_error` is called in all other logging -circumstances. - -On account of (3), `Logger` must do as little work as possible when an implementer decides that a -logging function should not log. If this library were to build diagnostic messages in all cases, and -then pass them to the `Logger`, then the cost of building the message would be paid even when the -`Logger` decides not to log. On account of (2), the library cannot define a `DD_LOG` macro that -hides an `if (logger.severity > ...)` branch. As a matter of taste, I don't want the library to be -littered with such branches explicitly. - -The compromise is to have `Logger::log_error` and `Logger::log_startup` accept a -[std::function](https://en.cppreference.com/w/cpp/utility/functional/function) that, if invoked, -does the work of building the diagnostic message. When a `Logger` implementation decides not to log, -the only cost paid at the call site is the construction of the `std::function` and the underlying -capturing lambda expression with which it was likely initialized. The signature of the -`std::function`, aliased as `Logger::LogFunc`, is `void(std::ostream&)`. I don't know whether this -results in a real runtime savings in the not-logging case, but it seems likely. - -`Logger` also has two convenience overloads of `log_error`: one that takes a `const Error&` and one -that takes a `StringView`. - -The `const Error&` overload reveals a contradiction in the design. If an `Error` is produced in a -context where its only destiny is to be passed to `Logger::log_error(const Error&)`, then the cost -of building `Error::message` will always be paid, in violation of constraint (3). One way to avoid -this would be to have versions of the `Error`-returning operations that instead accept a `Logger&` -and use `Logger::log_error(Logger::LogFunc)` directly. I think that the present state of things is -acceptable and that such a change is not warranted. +`Logger::log_error()` also has two convenience overloads, one taking an `Error` and one a +`StringView`. The `Error` overload doesn't get the deferred-cost benefit, since `Error::message` is +already built by the time an `Error` exists. The default implementation of `Logger` is `NullLogger`, defined in [null_logger.h](../src/datadog/null_logger.h). `NullLogger` doesn't log anything. @@ -658,20 +443,4 @@ A client library might wish to install `CerrLogger` instead. `CerrLogger` is def [cerr_logger.h](../include/datadog/cerr_logger.h) and logs to [std::cerr](https://en.cppreference.com/w/cpp/io/cerr) in both `log_error` and `log_startup`. -The `Logger` used by a `Tracer` is configured via `std::shared_ptr TracerConfig::logger`, -defined in [tracer_config.h](../include/datadog/tracer_config.h). - -Finally, constraint (1) is still a matter of debate. Support representatives have expressed -frustration with this library's, and its predecessor's, lack of a "debug mode" that logs the reason -for every decision made throughout the processing of a trace. This issue deserves revisiting. Here -are some potential approaches: - -- Introduce a "debug mode" that sends fine-grained internal information to Datadog, rather than to a - log, either as hidden tags on the trace or via a different data channel, such as the [Telemetry - API](https://github.com/DataDog/datadog-agent/blob/796ccb9e92326c85b51f519291e86eb5bc950180/pkg/trace/api/endpoints.go#L97). -- Introduce a "trace the tracer" mode that generates additional traces that represent operations - performed by the tracer. This technique was prototyped in the - [david.goffredo/traception](https://github.com/DataDog/dd-trace-cpp/tree/david.goffredo/traception) - branch. -- Add a `Logger::log_debug` function that optionally prints fine-grained tracing information to the - log, in violation of constraint (1). +A `Tracer`'s `Logger` is provided by `TracerConfig`. diff --git a/include/datadog/collector.h b/include/datadog/collector.h index 72ba27237..cb915d76f 100644 --- a/include/datadog/collector.h +++ b/include/datadog/collector.h @@ -1,14 +1,14 @@ #pragma once -// This component provides an interface, `Collector`, to which spans of -// completed trace segments can be sent. +// `Collector` is an interface to which spans of completed trace segments can be +// sent. // // `DatadogAgent`, defined in `datadog_agent.h`, implements `Collector` by // serializing the spans and sending them to a Datadog Agent. // // As a result of `send`ing spans to a `Collector`, the `TraceSampler` might be // adjusted to increase or decrease the rate at which traces are kept. See the -// `response_handler` parameter to `Collector::send`. +// `response_handler` parameter to `Collector::send()`. #include #include @@ -22,8 +22,8 @@ class TraceSampler; class Collector { public: - // Submit ownership of the specified `spans` to the collector. - // If the collector delivers a response relevant to trace sampling, + // Submit ownership of the specified `spans` to the `Collector`. + // If the `Collector` delivers a response relevant to trace sampling, // reconfigure the sampler using the specified `response_handler`. Return an // error if one occurs. This must be safe to call from multiple threads // concurrently. @@ -33,7 +33,6 @@ class Collector { // Return a JSON representation of this object's configuration. The JSON // representation is an object with the following properties: - // // - "type" is the unmangled, qualified name of the most-derived class, e.g. // "datadog::tracing::DatadogAgent". // - "config" is an object containing this object's configuration. "config" diff --git a/include/datadog/datadog_agent_config.h b/include/datadog/datadog_agent_config.h index cb5334877..e3deb5c40 100644 --- a/include/datadog/datadog_agent_config.h +++ b/include/datadog/datadog_agent_config.h @@ -2,7 +2,7 @@ // This component provides facilities for configuring a `DatadogAgent`. // -// `struct DatadogAgentConfig` contains fields that are used to configure +// The `DatadogAgentConfig` struct contains fields that are used to configure // `DatadogAgent`. The configuration must first be finalized before it can be // used by `DatadogAgent`. The function `finalize_config` produces either an // error or a `FinalizedDatadogAgentConfig`. The latter can be used by diff --git a/include/datadog/error.h b/include/datadog/error.h index c7f9d7a94..ccb4eedda 100644 --- a/include/datadog/error.h +++ b/include/datadog/error.h @@ -1,13 +1,13 @@ #pragma once -// This component provides a `struct`, `Error`, that represents a particular -// kind of failure together with a contextual message describing the failure. +// The `Error` struct represents a particular kind of failure together with a +// contextual message describing the failure. // // Errors are enumerated by `enum Error::Code`. `Error::Code` values are // consistent across library versions, so integer values in error diagnostics // can always be looked up here. // -// `struct Error` is the error type used by the `Expected` class template. See +// `Error` is the error type used by the `Expected` class template. See // `expected.h`. #include diff --git a/include/datadog/event_scheduler.h b/include/datadog/event_scheduler.h index 9a834dc8d..6a9002464 100644 --- a/include/datadog/event_scheduler.h +++ b/include/datadog/event_scheduler.h @@ -1,10 +1,10 @@ #pragma once -// This component provides an interface, `EventScheduler`, that allows a -// specified function-like object to be invoked at regular intervals. +// `EventScheduler` is an interface that allows a specified function-like object +// to be invoked at regular intervals. // // `DatadogAgent` uses an `EventScheduler` to periodically send batches of -// traces to the Datadog Agent. +// traces to the Datadog Agent, and to poll it for Remote Configuration updates. // // The default implementation is `ThreadedEventScheduler`. See // `threaded_event_scheduler.h`. @@ -20,17 +20,16 @@ class EventScheduler { public: using Cancel = std::function; - // Invoke the specified `callback` repeatedly, with the specified `interval` - // elapsing between invocations. The first invocation is after an initial - // `interval`. Return a function-like object that can be invoked without - // arguments to prevent subsequent invocations of `callback`. + // Arrange for the specified `callback` to be invoked repeatedly, with the + // specified `interval` elapsing between invocations. The first invocation is + // after an initial `interval`. Return a function-like object that can be + // invoked without arguments to prevent subsequent invocations of `callback`. virtual Cancel schedule_recurring_event( std::chrono::steady_clock::duration interval, std::function callback) = 0; // Return a JSON representation of this object's configuration. The JSON // representation is an object with the following properties: - // // - "type" is the unmangled, qualified name of the most-derived class, e.g. // "datadog::tracing::ThreadedEventScheduler". // - "config" is an object containing this object's configuration. "config" diff --git a/include/datadog/expected.h b/include/datadog/expected.h index 84c582c03..138000918 100644 --- a/include/datadog/expected.h +++ b/include/datadog/expected.h @@ -1,8 +1,8 @@ #pragma once -// This component provides a class template, `Expected`, that is either an -// instance of `T` or an instance of `Error`. `Expected` is either -// `nullopt` or an instance of `Error`. +// The `Expected` class template is either an instance of `T` or an +// instance of `Error`. `Expected` is either `nullopt` or an instance of +// `Error`. // // `Expected` is inspired by, but incompatible with, C++23's `std::expected`. // diff --git a/include/datadog/http_client.h b/include/datadog/http_client.h index 97e5abd9d..5463f8fdd 100644 --- a/include/datadog/http_client.h +++ b/include/datadog/http_client.h @@ -1,9 +1,9 @@ #pragma once -// This component provides an interface, `HTTPClient`, that represents an -// asynchronous HTTP client. +// The `HTTPClient` class represents an asynchronous HTTP client. // -// `HTTPClient` is used by `DatadogAgent` to send traces to the Datadog Agent. +// `HTTPClient` is used by `DatadogAgent` to send traces to the Datadog Agent +// and to poll it for remote configuration updates. // // If this library was built with support for libcurl, then `Curl` implements // `HTTPClient` in terms of libcurl. See `curl.h`. @@ -43,9 +43,11 @@ class HTTPClient { // end of the request. Invoke the specified `on_response` callback if/when // a response is delivered (even if that response contains an error HTTP // response status). Invoke the specified `on_error` if an error occurs - // outside of HTTP, such as a connection failure. If an error occurs while - // preparing the request, return an `Error`. The behavior is undefined if - // either of `on_response` or `on_error` throws an exception. + // outside of HTTP, such as a connection failure, or if `deadline` is exceeded + // before a response is received. If an error occurs while preparing the + // request, return an `Error`, without calling either of the callbacks. The + // behavior is undefined if either of `on_response` or `on_error` throws an + // exception. virtual Expected post( const URL& url, HeadersSetter set_headers, std::string body, ResponseHandler on_response, ErrorHandler on_error, @@ -57,7 +59,6 @@ class HTTPClient { // Return a JSON representation of this object's configuration. The JSON // representation is an object with the following properties: - // // - "type" is the unmangled, qualified name of the most-derived class, e.g. // "datadog::tracing::Curl". // - "config" is an object containing this object's configuration. "config" diff --git a/include/datadog/logger.h b/include/datadog/logger.h index bd5c5400e..d02666152 100644 --- a/include/datadog/logger.h +++ b/include/datadog/logger.h @@ -1,7 +1,7 @@ #pragma once -// This component provides an interface, `Logger`, that allows for the -// customization of how the library logs diagnostic and startup messages. +// The `Logger` interface allows for the customization of how the library logs +// diagnostic and startup messages. // // Errors, when they occur, are typically returned as `Error` values (often as // part of an `Expected` value). However, in "async" contexts where there is diff --git a/include/datadog/rate.h b/include/datadog/rate.h index caa90050f..286bf88c8 100644 --- a/include/datadog/rate.h +++ b/include/datadog/rate.h @@ -1,7 +1,7 @@ #pragma once -// This component provides a `class`, `Rate`, that is a `double` whose value is -// between zero and one, inclusive. +// The `Rate` class is a `double` whose value is between zero and one, +// inclusive. // // `Rate` objects are obtained by calling the static member function // `Rate::from` with a `double` argument. A default-constructed `Rate` has the diff --git a/include/datadog/span.h b/include/datadog/span.h index 43be554c0..f5958b375 100644 --- a/include/datadog/span.h +++ b/include/datadog/span.h @@ -1,14 +1,13 @@ #pragma once -// This component defines a class, `Span`, that represents an extent of time in -// which some operation of interest occurs, such as an RPC request, database -// query, calculation, etc. +// The `Span` class represents an extent of time in which some operation of +// interest occurs, such as an RPC request, database query, calculation, etc. // // `Span` objects are created by calling member functions on `Tracer` or on // another `Span` object. They are not instantiated directly. // // A `Span` has a start time, an end time, and a name (sometimes called its -// "operation name"). A span is associated with a service, a resource (such as +// "operation name"). A `Span` is associated with a service, a resource (such as // the URL endpoint in an HTTP request), and arbitrary key/value string pairs // known as tags. // @@ -26,19 +25,19 @@ // handler. That child might itself have children, such as a database query or // a request to an authentication service. // -// The complete set of spans that are related to each other via the parent/child -// relationship is called a trace. +// The complete set of `Span`s that are related to each other via the +// parent/child relationship is called a trace. // // A trace can extend across processes and networks via trace context // propagation. A `Span` can be _extracted_ from its external parent via -// `Tracer::extract_span`, and a `Span` can be _injected_ via `Span::inject` +// `Tracer::extract_span()`, and a `Span` can be _injected_ via `Span::inject()` // into an outside context from which its external children might be extracted. // -// If an error occurs during the operation that a span represents, the error can -// be noted in the span via the `set_error` family of member functions. +// If an error occurs during the operation that a `Span` represents, the error +// can be noted in the `Span` via the `set_error()` family of member functions. // // A `Span` is finished when it is destroyed. The end time can be overridden -// via the `set_end_time` member function prior to the span's destruction. +// via the `set_end_time()` member function prior to the `Span`'s destruction. #include #include diff --git a/include/datadog/span_sampler_config.h b/include/datadog/span_sampler_config.h index 7faaa8eb3..9dc853910 100644 --- a/include/datadog/span_sampler_config.h +++ b/include/datadog/span_sampler_config.h @@ -1,8 +1,8 @@ #pragma once -// This component provides a `struct`, `SpanSamplerConfig`, used to configure -// `SpanSampler`. `SpanSampler` accepts a `FinalizedSpanSamplerConfig`, which -// must be obtained from a call to `finalize_config`. +// The `SpanSamplerConfig` struct is used to configure `SpanSampler`. +// `SpanSampler` accepts a `FinalizedSpanSamplerConfig`, which must be obtained +// from a call to `finalize_config()`. // // `SpanSamplerConfig` is specified as the `span_sampler` property of // `TracerConfig`. diff --git a/include/datadog/trace_sampler_config.h b/include/datadog/trace_sampler_config.h index 685eeb82c..57dd6f6ef 100644 --- a/include/datadog/trace_sampler_config.h +++ b/include/datadog/trace_sampler_config.h @@ -1,8 +1,8 @@ #pragma once -// This component provides a `struct`, `TraceSamplerConfig`, used to configure -// `TraceSampler`. `TraceSampler` accepts a `FinalizedTraceSamplerConfig`, which -// must be obtained from a call to `finalize_config`. +// The `TraceSamplerConfig` struct is used to configure `TraceSampler`. +// `TraceSampler` accepts a `FinalizedTraceSamplerConfig`, which must be +// obtained from a call to `finalize_config()`. // // `TraceSamplerConfig` is specified as the `trace_sampler` property of // `TracerConfig`. diff --git a/include/datadog/trace_segment.h b/include/datadog/trace_segment.h index db32bf7ab..ea27dd838 100644 --- a/include/datadog/trace_segment.h +++ b/include/datadog/trace_segment.h @@ -1,25 +1,25 @@ #pragma once -// This component provides a class, `TraceSegment`, that represents a portion of -// a trace that is passing through this process. +// The `TraceSegment` class represents a portion of a trace that is passing +// through this process. // // `TraceSegment` is not instantiated directly. It is an implementation detail // of this library. // // A trace might begin in this process, or it might have been propagated in from -// outside (see `Tracer::extract_span`). A trace might remain in this process, -// or it might be propagated outward (see `Span::inject`) one or more times. +// outside (see `Tracer::extract_span()`). A trace might remain in this process, +// or it might be propagated outward (see `Span::inject()`) one or more times. // // A trace might pass through this process twice or more. Consider an RPC // server that receives a request, in handling that request makes a request to a // different service, and in the course of the other service handling its // request, the original service is called again. Both "passes" through this -// process are part of the same trace, but each pass is a different _trace -// segment_. +// process are part of the same trace, but each pass is a different trace +// segment. // // `TraceSegment` stores context and configuration shared among all spans within // the trace segment, and additionally owns the spans' data. When `Tracer` -// creates or extracts a span, it also creates a new `TraceSegment`. When a +// creates or extracts a `Span`, it also creates a new `TraceSegment`. When a // child `Span` is created from a `Span`, the child and the parent share the // same `TraceSegment`. // @@ -110,9 +110,9 @@ class TraceSegment { Logger& logger() const; - // Inject trace context for the specified `span` into the specified `writer`. - // Return whether the trace sampling decision was delegated. - // This function is the implementation of `Span::inject`. + // Inject trace context for the specified `span` into the specified `writer`, + // using the configured injection styles. Return whether the injection + // happened. This function is the implementation of `Span::inject()`. bool inject(DictWriter& writer, const SpanData& span); bool inject(DictWriter& writer, const SpanData& span, const InjectionOptions& options); diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 891b972fd..08ca42743 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -1,13 +1,13 @@ #pragma once -// This component provides a class, `Tracer`, that instantiates the mechanisms -// necessary for tracing, and provides member functions for creating spans. -// Each span created by `Tracer` is either the root of a new trace (see -// `create_span`) or part of an existing trace whose information is extracted -// from a provided key/value source (see `extract_span`). +// The `Tracer` class instantiates the mechanisms necessary for tracing, and +// provides member functions for creating `Span`s. Each `Span` created by +// `Tracer` is either the root of a new trace (see `Tracer::create_span()`) or +// part of an existing trace whose information is extracted from a provided +// key/value source (see `Tracer::extract_span()`). // // `Tracer` is instantiated with a `FinalizedTracerConfig`, which can be -// obtained from a `TracerConfig` via the `finalize_config` function. See +// obtained from a `TracerConfig` via the `finalize_config()` function. See // `tracer_config.h`. #include @@ -79,9 +79,9 @@ class Tracer { Expected extract_span(const DictReader& reader, const SpanConfig& config); - // Return a span extracted from the specified `reader` (see `extract_span`). + // Return a span extracted from the specified `reader` (see `extract_span()`). // If there is no span to extract, or if an error occurs during extraction, - // then return a span that is the root of a new trace (see `create_span`). + // then return a span that is the root of a new trace (see `create_span()`). // Optionally specify a `config` indicating the attributes of the span. Span extract_or_create_span(const DictReader& reader); Span extract_or_create_span(const DictReader& reader, diff --git a/include/datadog/tracer_config.h b/include/datadog/tracer_config.h index 5b464e64d..567594cfd 100644 --- a/include/datadog/tracer_config.h +++ b/include/datadog/tracer_config.h @@ -1,8 +1,8 @@ #pragma once -// This component provides a struct, `TracerConfig`, used to configure a -// `Tracer`. `Tracer` is instantiated with a `FinalizedTracerConfig`, which -// must be obtained from the result of a call to `finalize_config`. +// `TracerConfig` is a struct used to configure a `Tracer`. `Tracer` is +// instantiated with a `FinalizedTracerConfig`, which must be obtained from the +// result of a call to `finalize_config()`. #include @@ -204,7 +204,7 @@ struct TracerConfig { // `FinalizedTracerConfig` contains `Tracer` implementation details derived from // a valid `TracerConfig` and accompanying environment. -// `FinalizedTracerConfig` must be obtained by calling `finalize_config`. +// `FinalizedTracerConfig` must be obtained by calling `finalize_config()`. class FinalizedTracerConfig final { friend Expected finalize_config( const TracerConfig& config, const Clock& clock); diff --git a/src/datadog/datadog_agent.h b/src/datadog/datadog_agent.h index 993c11ee7..c4decc907 100644 --- a/src/datadog/datadog_agent.h +++ b/src/datadog/datadog_agent.h @@ -1,7 +1,7 @@ #pragma once -// This component provides a `class`, `DatadogAgent`, that implements the -// `Collector` interface in terms of periodic HTTP requests to a Datadog Agent. +// The `DatadogAgent` class implements the `Collector` interface in terms of +// periodic HTTP requests to a Datadog Agent. // // `DatadogAgent` is configured by `DatadogAgentConfig`. See // `datadog_agent_config.h`. diff --git a/src/datadog/threaded_event_scheduler.h b/src/datadog/threaded_event_scheduler.h index 764dfa708..da6b409b8 100644 --- a/src/datadog/threaded_event_scheduler.h +++ b/src/datadog/threaded_event_scheduler.h @@ -1,9 +1,8 @@ #pragma once -// This component provides a `class`, `ThreadedEventScheduler`, that implements -// the `EventScheduler` interface in terms of a dedicated event dispatching -// thread. It is the default implementation used if -// `DatadogAgent::event_scheduler` is not specified. +// The `ThreadedEventScheduler` class implements the `EventScheduler` interface +// in terms of a dedicated event dispatching thread. It is the default +// implementation used if `DatadogAgent::event_scheduler` is not specified. #include From f54ab381003f2fe052567cbca325e4c48bf81abf Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Thu, 16 Jul 2026 09:56:07 +0200 Subject: [PATCH 13/59] Create class diagram in the Design documentation (#339) --- docs/design.md | 142 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 37 deletions(-) diff --git a/docs/design.md b/docs/design.md index 17ff38af6..f13f1c8b7 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,10 +1,107 @@ # Datadog C++ Tracer Design -The primary purpose of this guide is to describe salient features of the Datadog C++ Tracer's -design. +This guide describes salient features of the Datadog C++ Tracer's design. ## Architecture +### Overview + +```mermaid +--- +title: Datadog C++ Tracer Architecture Overview +--- +classDiagram + class Span { + create_child() Span + inject(writer) + } + Span "0..n" o-- TraceSegment + Span "1" o-- "1" SpanData + + class SpanData + + class TraceSegment { + mutex_ 🔒 + } + TraceSegment *-- "0..n" SpanData + TraceSegment o-- Collector + TraceSegment o-- SpanSampler + TraceSegment o-- ConfigManager + TraceSegment o-- TraceSampler + + class Tracer { + create_span(config) Span + extract_span(reader) Span + } + Tracer "1..n" o-- Collector + Tracer "1" o-- "1" SpanSampler + Tracer "1" o-- "1" ConfigManager + Tracer -- FinalizedTracerConfig + + class FinalizedTracerConfig { + finalize_config(TracerConfig) FinalizedTracerConfig + } + + class SpanSampler { + mutex_ 🔒 + } + + class Collector { + send(spans) + } + + class DatadogAgent { + mutex_ 🔒 + flush() + } + DatadogAgent ..|> Collector + DatadogAgent o-- HTTPClient + DatadogAgent o-- EventScheduler + + class ConfigManager { + mutex_ 🔒 + } + ConfigManager o-- TraceSampler + + class TraceSampler { + mutex_ 🔒 + } + + class HTTPClient { + post() + } + + class Curl + Curl ..|> HTTPClient + + class EventScheduler + + class ThreadedEventScheduler { + mutex_ 🔒 + } + ThreadedEventScheduler ..|> EventScheduler + + class Logger { + log_startup() + log_error() + } + + class NullLogger + NullLogger ..|> Logger + + class CerrLogger + CerrLogger ..|> Logger +``` + +Intended usage is: + +1. Create a `TracerConfig`. +2. Use the `TracerConfig` to create a `Tracer`. +3. Use the `Tracer` to create and/or extract local root `Span`s. +4. Use `Span` to create children and/or inject context. +5. Use a `Span`'s `TraceSegment` to perform trace-wide operations. +6. When all `Span`s in a `TraceSegment` are finished, the segment is sent to the `Collector`. + ### Span [Span](../include/datadog/span.h) is the component with which users will interact the most. Each @@ -259,38 +356,7 @@ uses a different implementation, [AgentHTTPClient](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h), which uses Envoy's built-in HTTP facilities. libcurl is not involved at all. -### Logical Component Relationships - -- Vertices are components. -- Edges are ownership relationships between components. Each edge is labeled by the kind of pointer - that is used to implement the relationship. -- Components with a padlock are protected by a mutex. - -```mermaid ---- -title: Components Relationships -config: - layout: elk ---- -graph LR; - Tracer(Tracer) & TraceSegment("TraceSegment 🔒")-- shared -->Collector("Collector 🔒") & SpanSampler("SpanSampler 🔒") - Tracer & TraceSegment-- shared -->ConfigManager("ConfigManager 🔒") - ConfigManager & TraceSegment-- shared -->TraceSampler("TraceSampler 🔒") - TraceSegment-- "`**unique**`" -->SpanData(SpanData) - Span(Span)-- shared -->TraceSegment - Span-- "`**raw**`" -->SpanData -``` - -Intended usage is: - -1. Create a `TracerConfig`. -2. Use the `TracerConfig` to create a `Tracer`. -3. Use the `Tracer` to create and/or extract local root `Span`s. -4. Use `Span` to create children and/or inject context. -5. Use a `Span`'s `TraceSegment` to perform trace-wide operations. -6. When all `Span`s in a `TraceSegment` are finished, the segment is sent to the `Collector`. - -## EventScheduler +### EventScheduler `DatadogAgent` uses an `EventScheduler` to schedule its recurring work, at fixed intervals. @@ -312,7 +378,9 @@ also uses a different implementation, [EventScheduler](https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h), which uses Envoy's built-in event dispatch facilities. -## Configuration +## Operational Aspects + +### Configuration This library encodes configuration validation into the type system (see ["Parse, don't validate" by Alexis King](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate)). Invalid states @@ -346,7 +414,7 @@ This static validation happens once, at construction. `ConfigManager`, which is separately allows some configuration to change afterward, via a Remote Configuration update, rather than through `finalize_config()`. This path is also validated, by a different parser. -## Error Handling +### Error Handling Most error scenarios within this library are enumerated by `enum Error::Code`, defined in [error.h](../include/datadog/error.h). The integer values of the enumerated `Error::Code`s are @@ -413,7 +481,7 @@ value when it succeeds. It behaves in the same way as `Expected`, except that `operator*()` are not defined. `Expected` is implemented in terms of `std::optional`, but inverts the value of `explicit operator bool`. -## Logging +### Logging This library has a logging interface alongside its `Expected`/`Error` reporting, because the default `HTTPClient`/`EventScheduler` implementations do work on background threads where errors can occur From ddb288c5606321e27d34889f2e6432609bffeee3 Mon Sep 17 00:00:00 2001 From: MilanGarnier Date: Wed, 22 Jul 2026 13:49:44 +0200 Subject: [PATCH 14/59] feat(tracing): add span link support (#330) add span link struct and test enable span link tests implement Span::add_link add span link to msg pack encoding add spn link test for the Span class implenent add_link endpoint for parametric tests flatten array cleaner spanlink construction add extracted context struct cleaning up (move logic to span.cpp) format fix BAZEL build derive W3C flags from sampling priority in add_link(ExtractedContext) resolve https://github.com/DataDog/dd-trace-cpp/pull/330#discussion_r3499942743 change scope of ExtractedHeaders struct (restrict to parametric server) case insensitive lookup for headers nit: nested namespace syntax clearer variable names get rid of magic values in span_data::msgpack Cleaner msgpack_encode for span_link.cpp split RequestHandler::on_add_link make storedLinkContexts outside of on_extract_headers function bugfix: do not force sampling decision when writing tracestate in spanlink avoid collisions when adding links consecutively (parent_id=0) move span link into private types, expose spancontext and spanlinkattributes only always store trace_id_high fix typo in parametric server refact(tracing): nit change comment refactor(tracing): move span link attributes type to span.h refactor(tracing): make SpanContext a class; SpanLink wraps SpanContext SpanContext gains an explicit constructor instead of relying on default member initializers, and SpanLink now stores a SpanContext member instead of duplicating trace_id/span_id/tracestate/flags fields. Also introduces the W3CLinkContext type alias for TraceSegment::w3c_link_context's return type. test(system-tests): adapt request_handler to SpanContext constructor API do not care about sampling priority when adding span link Merge branch 'main' into milan.garnier/span-links-support Co-authored-by: milan.garnier --- BUILD.bazel | 3 + CMakeLists.txt | 2 + include/datadog/span.h | 14 +++ include/datadog/span_context.h | 34 ++++++ include/datadog/trace_segment.h | 14 ++- src/datadog/span.cpp | 17 +++ src/datadog/span_data.cpp | 142 ++++++++++++++----------- src/datadog/span_data.h | 3 + src/datadog/span_link.cpp | 78 ++++++++++++++ src/datadog/span_link.h | 22 ++++ src/datadog/trace_segment.cpp | 29 ++++++ test/CMakeLists.txt | 1 + test/system-tests/main.cpp | 4 + test/system-tests/request_handler.cpp | 131 +++++++++++++++++++++-- test/system-tests/request_handler.h | 8 ++ test/test_span.cpp | 96 +++++++++++++++++ test/test_span_link.cpp | 145 ++++++++++++++++++++++++++ 17 files changed, 674 insertions(+), 69 deletions(-) create mode 100644 include/datadog/span_context.h create mode 100644 src/datadog/span_link.cpp create mode 100644 src/datadog/span_link.h create mode 100644 test/test_span_link.cpp diff --git a/BUILD.bazel b/BUILD.bazel index df17ac563..1682bd658 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -55,6 +55,8 @@ cc_library( "src/datadog/span.cpp", "src/datadog/span_data.cpp", "src/datadog/span_data.h", + "src/datadog/span_link.cpp", + "src/datadog/span_link.h", "src/datadog/span_matcher.cpp", "src/datadog/span_sampler.cpp", "src/datadog/span_sampler.h", @@ -131,6 +133,7 @@ cc_library( "include/datadog/sampling_priority.h", "include/datadog/span.h", "include/datadog/span_config.h", + "include/datadog/span_context.h", "include/datadog/span_defaults.h", "include/datadog/span_matcher.h", "include/datadog/span_sampler_config.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cc154f17..1587fe746 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ target_sources(dd-trace-cpp-objects include/datadog/sampling_priority.h include/datadog/span.h include/datadog/span_config.h + include/datadog/span_context.h include/datadog/span_defaults.h include/datadog/span_matcher.h include/datadog/span_sampler_config.h @@ -203,6 +204,7 @@ target_sources(dd-trace-cpp-objects src/datadog/runtime_id.cpp src/datadog/span.cpp src/datadog/span_data.cpp + src/datadog/span_link.cpp src/datadog/span_matcher.cpp src/datadog/span_sampler_config.cpp src/datadog/span_sampler.cpp diff --git a/include/datadog/span.h b/include/datadog/span.h index f5958b375..1d0081069 100644 --- a/include/datadog/span.h +++ b/include/datadog/span.h @@ -43,9 +43,12 @@ #include #include #include +#include +#include #include "clock.h" #include "optional.h" +#include "span_context.h" #include "string_view.h" #include "trace_id.h" #include "trace_source.h" @@ -60,6 +63,9 @@ struct SpanConfig; struct SpanData; class TraceSegment; +// The map type used for user-supplied span-link attributes. +using SpanLinkAttributes = std::unordered_map; + class Span { std::shared_ptr trace_segment_; SpanData* data_; @@ -165,6 +171,14 @@ class Span { // Specifies the product (AppSec, DBM) that created this span. void set_source(Source); + // Return this span's identifying and propagation state. This does not make a + // sampling decision when one has not already been made. + SpanContext context() const; + + // Add a link to this span. + void add_link(const SpanContext& context, + const SpanLinkAttributes& attributes = {}); + // Write information about this span and its trace into the specified `writer` // using all of the configured injection propagation styles. void inject(DictWriter& writer) const; diff --git a/include/datadog/span_context.h b/include/datadog/span_context.h new file mode 100644 index 000000000..b0a95dcd0 --- /dev/null +++ b/include/datadog/span_context.h @@ -0,0 +1,34 @@ +#pragma once + +// This component defines `SpanContext`, the identifying and propagation state +// of a span. It can be supplied to `Span::add_link` to associate a span with a +// span in this or another trace. + +#include +#include + +#include "trace_id.h" + +namespace datadog::tracing { + +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; + // W3C `tracestate` header value, if any. + Optional tracestate; + // W3C trace flags, if any. + Optional flags; + + SpanContext(TraceID trace_id, std::uint64_t span_id, + Optional tracestate = nullopt, + Optional flags = nullopt) + : trace_id(trace_id), + span_id(span_id), + tracestate(tracestate), + flags(flags) {} +}; + +} // namespace datadog::tracing diff --git a/include/datadog/trace_segment.h b/include/datadog/trace_segment.h index ea27dd838..f7fa958ab 100644 --- a/include/datadog/trace_segment.h +++ b/include/datadog/trace_segment.h @@ -56,6 +56,8 @@ class SpanSampler; class TraceSampler; class ConfigManager; +using W3CLinkContext = std::pair; + class TraceSegment { mutable std::mutex mutex_; @@ -75,8 +77,8 @@ class TraceSegment { std::vector> spans_; std::size_t num_finished_spans_; Optional sampling_decision_; - Optional additional_w3c_tracestate_; - Optional additional_datadog_w3c_tracestate_; + const Optional additional_w3c_tracestate_; + const Optional additional_datadog_w3c_tracestate_; std::shared_ptr config_manager_; @@ -108,6 +110,14 @@ class TraceSegment { const Optional& origin() const; Optional sampling_decision() const; + // Return the W3C tracestate encoding and derived trace flags for `span`, + // based on this segment's sampling decision. Unlike `inject`, this never + // makes a sampling decision if one hasn't been made yet -- it returns + // `nullopt` instead of forcing (and thereby permanently finalizing) one. + // Used by `Span::context` without prematurely deciding sampling for the + // trace. + Optional w3c_link_context(const SpanData& span) const; + Logger& logger() const; // Inject trace context for the specified `span` into the specified `writer`, diff --git a/src/datadog/span.cpp b/src/datadog/span.cpp index 7d076996b..39f4153d3 100644 --- a/src/datadog/span.cpp +++ b/src/datadog/span.cpp @@ -164,6 +164,23 @@ void Span::set_source(Source source) { to_tag(source)); } +SpanContext Span::context() const { + SpanContext context{trace_id(), id()}; + + if (Optional w3c_context = + trace_segment_->w3c_link_context(*data_)) { + context.tracestate = std::move(w3c_context->first); + context.flags = w3c_context->second; + } + + return context; +} + +void Span::add_link(const SpanContext& context, + const SpanLinkAttributes& attributes) { + data_->span_links.emplace_back(context, attributes); +} + TraceSegment& Span::trace_segment() { return *trace_segment_; } const TraceSegment& Span::trace_segment() const { return *trace_segment_; } diff --git a/src/datadog/span_data.cpp b/src/datadog/span_data.cpp index 7ed4ebb21..ad3eb00cf 100644 --- a/src/datadog/span_data.cpp +++ b/src/datadog/span_data.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include "msgpack.h" #include "tags.h" @@ -74,66 +76,86 @@ void SpanData::apply_config(const SpanDefaults& defaults, } Expected msgpack_encode(std::string& destination, const SpanData& span) { - // clang-format off - msgpack::pack_map( - destination, - "service", [&](auto& destination) { - return msgpack::pack_string(destination, span.service); - }, - "name", [&](auto& destination) { - return msgpack::pack_string(destination, span.name); - }, - "resource", [&](auto& destination) { - return msgpack::pack_string(destination, span.resource); - }, - "trace_id", [&](auto& destination) { - msgpack::pack_integer(destination, span.trace_id.low); - return Expected{}; - }, - "span_id", [&](auto& destination) { - msgpack::pack_integer(destination, span.span_id); - return Expected{}; - }, - "parent_id", [&](auto& destination) { - msgpack::pack_integer(destination, span.parent_id); - return Expected{}; - }, - "start", [&](auto& destination) { - msgpack::pack_integer( - destination, std::uint64_t(std::chrono::duration_cast( - span.start.wall.time_since_epoch()) - .count())); - return Expected{}; - }, - "duration", [&](auto& destination) { - msgpack::pack_integer( - destination, - std::uint64_t(std::chrono::duration_cast(span.duration) - .count())); - return Expected{}; - }, - "error", [&](auto& destination) { - msgpack::pack_integer(destination, std::int32_t(span.error)); - return Expected{}; - }, - "meta", [&](auto& destination) { - return msgpack::pack_map(destination, span.tags, - [](std::string& destination, const auto& value) { - return msgpack::pack_string(destination, value); - }); - }, "metrics", - [&](auto& destination) { - return msgpack::pack_map(destination, span.numeric_tags, - [](std::string& destination, const auto& value) { - msgpack::pack_double(destination, value); - return Expected{}; - }); - }, "type", [&](auto& destination) { - return msgpack::pack_string(destination, span.service_type); - }); - // clang-format on - - return nullopt; + auto pack_service = [&](auto& destination) { + return msgpack::pack_string(destination, span.service); + }; + auto pack_name = [&](auto& destination) { + return msgpack::pack_string(destination, span.name); + }; + auto pack_resource = [&](auto& destination) { + return msgpack::pack_string(destination, span.resource); + }; + auto pack_trace_id = [&](auto& destination) { + msgpack::pack_integer(destination, span.trace_id.low); + return Expected{}; + }; + auto pack_span_id = [&](auto& destination) { + msgpack::pack_integer(destination, span.span_id); + return Expected{}; + }; + auto pack_parent_id = [&](auto& destination) { + msgpack::pack_integer(destination, span.parent_id); + return Expected{}; + }; + auto pack_start = [&](auto& destination) { + msgpack::pack_integer( + destination, + std::uint64_t(std::chrono::duration_cast( + span.start.wall.time_since_epoch()) + .count())); + return Expected{}; + }; + auto pack_duration = [&](auto& destination) { + msgpack::pack_integer( + destination, + std::uint64_t( + std::chrono::duration_cast(span.duration) + .count())); + return Expected{}; + }; + auto pack_error = [&](auto& destination) { + msgpack::pack_integer(destination, std::int32_t(span.error)); + return Expected{}; + }; + auto pack_meta = [&](auto& destination) { + return msgpack::pack_map(destination, span.tags, + [](std::string& destination, const auto& value) { + return msgpack::pack_string(destination, value); + }); + }; + auto pack_metrics = [&](auto& destination) { + return msgpack::pack_map(destination, span.numeric_tags, + [](std::string& destination, const auto& value) { + msgpack::pack_double(destination, value); + return Expected{}; + }); + }; + auto pack_type = [&](auto& destination) { + 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 msgpack_encode( diff --git a/src/datadog/span_data.h b/src/datadog/span_data.h index 36950427d..440e050ad 100644 --- a/src/datadog/span_data.h +++ b/src/datadog/span_data.h @@ -14,6 +14,8 @@ #include #include +#include "span_link.h" + namespace datadog { namespace tracing { @@ -33,6 +35,7 @@ struct SpanData { bool error = false; std::unordered_map tags; std::unordered_map numeric_tags; + std::vector span_links; Optional environment() const; Optional version() const; diff --git a/src/datadog/span_link.cpp b/src/datadog/span_link.cpp new file mode 100644 index 000000000..8419e39d8 --- /dev/null +++ b/src/datadog/span_link.cpp @@ -0,0 +1,78 @@ +#include "span_link.h" + +#include +#include + +#include "msgpack.h" + +namespace datadog::tracing { + +Expected msgpack_encode(std::string& destination, const SpanLink& link) { + const bool has_attributes = !link.attributes.empty(); + const bool has_tracestate = + link.context.tracestate.has_value() && !link.context.tracestate->empty(); + const bool has_flags = link.context.flags.has_value(); + + std::size_t size = 3; // trace_id, span_id, and trace_id_high are always + // present. + if (has_attributes) ++size; + if (has_tracestate) ++size; + if (has_flags) ++size; + + Expected result = msgpack::pack_map(destination, size); + if (!result) return result; + + result = msgpack::pack_map_suffix( + destination, "trace_id", + [&](std::string& destination) { + msgpack::pack_integer(destination, link.context.trace_id.low); + return Expected{}; + }, + "span_id", + [&](std::string& destination) { + msgpack::pack_integer(destination, link.context.span_id); + return Expected{}; + }, + "trace_id_high", + [&](std::string& destination) { + msgpack::pack_integer(destination, link.context.trace_id.high); + return Expected{}; + }); + if (!result) return result; + + if (has_attributes) { + result = msgpack::pack_map_suffix( + destination, "attributes", [&](std::string& destination) { + return msgpack::pack_map( + destination, link.attributes, + [](std::string& destination, const std::string& value) { + return msgpack::pack_string(destination, value); + }); + }); + if (!result) return result; + } + + if (has_tracestate) { + result = msgpack::pack_map_suffix( + destination, "tracestate", [&](std::string& destination) { + return msgpack::pack_string(destination, *link.context.tracestate); + }); + if (!result) return result; + } + + if (has_flags) { + result = msgpack::pack_map_suffix( + destination, "flags", [&](std::string& destination) { + // The high bit marks "flags is present" so a receiver can + // distinguish an explicit value of 0 from an omitted field. + msgpack::pack_integer( + destination, std::uint64_t(*link.context.flags | (1u << 31))); + return Expected{}; + }); + if (!result) return result; + } + + return result; +} + +} // namespace datadog::tracing diff --git a/src/datadog/span_link.h b/src/datadog/span_link.h new file mode 100644 index 000000000..8b049d6fa --- /dev/null +++ b/src/datadog/span_link.h @@ -0,0 +1,22 @@ +#pragma once + +// This component defines the internal span-link representation and its +// MessagePack serialization. Applications use `SpanContext` and +// `Span::add_link` instead. + +#include + +namespace datadog::tracing { + +class SpanLink { + public: + SpanContext context; + SpanLinkAttributes attributes; + + SpanLink(SpanContext context, SpanLinkAttributes attributes = {}) + : context(std::move(context)), attributes(std::move(attributes)) {} +}; + +Expected msgpack_encode(std::string& destination, const SpanLink& link); + +} // namespace datadog::tracing diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index 4a7181b05..e620c4315 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -202,6 +202,35 @@ Optional TraceSegment::sampling_decision() const { return sampling_decision_; } +Optional> TraceSegment::w3c_link_context( + const SpanData& span) const { + int sampling_priority; + std::vector> trace_tags; + { + std::lock_guard lock(mutex_); + if (!sampling_decision_) { + return nullopt; + } + sampling_priority = sampling_decision_->priority; + trace_tags = trace_tags_; + + auto& local_root_tags = spans_.front()->tags; + auto ts_tag_found = std::find_if( + local_root_tags.cbegin(), local_root_tags.cend(), + [](const auto& p) { return p.first == tags::internal::trace_source; }); + if (ts_tag_found != local_root_tags.cend()) { + trace_tags.emplace_back(tags::internal::trace_source, + ts_tag_found->second); + } + } + + return std::make_pair( + encode_tracestate(span.span_id, sampling_priority, origin_, trace_tags, + additional_datadog_w3c_tracestate_, + additional_w3c_tracestate_), + sampling_priority > 0 ? 1u : 0u); +} + Logger& TraceSegment::logger() const { return *logger_; } void TraceSegment::register_span(std::unique_ptr span) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7571aa8b7..1496765d2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable(tests test_parse_util.cpp test_smoke.cpp test_span.cpp + test_span_link.cpp test_span_sampler.cpp test_trace_id.cpp test_trace_segment.cpp diff --git a/test/system-tests/main.cpp b/test/system-tests/main.cpp index de7d421e1..18ba58466 100644 --- a/test/system-tests/main.cpp +++ b/test/system-tests/main.cpp @@ -128,6 +128,10 @@ int main(int argc, char* argv[]) { [&handler](const httplib::Request& req, httplib::Response& res) { handler.on_manual_keep(req, res); }); + svr.Post("/trace/span/add_link", + [&handler](const httplib::Request& req, httplib::Response& res) { + handler.on_add_link(req, res); + }); // Not implemented svr.Post("/trace/span/set_metric", diff --git a/test/system-tests/request_handler.cpp b/test/system-tests/request_handler.cpp index df6055837..e2c4728d8 100644 --- a/test/system-tests/request_handler.cpp +++ b/test/system-tests/request_handler.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -236,6 +237,82 @@ void RequestHandler::on_set_meta(const httplib::Request& req, res.status = 200; } +// Parse optional attributes, supporting flat strings and arrays. +static datadog::tracing::SpanLinkAttributes parse_link_attributes( + nlohmann::basic_json<> request_json) { + datadog::tracing::SpanLinkAttributes link_attributes; + + auto attributes = request_json.find("attributes"); + if (attributes == request_json.cend() || !attributes->is_object()) { + return link_attributes; + } + + for (const auto& [key, value] : attributes->items()) { + if (value.is_string()) { + link_attributes.emplace(key, value.get()); + } else if (value.is_array()) { + std::size_t idx = 0; + for (const auto& elem : value) { + std::string flat_key = key + "." + std::to_string(idx++); + if (elem.is_string()) { + link_attributes.emplace(flat_key, elem.get()); + } else if (elem.is_boolean()) { + link_attributes.emplace(flat_key, + elem.get() ? "true" : "false"); + } else if (elem.is_number_integer()) { + link_attributes.emplace(flat_key, + std::to_string(elem.get())); + } else if (elem.is_number_float()) { + link_attributes.emplace(flat_key, std::to_string(elem.get())); + } + } + } + } + + return link_attributes; +} + +void RequestHandler::on_add_link(const httplib::Request& req, + httplib::Response& res) { + const auto request_json = nlohmann::json::parse(req.body); + + auto span_id = utils::get_if_exists(request_json, "span_id"); + if (!span_id) { + VALIDATION_ERROR(res, "on_add_link: missing `span_id` field."); + } + + auto parent_id = utils::get_if_exists(request_json, "parent_id"); + if (!parent_id) { + VALIDATION_ERROR(res, "on_add_link: missing `parent_id` field."); + } + + auto span_link_attributes = parse_link_attributes(request_json); + + auto span = active_spans_.find(*span_id); + if (span == active_spans_.cend()) { + const auto msg = + "on_add_link: span not found for id " + std::to_string(*span_id); + VALIDATION_ERROR(res, msg); + } + + // The linked context is either another active span or a previously extracted + // propagation context, both keyed by `parent_id`. + auto linked_it = active_spans_.find(*parent_id); + if (linked_it != active_spans_.cend()) { + span->second.add_link(linked_it->second.context(), span_link_attributes); + } else { + auto context_it = link_contexts_.find(*parent_id); + if (context_it == link_contexts_.cend()) { + const auto msg = "on_add_link: linked context not found for parent_id " + + std::to_string(*parent_id); + VALIDATION_ERROR(res, msg); + } + span->second.add_link(context_it->second, span_link_attributes); + } + + res.status = 200; +} + void RequestHandler::on_set_metric(const httplib::Request& req, httplib::Response& res) { const auto request_json = nlohmann::json::parse(req.body); @@ -333,6 +410,42 @@ void RequestHandler::on_inject_headers(const httplib::Request& req, res.set_content(response_json.dump(), "application/json"); } +datadog::tracing::SpanContext RequestHandler::make_link_context( + const datadog::tracing::Expected& span, + const datadog::tracing::Optional& headers, + std::uint64_t upstream_id) { + datadog::tracing::SpanContext stored_context{span->trace_id(), upstream_id}; + datadog::tracing::Optional sampling_priority; + + for (const auto& hdr : *headers) { + if (hdr.size() != 2) continue; + const auto name = utils::tolower(hdr[0].get()); + if (name == "tracestate") { + stored_context.tracestate = hdr[1].get(); + } else if (name == "traceparent") { + const auto tp = hdr[1].get(); + const auto pos = tp.rfind('-'); + if (pos != std::string::npos && pos + 1 < tp.size()) { + try { + stored_context.flags = static_cast( + std::stoul(tp.substr(pos + 1), nullptr, 16)); + } catch (...) { + } + } + } else if (name == "x-datadog-sampling-priority") { + try { + sampling_priority = std::stoi(hdr[1].get()); + } catch (...) { + } + } + } + // Derive W3C flags from sampling priority when no traceparent flags present. + if (!stored_context.flags.has_value() && sampling_priority.has_value()) { + stored_context.flags = *sampling_priority > 0 ? 1u : 0u; + } + return stored_context; +} + void RequestHandler::on_extract_headers(const httplib::Request& req, httplib::Response& res) { const auto request_json = nlohmann::json::parse(req.body); @@ -345,18 +458,21 @@ void RequestHandler::on_extract_headers(const httplib::Request& req, auto span = tracer_.extract_span(utils::HeaderReader(*http_headers)); if (span.if_error()) { - const auto response_body_fail = nlohmann::json{ - {"span_id", nullptr}, - }; + const auto response_body_fail = nlohmann::json{{"span_id", nullptr}}; res.set_content(response_body_fail.dump(), "application/json"); return; } - const auto response_body = nlohmann::json{ - {"span_id", span->parent_id().value()}, - }; + const auto parent_id = span->parent_id(); + const auto upstream_id = parent_id.value_or(0); + const auto response_body = nlohmann::json{{"span_id", upstream_id}}; - tracing_context_[*span->parent_id()] = std::move(*http_headers); + // Fall back to the extracted span's own id when there's no parent id + // (e.g. root-context extraction), avoiding collisions. + const auto handle = parent_id.value_or(span->id()); + link_contexts_.insert_or_assign( + handle, make_link_context(span, http_headers, upstream_id)); + tracing_context_[handle] = std::move(*http_headers); // The span below will not be finished and flushed. blackhole_.emplace_back(std::move(*span)); @@ -369,6 +485,7 @@ void RequestHandler::on_span_flush(const httplib::Request& /* req */, scheduler_->flush_telemetry(); active_spans_.clear(); tracing_context_.clear(); + link_contexts_.clear(); res.status = 200; } diff --git a/test/system-tests/request_handler.h b/test/system-tests/request_handler.h index 09baf9753..c7ba7cc45 100644 --- a/test/system-tests/request_handler.h +++ b/test/system-tests/request_handler.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -24,6 +25,7 @@ class RequestHandler final { void on_span_start(const httplib::Request& req, httplib::Response& res); void on_span_end(const httplib::Request& req, httplib::Response& res); void on_set_meta(const httplib::Request& req, httplib::Response& res); + void on_add_link(const httplib::Request& req, httplib::Response& res); void on_set_metric(const httplib::Request& /* req */, httplib::Response& res); void on_manual_keep(const httplib::Request& req, httplib::Response& res); void on_manual_drop(const httplib::Request& req, httplib::Response& res); @@ -40,6 +42,7 @@ class RequestHandler final { std::shared_ptr logger_; std::unordered_map active_spans_; std::unordered_map tracing_context_; + std::unordered_map link_contexts_; // Previously, `/trace/span/start` was used to create new spans or create // child spans from the extracted tracing context. @@ -53,5 +56,10 @@ class RequestHandler final { // explaining the name :) std::vector blackhole_; + static datadog::tracing::SpanContext make_link_context( + const datadog::tracing::Expected& span, + const datadog::tracing::Optional& headers, + std::uint64_t upstream_id); + #undef VALIDATION_ERROR }; diff --git a/test/test_span.cpp b/test/test_span.cpp index 237c9cf1e..6608e60b8 100644 --- a/test/test_span.cpp +++ b/test/test_span.cpp @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -1084,3 +1086,97 @@ TEST_SPAN("injection behaviour when apm tracing is disabled") { CHECK(contains_tracing_context(writer.items)); } } + +TEST_SPAN( + "add_link records links on the span data, without forcing the linked " + "trace's sampling decision") { + TracerConfig config; + config.service = "testsvc"; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + TraceID linked_trace_id; + std::uint64_t linked_span_id = 0; + + { + auto span = tracer.create_span(); + auto linked = tracer.create_span(); + linked_trace_id = linked.trace_id(); + linked_span_id = linked.id(); + + const auto linked_context = linked.context(); + const SpanLinkAttributes attrs{{"link.key", "value"}}; + span.add_link(linked_context, attrs); + + // `linked`'s trace hasn't been sampled yet (its trace segment is still + // open), and obtaining its context must not force a decision -- doing so + // would permanently finalize sampling before the trace is finished. + REQUIRE_FALSE(linked.trace_segment().sampling_decision().has_value()); + } + + // Find the span that carries the link across all chunks. + const SpanData* span_with_link = nullptr; + for (const auto& chunk : collector->chunks) { + for (const auto& sd : chunk) { + if (!sd->span_links.empty()) { + span_with_link = sd.get(); + } + } + } + REQUIRE(span_with_link != nullptr); + REQUIRE(span_with_link->span_links.size() == 1); + const auto& link = span_with_link->span_links[0]; + REQUIRE(link.context.trace_id == linked_trace_id); + REQUIRE(link.context.span_id == linked_span_id); + REQUIRE(link.attributes.at("link.key") == "value"); + // Sampling hadn't been decided for the linked trace yet, so the link + // carries no flags/tracestate rather than ones derived from a forced, + // premature decision. + REQUIRE_FALSE(link.context.flags.has_value()); + REQUIRE_FALSE(link.context.tracestate.has_value()); +} + +TEST_SPAN( + "add_link populates flags/tracestate when the linked trace's sampling " + "decision is already made") { + TracerConfig config; + config.service = "testsvc"; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + { + auto span = tracer.create_span(); + auto linked = tracer.create_span(); + linked.trace_segment().override_sampling_priority( + SamplingPriority::USER_KEEP); + + const auto linked_context = linked.context(); + const SpanLinkAttributes attrs{{"link.key", "value"}}; + span.add_link(linked_context, attrs); + } + + // Find the span that carries the link across all chunks. + const SpanData* span_with_link = nullptr; + for (const auto& chunk : collector->chunks) { + for (const auto& sd : chunk) { + if (!sd->span_links.empty()) { + span_with_link = sd.get(); + } + } + } + REQUIRE(span_with_link != nullptr); + REQUIRE(span_with_link->span_links.size() == 1); + const auto& link = span_with_link->span_links[0]; + REQUIRE(link.context.flags.has_value()); + REQUIRE(*link.context.flags == 1u); +} diff --git a/test/test_span_link.cpp b/test/test_span_link.cpp new file mode 100644 index 000000000..b14c5dfe2 --- /dev/null +++ b/test/test_span_link.cpp @@ -0,0 +1,145 @@ +// Tests for `SpanLink` msgpack serialization. The on-the-wire field names and +// omission rules must match the other Datadog tracers (dd-trace-go, -py, -rs). + +#include +#include +#include + +#include "span_link.h" +#include "test.h" + +using namespace datadog::tracing; + +#define TEST_SPAN_LINK(x) TEST_CASE(x, "[span_link]") + +namespace { +// Encode a single link and decode it back to JSON for inspection. +nlohmann::json encode_to_json(const SpanLink& link) { + std::string buffer; + const auto result = msgpack_encode(buffer, link); + REQUIRE(result); + return nlohmann::json::from_msgpack(buffer); +} +} // namespace + +TEST_SPAN_LINK("minimal link encodes only trace_id and span_id") { + SpanLink link{ + SpanContext(TraceID(0x1122334455667788ULL, 0xBBBBBBBBBBBBBBBBULL), 42)}; + + const auto j = encode_to_json(link); + + REQUIRE(j.is_object()); + REQUIRE(j.size() == 3); + REQUIRE(j["trace_id"].get() == 0x1122334455667788ULL); + REQUIRE(j["trace_id_high"].get() == 0xBBBBBBBBBBBBBBBBULL); + REQUIRE(j["span_id"].get() == 42); + REQUIRE_FALSE(j.contains("attributes")); + REQUIRE_FALSE(j.contains("tracestate")); + REQUIRE_FALSE(j.contains("flags")); +} + +TEST_SPAN_LINK("128-bit trace id emits trace_id_high") { + SpanLink link{SpanContext( + TraceID(/*low=*/0xAAAAAAAAAAAAAAAAULL, /*high=*/0xBBBBBBBBBBBBBBBBULL), + 7)}; + + const auto j = encode_to_json(link); + + REQUIRE(j["trace_id"].get() == 0xAAAAAAAAAAAAAAAAULL); + REQUIRE(j["trace_id_high"].get() == 0xBBBBBBBBBBBBBBBBULL); + REQUIRE(j["span_id"].get() == 7); +} + +TEST_SPAN_LINK("attributes encode as a string map and omit when empty") { + SpanLink link{SpanContext(TraceID(1), 2)}; + + SECTION("present") { + link.attributes = {{"link.key", "value"}, {"k2", "v2"}}; + const auto j = encode_to_json(link); + REQUIRE(j["attributes"]["link.key"].get() == "value"); + REQUIRE(j["attributes"]["k2"].get() == "v2"); + } + + SECTION("empty -> omitted") { + const auto j = encode_to_json(link); + REQUIRE_FALSE(j.contains("attributes")); + } +} + +TEST_SPAN_LINK("tracestate omitted when empty, present otherwise") { + SpanLink link{SpanContext(TraceID(1), 2)}; + + SECTION("non-empty") { + link.context.tracestate = "dd=s:1"; + const auto j = encode_to_json(link); + REQUIRE(j["tracestate"].get() == "dd=s:1"); + } + + SECTION("empty string -> omitted") { + link.context.tracestate = ""; + const auto j = encode_to_json(link); + REQUIRE_FALSE(j.contains("tracestate")); + } + + SECTION("unset -> omitted") { + const auto j = encode_to_json(link); + REQUIRE_FALSE(j.contains("tracestate")); + } +} + +TEST_SPAN_LINK("flags set the high bit when present") { + SpanLink link{SpanContext(TraceID(1), 2)}; + + SECTION("sampled") { + link.context.flags = 1u; + const auto j = encode_to_json(link); + REQUIRE(j["flags"].get() == (1u | (1u << 31))); + } + + SECTION("zero is still present with high bit") { + link.context.flags = 0u; + const auto j = encode_to_json(link); + REQUIRE(j["flags"].get() == (1u << 31)); + } + + SECTION("unset -> omitted") { + const auto j = encode_to_json(link); + REQUIRE_FALSE(j.contains("flags")); + } +} + +#include "span_data.h" // internal header; available via test include dirs + +TEST_SPAN_LINK("SpanData omits span_links when there are none") { + SpanData span; + std::string buffer; + const auto result = msgpack_encode(buffer, span); + REQUIRE(result); + + const auto j = nlohmann::json::from_msgpack(buffer); + REQUIRE(j.is_object()); + REQUIRE_FALSE(j.contains("span_links")); +} + +TEST_SPAN_LINK("SpanData emits span_links array when present") { + SpanData span; + + SpanLink link{SpanContext(TraceID(/*low=*/0x99, /*high=*/0x11), 123)}; + link.attributes = {{"link.key", "value"}}; + span.span_links.push_back(link); + + std::string buffer; + const auto result = msgpack_encode(buffer, span); + REQUIRE(result); + + const auto j = nlohmann::json::from_msgpack(buffer); + REQUIRE(j.contains("span_links")); + REQUIRE(j["span_links"].is_array()); + REQUIRE(j["span_links"].size() == 1); + + const auto& encoded = j["span_links"][0]; + REQUIRE(encoded["trace_id"].get() == 0x99); + REQUIRE(encoded["trace_id_high"].get() == 0x11); + REQUIRE(encoded["span_id"].get() == 123); + REQUIRE(encoded["attributes"]["link.key"].get() == "value"); +} From 47b911d0b3f920648868a232a5f3900aa7306cef Mon Sep 17 00:00:00 2001 From: MilanGarnier Date: Wed, 22 Jul 2026 14:56:34 +0200 Subject: [PATCH 15/59] feat(tracing): add support for DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT (#337) add span link struct and test enable span link tests implement Span::add_link add span link to msg pack encoding add spn link test for the Span class implenent add_link endpoint for parametric tests flatten array cleaner spanlink construction add extracted context struct cleaning up (move logic to span.cpp) format fix BAZEL build derive W3C flags from sampling priority in add_link(ExtractedContext) resolve https://github.com/DataDog/dd-trace-cpp/pull/330#discussion_r3499942743 change scope of ExtractedHeaders struct (restrict to parametric server) case insensitive lookup for headers nit: nested namespace syntax clearer variable names get rid of magic values in span_data::msgpack Cleaner msgpack_encode for span_link.cpp split RequestHandler::on_add_link make storedLinkContexts outside of on_extract_headers function bugfix: do not force sampling decision when writing tracestate in spanlink avoid collisions when adding links consecutively (parent_id=0) Add DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT to config inversion Add DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT to config rebase add branch for PropagationBehaviorExtract::to_string_view Remove trailing newline from supported-configurations.json Matches the exact output of the config-inversion tool, which the verify CI job diffs against byte-for-byte. finalize tracer config full restart link implementation on_extract_headers: store with synthetic ids to avoid collisions (same as rust parametric) span link flags field flags comve from merged context insted of w3c only, and wrtie tracestate only if w3c context matches the extracted context format rename IGNORE to IGNORE_ because windows exists move span link into private types, expose spancontext and spanlinkattributes only always store trace_id_high fix typo in parametric server Merge branch 'milan.garnier/span-links-support' into milan.garnier/propagation-behavior-extract fix typo in parametric server Update include/datadog/tracer.h Co-authored-by: Zach Montoya Update include/datadog/propagation_behavior_extract.h Co-authored-by: Zach Montoya rename: IGNORE_ to IGNORE, undefining IGNORE legacy macro on windows builds test: keep trace_id = 0 in first span link test test: cover explicit CONTINUE extraction and baggage across propagation_behavior_extract Adds a case for PropagationBehaviorExtract::CONTINUE that asserts the extracted trace/parent id are resumed with no span link, plus cases asserting extract_baggage behaves identically for CONTINUE/RESTART and returns no result under IGNORE. refact(tracing): nit change comment refactor(tracing): move span link attributes type to span.h refactor(tracing): extract find_trace_source_tag helper in trace_segment.cpp refactor(tracing): make SpanContext a class; SpanLink wraps SpanContext SpanContext gains an explicit constructor instead of relying on default member initializers, and SpanLink now stores a SpanContext member instead of duplicating trace_id/span_id/tracestate/flags fields. Also introduces the W3CLinkContext type alias for TraceSegment::w3c_link_context's return type. refactor: simplify SpanData::msgpack_encode span_links branching test(system-tests): adapt request_handler to SpanContext constructor API refact(tracing): nit change comment refactor(tracing): move span link attributes type to span.h Update src/datadog/tracer.cpp Co-authored-by: Zach Montoya update comment propagation_behavior_extraxct find instead of std::find_if remove explicit nullopt branch in config bin/format for github suggestion refactor(tracing): make SpanContext a class; SpanLink wraps SpanContext SpanContext gains an explicit constructor instead of relying on default member initializers, and SpanLink now stores a SpanContext member instead of duplicating trace_id/span_id/tracestate/flags fields. Also introduces the W3CLinkContext type alias for TraceSegment::w3c_link_context's return type. test(system-tests): adapt request_handler to SpanContext constructor API do not care about sampling priority when adding span link Merge branch 'milan.garnier/span-links-support' into milan.garnier/propagation-behavior-extract Merge branch 'main' into milan.garnier/span-links-support Merge branch 'milan.garnier/span-links-support' into milan.garnier/propagation-behavior-extract merge main into branch Co-authored-by: milan.garnier --- BUILD.bazel | 2 + CMakeLists.txt | 2 + include/datadog/config.h | 1 + include/datadog/environment.h | 1 + .../datadog/propagation_behavior_extract.h | 36 +++ include/datadog/tracer.h | 5 + include/datadog/tracer_config.h | 11 + src/datadog/extracted_data.h | 1 + src/datadog/propagation_behavior_extract.cpp | 44 ++++ src/datadog/span_data.cpp | 45 ++-- src/datadog/telemetry/telemetry_impl.cpp | 2 + src/datadog/trace_segment.cpp | 37 +-- src/datadog/tracer.cpp | 118 +++++++--- src/datadog/tracer_config.cpp | 18 ++ src/datadog/w3c_propagation.cpp | 2 + supported-configurations.json | 7 + test/system-tests/request_handler.cpp | 22 +- test/test_span_link.cpp | 5 +- test/test_tracer.cpp | 220 ++++++++++++++++++ test/test_tracer_config.cpp | 80 +++++++ 20 files changed, 579 insertions(+), 80 deletions(-) create mode 100644 include/datadog/propagation_behavior_extract.h create mode 100644 src/datadog/propagation_behavior_extract.cpp diff --git a/BUILD.bazel b/BUILD.bazel index 1682bd658..1adff2a67 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -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", @@ -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", diff --git a/CMakeLists.txt b/CMakeLists.txt index 1587fe746..63f510862 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 @@ -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 diff --git a/include/datadog/config.h b/include/datadog/config.h index c02dfd9f3..3489a69c2 100644 --- a/include/datadog/config.h +++ b/include/datadog/config.h @@ -21,6 +21,7 @@ enum class ConfigName : char { TAGS, EXTRACTION_STYLES, INJECTION_STYLES, + PROPAGATION_BEHAVIOR_EXTRACT, STARTUP_LOGS, REPORT_TELEMETRY, DELEGATE_SAMPLING, diff --git a/include/datadog/environment.h b/include/datadog/environment.h index 6cfe231a1..930466014 100644 --- a/include/datadog/environment.h +++ b/include/datadog/environment.h @@ -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, \ diff --git a/include/datadog/propagation_behavior_extract.h b/include/datadog/propagation_behavior_extract.h new file mode 100644 index 000000000..c9a9d98a5 --- /dev/null +++ b/include/datadog/propagation_behavior_extract.h @@ -0,0 +1,36 @@ +#pragma once + +// This component provides an `enum class`, `PropagationBehaviorExtract`, that +// indicates how a tracer should handle an incoming trace context on +// extraction: propagate it normally, restart the trace while linking to the +// extracted context, or discard it entirely. 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 parse_propagation_behavior_extract( + StringView text); + +} // namespace tracing +} // namespace datadog diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 08ca42743..0bf90b8e9 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -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" @@ -45,6 +46,7 @@ class Tracer { Clock clock_; std::vector injection_styles_; std::vector extraction_styles_; + PropagationBehaviorExtract propagation_behavior_extract_; Optional hostname_; std::size_t tags_header_max_size_; // Store the tracer configuration in an in-memory file, allowing it to be @@ -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 extract_span(const DictReader& reader); Expected extract_span(const DictReader& reader, const SpanConfig& config); diff --git a/include/datadog/tracer_config.h b/include/datadog/tracer_config.h index 567594cfd..de36e6fc4 100644 --- a/include/datadog/tracer_config.h +++ b/include/datadog/tracer_config.h @@ -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" @@ -107,6 +108,14 @@ struct TracerConfig { // environment variables. Optional> 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 propagation_behavior_extract; + // `report_hostname` indicates whether the tracer will include the result of // `gethostname` with traces sent to the collector. Optional report_hostname; @@ -224,6 +233,8 @@ class FinalizedTracerConfig final { std::vector injection_styles; std::vector extraction_styles; + PropagationBehaviorExtract propagation_behavior_extract; + bool report_hostname; std::size_t tags_header_size; std::shared_ptr logger; diff --git a/src/datadog/extracted_data.h b/src/datadog/extracted_data.h index b2d17c303..a26274d78 100644 --- a/src/datadog/extracted_data.h +++ b/src/datadog/extracted_data.h @@ -40,6 +40,7 @@ struct ExtractedData { Optional additional_datadog_w3c_tracestate; // `style` is the extraction style used to obtain this `ExtractedData`. It's // for diagnostics. + Optional tracestate_full; Optional 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 diff --git a/src/datadog/propagation_behavior_extract.cpp b/src/datadog/propagation_behavior_extract.cpp new file mode 100644 index 000000000..b0d3059d6 --- /dev/null +++ b/src/datadog/propagation_behavior_extract.cpp @@ -0,0 +1,44 @@ +#include + +#include + +#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 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 diff --git a/src/datadog/span_data.cpp b/src/datadog/span_data.cpp index ad3eb00cf..1d3eebfd9 100644 --- a/src/datadog/span_data.cpp +++ b/src/datadog/span_data.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "msgpack.h" @@ -134,28 +133,28 @@ Expected 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 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 msgpack_encode( diff --git a/src/datadog/telemetry/telemetry_impl.cpp b/src/datadog/telemetry/telemetry_impl.cpp index 9f1e99143..b76738f76 100644 --- a/src/datadog/telemetry/telemetry_impl.cpp +++ b/src/datadog/telemetry/telemetry_impl.cpp @@ -92,6 +92,8 @@ std::string to_string(datadog::tracing::ConfigName name) { return "trace_propagation_style_extract"; case ConfigName::INJECTION_STYLES: return "trace_propagation_style_inject"; + case ConfigName::PROPAGATION_BEHAVIOR_EXTRACT: + return "trace_propagation_behavior_extract"; case ConfigName::STARTUP_LOGS: return "trace_startup_logs_enabled"; case ConfigName::REPORT_TELEMETRY: diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index e620c4315..c2eb639b0 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -110,6 +110,18 @@ void maybe_calculate_http_endpoint(HttpEndpointCalculationMode renaming_mode, } } +// If `local_root_tags` contains the `tags::internal::trace_source` tag, +// return its value; otherwise return `nullopt`. +Optional find_trace_source_tag( + const std::unordered_map& local_root_tags) { + const auto trace_source_tag_found = + local_root_tags.find(tags::internal::trace_source); + if (trace_source_tag_found == local_root_tags.cend()) { + return nullopt; + } + return trace_source_tag_found->second; +} + // Convert rate to a fixed-point string with 6 decimal digits, // stripping trailing zeros and a decimal point. Examples: // 0.100000 -> "0.1" @@ -214,13 +226,10 @@ Optional> TraceSegment::w3c_link_context( sampling_priority = sampling_decision_->priority; trace_tags = trace_tags_; - auto& local_root_tags = spans_.front()->tags; - auto ts_tag_found = std::find_if( - local_root_tags.cbegin(), local_root_tags.cend(), - [](const auto& p) { return p.first == tags::internal::trace_source; }); - if (ts_tag_found != local_root_tags.cend()) { - trace_tags.emplace_back(tags::internal::trace_source, - ts_tag_found->second); + const Optional trace_source_tag = + find_trace_source_tag(spans_.front()->tags); + if (trace_source_tag) { + trace_tags.emplace_back(tags::internal::trace_source, *trace_source_tag); } } @@ -448,18 +457,18 @@ bool TraceSegment::inject(DictWriter& writer, const SpanData& span, trace_tags = trace_tags_; } - auto& local_root_tags = spans_.front()->tags; + std::unordered_map& local_root_tags = + spans_.front()->tags; - auto ts_tag_found = std::find_if( - local_root_tags.cbegin(), local_root_tags.cend(), - [](const auto& p) { return p.first == tags::internal::trace_source; }); + const Optional trace_source_tag = + find_trace_source_tag(local_root_tags); // When tracing (the product) is disabled, skip tracing context propagation // when: // - the local root span is NOT created by another product (no `_dd.p.ts`) // - sampling priority is DROP if (!tracing_enabled_) { - if (ts_tag_found == local_root_tags.cend() && sampling_priority <= 0) { + if (!trace_source_tag && sampling_priority <= 0) { writer.erase("x-datadog-trace-id"); writer.erase("x-datadog-parent-id"); writer.erase("x-datadog-sampling-priority"); @@ -477,8 +486,8 @@ bool TraceSegment::inject(DictWriter& writer, const SpanData& span, } // Add `_dd.p.ts` to `trace_tags` for context propagation. - if (ts_tag_found != local_root_tags.cend()) { - trace_tags.emplace_back(tags::internal::trace_source, ts_tag_found->second); + if (trace_source_tag) { + trace_tags.emplace_back(tags::internal::trace_source, *trace_source_tag); } for (const auto style : injection_styles_) { diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index d1de11f89..6db215fcb 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -27,6 +27,7 @@ #include "root_session_id.h" #include "span_data.h" #include "span_sampler.h" +#include "string_util.h" #include "tags.h" #include "telemetry_metrics.h" #include "trace_sampler.h" @@ -61,6 +62,7 @@ Tracer::Tracer(const FinalizedTracerConfig& config, clock_(config.clock), injection_styles_(config.injection_styles), extraction_styles_(config.extraction_styles), + propagation_behavior_extract_(config.propagation_behavior_extract), tags_header_max_size_(config.tags_header_size), baggage_opts_(config.baggage_opts), baggage_injection_enabled_(false), @@ -86,10 +88,12 @@ Tracer::Tracer(const FinalizedTracerConfig& config, collector_ = agent; } - for (const auto style : extraction_styles_) { - if (style == PropagationStyle::BAGGAGE) { - baggage_extraction_enabled_ = true; - break; + if (propagation_behavior_extract_ != PropagationBehaviorExtract::IGNORE) { + for (const auto style : extraction_styles_) { + if (style == PropagationStyle::BAGGAGE) { + baggage_extraction_enabled_ = true; + break; + } } } @@ -229,6 +233,13 @@ Expected Tracer::extract_span(const DictReader& reader) { Expected Tracer::extract_span(const DictReader& reader, const SpanConfig& config) { + // ignore: Discard incoming context, new span with new sampling decision + if (propagation_behavior_extract_ == PropagationBehaviorExtract::IGNORE) { + return Error{ + Error::NO_SPAN_TO_EXTRACT, + "Ignoring context extraction (propagation_behavior_extract=ignore)"}; + } + assert(!extraction_styles_.empty()); AuditedReader audited_reader{reader}; @@ -417,37 +428,76 @@ Expected Tracer::extract_span(const DictReader& reader, merged_context.trace_tags.erase(found); } - // When APM Tracing is disabled, the incoming sampling decision MAY be - // overridden based on locally generated spans. As such, the received sampling - // decision is intentionally ignored, and the tracer is expected to make its - // own decision in accordance with the locally enabled product configuration. - Optional sampling_decision; - if (tracing_enabled_ && merged_context.sampling_priority) { - SamplingDecision decision; - decision.priority = *merged_context.sampling_priority; - // `decision.mechanism` is null. We might be able to infer it once we - // extract `trace_tags`, but we would have no use for it, so we won't. - decision.origin = SamplingDecision::Origin::EXTRACTED; - - sampling_decision = decision; - } + switch (propagation_behavior_extract_) { + case PropagationBehaviorExtract::CONTINUE: { + // When APM Tracing is disabled, the incoming sampling decision MAY be + // overridden based on locally generated spans. As such, the received + // sampling decision is intentionally ignored, and the tracer is expected + // to make its own decision in accordance with the locally enabled product + // configuration. + Optional sampling_decision; + if (tracing_enabled_ && merged_context.sampling_priority) { + SamplingDecision decision; + decision.priority = *merged_context.sampling_priority; + // `decision.mechanism` is null. We might be able to infer it once we + // extract `trace_tags`, but we would have no use for it, so we won't. + decision.origin = SamplingDecision::Origin::EXTRACTED; + sampling_decision = decision; + } - const auto span_data_ptr = span_data.get(); - telemetry::counter::increment(metrics::tracer::trace_segments_created, - {"new_continued:continued"}); - const auto segment = std::make_shared( - logger_, collector_, config_manager_->trace_sampler(), span_sampler_, - config_manager_->span_defaults(), config_manager_, runtime_id_, - injection_styles_, hostname_, std::move(merged_context.origin), - tags_header_max_size_, std::move(merged_context.trace_tags), - std::move(sampling_decision), - std::move(merged_context.additional_w3c_tracestate), - std::move(merged_context.additional_datadog_w3c_tracestate), - std::move(span_data), resource_renaming_mode_, tracing_enabled_); - Span span{span_data_ptr, segment, - [generator = generator_]() { return generator->span_id(); }, - clock_}; - return span; + const auto span_data_ptr = span_data.get(); + telemetry::counter::increment(metrics::tracer::trace_segments_created, + {"new_continued:continued"}); + const auto segment = std::make_shared( + logger_, collector_, config_manager_->trace_sampler(), span_sampler_, + config_manager_->span_defaults(), config_manager_, runtime_id_, + injection_styles_, hostname_, std::move(merged_context.origin), + tags_header_max_size_, std::move(merged_context.trace_tags), + std::move(sampling_decision), + std::move(merged_context.additional_w3c_tracestate), + std::move(merged_context.additional_datadog_w3c_tracestate), + std::move(span_data), resource_renaming_mode_, tracing_enabled_); + + Span span{span_data_ptr, segment, + [generator = generator_]() { return generator->span_id(); }, + clock_}; + return span; + } + case PropagationBehaviorExtract::RESTART: { + // restart: create a new trace, with a span link to the previous one + + std::string context_headers{to_string_view(*first_style_with_trace_id)}; + to_lower(context_headers); + auto link_attributes = SpanLinkAttributes{}; + link_attributes.emplace("reason", "propagation_behavior_extract"); + link_attributes.emplace("context_headers", std::move(context_headers)); + + Optional tracestate; + if (const auto w3c = extracted_contexts.find(PropagationStyle::W3C); + w3c != extracted_contexts.end() && + w3c->second.trace_id == span_data->trace_id) { + tracestate = w3c->second.tracestate_full; + } + + Optional flags = + merged_context.sampling_priority + ? Optional( + *merged_context.sampling_priority > 0 ? 1u : 0u) + : nullopt; + + auto restarted_span = create_span(config); + restarted_span.add_link( + SpanContext{span_data->trace_id, span_data->parent_id, tracestate, + flags}, + link_attributes); + return restarted_span; + } + default: + // Should be unreachable + return Error{Error::NO_SPAN_TO_EXTRACT, + "Ignoring context extraction (unexpected " + "propagation_behavior_extract value)"}; + } } Span Tracer::extract_or_create_span(const DictReader& reader) { diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 7b2b1aca9..4fe4f2fc6 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -8,7 +8,9 @@ #include #include +#include "datadog/config.h" #include "datadog/optional.h" +#include "datadog/propagation_behavior_extract.h" #include "datadog_agent.h" #include "json.hpp" #include "null_logger.h" @@ -234,6 +236,13 @@ Expected load_tracer_env_config(Logger &logger) { warn_message(var_name, *value, var_name_override, *value_override)}); } + const auto propagation_behavior_extract = + lookup(environment::DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT); + if (propagation_behavior_extract.has_value()) { + env_cfg.propagation_behavior_extract = parse_propagation_behavior_extract( + propagation_behavior_extract.value()); + } + try { const auto global_styles = styles_from_env(environment::DD_TRACE_PROPAGATION_STYLE); @@ -403,6 +412,15 @@ Expected finalize_config(const TracerConfig &user_config, final_config.injection_styles.erase(it); } + final_config.propagation_behavior_extract = resolve_and_record_config( + env_config->propagation_behavior_extract, + user_config.propagation_behavior_extract, &final_config.metadata, + ConfigName::PROPAGATION_BEHAVIOR_EXTRACT, + PropagationBehaviorExtract::CONTINUE, + [](const PropagationBehaviorExtract &behavior) { + return std::string{to_string_view(behavior)}; + }); + final_config.runtime_id = user_config.runtime_id; final_config.root_session_id = user_config.root_session_id; final_config.process_tags = user_config.process_tags; diff --git a/src/datadog/w3c_propagation.cpp b/src/datadog/w3c_propagation.cpp index b8174577b..acba657fa 100644 --- a/src/datadog/w3c_propagation.cpp +++ b/src/datadog/w3c_propagation.cpp @@ -287,6 +287,8 @@ void extract_tracestate( } const auto tracestate = trim(*maybe_tracestate); + result.tracestate_full = tracestate; + auto maybe_parsed = parse_tracestate(tracestate); if (!maybe_parsed) { // No "dd" entry in `tracestate`, so there's nothing to extract. diff --git a/supported-configurations.json b/supported-configurations.json index 051ff8b5d..186db9f51 100644 --- a/supported-configurations.json +++ b/supported-configurations.json @@ -203,6 +203,13 @@ "type": "boolean" } ], + "DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT": [ + { + "default": "continue", + "implementation": "B", + "type": "string" + } + ], "DD_TRACE_PROPAGATION_STYLE": [ { "default": "datadog,tracecontext,baggage", diff --git a/test/system-tests/request_handler.cpp b/test/system-tests/request_handler.cpp index e2c4728d8..a7440eef5 100644 --- a/test/system-tests/request_handler.cpp +++ b/test/system-tests/request_handler.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "httplib.h" @@ -15,6 +16,16 @@ namespace { +// Return an opaque key for an extracted context without a remote parent span +// (for example, in propagation restart mode). C++-generated span IDs have +// their most significant bit cleared, so setting it prevents collisions with +// IDs in active_spans_. +std::uint64_t next_synthetic_span_id() { + static std::atomic counter{0}; + return (std::uint64_t{1} << 63) | + counter.fetch_add(1, std::memory_order_relaxed); +} + std::string get_agent_url_from_traces_url(std::string traces_url) { // Strip the API path from the traces URL to get the agent URL // This API path is defined in src/datadog/datadog_agent.cpp. @@ -463,13 +474,12 @@ void RequestHandler::on_extract_headers(const httplib::Request& req, return; } - const auto parent_id = span->parent_id(); - const auto upstream_id = parent_id.value_or(0); - const auto response_body = nlohmann::json{{"span_id", upstream_id}}; + const auto upstream_id = span->parent_id().value_or(0); - // Fall back to the extracted span's own id when there's no parent id - // (e.g. root-context extraction), avoiding collisions. - const auto handle = parent_id.value_or(span->id()); + // Keep a remote parent span ID when extraction has one. Otherwise, return a + // synthetic key so a restart context can still be used as a parent_id. + const auto handle = span->parent_id().value_or(next_synthetic_span_id()); + const auto response_body = nlohmann::json{{"span_id", handle}}; link_contexts_.insert_or_assign( handle, make_link_context(span, http_headers, upstream_id)); tracing_context_[handle] = std::move(*http_headers); diff --git a/test/test_span_link.cpp b/test/test_span_link.cpp index b14c5dfe2..390f7bccd 100644 --- a/test/test_span_link.cpp +++ b/test/test_span_link.cpp @@ -23,15 +23,14 @@ nlohmann::json encode_to_json(const SpanLink& link) { } // namespace TEST_SPAN_LINK("minimal link encodes only trace_id and span_id") { - SpanLink link{ - SpanContext(TraceID(0x1122334455667788ULL, 0xBBBBBBBBBBBBBBBBULL), 42)}; + SpanLink link{SpanContext(TraceID(0x1122334455667788ULL), 42)}; const auto j = encode_to_json(link); REQUIRE(j.is_object()); REQUIRE(j.size() == 3); REQUIRE(j["trace_id"].get() == 0x1122334455667788ULL); - REQUIRE(j["trace_id_high"].get() == 0xBBBBBBBBBBBBBBBBULL); + REQUIRE(j["trace_id_high"].get() == 0); REQUIRE(j["span_id"].get() == 42); REQUIRE_FALSE(j.contains("attributes")); REQUIRE_FALSE(j.contains("tracestate")); diff --git a/test/test_tracer.cpp b/test/test_tracer.cpp index 598901d50..d41d51b7a 100644 --- a/test/test_tracer.cpp +++ b/test/test_tracer.cpp @@ -1544,6 +1544,188 @@ TEST_TRACER("span extraction") { } } +TEST_TRACER("continue extraction resumes the extracted trace") { + TracerConfig config; + config.service = "testsvc"; + config.propagation_behavior_extract = PropagationBehaviorExtract::CONTINUE; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + const auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + const std::unordered_map headers{ + {"x-datadog-trace-id", "1"}, + {"x-datadog-parent-id", "2"}, + {"x-datadog-sampling-priority", "2"}, + }; + + { + MockDictReader reader{headers}; + const auto span = tracer.extract_span(reader); + REQUIRE(span); + REQUIRE(span->trace_id().low == 1); + REQUIRE(span->parent_id() == 2); + } + + REQUIRE(collector->span_count() == 1); + const auto& span = collector->first_span(); + REQUIRE(span.trace_id.low == 1); + REQUIRE(span.parent_id == 2); + REQUIRE(span.span_links.empty()); +} + +TEST_TRACER("ignore extraction returns no span to extract") { + TracerConfig config; + config.service = "testsvc"; + config.propagation_behavior_extract = PropagationBehaviorExtract::IGNORE; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + const auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + const std::unordered_map headers{ + {"x-datadog-trace-id", "1"}, + {"x-datadog-parent-id", "2"}, + {"x-datadog-sampling-priority", "2"}, + }; + + MockDictReader reader{headers}; + const auto result = tracer.extract_span(reader); + REQUIRE(!result); + REQUIRE(result.error().code == Error::NO_SPAN_TO_EXTRACT); +} + +TEST_TRACER("restart extraction links to the extracted context") { + TracerConfig config; + config.service = "testsvc"; + config.propagation_behavior_extract = PropagationBehaviorExtract::RESTART; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + const auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + const std::unordered_map headers{ + {"x-datadog-trace-id", "1"}, + {"x-datadog-parent-id", "1"}, + {"x-datadog-sampling-priority", "2"}, + {"x-datadog-tags", "_dd.p.tid=1111111111111111"}, + {"traceparent", + "00-11111111111111110000000000000001-0000000000000001-01"}, + }; + + { + MockDictReader reader{headers}; + const auto span = tracer.extract_span(reader); + REQUIRE(span); + REQUIRE_FALSE(span->parent_id()); + } + + REQUIRE(collector->span_count() == 1); + const auto& span = collector->first_span(); + REQUIRE(span.span_links.size() == 1); + const auto& link = span.span_links.front(); + REQUIRE(link.context.trace_id.low == 1); + REQUIRE(link.context.trace_id.high == 0x1111111111111111); + REQUIRE(link.context.span_id == 1); + REQUIRE(link.attributes == SpanLinkAttributes{ + {"reason", "propagation_behavior_extract"}, + {"context_headers", "datadog"}, + }); + REQUIRE(link.context.flags == Optional(1u)); +} + +TEST_TRACER("restart extraction link preserves traceparent sampled flag") { + TracerConfig config; + config.service = "testsvc"; + config.propagation_behavior_extract = PropagationBehaviorExtract::RESTART; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + const auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + SECTION("sampled traceparent yields flags=1") { + const std::unordered_map headers{ + {"traceparent", + "00-11111111111111110000000000000001-0000000000000001-01"}, + }; + { + MockDictReader reader{headers}; + const auto span = tracer.extract_span(reader); + REQUIRE(span); + } + + REQUIRE(collector->span_count() == 1); + const auto& link = collector->first_span().span_links.front(); + REQUIRE(link.context.flags == Optional(1u)); + } + + SECTION("unsampled traceparent yields flags=0") { + const std::unordered_map headers{ + {"traceparent", + "00-11111111111111110000000000000001-0000000000000001-00"}, + }; + { + MockDictReader reader{headers}; + const auto span = tracer.extract_span(reader); + REQUIRE(span); + } + + REQUIRE(collector->span_count() == 1); + const auto& link = collector->first_span().span_links.front(); + REQUIRE(link.context.flags == Optional(0u)); + } +} + +TEST_TRACER("restart extraction link uses metadata from the selected context") { + TracerConfig config; + config.service = "testsvc"; + config.propagation_behavior_extract = PropagationBehaviorExtract::RESTART; + const auto collector = std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + + const auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + // Datadog is the default first extraction style. The W3C context is + // intentionally unrelated and must not contribute metadata to the link. + const std::unordered_map headers{ + {"x-datadog-trace-id", "1"}, + {"x-datadog-parent-id", "1"}, + {"x-datadog-sampling-priority", "2"}, + {"traceparent", + "00-00000000000000000000000000000002-0000000000000002-00"}, + {"tracestate", "vendor=unrelated"}, + }; + + { + MockDictReader reader{headers}; + const auto span = tracer.extract_span(reader); + REQUIRE(span); + } + + REQUIRE(collector->span_count() == 1); + const auto& link = collector->first_span().span_links.front(); + REQUIRE(link.context.trace_id.low == 1); + REQUIRE(link.context.trace_id.high == 0); + REQUIRE(link.context.span_id == 1); + REQUIRE(link.context.tracestate == nullopt); + REQUIRE(link.context.flags == Optional(1u)); +} + TEST_TRACER("baggage usage") { TracerConfig config; config.logger = std::make_shared(); @@ -1585,6 +1767,44 @@ TEST_TRACER("baggage usage") { } } +TEST_TRACER("baggage extraction and propagation_behavior_extract") { + TracerConfig config; + config.logger = std::make_shared(); + config.collector = std::make_shared(); + + const std::unordered_map headers{ + {"baggage", "data=dog"}, + }; + + SECTION("baggage extraction behaves identically for continue and restart") { + for (const auto behavior : {PropagationBehaviorExtract::CONTINUE, + PropagationBehaviorExtract::RESTART}) { + config.propagation_behavior_extract = behavior; + auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + + Tracer tracer(*finalized_config); + + MockDictReader reader{headers}; + auto maybe_baggage = tracer.extract_baggage(reader); + REQUIRE(maybe_baggage); + CHECK(maybe_baggage->get("data") == "dog"); + } + } + + SECTION("baggage extraction returns no result when ignoring context") { + config.propagation_behavior_extract = PropagationBehaviorExtract::IGNORE; + auto finalized_config = finalize_config(config); + REQUIRE(finalized_config); + + Tracer tracer(*finalized_config); + + MockDictReader reader{headers}; + auto maybe_baggage = tracer.extract_baggage(reader); + CHECK(!maybe_baggage); + } +} + TEST_TRACER("report hostname") { TracerConfig config; config.service = "testsvc"; diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index 5f6aad8ac..c313fb407 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -1293,6 +1293,86 @@ TRACER_CONFIG_TEST("TracerConfig propagation styles") { } } +TRACER_CONFIG_TEST("TracerConfig propagation behavior extract") { + TracerConfig config; + config.service = "testsvc"; + + const auto behavior_metadata = [](const FinalizedTracerConfig& finalized) { + return finalized.metadata.at(ConfigName::PROPAGATION_BEHAVIOR_EXTRACT); + }; + + SECTION("defaults to continue") { + const auto finalized = finalize_config(config); + REQUIRE(finalized); + CHECK(finalized->propagation_behavior_extract == + PropagationBehaviorExtract::CONTINUE); + + const auto& metadata = behavior_metadata(*finalized); + REQUIRE(metadata.size() == 1); + CHECK(metadata.back().origin == ConfigMetadata::Origin::DEFAULT); + CHECK(metadata.back().value == "continue"); + } + + SECTION("uses programmatic configuration") { + config.propagation_behavior_extract = PropagationBehaviorExtract::RESTART; + + const auto finalized = finalize_config(config); + REQUIRE(finalized); + CHECK(finalized->propagation_behavior_extract == + PropagationBehaviorExtract::RESTART); + + const auto& metadata = behavior_metadata(*finalized); + REQUIRE(metadata.size() == 2); + CHECK(metadata.back().origin == ConfigMetadata::Origin::CODE); + CHECK(metadata.back().value == "restart"); + } + + SECTION("environment configuration overrides programmatic configuration") { + const EnvGuard guard{"DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT", "ignore"}; + config.propagation_behavior_extract = PropagationBehaviorExtract::RESTART; + + const auto finalized = finalize_config(config); + REQUIRE(finalized); + CHECK(finalized->propagation_behavior_extract == + PropagationBehaviorExtract::IGNORE); + + const auto& metadata = behavior_metadata(*finalized); + REQUIRE(metadata.size() == 3); + CHECK(metadata.back().origin == + ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); + CHECK(metadata.back().value == "ignore"); + } + + SECTION("invalid environment configuration falls through to code") { + const EnvGuard guard{"DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT", "invalid"}; + config.propagation_behavior_extract = PropagationBehaviorExtract::RESTART; + + const auto finalized = finalize_config(config); + REQUIRE(finalized); + CHECK(finalized->propagation_behavior_extract == + PropagationBehaviorExtract::RESTART); + + const auto& metadata = behavior_metadata(*finalized); + REQUIRE(metadata.size() == 2); + CHECK(metadata.back().origin == ConfigMetadata::Origin::CODE); + CHECK(metadata.back().value == "restart"); + } + + SECTION("invalid environment configuration falls through to the default") { + const EnvGuard guard{"DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT", "invalid"}; + + const auto finalized = finalize_config(config); + REQUIRE(finalized); + CHECK(finalized->propagation_behavior_extract == + PropagationBehaviorExtract::CONTINUE); + + const auto& metadata = behavior_metadata(*finalized); + REQUIRE(metadata.size() == 1); + CHECK(metadata.back().origin == ConfigMetadata::Origin::DEFAULT); + CHECK(metadata.back().value == "continue"); + } +} + TRACER_CONFIG_TEST("configure 128-bit trace IDs") { TracerConfig config; config.service = "testsvc"; From 4b2d216a32d893c2d24b568a5f42cf14b7c40575 Mon Sep 17 00:00:00 2001 From: Shawn Potts <77298184+spottsdd@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:36:34 +0100 Subject: [PATCH 16/59] Fix shared library link flag in README (-ldd_trace_cpp -> -ldd-trace-cpp) (#344) CMakeLists.txt sets OUTPUT_NAME "dd-trace-cpp" for the shared and static targets, so the installed file is libdd-trace-cpp.so/.a. The README's dynamic linking section still referenced the old -ldd_trace_cpp flag, which doesn't match any installed library name and fails at link time. Co-authored-by: Cursor --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9778eeaa5..ebe5aabd5 100644 --- a/README.md +++ b/README.md @@ -104,12 +104,12 @@ c++ -I/path/to/dd-trace-cpp/.install/include -c -o my_app.o my_app.cpp ``` When linking an executable that uses `dd-trace-cpp`, specify linkage to the -built library using the `-ldd_trace_cpp` option and an appropriate `-L` option. +built library using the `-ldd-trace-cpp` option and an appropriate `-L` option. If the library was installed into the default system directories, then the `-L` -options is not needed. The `-ldd_trace_cpp` option is always needed. +options is not needed. The `-ldd-trace-cpp` option is always needed. ```shell -c++ -o my_app my_app.o -L/path/to/dd-trace-cpp/.install/lib -ldd_trace_cpp +c++ -o my_app my_app.o -L/path/to/dd-trace-cpp/.install/lib -ldd-trace-cpp ``` ## Contributing From 551226d065ea7178e5283c0bcf442de985c8c06e Mon Sep 17 00:00:00 2001 From: Brian Marks Date: Thu, 30 Jul 2026 14:57:16 -0400 Subject: [PATCH 17/59] ci: skip Datadog uploads without an API key (#346) --- .github/workflows/dev.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 005797be1..16b607a2c 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -55,7 +55,7 @@ jobs: packages: read env: BUILD_DIR: .build - DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY }} + HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Configure @@ -67,7 +67,9 @@ jobs: env: ASAN_OPTIONS: alloc_dealloc_mismatch=0 - name: Upload test report to Datadog - if: success() || failure() + if: (success() || failure()) && env.HAS_DD_API_KEY == 'true' + env: + DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY }} run: | curl -L --fail "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-${{ matrix.arch }}" --output "/usr/local/bin/datadog-ci" && chmod +x /usr/local/bin/datadog-ci datadog-ci junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp .build/report.xml @@ -137,7 +139,7 @@ jobs: contents: read packages: read env: - DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY }} + HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Dependency Manager (scoop) @@ -157,7 +159,9 @@ jobs: & 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1' -arch ${{ matrix.arch }} .\build\test\tests.exe -r junit -o report.xml - name: Upload test report to Datadog - if: success() || failure() + if: (success() || failure()) && env.HAS_DD_API_KEY == 'true' + env: + DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY }} run: | Invoke-WebRequest -Uri "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_win-x64" -OutFile "datadog-ci.exe" ./datadog-ci.exe junit upload --service dd-trace-cpp --tags test.source.file:test/*.cpp report.xml @@ -172,10 +176,13 @@ jobs: permissions: contents: read packages: read + env: + HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - run: bin/test --coverage --verbose - name: Upload code coverage report to Datadog + if: success() && env.HAS_DD_API_KEY == 'true' # See https://github.com/DataDog/coverage-upload-github-action/releases uses: DataDog/coverage-upload-github-action@2ba057033351887422f8eb0203d1990c3acbc8c5 # v1.0.4 with: From 0825debd12d7d4a21783392898b0a5831f00a635 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2026 14:15:16 -0400 Subject: [PATCH 18/59] build(deps): bump the gh-actions-packages group with 4 updates (#333) Bumps the gh-actions-packages group with 4 updates: [actions/checkout](https://github.com/actions/checkout), [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [DataDog/coverage-upload-github-action](https://github.com/datadog/coverage-upload-github-action). Updates `actions/checkout` from 6.0.2 to 7.0.0 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) Updates `github/codeql-action/init` from 4.36.0 to 4.36.2 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7211b7c8077ea37d8641b6271f6a365a22a5fbfa...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) Updates `github/codeql-action/analyze` from 4.36.0 to 4.36.2 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7211b7c8077ea37d8641b6271f6a365a22a5fbfa...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) Updates `DataDog/coverage-upload-github-action` from 1.0.4 to 1.0.5 - [Release notes](https://github.com/datadog/coverage-upload-github-action/releases) - [Commits](https://github.com/datadog/coverage-upload-github-action/compare/2ba057033351887422f8eb0203d1990c3acbc8c5...d9548b1c3c4ab639d5d3ab29a1508af188975f77) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: gh-actions-packages - dependency-name: github/codeql-action/init dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gh-actions-packages - dependency-name: github/codeql-action/analyze dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gh-actions-packages - dependency-name: DataDog/coverage-upload-github-action dependency-version: 1.0.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gh-actions-packages ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Brian Marks --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/dev.yml | 14 +++++++------- .github/workflows/main.yml | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8ef74cc1b..d7dcb0bc9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,10 +22,10 @@ jobs: language: [ 'cpp' ] steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Initialize CodeQL - uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: languages: ${{ matrix.language }} @@ -36,4 +36,4 @@ jobs: run: bin/cmake-build --preset=ci-codeql - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 16b607a2c..1980e4ec9 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -9,7 +9,7 @@ jobs: env: BUILD_DIR: .build steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Check format run: bin/check-format - name: Shellcheck @@ -57,7 +57,7 @@ jobs: BUILD_DIR: .build HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Configure run: bin/with-toolchain ${{ matrix.toolchain }} cmake . -B .build --preset ci-clang - name: Build @@ -93,7 +93,7 @@ jobs: container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-${{matrix.docker-arch}} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Build run: bin/with-toolchain ${{ matrix.toolchain }} bazelisk --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp @@ -107,7 +107,7 @@ jobs: matrix: bazelrc: [".bazelrc.absl", ".bazelrc.std"] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Dependency Manager (scoop) run: | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser @@ -141,7 +141,7 @@ jobs: env: HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Dependency Manager (scoop) run: | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser @@ -179,12 +179,12 @@ jobs: env: HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - run: bin/test --coverage --verbose - name: Upload code coverage report to Datadog if: success() && env.HAS_DD_API_KEY == 'true' # See https://github.com/DataDog/coverage-upload-github-action/releases - uses: DataDog/coverage-upload-github-action@2ba057033351887422f8eb0203d1990c3acbc8c5 # v1.0.4 + uses: DataDog/coverage-upload-github-action@d9548b1c3c4ab639d5d3ab29a1508af188975f77 # v1.0.5 with: api_key: ${{ secrets.DD_CI_VIS_API_KEY }} files: .coverage/filtered.info diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 68b670262..2fd051b1c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: env: DURATION_SEC: 300 # 5min steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Configure run: bin/with-toolchain llvm cmake . -B .build -DCMAKE_BUILD_TYPE=Debug -DDD_TRACE_BUILD_FUZZERS=1 -DDD_TRACE_ENABLE_SANITIZE=1 -DDD_TRACE_TRANSPORT=none - name: Build From b8001d7f35f231b221c3b71a1d38e09be89769ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2026 14:15:27 -0400 Subject: [PATCH 19/59] build(deps): update Bazel dependencies and pin Bazel 9.1.1 (#332) * build(deps): bump the bazel-packages group across 1 directory with 2 updates Bumps the bazel-packages group with 2 updates in the / directory: [abseil-cpp](https://github.com/abseil/abseil-cpp) and [rules_cc](https://github.com/bazelbuild/rules_cc). Updates `abseil-cpp` from 20260107.1 to 20260526.0 - [Release notes](https://github.com/abseil/abseil-cpp/releases) - [Commits](https://github.com/abseil/abseil-cpp/compare/20260107.1...20260526.0) Updates `rules_cc` from 0.2.14 to 0.2.21 - [Release notes](https://github.com/bazelbuild/rules_cc/releases) - [Commits](https://github.com/bazelbuild/rules_cc/compare/0.2.14...0.2.21) --- updated-dependencies: - dependency-name: abseil-cpp dependency-version: '20260526.0' dependency-type: direct:production update-type: version-update:semver-major dependency-group: bazel-packages - dependency-name: rules_cc dependency-version: 0.2.20 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: bazel-packages ... Signed-off-by: dependabot[bot] * build: pin Bazel 9.1.1 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Zach Montoya Co-authored-by: Brian Marks Co-authored-by: Brian Marks --- .bazelversion | 1 + MODULE.bazel | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .bazelversion diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..44931da26 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +9.1.1 diff --git a/MODULE.bazel b/MODULE.bazel index 3b4551359..2a79e71ee 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -3,7 +3,7 @@ module( version = "2.1.2", ) -bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "com_google_absl") +bazel_dep(name = "abseil-cpp", version = "20260526.0", repo_name = "com_google_absl") bazel_dep(name = "bazel_skylib", version = "1.9.0") bazel_dep(name = "platforms", version = "1.1.0") -bazel_dep(name = "rules_cc", version = "0.2.18") +bazel_dep(name = "rules_cc", version = "0.2.21") From fa2e9efb6abb9853113112d61110b845989d7595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:59:48 +0200 Subject: [PATCH 20/59] build(deps): bump the gh-actions-packages group with 3 updates (#348) --- .github/workflows/codeql-analysis.yml | 6 +++--- .github/workflows/dev.yml | 12 ++++++------ .github/workflows/main.yml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d7dcb0bc9..376de4877 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,10 +22,10 @@ jobs: language: [ 'cpp' ] steps: - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: languages: ${{ matrix.language }} @@ -36,4 +36,4 @@ jobs: run: bin/cmake-build --preset=ci-codeql - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 1980e4ec9..2420f2401 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -9,7 +9,7 @@ jobs: env: BUILD_DIR: .build steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Check format run: bin/check-format - name: Shellcheck @@ -57,7 +57,7 @@ jobs: BUILD_DIR: .build HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Configure run: bin/with-toolchain ${{ matrix.toolchain }} cmake . -B .build --preset ci-clang - name: Build @@ -93,7 +93,7 @@ jobs: container: image: datadog/docker-library:dd-trace-cpp-ci-23768e9-${{matrix.docker-arch}} steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Build run: bin/with-toolchain ${{ matrix.toolchain }} bazelisk --bazelrc=${{ matrix.bazelrc }} build dd_trace_cpp @@ -107,7 +107,7 @@ jobs: matrix: bazelrc: [".bazelrc.absl", ".bazelrc.std"] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Dependency Manager (scoop) run: | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser @@ -141,7 +141,7 @@ jobs: env: HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Dependency Manager (scoop) run: | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser @@ -179,7 +179,7 @@ jobs: env: HAS_DD_API_KEY: ${{ secrets.DD_CI_VIS_API_KEY != '' }} steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - run: bin/test --coverage --verbose - name: Upload code coverage report to Datadog if: success() && env.HAS_DD_API_KEY == 'true' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2fd051b1c..77e1bd827 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: env: DURATION_SEC: 300 # 5min steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Configure run: bin/with-toolchain llvm cmake . -B .build -DCMAKE_BUILD_TYPE=Debug -DDD_TRACE_BUILD_FUZZERS=1 -DDD_TRACE_ENABLE_SANITIZE=1 -DDD_TRACE_TRANSPORT=none - name: Build From 5cd95652e8eecacac16cd41a55fabe3e417b470d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:59:57 +0200 Subject: [PATCH 21/59] build(deps): bump the bazel-packages group with 2 updates (#347) --- MODULE.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 2a79e71ee..65ca21889 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,6 +4,6 @@ module( ) bazel_dep(name = "abseil-cpp", version = "20260526.0", repo_name = "com_google_absl") -bazel_dep(name = "bazel_skylib", version = "1.9.0") +bazel_dep(name = "bazel_skylib", version = "1.9.2") bazel_dep(name = "platforms", version = "1.1.0") -bazel_dep(name = "rules_cc", version = "0.2.21") +bazel_dep(name = "rules_cc", version = "0.2.22") From 5d97eaae384a743180025cb4c2312d29f404daf5 Mon Sep 17 00:00:00 2001 From: Shawn Potts <77298184+spottsdd@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:39:31 +0100 Subject: [PATCH 22/59] Fix cmake install missing http_endpoint_calculation_mode.h (#345) --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 63f510862..bba77378c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,6 +146,7 @@ target_sources(dd-trace-cpp-objects include/datadog/event_scheduler.h include/datadog/expected.h include/datadog/http_client.h + include/datadog/http_endpoint_calculation_mode.h include/datadog/id_generator.h include/datadog/injection_options.h include/datadog/logger.h From a835232845a0cfe422247673e7c5407ae509be07 Mon Sep 17 00:00:00 2001 From: Gustavo Lopes Date: Wed, 5 Aug 2026 16:21:39 +0100 Subject: [PATCH 23/59] Place _dd.apm.enabled:0 in every span (#343) * Place _dd.apm.enabled:0 in every span * address review comments --- src/datadog/trace_segment.cpp | 10 +++----- test/test_tracer.cpp | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index c2eb639b0..555f648c0 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -328,16 +328,12 @@ void TraceSegment::span_finished() { } } - // RFC seems to only mandate that this be set if the trace is kept. - // However, system-tests expect this to always be set. - // Add it all the time; can't hurt - if (!tracing_enabled_) { - local_root.numeric_tags[tags::internal::apm_enabled] = 0; - } - // Some tags are repeated on all spans. for (const auto& span_ptr : spans_) { SpanData& span = *span_ptr; + if (!tracing_enabled_) { + span.numeric_tags[tags::internal::apm_enabled] = 0; + } if (origin_) { span.tags[tags::internal::origin] = *origin_; } diff --git a/test/test_tracer.cpp b/test/test_tracer.cpp index d41d51b7a..94c14b6f6 100644 --- a/test/test_tracer.cpp +++ b/test/test_tracer.cpp @@ -2118,6 +2118,29 @@ TEST_TRACER("move semantics") { (void)tracer2; } +TEST_TRACER("APM tracing enabled") { + TracerConfig config; + config.service = "testsvc"; + config.name = "test.op"; + const std::shared_ptr collector = + std::make_shared(); + config.collector = collector; + config.logger = std::make_shared(); + config.tracing_enabled = true; + + Expected finalized_config = finalize_config(config); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + tracer.create_span(); + + REQUIRE(collector->chunks.size() == 1); + REQUIRE(collector->chunks.front().size() == 1); + const SpanData& span = *collector->chunks.front().front(); + // tracing needs to be disabled for this tag to be set + CHECK(span.numeric_tags.count(tags::internal::apm_enabled) == 0); +} + TEST_TRACER("APM tracing disabled") { TracerConfig config; config.service = "testsvc"; @@ -2130,6 +2153,29 @@ TEST_TRACER("APM tracing disabled") { TimePoint current_time = default_clock(); auto clock = [¤t_time]() { return current_time; }; + SECTION("_dd.apm.enabled is added to every span") { + Expected finalized_config = + finalize_config(config, clock); + REQUIRE(finalized_config); + Tracer tracer{*finalized_config}; + + SpanConfig service_entry_config; + service_entry_config.service = "child-service"; + + { + Span root = tracer.create_span(); + root.create_child(); + root.create_child(service_entry_config); + } + + REQUIRE(collector->chunks.size() == 1); + const auto& chunk = collector->chunks.front(); + REQUIRE(chunk.size() == 3); + for (const auto& span : chunk) { + CHECK(span->numeric_tags.at(tags::internal::apm_enabled) == 0); + } + } + SECTION("sampling behaviour") { SECTION("span with _dd.p.ts is kept") { auto finalized_config = finalize_config(config, clock); From 84ec379702b14fe75ec24006d75b2ba382f4711f Mon Sep 17 00:00:00 2001 From: Xavier Lamorlette Date: Fri, 7 Aug 2026 10:23:55 +0200 Subject: [PATCH 24/59] Add 'Clean Code' and 'C++ Code Style' sections to the 'Conventions' document (#349) --- AGENTS.md | 13 +++++++++ CONTRIBUTING.md | 10 ++++--- docs/README.md | 2 +- docs/conventions.md | 67 +++++++++++++++++++++++++++++++-------------- 4 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..bb38bbfbf --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,13 @@ +# Agent Instructions + +## Conventions + +Follow [docs/conventions.md](docs/conventions.md). + +## Build & Test + +See [docs/development.md](docs/development.md) for build, test, and formatting instructions. + +## Architecture + +See [docs/design.md](docs/design.md) for the library's architecture and design rationale. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4cebc1356..e468810b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,10 +2,12 @@ Pull requests for bug fixes are welcome. -Before submitting new features or changes to current functionality, [open an +Before submitting new features or changes to current functionality, please [open an issue](https://github.com/DataDog/dd-trace-cpp/issues/new) and discuss your ideas or propose the changes you wish to make. After a resolution is reached, a PR can be submitted for review. -Please refer to the [documentation](docs) to learn about the architecture of the Datadog of C++ Tracing -Library and the development processes, notably testing and code formatting, which are mandatory before -submitting code changes. +Sefer to the [documentation](docs) to learn about the architecture of the Datadog C++ Tracer Library +and its development processes. In particular, review: + +- [Conventions](docs/conventions.md); +- [Development Processes](docs/development.md). diff --git a/docs/README.md b/docs/README.md index 99adaf433..f9ff5d69e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,5 +3,5 @@ This directory contains documentation of the Datadog C++ Tracer, including: - [Design](design.md) -- [Conventions and Rationale](conventions.md) +- [Conventions](conventions.md) - [Development Processes](development.md) diff --git a/docs/conventions.md b/docs/conventions.md index 353954a9d..7952059a3 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -1,21 +1,28 @@ -# Datadog C++ Tracer Conventions and Rationale +# Datadog C++ Tracer Conventions + +This document defines repository-wide conventions for `dd-trace-cpp`. Apply these conventions to all +new and modified code. ## C++ Version -We use **C++17** to ensure maximum compatibility. +The project targets **C++17** for broad compatibility. + +All code must compile as C++17. Do not use features introduced in C++20 or later. ## Build Systems -**CMake** is the primary build system supported, as documented in [the main Readme](../README.md). It is -how downstreams consumers, such as the Datadog Nginx module, embed the library (see +- **CMake** is the primary build system supported, as documented in [the main Readme](../README.md). +Downstream consumers, such as the Datadog Nginx module, use CMake to embed the library (see [nginx-datadog/CMakeLists.txt](https://github.com/DataDog/nginx-datadog/blob/c29a57f/CMakeLists.txt#L121)). - -**Bazel** is used internally for CI and by the Envoy integration (see +- **Bazel** is used internally for CI and by the Envoy integration (see [envoy/source/extensions/tracers/datadog/BUILD](https://github.com/envoyproxy/envoy/blob/9d47ea91cc/source/extensions/tracers/datadog/BUILD#L52)). -## C Standard Libaries +## C Standard Libraries + +The project supports: -We support **glibc** (GUN C Library) and [**musl**](https://en.wikipedia.org/wiki/Musl) (notably used by Alpine Linux). +- **glibc** (GNU C Library); +- [**musl**](https://en.wikipedia.org/wiki/Musl) (notably used by Alpine Linux). ## C++ Standard Library vs Abseil @@ -29,22 +36,42 @@ and ## Header Files Organization -We separate public and private APIs. Public headers live in `include/datadog` and are the only ones exported. Internal headers live in `src` and are not installed. +Public and private APIs are kept separate: + +- Public headers live in `include/datadog` and are the only ones exported. +- Internal headers live in `src` and are not installed. ## Testing Frameworks -**Catch2** is used for unit tests. +- Use **Catch2** for unit tests. +- Use **Google Benchmark** for performance benchmarks. + +## Clean Code + +- Use meaningful variable and function names. +- Do not use single-letter variable names. +- Avoid abbreviations, unless very common and unambiguous. +- Avoid obvious comments. +- Prefer clearer variable and function names over explanatory comments. +- Keep functions small and focused (<~ 20 lines when practical). +- When practical, place caller functions before callees, so the code can be read from top to bottom. + +## C++ Code Style -**Google Benchmark** is used for performance benchmarks. +- Use modern C++ idioms. +- Prefer explicit types. Use `auto` only for very long type names (>~ 50 characters). +- Never use C-style casts. +- Use raw pointers only when absolutely necessary. +- Use C++17 nested namespace syntax. +- Minimize the number of `#include` lines. Do not enforce the include-what-you-use rule. ## Naming Conventions -- `class TypeName;` -- `.member_function();` -- `free_function();` -- `f(int func_arg);` -- `int local_var;` -- `int private_member_;` -- `int public_member;` -- `enum Color { red, green, blue };` -- `which_one` +- class: `class TypeName;` +- class member function: `.member_function();` +- class public member: `int public_member;` +- class private member: `int private_member_;` +- free function: `free_function();` +- function argument: `function(int func_arg);` +- local variable: `int local_var;` +- enumeration: `enum class Color { RED, GREEN, BLUE };` From 6cbe22e4c809c184d517b50cdf19074fa31a8844 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 4 Jun 2026 14:05:10 +0000 Subject: [PATCH 25/59] Import process context reference implementation Imported `otel_process_ctx.c` (renamed to cpp) and `otel_process_ctx.h` from with no changes. --- src/datadog/otel_process_ctx.cpp | 876 +++++++++++++++++++++++++++++++ src/datadog/otel_process_ctx.h | 153 ++++++ 2 files changed, 1029 insertions(+) create mode 100644 src/datadog/otel_process_ctx.cpp create mode 100644 src/datadog/otel_process_ctx.h diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp new file mode 100644 index 000000000..a68dac9d0 --- /dev/null +++ b/src/datadog/otel_process_ctx.cpp @@ -0,0 +1,876 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache License (Version 2.0). +// This product includes software developed at Datadog (https://www.datadoghq.com/) Copyright 2025 Datadog, Inc. + +#include "otel_process_ctx.h" + +#ifndef _GNU_SOURCE + #define _GNU_SOURCE +#endif + +// Note: Things here are needed for NOOP. Things that are only for non-NOOP get added further below. + +#include + +#define ADD_QUOTES_HELPER(x) #x +#define ADD_QUOTES(x) ADD_QUOTES_HELPER(x) + +static const otel_process_ctx_data empty_data = { + .deployment_environment_name = NULL, + .service_instance_id = NULL, + .service_name = NULL, + .service_version = NULL, + .telemetry_sdk_language = NULL, + .telemetry_sdk_version = NULL, + .telemetry_sdk_name = NULL, + .resource_attributes = NULL, + .extra_attributes = NULL, + .thread_ctx_config = NULL +}; + +#if (defined(OTEL_PROCESS_CTX_NOOP) && OTEL_PROCESS_CTX_NOOP) || !defined(__linux__) + // NOOP implementations when OTEL_PROCESS_CTX_NOOP is defined or not on Linux + + otel_process_ctx_result otel_process_ctx_publish(const otel_process_ctx_data *data) { + (void) data; // Suppress unused parameter warning + return (otel_process_ctx_result) {.success = false, .error_message = "OTEL_PROCESS_CTX_NOOP mode is enabled - no-op implementation (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + + bool otel_process_ctx_drop_current(void) { + return true; // Nothing to do, this always succeeds + } + + #ifndef OTEL_PROCESS_CTX_NO_READ + otel_process_ctx_read_result otel_process_ctx_read(void) { + return (otel_process_ctx_read_result) {.success = false, .error_message = "OTEL_PROCESS_CTX_NOOP mode is enabled - no-op implementation (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", .data = empty_data}; + } + + bool otel_process_ctx_read_drop(otel_process_ctx_read_result *result) { + (void) result; // Suppress unused parameter warning + return false; + } + #endif // OTEL_PROCESS_CTX_NO_READ +#else // OTEL_PROCESS_CTX_NOOP + +#ifdef __cplusplus + #include + using std::atomic_thread_fence; + using std::memory_order_seq_cst; +#else + #include +#endif +#include +#include +#include +#include +#include +#include +#include + +#define KEY_VALUE_LIMIT 4096 +#define UINT14_MAX 16383 +#define OTEL_CTX_SIGNATURE "OTEL_CTX" + +#ifndef PR_SET_VMA + #define PR_SET_VMA 0x53564d41 + #define PR_SET_VMA_ANON_NAME 0 +#endif + +#ifndef MFD_NOEXEC_SEAL + #define MFD_NOEXEC_SEAL 8U +#endif + +/** + * The process context data that's written into the published anonymous mapping. + * + * An outside-of-process reader will read this struct + otel_process_payload to get the data. + */ +typedef struct __attribute__((packed, aligned(8))) { + char otel_process_ctx_signature[8]; // Always "OTEL_CTX" + uint32_t otel_process_ctx_version; // Always > 0, incremented when the data structure changes, currently v2 + uint32_t otel_process_payload_size; // Always > 0, size of storage + uint64_t otel_process_monotonic_published_at_ns; // Timestamp from when the context was published in nanoseconds from CLOCK_BOOTTIME. 0 during updates. + char *otel_process_payload; // Always non-null, points to the storage for the data; expected to be a protobuf map of string key/value pairs, null-terminated +} otel_process_ctx_mapping; + +/** + * The full state of a published process context. + * + * It is used to store the all data for the process context and that needs to be kept around while the context is published. + */ +typedef struct { + // The pid of the process that published the context. + pid_t publisher_pid; + // The actual mapping of the process context. Note that because we `madvise(..., MADV_DONTFORK)` this mapping is not + // propagated to child processes and thus `mapping` is only valid on the process that published the context. + otel_process_ctx_mapping *mapping; + // The process context payload. + char *payload; +} otel_process_ctx_state; + +/** + * Only one context is active, so we keep its state as a global. + */ +static otel_process_ctx_state published_state; + +static otel_process_ctx_result otel_process_ctx_update(uint64_t monotonic_published_at_ns, const otel_process_ctx_data *data); +static otel_process_ctx_result otel_process_ctx_encode_protobuf_payload(char **out, uint32_t *out_size, otel_process_ctx_data data); + +static uint64_t monotonic_time_now_ns(void) { + struct timespec ts; + if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) return 0; + return ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} + +static bool ctx_is_published(otel_process_ctx_state state) { + return state.mapping != NULL && state.mapping != MAP_FAILED && getpid() == state.publisher_pid; +} + +// The process context is designed to be read by an outside-of-process reader. Thus, for concurrency purposes the steps +// on this method are ordered in a way to avoid races, or if not possible to avoid, to allow the reader to detect if there was a race. +otel_process_ctx_result otel_process_ctx_publish(const otel_process_ctx_data *data) { + if (!data) return (otel_process_ctx_result) {.success = false, .error_message = "otel_process_ctx_data is NULL (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + + uint64_t monotonic_published_at_ns = monotonic_time_now_ns(); + if (monotonic_published_at_ns == 0) { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to get current time (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + + // Step: If the context has been published by this process, update it in place + if (ctx_is_published(published_state)) return otel_process_ctx_update(monotonic_published_at_ns, data); + + // Step: Drop any previous context state if it exists + // No state should be around anywhere after this step. + if (!otel_process_ctx_drop_current()) { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to drop previous context (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + + // Step: Prepare the payload to be published + // The payload SHOULD be ready and valid before trying to actually create the mapping. + uint32_t payload_size = 0; + otel_process_ctx_result result = otel_process_ctx_encode_protobuf_payload(&published_state.payload, &payload_size, *data); + if (!result.success) return result; + + // Step: Create the mapping + const ssize_t mapping_size = sizeof(otel_process_ctx_mapping); + published_state.publisher_pid = getpid(); // This allows us to detect in forks that we shouldn't touch the mapping + int fd = memfd_create("OTEL_CTX", MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); + if (fd < 0) { + // MFD_NOEXEC_SEAL is a newer flag; older kernels reject unknown flags, so let's retry without it + fd = memfd_create("OTEL_CTX", MFD_CLOEXEC | MFD_ALLOW_SEALING); + } + bool failed_to_close_fd = false; + if (fd >= 0) { + // Try to create mapping from memfd + if (ftruncate(fd, mapping_size) == -1) { + close(fd); // Swallow errors here, truncation already failed anyway + otel_process_ctx_drop_current(); + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to truncate memfd (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + published_state.mapping = (otel_process_ctx_mapping *) mmap(NULL, mapping_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + failed_to_close_fd = (close(fd) == -1); + } else { + // Fallback: Use an anonymous mapping instead + published_state.mapping = (otel_process_ctx_mapping *) mmap(NULL, mapping_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + if (published_state.mapping == MAP_FAILED || failed_to_close_fd) { + otel_process_ctx_drop_current(); + + if (failed_to_close_fd) { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to close memfd (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } else { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to allocate mapping (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + } + + // Step: Setup MADV_DONTFORK + // This ensures that the mapping is not propagated to child processes (they should call update/publish again). + if (madvise(published_state.mapping, mapping_size, MADV_DONTFORK) == -1) { + if (otel_process_ctx_drop_current()) { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to setup MADV_DONTFORK (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } else { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to drop context (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + } + + // Step: Populate the mapping + // The payload and any extra fields must come first and not be reordered with the monotonic_published_at_ns by the compiler. + *published_state.mapping = (otel_process_ctx_mapping) { + .otel_process_ctx_signature = { 'O', 'T', 'E', 'L', '_', 'C', 'T', 'X' }, + .otel_process_ctx_version = 2, + .otel_process_payload_size = payload_size, + .otel_process_monotonic_published_at_ns = 0, // Set in "Step: Populate the monotonic_published_at_ns into the mapping" below + .otel_process_payload = published_state.payload + }; + + // Step: Synchronization - Mapping has been filled and is missing monotonic_published_at_ns + // Make sure the initialization of the mapping + payload above does not get reordered with setting the monotonic_published_at_ns below. Setting + // the monotonic_published_at_ns is what tells an outside reader that the context is fully published. + atomic_thread_fence(memory_order_seq_cst); + + // Step: Populate the monotonic_published_at_ns into the mapping + // The monotonic_published_at_ns must come last and not be reordered with the fields above by the compiler. After this step, external readers + // can read the monotonic_published_at_ns and know that the payload is ready to be read. + published_state.mapping->otel_process_monotonic_published_at_ns = monotonic_published_at_ns; + + // Step: Attempt to name the mapping so outside readers can: + // * Find it by name + // * Hook on prctl to detect when new mappings are published + if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, published_state.mapping, mapping_size, OTEL_CTX_SIGNATURE) == -1) { + // Naming an anonymous mapping is an optional Linux 5.17+ feature (`CONFIG_ANON_VMA_NAME`). + // Many distros, such as Ubuntu and Arch enable it. On earlier kernel versions or kernels without the feature, this call can fail. + // + // It's OK for this to fail because (per-usecase): + // 1. "Find it by name" => As a fallback, it's possible to scan the mappings and for the memfd name. + // 2. "Hook on prctl" => When hooking on prctl via eBPF it's still possible to see this call, even when it's not supported/enabled. + // This works even on older kernels! For this reason we unconditionally make this call even on older kernels -- to + // still allow detection via hooking onto prctl. + } + + // All done! + + return (otel_process_ctx_result) {.success = true, .error_message = NULL}; +} + +bool otel_process_ctx_drop_current(void) { + otel_process_ctx_state state = published_state; + + // Zero out the state and make sure no operations below are reordered with zeroing + published_state = (otel_process_ctx_state) {.publisher_pid = 0, .mapping = NULL, .payload = NULL}; + atomic_thread_fence(memory_order_seq_cst); + + bool success = true; + + // The mapping only exists if it was created by the current process; if it was inherited by a fork it doesn't exist anymore + // (due to the MADV_DONTFORK) and we don't need to do anything to it. + if (ctx_is_published(state)) { + success = munmap(state.mapping, sizeof(otel_process_ctx_mapping)) == 0; + } + + // The payload may have been inherited from a parent. This is a regular malloc so we need to free it so we don't leak. + free(state.payload); + + return success; +} + +static otel_process_ctx_result otel_process_ctx_update(uint64_t monotonic_published_at_ns, const otel_process_ctx_data *data) { + if (data == NULL || !ctx_is_published(published_state)) { + return (otel_process_ctx_result) {.success = false, .error_message = "Unexpected: otel_process_ctx_data is NULL or context is not published (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + + if (monotonic_published_at_ns == published_state.mapping->otel_process_monotonic_published_at_ns) { + // Advance published_at_ns to allow readers to detect the update + monotonic_published_at_ns++; + } + + // Step: Prepare the new payload to be published + // The payload SHOULD be ready and valid before trying to actually update the mapping. + uint32_t payload_size = 0; + char *payload; + otel_process_ctx_result result = otel_process_ctx_encode_protobuf_payload(&payload, &payload_size, *data); + if (!result.success) return result; + + // Step: Zero out monotonic_published_at_ns in the mapping + // This enables readers to detect that an update is in-progress + published_state.mapping->otel_process_monotonic_published_at_ns = 0; + + // Step: Synchronization - Make sure readers observe the zeroing above before anything else below + atomic_thread_fence(memory_order_seq_cst); + + // Step: Install updated data + published_state.mapping->otel_process_payload_size = payload_size; + published_state.mapping->otel_process_payload = payload; + + // Step: Synchronization - Make sure readers observe the updated data before anything else below + atomic_thread_fence(memory_order_seq_cst); + + // Step: Install new monotonic_published_at_ns + // The update is now complete -- readers that observe the new timestamp will observe the updated payload + published_state.mapping->otel_process_monotonic_published_at_ns = monotonic_published_at_ns; + + // Step: Attempt to name the mapping so outside readers can detect the update + if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, published_state.mapping, sizeof(otel_process_ctx_mapping), OTEL_CTX_SIGNATURE) == -1) { + // It's OK for this to fail -- see otel_process_ctx_publish for why + } + + // Step: Update bookkeeping + free(published_state.payload); // This was still pointing to the old payload + published_state.payload = payload; + + // All done! + + return (otel_process_ctx_result) {.success = true, .error_message = NULL}; +} + +// The caller is responsible for enforcing that value fits within UINT14_MAX +static size_t protobuf_varint_size(uint16_t value) { return value >= 128 ? 2 : 1; } + +// Field tag for record + varint len + data +static size_t protobuf_record_size(size_t len) { return 1 + protobuf_varint_size(len) + len; } + +static size_t protobuf_string_size(const char *str) { return protobuf_record_size(strlen(str)); } + +static size_t protobuf_otel_keyvalue_string_size(const char *key, const char *value) { + size_t key_field_size = protobuf_string_size(key); // String + size_t value_field_size = protobuf_record_size(protobuf_string_size(value)); // Nested AnyValue message with a string inside + return key_field_size + value_field_size; // Does not include the keyvalue record tag + size, only its payload +} + +static size_t protobuf_otel_array_value_content_size(const char **strings) { + size_t total = 0; + for (size_t i = 0; strings[i] != NULL; i++) { + total += protobuf_record_size(protobuf_string_size(strings[i])); // ArrayValue.values[i]: AnyValue{string_value} + } + return total; +} + +// As a simplification, we enforce that keys and values are <= 4096 (KEY_VALUE_LIMIT) so that their size + extra bytes always fits within UINT14_MAX +static otel_process_ctx_result validate_and_calculate_protobuf_payload_size(size_t *out_pairs_size, const char **pairs) { + size_t num_entries = 0; + for (size_t i = 0; pairs[i] != NULL; i++) num_entries++; + if (num_entries % 2 != 0) { + return (otel_process_ctx_result) {.success = false, .error_message = "Value in otel_process_ctx_data is NULL (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + + *out_pairs_size = 0; + for (size_t i = 0; pairs[i * 2] != NULL; i++) { + const char *key = pairs[i * 2]; + const char *value = pairs[i * 2 + 1]; + + if (strlen(key) > KEY_VALUE_LIMIT) { + return (otel_process_ctx_result) {.success = false, .error_message = "Length of key in otel_process_ctx_data exceeds 4096 limit (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + if (strlen(value) > KEY_VALUE_LIMIT) { + return (otel_process_ctx_result) {.success = false, .error_message = "Length of value in otel_process_ctx_data exceeds 4096 limit (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + + *out_pairs_size += protobuf_record_size(protobuf_otel_keyvalue_string_size(key, value)); // KeyValue message + } + return (otel_process_ctx_result) {.success = true, .error_message = NULL}; +} + +/** + * Writes a protobuf varint encoding for the given value. + * As a simplification, only supports values that fit in 1 or 2 bytes (0-16383 UINT14_MAX). + */ +static void write_protobuf_varint(char **ptr, uint16_t value) { + if (protobuf_varint_size(value) == 1) { + *(*ptr)++ = (char)value; + } else { + // Two bytes: first byte has MSB set, second byte has value + *(*ptr)++ = (char)((value & 0x7F) | 0x80); // Low 7 bits + continuation bit + *(*ptr)++ = (char)(value >> 7); // High 7 bits + } +} + +static void write_protobuf_string(char **ptr, const char *str) { + size_t len = strlen(str); + write_protobuf_varint(ptr, len); + memcpy(*ptr, str, len); + *ptr += len; +} + +static void write_protobuf_tag(char **ptr, uint8_t field_number) { + *(*ptr)++ = (char)((field_number << 3) | 2); // Field type is always 2 (LEN) +} + +static void write_attribute(char **ptr, uint8_t field_number, const char *key, const char *value) { + write_protobuf_tag(ptr, field_number); + write_protobuf_varint(ptr, protobuf_otel_keyvalue_string_size(key, value)); + + // KeyValue + write_protobuf_tag(ptr, 1); // KeyValue.key (field 1) + write_protobuf_string(ptr, key); + write_protobuf_tag(ptr, 2); // KeyValue.value (field 2) + write_protobuf_varint(ptr, protobuf_string_size(value)); + + // AnyValue + write_protobuf_tag(ptr, 1); // AnyValue.string_value (field 1) + write_protobuf_string(ptr, value); +} + +static void write_array_attribute(char **ptr, uint8_t field_number, const char *key, const char **strings) { + size_t array_value_content_size = protobuf_otel_array_value_content_size(strings); + size_t any_value_content_size = protobuf_record_size(array_value_content_size); + size_t kv_content_size = protobuf_string_size(key) + protobuf_record_size(any_value_content_size); + + write_protobuf_tag(ptr, field_number); + write_protobuf_varint(ptr, kv_content_size); + + write_protobuf_tag(ptr, 1); // KeyValue.key (field 1) + write_protobuf_string(ptr, key); + + write_protobuf_tag(ptr, 2); // KeyValue.value (field 2) = AnyValue message + write_protobuf_varint(ptr, any_value_content_size); + + write_protobuf_tag(ptr, 5); // AnyValue.array_value (field 5) = ArrayValue message + write_protobuf_varint(ptr, array_value_content_size); + + for (size_t i = 0; strings[i] != NULL; i++) { // ArrayValue.values (field 1) - repeated AnyValue entries + write_protobuf_tag(ptr, 1); // ArrayValue.values[i] + write_protobuf_varint(ptr, protobuf_string_size(strings[i])); // Inner AnyValue size + write_protobuf_tag(ptr, 1); // AnyValue.string_value (field 1) + write_protobuf_string(ptr, strings[i]); + } +} + +// Encode the payload as protobuf bytes. +// +// This method implements an extremely compact but limited protobuf encoder for the ProcessContext message. +// It encodes all fields as Resource attributes (KeyValue pairs). +// For extra compact code, it fixes strings at up to 4096 bytes. +static otel_process_ctx_result otel_process_ctx_encode_protobuf_payload(char **out, uint32_t *out_size, otel_process_ctx_data data) { + const char *pairs[] = { + "deployment.environment.name", data.deployment_environment_name, + "service.instance.id", data.service_instance_id, + "service.name", data.service_name, + "service.version", data.service_version, + "telemetry.sdk.language", data.telemetry_sdk_language, + "telemetry.sdk.version", data.telemetry_sdk_version, + "telemetry.sdk.name", data.telemetry_sdk_name, + NULL + }; + + size_t pairs_size = 0; + otel_process_ctx_result validation_result = validate_and_calculate_protobuf_payload_size(&pairs_size, (const char **) pairs); + if (!validation_result.success) return validation_result; + + size_t resource_attributes_pairs_size = 0; + if (data.resource_attributes != NULL) { + validation_result = validate_and_calculate_protobuf_payload_size(&resource_attributes_pairs_size, data.resource_attributes); + if (!validation_result.success) return validation_result; + } + + size_t extra_attributes_pairs_size = 0; + if (data.extra_attributes != NULL) { + validation_result = validate_and_calculate_protobuf_payload_size(&extra_attributes_pairs_size, data.extra_attributes); + if (!validation_result.success) return validation_result; + } + + size_t thread_ctx_pairs_size = 0; + if (data.thread_ctx_config != NULL) { + if (data.thread_ctx_config->schema_version != NULL) { + const char *thread_ctx_pairs[] = {"threadlocal.schema_version", data.thread_ctx_config->schema_version, NULL}; + validation_result = validate_and_calculate_protobuf_payload_size(&thread_ctx_pairs_size, thread_ctx_pairs); + if (!validation_result.success) return validation_result; + } + if (data.thread_ctx_config->attribute_key_map != NULL) { + if (data.thread_ctx_config->schema_version == NULL) { + return (otel_process_ctx_result) {.success = false, .error_message = "attribute_key_map requires schema_version to be set (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + for (size_t i = 0; data.thread_ctx_config->attribute_key_map[i] != NULL; i++) { + if (strlen(data.thread_ctx_config->attribute_key_map[i]) > KEY_VALUE_LIMIT) { + return (otel_process_ctx_result) {.success = false, .error_message = "Length of attribute_key_map entry exceeds 4096 limit (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + } + size_t array_value_content_size = protobuf_otel_array_value_content_size(data.thread_ctx_config->attribute_key_map); + size_t any_value_content_size = protobuf_record_size(array_value_content_size); + size_t kv_content_size = protobuf_string_size("threadlocal.attribute_key_map") + protobuf_record_size(any_value_content_size); + if (kv_content_size > UINT14_MAX) { + return (otel_process_ctx_result) {.success = false, .error_message = "Encoded size of attribute_key_map exceeds UINT14_MAX limit (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + thread_ctx_pairs_size += protobuf_record_size(kv_content_size); + } + } + + size_t resource_size = pairs_size + resource_attributes_pairs_size; + if (resource_size > UINT14_MAX) { + return (otel_process_ctx_result) {.success = false, .error_message = "Encoded size of resource attributes exceeds UINT14_MAX limit (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + size_t total_size = protobuf_record_size(resource_size) + extra_attributes_pairs_size + thread_ctx_pairs_size; + + char *encoded = (char *) calloc(total_size, 1); + if (!encoded) { + return (otel_process_ctx_result) {.success = false, .error_message = "Failed to allocate memory for payload (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + } + char *ptr = encoded; + + // ProcessContext.resource (field 1) + write_protobuf_tag(&ptr, 1); + write_protobuf_varint(&ptr, resource_size); + + for (size_t i = 0; pairs[i * 2] != NULL; i++) { + write_attribute(&ptr, 1, pairs[i * 2], pairs[i * 2 + 1]); + } + + for (size_t i = 0; data.resource_attributes != NULL && data.resource_attributes[i * 2] != NULL; i++) { + write_attribute(&ptr, 1, data.resource_attributes[i * 2], data.resource_attributes[i * 2 + 1]); + } + + // ProcessContext.extra_attributes (field 2) + for (size_t i = 0; data.extra_attributes != NULL && data.extra_attributes[i * 2] != NULL; i++) { + write_attribute(&ptr, 2, data.extra_attributes[i * 2], data.extra_attributes[i * 2 + 1]); + } + + if (data.thread_ctx_config != NULL) { + if (data.thread_ctx_config->schema_version != NULL) { + write_attribute(&ptr, 2, "threadlocal.schema_version", data.thread_ctx_config->schema_version); + } + if (data.thread_ctx_config->attribute_key_map != NULL) { + write_array_attribute(&ptr, 2, "threadlocal.attribute_key_map", data.thread_ctx_config->attribute_key_map); + } + } + + *out = encoded; + *out_size = (uint32_t) total_size; + + return (otel_process_ctx_result) {.success = true, .error_message = NULL}; +} + +#ifndef OTEL_PROCESS_CTX_NO_READ + #include + #include + #include + #include + + // Note: The below parsing code is only for otel_process_ctx_read and is only provided for debugging + // and testing purposes. + + static void *parse_mapping_start(char *line) { + char *endptr = NULL; + unsigned long long start = strtoull(line, &endptr, 16); + if (start == 0 || start == ULLONG_MAX) return NULL; + return (void *)(uintptr_t) start; + } + + static otel_process_ctx_mapping *try_finding_mapping(void) { + char line[8192]; + otel_process_ctx_mapping *result = NULL; + + FILE *fp = fopen("/proc/self/maps", "r"); + if (!fp) return result; + + while (fgets(line, sizeof(line), fp)) { + bool is_process_ctx = strstr(line, "[anon_shmem:OTEL_CTX]") != NULL || strstr(line, "[anon:OTEL_CTX]") != NULL || strstr(line, "/memfd:OTEL_CTX") != NULL; + if (is_process_ctx) { + result = (otel_process_ctx_mapping *)parse_mapping_start(line); + break; + } + } + + fclose(fp); + return result; + } + + // Helper function to read a protobuf varint (limited to 1-2 bytes, max value UINT14_MAX, matching write_protobuf_varint above) + static bool read_protobuf_varint(char **ptr, char *end_ptr, uint16_t *value) { + if (*ptr >= end_ptr) return false; + + unsigned char first_byte = (unsigned char)**ptr; + (*ptr)++; + + if (first_byte < 128) { + *value = first_byte; + return true; + } else { + if (*ptr >= end_ptr) return false; + unsigned char second_byte = (unsigned char)**ptr; + (*ptr)++; + + *value = (first_byte & 0x7F) | (second_byte << 7); + return *value <= UINT14_MAX; + } + } + + // Helper function to read a protobuf string into a buffer, within the same limits as the encoder imposes + static bool read_protobuf_string(char **ptr, char *end_ptr, char *buffer) { + uint16_t len; + if (!read_protobuf_varint(ptr, end_ptr, &len) || len >= KEY_VALUE_LIMIT + 1 || *ptr + len > end_ptr) return false; + + memcpy(buffer, *ptr, len); + buffer[len] = '\0'; + *ptr += len; + + return true; + } + + // Reads field name and validates the fixed LEN wire type + static bool read_protobuf_tag(char **ptr, char *end_ptr, uint8_t *field_number) { + if (*ptr >= end_ptr) return false; + + unsigned char tag = (unsigned char)**ptr; + (*ptr)++; + + uint8_t wire_type = tag & 0x07; + *field_number = tag >> 3; + + return wire_type == 2; // We only need the LEN wire type for now + } + + // Peeks at the key of an OTel KeyValue message without advancing the pointer. + static bool peek_protobuf_key(char *ptr, char *end_ptr, char *key_buffer) { + char *p = ptr; + uint8_t kv_field; + if (!read_protobuf_tag(&p, end_ptr, &kv_field)) return false; + if (kv_field != 1) return false; // KeyValue.key is field 1 + return read_protobuf_string(&p, end_ptr, key_buffer); + } + + // Reads an OTel KeyValue message (key string + AnyValue-wrapped string) into the provided buffers. + static bool read_protobuf_keyvalue(char **ptr, char *end_ptr, char *key_buffer, char *value_buffer) { + bool key_found = false; + bool value_found = false; + + while (*ptr < end_ptr) { + uint8_t kv_field; + if (!read_protobuf_tag(ptr, end_ptr, &kv_field)) return false; + + if (kv_field == 1) { // KeyValue.key + if (!read_protobuf_string(ptr, end_ptr, key_buffer)) return false; + key_found = true; + } else if (kv_field == 2) { // KeyValue.value (AnyValue) + uint16_t _any_len; // Unused, but we still need to consume + validate the varint + if (!read_protobuf_varint(ptr, end_ptr, &_any_len)) return false; + uint8_t any_field; + if (!read_protobuf_tag(ptr, end_ptr, &any_field)) return false; + + if (any_field == 1) { // AnyValue.string_value + if (!read_protobuf_string(ptr, end_ptr, value_buffer)) return false; + value_found = true; + } + } + } + + return key_found && value_found; + } + + // Reads an AnyValue.array_value (field 5) from ptr; ptr must be at KeyValue.value (tag 2). + // Allocates a NULL-terminated array of strings and sets *out_array immediately. On error the caller must free it. + static bool read_protobuf_array_value_strings(char **ptr, char *end_ptr, char *value_buffer, const char ***out_array) { + uint8_t field; + if (!read_protobuf_tag(ptr, end_ptr, &field) || field != 2) return false; + uint16_t any_len; + if (!read_protobuf_varint(ptr, end_ptr, &any_len)) return false; + char *any_end = *ptr + any_len; + if (any_end > end_ptr) return false; + + if (!read_protobuf_tag(ptr, any_end, &field) || field != 5) return false; + uint16_t array_len; + if (!read_protobuf_varint(ptr, any_end, &array_len)) return false; + char *array_end = *ptr + array_len; + if (array_end > any_end) return false; + + size_t max = 100; + size_t capacity = max + 1; + const char **arr = (const char **) calloc(capacity, sizeof(char *)); + if (!arr) return false; + *out_array = arr; + size_t count = 0; + + while (*ptr < array_end) { + if (count >= max) return false; + if (!read_protobuf_tag(ptr, array_end, &field) || field != 1) return false; + uint16_t item_len; + if (!read_protobuf_varint(ptr, array_end, &item_len)) return false; + char *item_end = *ptr + item_len; + if (item_end > array_end) return false; + if (!read_protobuf_tag(ptr, item_end, &field) || field != 1) return false; + if (!read_protobuf_string(ptr, item_end, value_buffer)) return false; + char *dup = strdup(value_buffer); + if (!dup) return false; + arr[count++] = dup; + } + + return true; + } + + static bool ensure_thread_ctx_config(otel_process_ctx_data *data_out) { + if (data_out->thread_ctx_config) return true; + otel_thread_ctx_config_data *setup = (otel_thread_ctx_config_data *) calloc(1, sizeof(otel_thread_ctx_config_data)); + if (!setup) return false; + data_out->thread_ctx_config = setup; + return true; + } + + // Simplified protobuf decoder to match the exact encoder above. If the protobuf data doesn't match the encoder, this will + // return false. + static bool otel_process_ctx_decode_payload(char *payload, uint32_t payload_size, otel_process_ctx_data *data_out, char *key_buffer, char *value_buffer) { + char *ptr = payload; + char *end_ptr = payload + payload_size; + + *data_out = empty_data; + + // Parse ProcessContext wrapper - expect field 1 (resource) + uint8_t process_ctx_field; + if (!read_protobuf_tag(&ptr, end_ptr, &process_ctx_field) || process_ctx_field != 1) return false; + + uint16_t resource_len; + if (!read_protobuf_varint(&ptr, end_ptr, &resource_len)) return false; + char *resource_end = ptr + resource_len; + if (resource_end > end_ptr) return false; + + size_t resource_index = 0; + size_t resource_capacity = 201; // Allocate space for 100 pairs + NULL terminator entry + data_out->resource_attributes = (const char **) calloc(resource_capacity, sizeof(char *)); + if (data_out->resource_attributes == NULL) return false; + + size_t extra_attributes_index = 0; + size_t extra_attributes_capacity = 201; // Allocate space for 100 pairs + NULL terminator entry + data_out->extra_attributes = (const char **) calloc(extra_attributes_capacity, sizeof(char *)); + if (data_out->extra_attributes == NULL) return false; + + // Parse resource attributes (field 1) + while (ptr < resource_end) { + uint8_t field_number; + if (!read_protobuf_tag(&ptr, resource_end, &field_number) || field_number != 1) return false; + + uint16_t kv_len; + if (!read_protobuf_varint(&ptr, resource_end, &kv_len)) return false; + char *kv_end = ptr + kv_len; + if (kv_end > resource_end) return false; + + if (!read_protobuf_keyvalue(&ptr, kv_end, key_buffer, value_buffer)) return false; + + char *value = strdup(value_buffer); + if (!value) return false; + + // Dispatch based on key + const char **field = NULL; + if (strcmp(key_buffer, "deployment.environment.name") == 0) { field = &data_out->deployment_environment_name; } + else if (strcmp(key_buffer, "service.instance.id") == 0) { field = &data_out->service_instance_id; } + else if (strcmp(key_buffer, "service.name") == 0) { field = &data_out->service_name; } + else if (strcmp(key_buffer, "service.version") == 0) { field = &data_out->service_version; } + else if (strcmp(key_buffer, "telemetry.sdk.language") == 0) { field = &data_out->telemetry_sdk_language; } + else if (strcmp(key_buffer, "telemetry.sdk.version") == 0) { field = &data_out->telemetry_sdk_version; } + else if (strcmp(key_buffer, "telemetry.sdk.name") == 0) { field = &data_out->telemetry_sdk_name; } + + if (field != NULL) { + if (*field != NULL) { free(value); return false; } + *field = value; + } else { + char *key = strdup(key_buffer); + + if (!key || resource_index + 2 >= resource_capacity) { + free(key); + free(value); + return false; + } + data_out->resource_attributes[resource_index] = key; + data_out->resource_attributes[resource_index + 1] = value; + resource_index += 2; + } + } + + // Parse extra attributes (field 2) + while (ptr < end_ptr) { + uint8_t extra_ctx_field; + if (!read_protobuf_tag(&ptr, end_ptr, &extra_ctx_field) || extra_ctx_field != 2) return false; + + uint16_t kv_len; + if (!read_protobuf_varint(&ptr, end_ptr, &kv_len)) return false; + char *kv_end = ptr + kv_len; + if (kv_end > end_ptr) return false; + + if (!peek_protobuf_key(ptr, kv_end, key_buffer)) return false; + + if (strcmp(key_buffer, "threadlocal.attribute_key_map") == 0) { + // Consume key to advance ptr + uint8_t kv_field; + if (!read_protobuf_tag(&ptr, kv_end, &kv_field) || kv_field != 1) return false; + if (!read_protobuf_string(&ptr, kv_end, key_buffer)) return false; + if (!ensure_thread_ctx_config(data_out)) return false; + if (data_out->thread_ctx_config->attribute_key_map != NULL) return false; + if (!read_protobuf_array_value_strings(&ptr, kv_end, value_buffer, &((otel_thread_ctx_config_data *)data_out->thread_ctx_config)->attribute_key_map)) return false; + } else { + if (!read_protobuf_keyvalue(&ptr, kv_end, key_buffer, value_buffer)) return false; + + char *value = strdup(value_buffer); + if (!value) return false; + + // Dispatch based on key + if (strcmp(key_buffer, "threadlocal.schema_version") == 0) { + if (!ensure_thread_ctx_config(data_out)) { free(value); return false; } + if (data_out->thread_ctx_config->schema_version != NULL) { free(value); return false; } + ((otel_thread_ctx_config_data *)data_out->thread_ctx_config)->schema_version = value; + } else { + char *key = strdup(key_buffer); + if (!key || extra_attributes_index + 2 >= extra_attributes_capacity) { + free(key); + free(value); + return false; + } + data_out->extra_attributes[extra_attributes_index] = key; + data_out->extra_attributes[extra_attributes_index + 1] = value; + extra_attributes_index += 2; + } + } + } + + // Validate all required fields were found + return data_out->deployment_environment_name != NULL && + data_out->service_instance_id != NULL && + data_out->service_name != NULL && + data_out->service_version != NULL && + data_out->telemetry_sdk_language != NULL && + data_out->telemetry_sdk_version != NULL && + data_out->telemetry_sdk_name != NULL; + } + + void otel_process_ctx_read_data_drop(otel_process_ctx_data data) { + if (data.deployment_environment_name) free((void *)data.deployment_environment_name); + if (data.service_instance_id) free((void *)data.service_instance_id); + if (data.service_name) free((void *)data.service_name); + if (data.service_version) free((void *)data.service_version); + if (data.telemetry_sdk_language) free((void *)data.telemetry_sdk_language); + if (data.telemetry_sdk_version) free((void *)data.telemetry_sdk_version); + if (data.telemetry_sdk_name) free((void *)data.telemetry_sdk_name); + if (data.resource_attributes) { + for (int i = 0; data.resource_attributes[i] != NULL; i++) free((void *)data.resource_attributes[i]); + free((void *)data.resource_attributes); + } + if (data.extra_attributes) { + for (int i = 0; data.extra_attributes[i] != NULL; i++) free((void *)data.extra_attributes[i]); + free((void *)data.extra_attributes); + } + if (data.thread_ctx_config) { + if (data.thread_ctx_config->schema_version) free((void *)data.thread_ctx_config->schema_version); + if (data.thread_ctx_config->attribute_key_map) { + for (int i = 0; data.thread_ctx_config->attribute_key_map[i] != NULL; i++) { + free((void *)data.thread_ctx_config->attribute_key_map[i]); + } + free((void *)data.thread_ctx_config->attribute_key_map); + } + free((void *)data.thread_ctx_config); + } + } + + otel_process_ctx_read_result otel_process_ctx_read(void) { + otel_process_ctx_mapping *mapping = try_finding_mapping(); + if (!mapping) { + return (otel_process_ctx_read_result) {.success = false, .error_message = "No OTEL_CTX mapping found (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", .data = empty_data}; + } + + if (strncmp(mapping->otel_process_ctx_signature, OTEL_CTX_SIGNATURE, sizeof(mapping->otel_process_ctx_signature)) != 0 || mapping->otel_process_ctx_version != 2) { + return (otel_process_ctx_read_result) {.success = false, .error_message = "Invalid OTEL_CTX signature or version (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", .data = empty_data}; + } + + otel_process_ctx_data data = empty_data; + + char *key_buffer = (char *) calloc(KEY_VALUE_LIMIT + 1, 1); + char *value_buffer = (char *) calloc(KEY_VALUE_LIMIT + 1, 1); + if (!key_buffer || !value_buffer) { + free(key_buffer); + free(value_buffer); + return (otel_process_ctx_read_result) {.success = false, .error_message = "Failed to allocate decode buffers (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", .data = empty_data}; + } + + bool success = otel_process_ctx_decode_payload(mapping->otel_process_payload, mapping->otel_process_payload_size, &data, key_buffer, value_buffer); + free(key_buffer); + free(value_buffer); + + if (!success) { + otel_process_ctx_read_data_drop(data); + return (otel_process_ctx_read_result) {.success = false, .error_message = "Failed to decode payload (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", .data = empty_data}; + } + + return (otel_process_ctx_read_result) {.success = true, .error_message = NULL, .data = data}; + } + + bool otel_process_ctx_read_drop(otel_process_ctx_read_result *result) { + if (!result || !result->success) return false; + otel_process_ctx_read_data_drop(result->data); + *result = (otel_process_ctx_read_result) {.success = false, .error_message = "Data dropped", .data = empty_data}; + return true; + } +#endif // OTEL_PROCESS_CTX_NO_READ + +#endif // OTEL_PROCESS_CTX_NOOP diff --git a/src/datadog/otel_process_ctx.h b/src/datadog/otel_process_ctx.h new file mode 100644 index 000000000..909cd01ef --- /dev/null +++ b/src/datadog/otel_process_ctx.h @@ -0,0 +1,153 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache License (Version 2.0). +// This product includes software developed at Datadog (https://www.datadoghq.com/) Copyright 2025 Datadog, Inc. + +#pragma once + +#define OTEL_PROCESS_CTX_VERSION_MAJOR 1 +#define OTEL_PROCESS_CTX_VERSION_MINOR 0 +#define OTEL_PROCESS_CTX_VERSION_PATCH 0 +#define OTEL_PROCESS_CTX_VERSION_STRING "1.0.0" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * # OpenTelemetry Process Context reference implementation + * + * `otel_process_ctx.h` and `otel_process_ctx.c` provide a reference implementation for the OpenTelemetry + * process-level context sharing specification. + * (https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/profiles/4719-process-ctx.md) + * + * This reference implementation is Linux-only, as the specification currently only covers Linux. + * On non-Linux OS's (or when OTEL_PROCESS_CTX_NOOP is defined) no-op versions of functions are supplied. + */ + + /** + * Config for the experimental thread context sharing mechanism, see + * https://github.com/open-telemetry/opentelemetry-specification/pull/4947 for usage + * details. + */ +typedef struct { + const char *schema_version; + // NULL-terminated array of attribute key strings to be used in thread context. + // Can be NULL if not needed. + const char **attribute_key_map; +} otel_thread_ctx_config_data; + +/** + * Data that can be published as a process context. + * + * Every string MUST be valid for the duration of the call to `otel_process_ctx_publish`. + * Strings will be copied into the context. + * + * Strings MUST be: + * * Non-NULL + * * UTF-8 encoded + * * Not longer than INT16_MAX bytes + * + * Strings MAY be: + * * Empty + */ +typedef struct { + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/deployment/#deployment-environment-name + const char *deployment_environment_name; + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/#service-instance-id + const char *service_instance_id; + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/#service-name + const char *service_name; + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/#service-version + const char *service_version; + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/telemetry/#telemetry-sdk-language + const char *telemetry_sdk_language; + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/telemetry/#telemetry-sdk-version + const char *telemetry_sdk_version; + // https://opentelemetry.io/docs/specs/semconv/registry/attributes/telemetry/#telemetry-sdk-name + const char *telemetry_sdk_name; + // Additional key/value pairs as resource attributes https://opentelemetry.io/docs/specs/otel/resource/sdk/ + // Can be NULL if no resource attributes are needed; if non-NULL, this array MUST be terminated with a NULL entry. + // Every even entry is a key, every odd entry is a value (E.g. "key1", "value1", "key2", "value2", NULL). + const char **resource_attributes; + // Additional key/value pairs as extra attributes (ProcessContext.extra_attributes in process_context.proto) + // Can be NULL if no extra attributes are needed; if non-NULL, this array MUST be terminated with a NULL entry. + // Every even entry is a key, every odd entry is a value (E.g. "key1", "value1", "key2", "value2", NULL). + const char **extra_attributes; + // Experimental thread context sharing mechanism configuration. See struct definition for details. Can be NULL. + const otel_thread_ctx_config_data *thread_ctx_config; +} otel_process_ctx_data; + +/** Number of entries in the `otel_process_ctx_data` struct. Can be used to easily detect when the struct is updated. */ +#define OTEL_PROCESS_CTX_DATA_ENTRIES sizeof(otel_process_ctx_data) / sizeof(char *) + +typedef struct { + bool success; + const char *error_message; // Static strings only, non-NULL if success is false +} otel_process_ctx_result; + +/** + * Publishes a OpenTelemetry process context with the given data. + * + * The context should remain alive until the application exits (or is just about to exit). + * This method is NOT thread-safe. + * + * Calling `publish` multiple times is supported and will replace a previous context (only one is published at any given + * time). Calling `publish` multiple times usually happens when: + * * Some of the `otel_process_ctx_data` changes due to a live system reconfiguration for the same process + * * The process is forked (to provide a new `service_instance_id`) + * + * This API can be called in a fork of the process that published the previous context, even though + * the context is not carried over into forked processes (although part of its memory allocations are). + * + * @param data Pointer to the data to publish. This data is copied into the context and only needs to be valid for the duration of + * the call. Must not be `NULL`. + * @return The result of the operation. + */ +otel_process_ctx_result otel_process_ctx_publish(const otel_process_ctx_data *data); + +/** + * Drops the current OpenTelemetry process context, if any. + * + * This method is safe to call even there's no current context. + * This method is NOT thread-safe. + * + * This API can be called in a fork of the process that published the current context to clean memory allocations + * related to the parent's context (even though the context itself is not carried over into forked processes). + * + * @return `true` if the context was successfully dropped or no context existed, `false` otherwise. + */ +bool otel_process_ctx_drop_current(void); + +/** This can be disabled if no read support is required. */ +#ifndef OTEL_PROCESS_CTX_NO_READ + typedef struct { + bool success; + const char *error_message; // Static strings only, non-NULL if success is false + otel_process_ctx_data data; // Strings are allocated using `malloc` and the caller is responsible for `free`ing them + } otel_process_ctx_read_result; + + /** + * Reads the current OpenTelemetry process context, if any. + * + * Useful for debugging and testing purposes. Underlying returned strings in `data` are dynamically allocated using + * `malloc` and `otel_process_ctx_read_drop` must be called to free them. + * + * Thread-safety: This function assumes there is no concurrent mutation of the process context. + * + * @return The result of the operation. If successful, `data` contains the retrieved context data. + */ + otel_process_ctx_read_result otel_process_ctx_read(void); + + /** + * Drops the data resulting from a previous call to `otel_process_ctx_read`. + * + * @param result The result of a previous call to `otel_process_ctx_read`. Must not be `NULL`. + * @return `true` if the data was successfully dropped, `false` otherwise. + */ + bool otel_process_ctx_read_drop(otel_process_ctx_read_result *result); +#endif + +#ifdef __cplusplus +} +#endif From dd9541306a9b9d56150b2139af20235bb6c1e071 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 4 Jun 2026 15:15:34 +0000 Subject: [PATCH 26/59] feat: [PROF-14789] Publish OTel process context **What does this PR do?** This PR adds support for publishing the OpenTelemetry Process Context (aka OTEP 4719 -- ). This mechanism is very similar to Datadog's existing "process discovery"/"tracer-info" mechanism, so the actual change in `trace.cpp` is very minimal (this is by design :p ). This data will be read by OTel-compliant tools, of which the eBPF Profiler (which Datadog will also support as part of our Continuous Profiler product) is the first one. **Motivation:** We're adding support for OTEP 4719 to all Datadog SDKs, so dd-trace-cpp is actually one of the last ones to adopt this. See (Datadog-only link) for an up-to-date list of all SDKs. **Additional Notes:** The `otel_process_ctx.cpp` and `otel_process_ctx.h` come from the reference implementation we're maintaining upstream with OTel in . They are already in use in dd-trace-java as well. Review-wise, my suggestion for those would be to focus on correctness -- ideally we want to be able to quickly update to the latest version when needed, which is made easier if we have a minimal delta on upstream. (I'm the one maintaining this upstream so I can propagate fixes/changes as well so we don't have to diverge). **How to test the change?** This change includes test coverage. Also, I've tested this in practice using the `otel_process_ctx_dump.sh` script from the https://github.com/open-telemetry/sig-profiling/ repo. Here's how that looks: ``` $ sudo ./otel_process_ctx_dump.sh 2394947 Found OTEL context for PID 2394947 Start address: 7c072aace000 00000000 4f 54 45 4c 5f 43 54 58 02 00 00 00 c3 01 00 00 |OTEL_CTX........| 00000010 68 5b 15 20 9a 25 21 00 60 f0 6e 16 c5 5b 00 00 |h[. .%!.`.n..[..| 00000020 Parsed struct: otel_process_ctx_signature : "OTEL_CTX" otel_process_ctx_version : 2 otel_process_payload_size : 451 otel_process_monotonic_published_at_ns : 9330018124913512 otel_process_payload : 0x00005bc5166ef060 Payload dump (451 bytes): 00000000 0a af 02 0a 21 0a 1b 64 65 70 6c 6f 79 6d 65 6e |....!..deploymen| 00000010 74 2e 65 6e 76 69 72 6f 6e 6d 65 6e 74 2e 6e 61 |t.environment.na| 00000020 6d 65 12 02 0a 00 0a 3d 0a 13 73 65 72 76 69 63 |me.....=..servic| 00000030 65 2e 69 6e 73 74 61 6e 63 65 2e 69 64 12 26 0a |e.instance.id.&.| 00000040 24 38 32 65 39 38 38 38 64 2d 33 36 65 62 2d 34 |$82e9888d-36eb-4| 00000050 39 63 66 2d 61 63 63 38 2d 36 38 32 39 34 39 63 |9cf-acc8-682949c| 00000060 34 39 32 37 33 0a 20 0a 0c 73 65 72 76 69 63 65 |49273. ..service| 00000070 2e 6e 61 6d 65 12 10 0a 0e 63 70 70 2d 65 78 70 |.name....cpp-exp| 00000080 65 72 69 6d 65 6e 74 0a 15 0a 0f 73 65 72 76 69 |eriment....servi| 00000090 63 65 2e 76 65 72 73 69 6f 6e 12 02 0a 00 0a 1f |ce.version......| 000000a0 0a 16 74 65 6c 65 6d 65 74 72 79 2e 73 64 6b 2e |..telemetry.sdk.| 000000b0 6c 61 6e 67 75 61 67 65 12 05 0a 03 63 70 70 0a |language....cpp.| 000000c0 21 0a 15 74 65 6c 65 6d 65 74 72 79 2e 73 64 6b |!..telemetry.sdk| 000000d0 2e 76 65 72 73 69 6f 6e 12 08 0a 06 76 32 2e 31 |.version....v2.1| 000000e0 2e 31 0a 24 0a 12 74 65 6c 65 6d 65 74 72 79 2e |.1.$..telemetry.| 000000f0 73 64 6b 2e 6e 61 6d 65 12 0e 0a 0c 64 64 2d 74 |sdk.name....dd-t| 00000100 72 61 63 65 2d 63 70 70 0a 0f 0a 09 68 6f 73 74 |race-cpp....host| 00000110 2e 6e 61 6d 65 12 02 0a 00 0a 17 0a 0c 63 6f 6e |.name........con| 00000120 74 61 69 6e 65 72 2e 69 64 12 07 0a 05 31 32 39 |tainer.id....129| 00000130 37 30 12 8e 01 0a 14 64 61 74 61 64 6f 67 2e 70 |70.....datadog.p| 00000140 72 6f 63 65 73 73 5f 74 61 67 73 12 76 0a 74 65 |rocess_tags.v.te| 00000150 6e 74 72 79 70 6f 69 6e 74 2e 62 61 73 65 64 69 |ntrypoint.basedi| 00000160 72 3a 62 75 69 6c 64 2c 65 6e 74 72 79 70 6f 69 |r:build,entrypoi| 00000170 6e 74 2e 77 6f 72 6b 64 69 72 3a 63 70 70 2d 65 |nt.workdir:cpp-e| 00000180 78 70 65 72 69 6d 65 6e 74 2c 65 6e 74 72 79 70 |xperiment,entryp| 00000190 6f 69 6e 74 2e 74 79 70 65 3a 65 78 65 63 75 74 |oint.type:execut| 000001a0 61 62 6c 65 2c 65 6e 74 72 79 70 6f 69 6e 74 2e |able,entrypoint.| 000001b0 6e 61 6d 65 3a 63 70 70 2d 65 78 70 65 72 69 6d |name:cpp-experim| 000001c0 65 6e 74 |ent| 000001c3 Protobuf decode: resource { attributes { key: "deployment.environment.name" value { string_value: "" } } attributes { key: "service.instance.id" value { string_value: "82e9888d-36eb-49cf-acc8-682949c49273" } } attributes { key: "service.name" value { string_value: "cpp-experiment" } } attributes { key: "service.version" value { string_value: "" } } attributes { key: "telemetry.sdk.language" value { string_value: "cpp" } } attributes { key: "telemetry.sdk.version" value { string_value: "v2.1.1" } } attributes { key: "telemetry.sdk.name" value { string_value: "dd-trace-cpp" } } attributes { key: "host.name" value { string_value: "" } } attributes { key: "container.id" value { string_value: "12970" } } } extra_attributes { key: "datadog.process_tags" value { string_value: "entrypoint.basedir:build,entrypoint.workdir:cpp-experiment,entrypoint.type:executable,entrypoint.name:cpp-experiment" } } ``` --- BUILD.bazel | 2 + CMakeLists.txt | 1 + include/datadog/tracer.h | 3 + src/datadog/otel_process_ctx.cpp | 8 +++ src/datadog/tracer.cpp | 75 ++++++++++++++++++---- test/CMakeLists.txt | 1 + test/test_otel_process_ctx.cpp | 107 +++++++++++++++++++++++++++++++ 7 files changed, 183 insertions(+), 14 deletions(-) create mode 100644 test/test_otel_process_ctx.cpp diff --git a/BUILD.bazel b/BUILD.bazel index df17ac563..db9e0e655 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -39,6 +39,8 @@ cc_library( "src/datadog/msgpack.cpp", "src/datadog/msgpack.h", "src/datadog/null_logger.h", + "src/datadog/otel_process_ctx.cpp", + "src/datadog/otel_process_ctx.h", "src/datadog/parse_util.cpp", "src/datadog/parse_util.h", "src/datadog/platform_util.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cc154f17..a892ad0a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,7 @@ target_sources(dd-trace-cpp-objects src/datadog/limiter.cpp src/datadog/logger.cpp src/datadog/msgpack.cpp + src/datadog/otel_process_ctx.cpp src/datadog/parse_util.cpp src/datadog/propagation_style.cpp src/datadog/random.cpp diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 6a032a133..692139116 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -65,6 +65,9 @@ class Tracer { Tracer(const FinalizedTracerConfig& config, const std::shared_ptr& generator); + // Drops all state, including process discovery and process context. + ~Tracer(); + // Create a new trace and return the root span of the trace. Optionally // specify a `config` indicating the attributes of the root span. Span create_span(); diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index a68dac9d0..bf16e9ccc 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -7,6 +7,14 @@ #define _GNU_SOURCE #endif +#if defined(__GNUC__) && defined(__cplusplus) && __cplusplus < 202002L + // This file uses C99 compound literals with designated initializers + // throughout. They are standard in C (since C99) and in C++ (since C++20), + // but trigger -Wpedantic when compiled as C++17 or older. Silence them at + // translation-unit scope so the file builds cleanly under strict flags. + #pragma GCC diagnostic ignored "-Wpedantic" +#endif + // Note: Things here are needed for NOOP. Things that are only for non-NOOP get added further below. #include diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 4209ac228..219e69a44 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -22,6 +22,7 @@ #include "hex.h" #include "json.hpp" #include "msgpack.h" +#include "otel_process_ctx.h" #include "platform_util.h" #include "random.h" #include "root_session_id.h" @@ -120,6 +121,10 @@ Tracer::Tracer(const FinalizedTracerConfig& config, store_config(process_tags); } +Tracer::~Tracer() { + otel_process_ctx_drop_current(); +} + std::string Tracer::config() const { // clang-format off auto config = nlohmann::json::object({ @@ -160,9 +165,16 @@ void Tracer::store_config( metadata_file_ = std::make_unique(std::move(*maybe_file)); - auto defaults = config_manager_->span_defaults(); - - std::string container_id = ""; + const auto defaults = config_manager_->span_defaults(); + const std::string runtime_id_string = runtime_id_.string(); + const std::string tracer_version = signature_.library_version; + const std::string tracer_language(signature_.library_language); + const std::string hostname_value = hostname_.value_or(""); + const std::string service_name = defaults->service; + const std::string service_env = defaults->environment; + const std::string service_version = defaults->version; + const std::string process_tags_joined = join_tags(process_tags); + std::string container_id; if (auto maybe_container_id = container::get_id()) { container_id = maybe_container_id->value; } @@ -172,23 +184,58 @@ void Tracer::store_config( // clang-format off msgpack::pack_map( - buffer, - "schema_version", [&](auto& buffer) { msgpack::pack_integer(buffer, std::uint64_t(2)); return Expected{}; }, - "runtime_id", [&](auto& buffer) { return msgpack::pack_string(buffer, runtime_id_.string()); }, - "tracer_version", [&](auto& buffer) { return msgpack::pack_string(buffer, signature_.library_version); }, - "tracer_language", [&](auto& buffer) { return msgpack::pack_string(buffer, signature_.library_language); }, - "hostname", [&](auto& buffer) { return msgpack::pack_string(buffer, hostname_.value_or("")); }, - "service_name", [&](auto& buffer) { return msgpack::pack_string(buffer, defaults->service); }, - "service_env", [&](auto& buffer) { return msgpack::pack_string(buffer, defaults->environment); }, - "service_version", [&](auto& buffer) { return msgpack::pack_string(buffer, defaults->version); }, - "process_tags", [&](auto& buffer) { return msgpack::pack_string(buffer, join_tags(process_tags)); }, - "container_id", [&](auto& buffer) { return msgpack::pack_string(buffer, container_id); } + buffer, + "schema_version", [&](auto& buffer) { msgpack::pack_integer(buffer, std::uint64_t(2)); return Expected{}; }, + "runtime_id", [&](auto& buffer) { return msgpack::pack_string(buffer, runtime_id_string); }, + "tracer_version", [&](auto& buffer) { return msgpack::pack_string(buffer, tracer_version); }, + "tracer_language", [&](auto& buffer) { return msgpack::pack_string(buffer, tracer_language); }, + "hostname", [&](auto& buffer) { return msgpack::pack_string(buffer, hostname_value); }, + "service_name", [&](auto& buffer) { return msgpack::pack_string(buffer, service_name); }, + "service_env", [&](auto& buffer) { return msgpack::pack_string(buffer, service_env); }, + "service_version", [&](auto& buffer) { return msgpack::pack_string(buffer, service_version); }, + "process_tags", [&](auto& buffer) { return msgpack::pack_string(buffer, process_tags_joined); }, + "container_id", [&](auto& buffer) { return msgpack::pack_string(buffer, container_id); } ); // clang-format on if (!metadata_file_->write_then_seal(buffer)) { logger_->log_error("Either failed to write or seal the configuration file"); + return; + } + +#ifdef __linux__ + // Publish the same metadata as an OpenTelemetry process context. + const char* resource_attrs[] = { + "host.name", hostname_value.c_str(), + "container.id", container_id.c_str(), + nullptr, + }; + const char* extra_attrs[] = { + "datadog.process_tags", + process_tags_joined.c_str(), + nullptr, + }; + + otel_process_ctx_data otel_data = {}; + otel_data.deployment_environment_name = service_env.c_str(); + otel_data.service_instance_id = runtime_id_string.c_str(); + otel_data.service_name = service_name.c_str(); + otel_data.service_version = service_version.c_str(); + otel_data.telemetry_sdk_language = tracer_language.c_str(); + otel_data.telemetry_sdk_version = tracer_version.c_str(); + otel_data.telemetry_sdk_name = "dd-trace-cpp"; + otel_data.resource_attributes = resource_attrs; + otel_data.extra_attributes = extra_attrs; + otel_data.thread_ctx_config = nullptr; + + const auto otel_result = otel_process_ctx_publish(&otel_data); + if (!otel_result.success) { + logger_->log_error([&](std::ostream& log) { + log << "Failed to publish OpenTelemetry process context: " + << otel_result.error_message; + }); } +#endif } Span Tracer::create_span() { return create_span(SpanConfig{}); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7571aa8b7..e2298776e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -29,6 +29,7 @@ add_executable(tests test_glob.cpp test_limiter.cpp test_msgpack.cpp + test_otel_process_ctx.cpp test_platform_util.cpp test_parse_util.cpp test_smoke.cpp diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp new file mode 100644 index 000000000..e331f72b7 --- /dev/null +++ b/test/test_otel_process_ctx.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mocks/collectors.h" +#include "mocks/loggers.h" +#include "otel_process_ctx.h" +#include "platform_util.h" +#include "string_util.h" +#include "test.h" + +namespace fs = std::filesystem; +using namespace datadog::tracing; + +#define OTEL_CTX_TEST(x) TEST_CASE(x, "[otel_process_ctx]") + +namespace { + +std::map to_map(const char** kv) { + std::map out; + if (kv == nullptr) return out; + for (std::size_t i = 0; kv[i] != nullptr && kv[i + 1] != nullptr; i += 2) { + out.emplace(kv[i], kv[i + 1]); + } + return out; +} + +} // namespace + +OTEL_CTX_TEST("Tracer construction publishes OTel process context") { +#ifndef __linux__ + SUCCEED("OpenTelemetry process context is Linux-only"); + return; +#endif + + std::string expected_container_id; + if (auto id = container::get_id()) { + expected_container_id = id->value; + } + const RuntimeID expected_runtime_id = RuntimeID::generate(); + + std::unordered_map expected_process_tags = { + {"custom.tag", "custom-value"}, + }; + expected_process_tags.emplace("entrypoint.name", get_process_name()); + expected_process_tags.emplace("entrypoint.type", "executable"); + expected_process_tags.emplace("entrypoint.workdir", + fs::current_path().filename().string()); + if (auto path = get_process_path()) { + expected_process_tags.emplace("entrypoint.basedir", + path->parent_path().filename().string()); + } + + TracerConfig config; + config.service = "otel-ctx-svc"; + config.environment = "otel-ctx-env"; + config.version = "1.2.3"; + config.runtime_id = expected_runtime_id; + config.report_hostname = true; + config.process_tags = {{"custom.tag", "custom-value"}}; + config.collector = std::make_shared(); + config.logger = std::make_shared(); + + auto finalized = finalize_config(config); + REQUIRE(finalized); + + { + Tracer tracer{*finalized}; + + auto read_result = otel_process_ctx_read(); + REQUIRE(read_result.success); + const auto& data = read_result.data; + + CHECK(std::string(data.service_name) == "otel-ctx-svc"); + CHECK(std::string(data.deployment_environment_name) == "otel-ctx-env"); + CHECK(std::string(data.service_version) == "1.2.3"); + CHECK(std::string(data.service_instance_id) == expected_runtime_id.string()); + CHECK(std::string(data.telemetry_sdk_language) == "cpp"); + CHECK(std::string(data.telemetry_sdk_name) == "dd-trace-cpp"); + CHECK(std::string(data.telemetry_sdk_version) == tracer_version); + + const std::map expected_resource = { + {"host.name", get_hostname()}, + {"container.id", expected_container_id}, + }; + CHECK(to_map(data.resource_attributes) == expected_resource); + + const std::map expected_extra = { + {"datadog.process_tags", join_tags(expected_process_tags)}, + }; + CHECK(to_map(data.extra_attributes) == expected_extra); + + REQUIRE(otel_process_ctx_read_drop(&read_result)); + } + + auto post_read = otel_process_ctx_read(); + CHECK_FALSE(post_read.success); + if (post_read.success) { + otel_process_ctx_read_drop(&post_read); + } +} From fb1e9a76e1a353341028fa4ec8a7299a206485a8 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 5 Jun 2026 08:15:58 +0000 Subject: [PATCH 27/59] Make autoformatter happy --- src/datadog/otel_process_ctx.cpp | 4 ++++ src/datadog/otel_process_ctx.h | 4 ++++ src/datadog/tracer.cpp | 7 ++----- test/test_otel_process_ctx.cpp | 3 ++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index bf16e9ccc..3d5194fe5 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -1,3 +1,7 @@ +// clang-format off +// This file is a verbatim copy of an upstream reference implementation; do +// not let clang-format rewrite it. + // Unless explicitly stated otherwise all files in this repository are licensed under the Apache License (Version 2.0). // This product includes software developed at Datadog (https://www.datadoghq.com/) Copyright 2025 Datadog, Inc. diff --git a/src/datadog/otel_process_ctx.h b/src/datadog/otel_process_ctx.h index 909cd01ef..ca0473222 100644 --- a/src/datadog/otel_process_ctx.h +++ b/src/datadog/otel_process_ctx.h @@ -1,3 +1,7 @@ +// clang-format off +// This file is a verbatim copy of an upstream reference implementation; do +// not let clang-format rewrite it. + // Unless explicitly stated otherwise all files in this repository are licensed under the Apache License (Version 2.0). // This product includes software developed at Datadog (https://www.datadoghq.com/) Copyright 2025 Datadog, Inc. diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 219e69a44..146c0f290 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -121,9 +121,7 @@ Tracer::Tracer(const FinalizedTracerConfig& config, store_config(process_tags); } -Tracer::~Tracer() { - otel_process_ctx_drop_current(); -} +Tracer::~Tracer() { otel_process_ctx_drop_current(); } std::string Tracer::config() const { // clang-format off @@ -206,8 +204,7 @@ void Tracer::store_config( #ifdef __linux__ // Publish the same metadata as an OpenTelemetry process context. const char* resource_attrs[] = { - "host.name", hostname_value.c_str(), - "container.id", container_id.c_str(), + "host.name", hostname_value.c_str(), "container.id", container_id.c_str(), nullptr, }; const char* extra_attrs[] = { diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index e331f72b7..bb8f30e12 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -80,7 +80,8 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { CHECK(std::string(data.service_name) == "otel-ctx-svc"); CHECK(std::string(data.deployment_environment_name) == "otel-ctx-env"); CHECK(std::string(data.service_version) == "1.2.3"); - CHECK(std::string(data.service_instance_id) == expected_runtime_id.string()); + CHECK(std::string(data.service_instance_id) == + expected_runtime_id.string()); CHECK(std::string(data.telemetry_sdk_language) == "cpp"); CHECK(std::string(data.telemetry_sdk_name) == "dd-trace-cpp"); CHECK(std::string(data.telemetry_sdk_version) == tracer_version); From c8261daca3882d16c613061d654e0b8d4137ed2b Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 5 Jun 2026 08:32:06 +0000 Subject: [PATCH 28/59] Tweak to make CI happy --- src/datadog/otel_process_ctx.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index 3d5194fe5..415a50b18 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -14,9 +14,11 @@ #if defined(__GNUC__) && defined(__cplusplus) && __cplusplus < 202002L // This file uses C99 compound literals with designated initializers // throughout. They are standard in C (since C99) and in C++ (since C++20), - // but trigger -Wpedantic when compiled as C++17 or older. Silence them at - // translation-unit scope so the file builds cleanly under strict flags. + // but trigger -Wpedantic (older GCC) or -Wc++20-extensions (newer GCC) when + // compiled as C++17 or older. Silence both at translation-unit scope so the + // file builds cleanly under strict flags. #pragma GCC diagnostic ignored "-Wpedantic" + #pragma GCC diagnostic ignored "-Wc++20-extensions" #endif // Note: Things here are needed for NOOP. Things that are only for non-NOOP get added further below. From 74754ca6f180d4bba13b11cd6af26aacad710784 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 5 Jun 2026 08:41:28 +0000 Subject: [PATCH 29/59] Another try at making CI happy --- src/datadog/otel_process_ctx.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index 415a50b18..af488d161 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -15,8 +15,9 @@ // This file uses C99 compound literals with designated initializers // throughout. They are standard in C (since C99) and in C++ (since C++20), // but trigger -Wpedantic (older GCC) or -Wc++20-extensions (newer GCC) when - // compiled as C++17 or older. Silence both at translation-unit scope so the - // file builds cleanly under strict flags. + // compiled as C++17 or older. Silencing -Wpragmas first lets GCC versions + // that don't know -Wc++20-extensions accept the pragma silently. + #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wc++20-extensions" #endif From ac6e7c0feed12cf5e6ffe453be04d2111e900e12 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 5 Jun 2026 09:11:31 +0000 Subject: [PATCH 30/59] More small tweaks to make CI happy --- src/datadog/otel_process_ctx.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index af488d161..3ae2f4394 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -29,17 +29,19 @@ #define ADD_QUOTES_HELPER(x) #x #define ADD_QUOTES(x) ADD_QUOTES_HELPER(x) +// Positional aggregate init (no designated initializers) so this file's NOOP +// path compiles on MSVC at /std:c++17. static const otel_process_ctx_data empty_data = { - .deployment_environment_name = NULL, - .service_instance_id = NULL, - .service_name = NULL, - .service_version = NULL, - .telemetry_sdk_language = NULL, - .telemetry_sdk_version = NULL, - .telemetry_sdk_name = NULL, - .resource_attributes = NULL, - .extra_attributes = NULL, - .thread_ctx_config = NULL + NULL, // deployment_environment_name + NULL, // service_instance_id + NULL, // service_name + NULL, // service_version + NULL, // telemetry_sdk_language + NULL, // telemetry_sdk_version + NULL, // telemetry_sdk_name + NULL, // resource_attributes + NULL, // extra_attributes + NULL // thread_ctx_config }; #if (defined(OTEL_PROCESS_CTX_NOOP) && OTEL_PROCESS_CTX_NOOP) || !defined(__linux__) @@ -47,7 +49,8 @@ static const otel_process_ctx_data empty_data = { otel_process_ctx_result otel_process_ctx_publish(const otel_process_ctx_data *data) { (void) data; // Suppress unused parameter warning - return (otel_process_ctx_result) {.success = false, .error_message = "OTEL_PROCESS_CTX_NOOP mode is enabled - no-op implementation (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + otel_process_ctx_result result = {false, "OTEL_PROCESS_CTX_NOOP mode is enabled - no-op implementation (" __FILE__ ":" ADD_QUOTES(__LINE__) ")"}; + return result; } bool otel_process_ctx_drop_current(void) { @@ -56,7 +59,8 @@ static const otel_process_ctx_data empty_data = { #ifndef OTEL_PROCESS_CTX_NO_READ otel_process_ctx_read_result otel_process_ctx_read(void) { - return (otel_process_ctx_read_result) {.success = false, .error_message = "OTEL_PROCESS_CTX_NOOP mode is enabled - no-op implementation (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", .data = empty_data}; + otel_process_ctx_read_result result = {false, "OTEL_PROCESS_CTX_NOOP mode is enabled - no-op implementation (" __FILE__ ":" ADD_QUOTES(__LINE__) ")", empty_data}; + return result; } bool otel_process_ctx_read_drop(otel_process_ctx_read_result *result) { From e19da4b529e018e76ed04bc867579d811c38f39d Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 5 Jun 2026 10:12:20 +0000 Subject: [PATCH 31/59] More CI fixes --- src/datadog/tracer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 146c0f290..9c1746650 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -165,7 +165,7 @@ void Tracer::store_config( const auto defaults = config_manager_->span_defaults(); const std::string runtime_id_string = runtime_id_.string(); - const std::string tracer_version = signature_.library_version; + const std::string tracer_version_value = signature_.library_version; const std::string tracer_language(signature_.library_language); const std::string hostname_value = hostname_.value_or(""); const std::string service_name = defaults->service; @@ -185,7 +185,7 @@ void Tracer::store_config( buffer, "schema_version", [&](auto& buffer) { msgpack::pack_integer(buffer, std::uint64_t(2)); return Expected{}; }, "runtime_id", [&](auto& buffer) { return msgpack::pack_string(buffer, runtime_id_string); }, - "tracer_version", [&](auto& buffer) { return msgpack::pack_string(buffer, tracer_version); }, + "tracer_version", [&](auto& buffer) { return msgpack::pack_string(buffer, tracer_version_value); }, "tracer_language", [&](auto& buffer) { return msgpack::pack_string(buffer, tracer_language); }, "hostname", [&](auto& buffer) { return msgpack::pack_string(buffer, hostname_value); }, "service_name", [&](auto& buffer) { return msgpack::pack_string(buffer, service_name); }, @@ -219,7 +219,7 @@ void Tracer::store_config( otel_data.service_name = service_name.c_str(); otel_data.service_version = service_version.c_str(); otel_data.telemetry_sdk_language = tracer_language.c_str(); - otel_data.telemetry_sdk_version = tracer_version.c_str(); + otel_data.telemetry_sdk_version = tracer_version_value.c_str(); otel_data.telemetry_sdk_name = "dd-trace-cpp"; otel_data.resource_attributes = resource_attrs; otel_data.extra_attributes = extra_attrs; From a7e4d45d90981b263f932c9b7edbeac17ea7e08b Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 5 Jun 2026 10:30:53 +0000 Subject: [PATCH 32/59] More making CI happy --- test/test_otel_process_ctx.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index bb8f30e12..ad8e1f6a0 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -36,9 +36,7 @@ std::map to_map(const char** kv) { OTEL_CTX_TEST("Tracer construction publishes OTel process context") { #ifndef __linux__ SUCCEED("OpenTelemetry process context is Linux-only"); - return; -#endif - +#else std::string expected_container_id; if (auto id = container::get_id()) { expected_container_id = id->value; @@ -105,4 +103,5 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { if (post_read.success) { otel_process_ctx_read_drop(&post_read); } +#endif } From 09df310d1161deb6ba100cffba06e02dbb85e85b Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Mon, 8 Jun 2026 09:14:50 +0100 Subject: [PATCH 33/59] Add links to where `otel_process_ctx.h/.cpp This makes it more clear where they came from so in the future we can keep them up-to-date/in-sync. --- src/datadog/otel_process_ctx.cpp | 3 +++ src/datadog/otel_process_ctx.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index 3ae2f4394..aff2de53b 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -2,6 +2,9 @@ // This file is a verbatim copy of an upstream reference implementation; do // not let clang-format rewrite it. +// The upstream home for this file is +// https://github.com/open-telemetry/sig-profiling/blob/main/process-context/c-and-cpp/otel_process_ctx.c + // Unless explicitly stated otherwise all files in this repository are licensed under the Apache License (Version 2.0). // This product includes software developed at Datadog (https://www.datadoghq.com/) Copyright 2025 Datadog, Inc. diff --git a/src/datadog/otel_process_ctx.h b/src/datadog/otel_process_ctx.h index ca0473222..a1ebec6b6 100644 --- a/src/datadog/otel_process_ctx.h +++ b/src/datadog/otel_process_ctx.h @@ -2,6 +2,9 @@ // This file is a verbatim copy of an upstream reference implementation; do // not let clang-format rewrite it. +// The upstream home for this file is +// https://github.com/open-telemetry/sig-profiling/blob/main/process-context/c-and-cpp/otel_process_ctx.h + // Unless explicitly stated otherwise all files in this repository are licensed under the Apache License (Version 2.0). // This product includes software developed at Datadog (https://www.datadoghq.com/) Copyright 2025 Datadog, Inc. From 76a27ca7a2c161154b1a543c77efac97ed461c62 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 18 Jun 2026 15:56:10 +0000 Subject: [PATCH 34/59] Introduce new constant with library name, rather than hardcoding in random places --- include/datadog/version.h | 3 +++ src/datadog/error.cpp | 5 +++-- src/datadog/tracer.cpp | 2 +- src/datadog/version.cpp | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/datadog/version.h b/include/datadog/version.h index 90f4ffca5..96f9889eb 100644 --- a/include/datadog/version.h +++ b/include/datadog/version.h @@ -4,6 +4,9 @@ namespace datadog::tracing { +// This library's name +extern const char *const tracer_library_name; + // The release version at or before this code revision, e.g. "v0.1.12". // That is, this code is at least as recent as `tracer_version`, but may be // more recent. diff --git a/src/datadog/error.cpp b/src/datadog/error.cpp index 8aa8d2f7f..ba7ab6f46 100644 --- a/src/datadog/error.cpp +++ b/src/datadog/error.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -6,8 +7,8 @@ namespace datadog { namespace tracing { std::ostream& operator<<(std::ostream& stream, const Error& error) { - return stream << "[dd-trace-cpp error code " << int(error.code) << "] " - << error.message; + return stream << "[" << tracer_library_name << " error code " + << int(error.code) << "] " << error.message; } Error Error::with_prefix(StringView prefix) const { diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 9c1746650..f777d3c5a 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -220,7 +220,7 @@ void Tracer::store_config( otel_data.service_version = service_version.c_str(); otel_data.telemetry_sdk_language = tracer_language.c_str(); otel_data.telemetry_sdk_version = tracer_version_value.c_str(); - otel_data.telemetry_sdk_name = "dd-trace-cpp"; + otel_data.telemetry_sdk_name = tracer_library_name; otel_data.resource_attributes = resource_attrs; otel_data.extra_attributes = extra_attrs; otel_data.thread_ctx_config = nullptr; diff --git a/src/datadog/version.cpp b/src/datadog/version.cpp index 7c5b4d29e..2b25a2690 100644 --- a/src/datadog/version.cpp +++ b/src/datadog/version.cpp @@ -2,10 +2,12 @@ namespace datadog::tracing { +#define DD_TRACE_LIBRARY_NAME "dd-trace-cpp" #define DD_TRACE_VERSION "v2.1.1" +const char* const tracer_library_name = DD_TRACE_LIBRARY_NAME; const char* const tracer_version = DD_TRACE_VERSION; const char* const tracer_version_string = - "[dd-trace-cpp version " DD_TRACE_VERSION "]"; + "[" DD_TRACE_LIBRARY_NAME " version " DD_TRACE_VERSION "]"; } // namespace datadog::tracing From 36f61aeb1c3e9f37daa9f030fa3d3328d2d089f4 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 18 Jun 2026 16:15:30 +0000 Subject: [PATCH 35/59] Minor: Remove redundant includes --- test/test_otel_process_ctx.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index ad8e1f6a0..5bded8c9f 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -1,12 +1,4 @@ -#include #include -#include -#include - -#include -#include -#include -#include #include "mocks/collectors.h" #include "mocks/loggers.h" From a61a41b5b30c542430a68cef114cea1ef8f15ec1 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 18 Jun 2026 16:17:16 +0000 Subject: [PATCH 36/59] Minor: Use references when building up metadata --- src/datadog/tracer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index f777d3c5a..4ae1b96ca 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -164,13 +164,13 @@ void Tracer::store_config( metadata_file_ = std::make_unique(std::move(*maybe_file)); const auto defaults = config_manager_->span_defaults(); - const std::string runtime_id_string = runtime_id_.string(); - const std::string tracer_version_value = signature_.library_version; + const std::string& runtime_id_string = runtime_id_.string(); + const std::string& tracer_version_value = signature_.library_version; const std::string tracer_language(signature_.library_language); const std::string hostname_value = hostname_.value_or(""); - const std::string service_name = defaults->service; - const std::string service_env = defaults->environment; - const std::string service_version = defaults->version; + const std::string& service_name = defaults->service; + const std::string& service_env = defaults->environment; + const std::string& service_version = defaults->version; const std::string process_tags_joined = join_tags(process_tags); std::string container_id; if (auto maybe_container_id = container::get_id()) { From 135225665152b1c56bd7ca510873fe314200a1ad Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Thu, 18 Jun 2026 17:10:51 +0000 Subject: [PATCH 37/59] Minor: Don't compare unordered maps as it can easily break --- test/test_otel_process_ctx.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index 5bded8c9f..d80426bd3 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -4,7 +4,6 @@ #include "mocks/loggers.h" #include "otel_process_ctx.h" #include "platform_util.h" -#include "string_util.h" #include "test.h" namespace fs = std::filesystem; @@ -23,6 +22,16 @@ std::map to_map(const char** kv) { return out; } +std::map parse_joined_tags(const std::string& s) { + std::map out; + std::istringstream in(s); + for (std::string pair; std::getline(in, pair, ',');) { + const auto colon = pair.find(':'); + out.emplace(pair.substr(0, colon), pair.substr(colon + 1)); + } + return out; +} + } // namespace OTEL_CTX_TEST("Tracer construction publishes OTel process context") { @@ -35,7 +44,7 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { } const RuntimeID expected_runtime_id = RuntimeID::generate(); - std::unordered_map expected_process_tags = { + std::map expected_process_tags = { {"custom.tag", "custom-value"}, }; expected_process_tags.emplace("entrypoint.name", get_process_name()); @@ -82,10 +91,11 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { }; CHECK(to_map(data.resource_attributes) == expected_resource); - const std::map expected_extra = { - {"datadog.process_tags", join_tags(expected_process_tags)}, - }; - CHECK(to_map(data.extra_attributes) == expected_extra); + const auto extra = to_map(data.extra_attributes); + REQUIRE(extra.size() == 1); + REQUIRE(extra.count("datadog.process_tags") == 1); + CHECK(parse_joined_tags(extra.at("datadog.process_tags")) == + expected_process_tags); REQUIRE(otel_process_ctx_read_drop(&read_result)); } From 93ead451eefc34e77ac44e3e638912f8775c0438 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 19 Jun 2026 12:12:25 +0000 Subject: [PATCH 38/59] Tweak behavior when report_hostname is disabled + add test --- src/datadog/tracer.cpp | 8 +++++++- test/test_otel_process_ctx.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 4ae1b96ca..bf72f9592 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -203,10 +203,16 @@ void Tracer::store_config( #ifdef __linux__ // Publish the same metadata as an OpenTelemetry process context. - const char* resource_attrs[] = { + + // Make sure to leave host.name first... + const char* all_resource_attrs[] = { "host.name", hostname_value.c_str(), "container.id", container_id.c_str(), nullptr, }; + // ...so that we can omit it when it's not available. + const char** resource_attrs = + hostname_ ? all_resource_attrs : all_resource_attrs + 2; + const char* extra_attrs[] = { "datadog.process_tags", process_tags_joined.c_str(), diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index d80426bd3..fd9a51d40 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -107,3 +107,30 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { } #endif } + +OTEL_CTX_TEST("host.name is omitted when report_hostname is false") { +#ifndef __linux__ + SUCCEED("OpenTelemetry process context is Linux-only"); +#else + TracerConfig config; + config.service = "otel-ctx-svc"; + config.report_hostname = false; + config.collector = std::make_shared(); + config.logger = std::make_shared(); + + auto finalized = finalize_config(config); + REQUIRE(finalized); + + Tracer tracer{*finalized}; + auto read_result = otel_process_ctx_read(); + REQUIRE(read_result.success); + + // Sanity check that context is not empty + CHECK(std::string(read_result.data.service_name) == "otel-ctx-svc"); + + const auto resource = to_map(read_result.data.resource_attributes); + CHECK(resource.count("host.name") == 0); + + REQUIRE(otel_process_ctx_read_drop(&read_result)); +#endif +} From d8cf02613dff18970e729903de61f24f48a1c3e5 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 19 Jun 2026 12:27:19 +0000 Subject: [PATCH 39/59] Add missing `static` declaration --- src/datadog/otel_process_ctx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datadog/otel_process_ctx.cpp b/src/datadog/otel_process_ctx.cpp index aff2de53b..9056e11dc 100644 --- a/src/datadog/otel_process_ctx.cpp +++ b/src/datadog/otel_process_ctx.cpp @@ -827,7 +827,7 @@ static otel_process_ctx_result otel_process_ctx_encode_protobuf_payload(char **o data_out->telemetry_sdk_name != NULL; } - void otel_process_ctx_read_data_drop(otel_process_ctx_data data) { + static void otel_process_ctx_read_data_drop(otel_process_ctx_data data) { if (data.deployment_environment_name) free((void *)data.deployment_environment_name); if (data.service_instance_id) free((void *)data.service_instance_id); if (data.service_name) free((void *)data.service_name); From fde363c37848c7551be4a6371114ddba50d9ead5 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 19 Jun 2026 12:31:25 +0000 Subject: [PATCH 40/59] Minor: Fix wording in comment to use infinitive --- include/datadog/tracer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 692139116..a1c851414 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -65,7 +65,7 @@ class Tracer { Tracer(const FinalizedTracerConfig& config, const std::shared_ptr& generator); - // Drops all state, including process discovery and process context. + // Drop all state, including process discovery and process context. ~Tracer(); // Create a new trace and return the root span of the trace. Optionally From 822d0657bd5b8d8f35c0c1ec0d13ca33fa2c3028 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 19 Jun 2026 15:38:27 +0000 Subject: [PATCH 41/59] Introduce move-only RAII guard and mutex to ensure correctness Before this change, Tracer had a user-declared destructor that called otel_process_ctx_drop_current() directly. That caused two problems: 1. Declaring ~Tracer() suppresses the implicit move constructor and move assignment, while leaving copy operations in place. Tracer became accidentally copyable and non-movable -- the exact wrong shape for a class that owns a process-wide singleton. Callers like nginx-datadog that return Tracer by value silently bound to the copy ctor, and the source's destructor then dropped the global context out from under the live copy. 2. otel_process_ctx_publish / otel_process_ctx_drop_current are documented as not thread-safe. Concurrent construction or destruction of Tracers across threads would race on the global published_state. This change introduces OtelCtxGuard, a small RAII type that owns the published OpenTelemetry process context, and a publish_otel_process_ctx() factory that returns one. Tracer now holds the guard via std::unique_ptr, which gives us: - Move-only Tracer. Move ops are implicitly defaulted (the previous explicit ~Tracer() body is gone) and copy ops are implicitly deleted through the unique_ptr member. A failed or skipped publish is represented as a null guard, so the destructor is correctly a no-op in that case. - Symmetric publish/drop encapsulation. Both directions through the C API go through OtelCtxGuard, and tracer.cpp no longer references otel_process_ctx_publish / otel_process_ctx_drop_current directly. - Thread safety. A mutex internal to the guard serializes publish and drop, so concurrent Tracer construction/destruction across threads is safe. Multi-instance behavior is "last writer wins": the C API holds at most one published context per process, and any guard destruction drops whatever is current. This matches the common case (one Tracer per process) and is documented at the top of otel_process_ctx_guard.h. --- BUILD.bazel | 2 ++ CMakeLists.txt | 1 + include/datadog/tracer.h | 12 +++++++- src/datadog/otel_process_ctx_guard.cpp | 39 ++++++++++++++++++++++++++ src/datadog/otel_process_ctx_guard.h | 32 +++++++++++++++++++++ src/datadog/tracer.cpp | 14 ++++----- 6 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 src/datadog/otel_process_ctx_guard.cpp create mode 100644 src/datadog/otel_process_ctx_guard.h diff --git a/BUILD.bazel b/BUILD.bazel index db9e0e655..11dfc5c7b 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -41,6 +41,8 @@ cc_library( "src/datadog/null_logger.h", "src/datadog/otel_process_ctx.cpp", "src/datadog/otel_process_ctx.h", + "src/datadog/otel_process_ctx_guard.cpp", + "src/datadog/otel_process_ctx_guard.h", "src/datadog/parse_util.cpp", "src/datadog/parse_util.h", "src/datadog/platform_util.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index a892ad0a4..63a291040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ target_sources(dd-trace-cpp-objects src/datadog/logger.cpp src/datadog/msgpack.cpp src/datadog/otel_process_ctx.cpp + src/datadog/otel_process_ctx_guard.cpp src/datadog/parse_util.cpp src/datadog/propagation_style.cpp src/datadog/random.cpp diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index a1c851414..6f058dd6a 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -33,6 +33,7 @@ class TraceSampler; class SpanSampler; class IDGenerator; class InMemoryFile; +class OtelCtxGuard; class Tracer { std::shared_ptr logger_; @@ -51,6 +52,8 @@ class Tracer { // read to determine if the process is instrumented with a tracer and to // retrieve relevant tracing information. std::shared_ptr metadata_file_; + // Owns the published OpenTelemetry process context, if any. + std::unique_ptr otel_guard_; Baggage::Options baggage_opts_; bool baggage_injection_enabled_; bool baggage_extraction_enabled_; @@ -65,9 +68,16 @@ class Tracer { Tracer(const FinalizedTracerConfig& config, const std::shared_ptr& generator); - // Drop all state, including process discovery and process context. ~Tracer(); + // Move-only. The otel context guarded by OtelCtxGuard is a process-wide + // singleton; duplicating ownership would lead to spurious drops, so copies + // are disallowed. + Tracer(Tracer&&) noexcept; + Tracer& operator=(Tracer&&) noexcept; + Tracer(const Tracer&) = delete; + Tracer& operator=(const Tracer&) = delete; + // Create a new trace and return the root span of the trace. Optionally // specify a `config` indicating the attributes of the root span. Span create_span(); diff --git a/src/datadog/otel_process_ctx_guard.cpp b/src/datadog/otel_process_ctx_guard.cpp new file mode 100644 index 000000000..2f7ac78d5 --- /dev/null +++ b/src/datadog/otel_process_ctx_guard.cpp @@ -0,0 +1,39 @@ +#include "otel_process_ctx_guard.h" + +#include + +#include +#include + +namespace datadog { +namespace tracing { +namespace { + +std::mutex& otel_ctx_mutex() { + static std::mutex m; + return m; +} + +} // namespace + +OtelCtxGuard::~OtelCtxGuard() { + std::lock_guard lock(otel_ctx_mutex()); + otel_process_ctx_drop_current(); +} + +std::unique_ptr publish_otel_process_ctx( + const otel_process_ctx_data& data, Logger& logger) { + std::lock_guard lock(otel_ctx_mutex()); + const auto result = otel_process_ctx_publish(&data); + if (!result.success) { + logger.log_error([&](std::ostream& log) { + log << "Failed to publish OpenTelemetry process context: " + << result.error_message; + }); + return nullptr; + } + return std::make_unique(); +} + +} // namespace tracing +} // namespace datadog diff --git a/src/datadog/otel_process_ctx_guard.h b/src/datadog/otel_process_ctx_guard.h new file mode 100644 index 000000000..e35c26023 --- /dev/null +++ b/src/datadog/otel_process_ctx_guard.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "otel_process_ctx.h" + +namespace datadog { +namespace tracing { + +class Logger; + +// RAII handle for a published OpenTelemetry process context. Destroying the +// guard drops the process-wide context. +// +// Multi-instance behavior: the OTel context is a per-process singleton. +// A successful publish replaces any previously-published context, and +// destroying any guard drops whatever is current (last writer wins style). +// +// This global state is serialized via an internal mutex so this class is +// thread-safe. +class OtelCtxGuard { + public: + ~OtelCtxGuard(); +}; + +// Publish the OTel process context. Returns a guard whose destructor drops +// the context, or nullptr on failure (errors are logged via `logger`). +std::unique_ptr publish_otel_process_ctx( + const otel_process_ctx_data& data, Logger& logger); + +} // namespace tracing +} // namespace datadog diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index bf72f9592..f00166ea1 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -22,7 +22,7 @@ #include "hex.h" #include "json.hpp" #include "msgpack.h" -#include "otel_process_ctx.h" +#include "otel_process_ctx_guard.h" #include "platform_util.h" #include "random.h" #include "root_session_id.h" @@ -121,7 +121,9 @@ Tracer::Tracer(const FinalizedTracerConfig& config, store_config(process_tags); } -Tracer::~Tracer() { otel_process_ctx_drop_current(); } +Tracer::~Tracer() = default; +Tracer::Tracer(Tracer&&) noexcept = default; +Tracer& Tracer::operator=(Tracer&&) noexcept = default; std::string Tracer::config() const { // clang-format off @@ -231,13 +233,7 @@ void Tracer::store_config( otel_data.extra_attributes = extra_attrs; otel_data.thread_ctx_config = nullptr; - const auto otel_result = otel_process_ctx_publish(&otel_data); - if (!otel_result.success) { - logger_->log_error([&](std::ostream& log) { - log << "Failed to publish OpenTelemetry process context: " - << otel_result.error_message; - }); - } + otel_guard_ = publish_otel_process_ctx(otel_data, *logger_); #endif } From 3ff726b1921d2a29e92ab50d8cfd088a0dbcace4 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Fri, 19 Jun 2026 15:50:46 +0000 Subject: [PATCH 42/59] Tighten tests for moving the tracer instance --- test/test_tracer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/test/test_tracer.cpp b/test/test_tracer.cpp index 72231115f..9c4a7da49 100644 --- a/test/test_tracer.cpp +++ b/test/test_tracer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "matchers.h" @@ -1882,8 +1883,16 @@ TEST_TRACER("heterogeneous extraction") { REQUIRE(writer.items == test_case.expected_injected_headers); } -TEST_TRACER("move semantics") { - // Verify that `Tracer` can be moved. +TEST_TRACER("move-only semantics") { + static_assert(std::is_move_constructible::value, + "Tracer must be move-constructible"); + static_assert(std::is_move_assignable::value, + "Tracer must be move-assignable"); + static_assert(!std::is_copy_constructible::value, + "Tracer must not be copy-constructible"); + static_assert(!std::is_copy_assignable::value, + "Tracer must not be copy-assignable"); + TracerConfig config; config.service = "testsvc"; config.logger = std::make_shared(); @@ -1891,11 +1900,11 @@ TEST_TRACER("move semantics") { auto finalized_config = finalize_config(config); REQUIRE(finalized_config); - Tracer tracer1{*finalized_config}; - // This must compile. + // The moved-into Tracer must remain usable. + Tracer tracer1{*finalized_config}; Tracer tracer2{std::move(tracer1)}; - (void)tracer2; + { auto span = tracer2.create_span(); } } TEST_TRACER("APM tracing disabled") { From 3a558812867afc30c6af4c6851b3c9f2358aa3b3 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Tue, 21 Jul 2026 13:30:23 +0000 Subject: [PATCH 43/59] Avoid using auto to improve readibility --- src/datadog/tracer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index c2c881cb6..4c97b2858 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -165,7 +165,8 @@ void Tracer::store_config( metadata_file_ = std::make_unique(std::move(*maybe_file)); - const auto defaults = config_manager_->span_defaults(); + const std::shared_ptr defaults = + config_manager_->span_defaults(); const std::string& runtime_id_string = runtime_id_.string(); const std::string& tracer_version_value = signature_.library_version; const std::string tracer_language(signature_.library_language); From 7a803393581e6cc9c8968ac7131ee13b42526e7a Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Tue, 21 Jul 2026 13:34:47 +0000 Subject: [PATCH 44/59] Use compound namespaces --- src/datadog/otel_process_ctx_guard.cpp | 6 ++---- src/datadog/otel_process_ctx_guard.h | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/datadog/otel_process_ctx_guard.cpp b/src/datadog/otel_process_ctx_guard.cpp index 2f7ac78d5..2d9e9aa3b 100644 --- a/src/datadog/otel_process_ctx_guard.cpp +++ b/src/datadog/otel_process_ctx_guard.cpp @@ -5,8 +5,7 @@ #include #include -namespace datadog { -namespace tracing { +namespace datadog::tracing { namespace { std::mutex& otel_ctx_mutex() { @@ -35,5 +34,4 @@ std::unique_ptr publish_otel_process_ctx( return std::make_unique(); } -} // namespace tracing -} // namespace datadog +} // namespace datadog::tracing diff --git a/src/datadog/otel_process_ctx_guard.h b/src/datadog/otel_process_ctx_guard.h index e35c26023..1473418d7 100644 --- a/src/datadog/otel_process_ctx_guard.h +++ b/src/datadog/otel_process_ctx_guard.h @@ -4,8 +4,7 @@ #include "otel_process_ctx.h" -namespace datadog { -namespace tracing { +namespace datadog::tracing { class Logger; @@ -28,5 +27,4 @@ class OtelCtxGuard { std::unique_ptr publish_otel_process_ctx( const otel_process_ctx_data& data, Logger& logger); -} // namespace tracing -} // namespace datadog +} // namespace datadog::tracing From c91a28ad7d2a5de3a84489d89f41ed9940bb4600 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Tue, 21 Jul 2026 13:38:45 +0000 Subject: [PATCH 45/59] Improve naming --- src/datadog/otel_process_ctx_guard.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/datadog/otel_process_ctx_guard.cpp b/src/datadog/otel_process_ctx_guard.cpp index 2d9e9aa3b..572e0f464 100644 --- a/src/datadog/otel_process_ctx_guard.cpp +++ b/src/datadog/otel_process_ctx_guard.cpp @@ -8,7 +8,7 @@ namespace datadog::tracing { namespace { -std::mutex& otel_ctx_mutex() { +std::mutex& get_otel_context_mutex() { static std::mutex m; return m; } @@ -16,13 +16,13 @@ std::mutex& otel_ctx_mutex() { } // namespace OtelCtxGuard::~OtelCtxGuard() { - std::lock_guard lock(otel_ctx_mutex()); + std::lock_guard lock(get_otel_context_mutex()); otel_process_ctx_drop_current(); } std::unique_ptr publish_otel_process_ctx( const otel_process_ctx_data& data, Logger& logger) { - std::lock_guard lock(otel_ctx_mutex()); + std::lock_guard lock(get_otel_context_mutex()); const auto result = otel_process_ctx_publish(&data); if (!result.success) { logger.log_error([&](std::ostream& log) { From dea073f9d791aee16d761e0aa17d121913cddd8d Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Tue, 21 Jul 2026 13:39:40 +0000 Subject: [PATCH 46/59] More naming improvements --- src/datadog/otel_process_ctx_guard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/datadog/otel_process_ctx_guard.cpp b/src/datadog/otel_process_ctx_guard.cpp index 572e0f464..24bbf9fcc 100644 --- a/src/datadog/otel_process_ctx_guard.cpp +++ b/src/datadog/otel_process_ctx_guard.cpp @@ -9,8 +9,8 @@ namespace datadog::tracing { namespace { std::mutex& get_otel_context_mutex() { - static std::mutex m; - return m; + static std::mutex mutex; + return mutex; } } // namespace From 0da90274fcaa9b7cba70ec456fa06c746a369e47 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Tue, 21 Jul 2026 13:42:16 +0000 Subject: [PATCH 47/59] More naming improvements --- include/datadog/tracer.h | 2 +- src/datadog/tracer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 4c3963bf9..2c9d6fdb6 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -53,7 +53,7 @@ class Tracer { // retrieve relevant tracing information. std::shared_ptr metadata_file_; // Owns the published OpenTelemetry process context, if any. - std::unique_ptr otel_guard_; + std::unique_ptr otel_context_guard_; Baggage::Options baggage_opts_; bool baggage_injection_enabled_; bool baggage_extraction_enabled_; diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 4c97b2858..c2b3474d5 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -234,7 +234,7 @@ void Tracer::store_config( otel_data.extra_attributes = extra_attrs; otel_data.thread_ctx_config = nullptr; - otel_guard_ = publish_otel_process_ctx(otel_data, *logger_); + otel_context_guard_ = publish_otel_process_ctx(otel_data, *logger_); #endif } From b66a2ad8544ea3024b7d41a12ee20e9e62e32895 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Tue, 21 Jul 2026 13:44:53 +0000 Subject: [PATCH 48/59] Make test code stricter --- test/test_otel_process_ctx.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index fd9a51d40..bb3dd618f 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -13,20 +13,23 @@ using namespace datadog::tracing; namespace { -std::map to_map(const char** kv) { +std::map to_map(const char** key_value_array) { std::map out; - if (kv == nullptr) return out; - for (std::size_t i = 0; kv[i] != nullptr && kv[i + 1] != nullptr; i += 2) { - out.emplace(kv[i], kv[i + 1]); + if (key_value_array == nullptr) return out; + for (std::size_t index = 0; key_value_array[index] != nullptr; index += 2) { + REQUIRE(key_value_array[index + 1] != nullptr); + out.emplace(key_value_array[index], key_value_array[index + 1]); } return out; } -std::map parse_joined_tags(const std::string& s) { +std::map parse_joined_tags( + const std::string& joined_tags) { std::map out; - std::istringstream in(s); + std::istringstream in(joined_tags); for (std::string pair; std::getline(in, pair, ',');) { const auto colon = pair.find(':'); + REQUIRE(colon != std::string::npos); out.emplace(pair.substr(0, colon), pair.substr(colon + 1)); } return out; From 1dfe8ff9a6b82c3726304e4e7ba6e2d9d74c4fe3 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 22 Jul 2026 10:46:54 +0000 Subject: [PATCH 49/59] Add test for existing memfd datadog-tracer-info publishing logic This includes a for-tests-only msgpack decoder dependency. --- cmake/deps/msgpack.cmake | 19 ++++++ test/CMakeLists.txt | 5 +- test/common/ctx_sharing_helpers.h | 47 ++++++++++++++ test/test_otel_process_ctx.cpp | 30 +-------- test/test_tracer_config.cpp | 104 ++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 28 deletions(-) create mode 100644 cmake/deps/msgpack.cmake create mode 100644 test/common/ctx_sharing_helpers.h diff --git a/cmake/deps/msgpack.cmake b/cmake/deps/msgpack.cmake new file mode 100644 index 000000000..9a5935d7c --- /dev/null +++ b/cmake/deps/msgpack.cmake @@ -0,0 +1,19 @@ +include(FetchContent) + +# Header-only; used only by the test suite to decode msgpack payloads written +# by the library, so we don't need Boost, its own tests, examples, or docs. +set(MSGPACK_USE_BOOST OFF CACHE BOOL "" FORCE) +set(MSGPACK_CXX17 ON CACHE BOOL "" FORCE) +set(MSGPACK_BUILD_TESTS OFF CACHE BOOL "" FORCE) +set(MSGPACK_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set(MSGPACK_BUILD_DOCS OFF CACHE BOOL "" FORCE) + +FetchContent_Declare(msgpack-cxx + URL https://github.com/msgpack/msgpack-c/archive/refs/tags/cpp-8.0.0.tar.gz + URL_HASH SHA256=f634fb7052da4478096f2a02dfb6d91174e5836b317afb006375249ccb086aa8 + FIND_PACKAGE_ARGS NAMES msgpack-cxx + EXCLUDE_FROM_ALL + SYSTEM +) + +FetchContent_MakeAvailable(msgpack-cxx) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e2298776e..b4c636542 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,5 @@ +include(${CMAKE_SOURCE_DIR}/cmake/deps/msgpack.cmake) + add_executable(tests # test driver main.cpp @@ -61,10 +63,11 @@ target_compile_definitions(tests CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS ) -target_link_libraries(tests +target_link_libraries(tests PRIVATE dd-trace-cpp::static dd-trace-cpp::specs + msgpack-cxx ) if(DD_TRACE_TRANSPORT STREQUAL "curl") diff --git a/test/common/ctx_sharing_helpers.h b/test/common/ctx_sharing_helpers.h new file mode 100644 index 000000000..281f08694 --- /dev/null +++ b/test/common/ctx_sharing_helpers.h @@ -0,0 +1,47 @@ +#pragma once + +// Shared helpers for tests that verify the process-level metadata that +// `Tracer` publishes on construction. + +#include +#include +#include +#include +#include + +#include "../test.h" +#include "platform_util.h" + +namespace datadog::test { + +// Returns the process tags that `Tracer` is expected to publish: the +// tags from the config + `entrypoint` tags that get added extra. +inline std::map expected_published_process_tags( + const std::unordered_map& config_process_tags) { + std::map tags(config_process_tags.begin(), + config_process_tags.end()); + tags.emplace("entrypoint.name", tracing::get_process_name()); + tags.emplace("entrypoint.type", "executable"); + tags.emplace("entrypoint.workdir", + std::filesystem::current_path().filename().string()); + if (auto path = tracing::get_process_path()) { + tags.emplace("entrypoint.basedir", path->parent_path().filename().string()); + } + return tags; +} + +// Parses a comma-separated "key:value,key:value" string, as produced by +// `datadog::tracing::join_tags`, back into a map. +inline std::map parse_joined_tags( + const std::string& joined_tags) { + std::map out; + std::istringstream in(joined_tags); + for (std::string pair; std::getline(in, pair, ',');) { + const auto colon = pair.find(':'); + REQUIRE(colon != std::string::npos); + out.emplace(pair.substr(0, colon), pair.substr(colon + 1)); + } + return out; +} + +} // namespace datadog::test diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index bb3dd618f..c557ea830 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -1,12 +1,12 @@ #include +#include "common/ctx_sharing_helpers.h" #include "mocks/collectors.h" #include "mocks/loggers.h" #include "otel_process_ctx.h" #include "platform_util.h" #include "test.h" -namespace fs = std::filesystem; using namespace datadog::tracing; #define OTEL_CTX_TEST(x) TEST_CASE(x, "[otel_process_ctx]") @@ -23,18 +23,6 @@ std::map to_map(const char** key_value_array) { return out; } -std::map parse_joined_tags( - const std::string& joined_tags) { - std::map out; - std::istringstream in(joined_tags); - for (std::string pair; std::getline(in, pair, ',');) { - const auto colon = pair.find(':'); - REQUIRE(colon != std::string::npos); - out.emplace(pair.substr(0, colon), pair.substr(colon + 1)); - } - return out; -} - } // namespace OTEL_CTX_TEST("Tracer construction publishes OTel process context") { @@ -47,18 +35,6 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { } const RuntimeID expected_runtime_id = RuntimeID::generate(); - std::map expected_process_tags = { - {"custom.tag", "custom-value"}, - }; - expected_process_tags.emplace("entrypoint.name", get_process_name()); - expected_process_tags.emplace("entrypoint.type", "executable"); - expected_process_tags.emplace("entrypoint.workdir", - fs::current_path().filename().string()); - if (auto path = get_process_path()) { - expected_process_tags.emplace("entrypoint.basedir", - path->parent_path().filename().string()); - } - TracerConfig config; config.service = "otel-ctx-svc"; config.environment = "otel-ctx-env"; @@ -97,8 +73,8 @@ OTEL_CTX_TEST("Tracer construction publishes OTel process context") { const auto extra = to_map(data.extra_attributes); REQUIRE(extra.size() == 1); REQUIRE(extra.count("datadog.process_tags") == 1); - CHECK(parse_joined_tags(extra.at("datadog.process_tags")) == - expected_process_tags); + CHECK(datadog::test::parse_joined_tags(extra.at("datadog.process_tags")) == + datadog::test::expected_published_process_tags(config.process_tags)); REQUIRE(otel_process_ctx_read_drop(&read_result)); } diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index 5f6aad8ac..c83d47ed1 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -5,6 +5,15 @@ #include #include +#if defined(__linux__) +// Used to test writing to the `datadog-tracer-info` file; this is a Linux-only feature. +#include +#include + +#include +#include +#endif + #include #include #include @@ -26,6 +35,13 @@ #include "null_logger.h" #include "test.h" +#if defined(__linux__) +// Used to test writing to the `datadog-tracer-info` file; this is a Linux-only feature. +#include "common/ctx_sharing_helpers.h" +#include "platform_util.h" +#include "string_util.h" +#endif + namespace datadog { namespace tracing { @@ -1540,3 +1556,91 @@ TRACER_CONFIG_TEST("telemetry products contain configuration precedence") { CHECK(configs[0].value == "1.2.3"); } } + +TRACER_CONFIG_TEST("Tracer construction publishes tracer info file") { +#ifndef __linux__ + SUCCEED("In-memory tracer info file is Linux-only"); +#else + std::string expected_container_id; + if (auto id = container::get_id()) { + expected_container_id = id->value; + } + const RuntimeID expected_runtime_id = RuntimeID::generate(); + + TracerConfig config; + config.service = "tracer-info-svc"; + config.environment = "tracer-info-env"; + config.version = "4.5.6"; + config.runtime_id = expected_runtime_id; + config.report_hostname = true; + config.process_tags = {{"custom.tag", "custom-value"}}; + config.collector = std::make_shared(); + config.logger = std::make_shared(); + + auto finalized = finalize_config(config); + REQUIRE(finalized); + + // Find the "/proc/self/fd/" path of the memfd whose name starts with + // "datadog-tracer-info-", i.e. the file written by `Tracer::store_config`. + auto find_tracer_info_path = []() -> Optional { + DIR* dir = opendir("/proc/self/fd"); + if (dir == nullptr) return nullopt; + + char target[PATH_MAX]; + Optional found; + for (struct dirent* entry = readdir(dir); entry != nullptr; + entry = readdir(dir)) { + if (entry->d_type != DT_LNK) continue; + + const std::string link_path = + std::string("/proc/self/fd/") + entry->d_name; + auto len = readlink(link_path.c_str(), target, sizeof(target) - 1); + if (len == -1) continue; + target[len] = '\0'; + + if (starts_with(target, "/memfd:datadog-tracer-info-")) { + found = link_path; + break; + } + } + + closedir(dir); + return found; + }; + + { + Tracer tracer{*finalized}; + + auto tracer_info_path = find_tracer_info_path(); + REQUIRE(tracer_info_path); + + std::ifstream file(*tracer_info_path, std::ios::binary); + REQUIRE(file.is_open()); + const std::string buffer((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + REQUIRE(!buffer.empty()); + + const auto handle = ::msgpack::unpack(buffer.data(), buffer.size()); + const auto fields = + handle.get().as >(); + + CHECK(fields.at("schema_version").as() == 2); + CHECK(fields.at("runtime_id").as() == + expected_runtime_id.string()); + CHECK(fields.at("tracer_version").as() == tracer_version); + CHECK(fields.at("tracer_language").as() == "cpp"); + CHECK(fields.at("hostname").as() == get_hostname()); + CHECK(fields.at("service_name").as() == "tracer-info-svc"); + CHECK(fields.at("service_env").as() == "tracer-info-env"); + CHECK(fields.at("service_version").as() == "4.5.6"); + CHECK(fields.at("container_id").as() == expected_container_id); + CHECK(datadog::test::parse_joined_tags( + fields.at("process_tags").as()) == + datadog::test::expected_published_process_tags(config.process_tags)); + + REQUIRE(find_tracer_info_path()); + } + + CHECK(!find_tracer_info_path()); +#endif +} From 1dc4c3054d2115acb5991f93d10cd0fd2e8c4b30 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 22 Jul 2026 11:38:49 +0000 Subject: [PATCH 50/59] Streamline `store_config` logic --- src/datadog/otel_process_ctx_guard.cpp | 7 +++++ src/datadog/tracer.cpp | 43 ++++++++++++++------------ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/datadog/otel_process_ctx_guard.cpp b/src/datadog/otel_process_ctx_guard.cpp index 24bbf9fcc..38e5201ba 100644 --- a/src/datadog/otel_process_ctx_guard.cpp +++ b/src/datadog/otel_process_ctx_guard.cpp @@ -22,6 +22,12 @@ OtelCtxGuard::~OtelCtxGuard() { std::unique_ptr publish_otel_process_ctx( const otel_process_ctx_data& data, Logger& logger) { +#ifndef __linux__ + // Feature is Linux-only, nothing to do elsewhere + (void)data; + (void)logger; + return nullptr; +#else std::lock_guard lock(get_otel_context_mutex()); const auto result = otel_process_ctx_publish(&data); if (!result.success) { @@ -32,6 +38,7 @@ std::unique_ptr publish_otel_process_ctx( return nullptr; } return std::make_unique(); +#endif } } // namespace datadog::tracing diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index c2b3474d5..7df7c465e 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "config_manager.h" #include "datadog_agent.h" @@ -152,6 +153,24 @@ std::string Tracer::config() const { return config.dump(); } +namespace { + +std::vector otel_resource_attrs( + const Optional& hostname, const std::string& container_id) { + if (hostname) { + return {"host.name", hostname->c_str(), "container.id", + container_id.c_str(), nullptr}; + } + return {"container.id", container_id.c_str(), nullptr}; +} + +std::vector otel_extra_attrs( + const std::string& process_tags_joined) { + return {"datadog.process_tags", process_tags_joined.c_str(), nullptr}; +} + +} // namespace + void Tracer::store_config( const std::unordered_map& process_tags) { auto maybe_file = @@ -204,23 +223,8 @@ void Tracer::store_config( return; } -#ifdef __linux__ - // Publish the same metadata as an OpenTelemetry process context. - - // Make sure to leave host.name first... - const char* all_resource_attrs[] = { - "host.name", hostname_value.c_str(), "container.id", container_id.c_str(), - nullptr, - }; - // ...so that we can omit it when it's not available. - const char** resource_attrs = - hostname_ ? all_resource_attrs : all_resource_attrs + 2; - - const char* extra_attrs[] = { - "datadog.process_tags", - process_tags_joined.c_str(), - nullptr, - }; + auto resource_attrs = otel_resource_attrs(hostname_, container_id); + auto extra_attrs = otel_extra_attrs(process_tags_joined); otel_process_ctx_data otel_data = {}; otel_data.deployment_environment_name = service_env.c_str(); @@ -230,12 +234,11 @@ void Tracer::store_config( otel_data.telemetry_sdk_language = tracer_language.c_str(); otel_data.telemetry_sdk_version = tracer_version_value.c_str(); otel_data.telemetry_sdk_name = tracer_library_name; - otel_data.resource_attributes = resource_attrs; - otel_data.extra_attributes = extra_attrs; + otel_data.resource_attributes = resource_attrs.data(); + otel_data.extra_attributes = extra_attrs.data(); otel_data.thread_ctx_config = nullptr; otel_context_guard_ = publish_otel_process_ctx(otel_data, *logger_); -#endif } Span Tracer::create_span() { return create_span(SpanConfig{}); } From df911d5a41c5efa60bded6229c3dde8a850838f1 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 29 Jul 2026 04:58:04 +0000 Subject: [PATCH 51/59] Improve handling for many multiple tracer instances When multiple tracers are alive (as is expected from our envoy integration), we now correctly handle that -- the process context remains published until the last tracer is destroyed, and we also correctly handle the differing runtime-ids. --- BUILD.bazel | 4 +- CMakeLists.txt | 2 +- include/datadog/tracer.h | 10 +- src/datadog/otel_process_ctx_guard.cpp | 44 ------ src/datadog/otel_process_ctx_guard.h | 30 ---- src/datadog/otel_process_ctx_registration.cpp | 143 ++++++++++++++++++ src/datadog/otel_process_ctx_registration.h | 76 ++++++++++ src/datadog/tracer.cpp | 50 ++---- test/test_otel_process_ctx.cpp | 101 +++++++++++++ 9 files changed, 342 insertions(+), 118 deletions(-) delete mode 100644 src/datadog/otel_process_ctx_guard.cpp delete mode 100644 src/datadog/otel_process_ctx_guard.h create mode 100644 src/datadog/otel_process_ctx_registration.cpp create mode 100644 src/datadog/otel_process_ctx_registration.h diff --git a/BUILD.bazel b/BUILD.bazel index 11dfc5c7b..a4f9e82ef 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -41,8 +41,8 @@ cc_library( "src/datadog/null_logger.h", "src/datadog/otel_process_ctx.cpp", "src/datadog/otel_process_ctx.h", - "src/datadog/otel_process_ctx_guard.cpp", - "src/datadog/otel_process_ctx_guard.h", + "src/datadog/otel_process_ctx_registration.cpp", + "src/datadog/otel_process_ctx_registration.h", "src/datadog/parse_util.cpp", "src/datadog/parse_util.h", "src/datadog/platform_util.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 63a291040..7f972fff8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,7 +195,7 @@ target_sources(dd-trace-cpp-objects src/datadog/logger.cpp src/datadog/msgpack.cpp src/datadog/otel_process_ctx.cpp - src/datadog/otel_process_ctx_guard.cpp + src/datadog/otel_process_ctx_registration.cpp src/datadog/parse_util.cpp src/datadog/propagation_style.cpp src/datadog/random.cpp diff --git a/include/datadog/tracer.h b/include/datadog/tracer.h index 2c9d6fdb6..c73cee16f 100644 --- a/include/datadog/tracer.h +++ b/include/datadog/tracer.h @@ -33,7 +33,7 @@ class TraceSampler; class SpanSampler; class IDGenerator; class InMemoryFile; -class OtelCtxGuard; +class OtelCtxRegistration; class Tracer { std::shared_ptr logger_; @@ -52,8 +52,7 @@ class Tracer { // read to determine if the process is instrumented with a tracer and to // retrieve relevant tracing information. std::shared_ptr metadata_file_; - // Owns the published OpenTelemetry process context, if any. - std::unique_ptr otel_context_guard_; + std::unique_ptr otel_context_registration_; Baggage::Options baggage_opts_; bool baggage_injection_enabled_; bool baggage_extraction_enabled_; @@ -70,9 +69,8 @@ class Tracer { ~Tracer(); - // Move-only. The otel context guarded by OtelCtxGuard is a process-wide - // singleton; duplicating ownership would lead to spurious drops, so copies - // are disallowed. + // Move-only. OtelCtxRegistration is a per-tracer-instance handle; duplicating + // ownership would break that invariant, thus copies are disallowed. Tracer(Tracer&&) noexcept; Tracer& operator=(Tracer&&) noexcept; Tracer(const Tracer&) = delete; diff --git a/src/datadog/otel_process_ctx_guard.cpp b/src/datadog/otel_process_ctx_guard.cpp deleted file mode 100644 index 38e5201ba..000000000 --- a/src/datadog/otel_process_ctx_guard.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "otel_process_ctx_guard.h" - -#include - -#include -#include - -namespace datadog::tracing { -namespace { - -std::mutex& get_otel_context_mutex() { - static std::mutex mutex; - return mutex; -} - -} // namespace - -OtelCtxGuard::~OtelCtxGuard() { - std::lock_guard lock(get_otel_context_mutex()); - otel_process_ctx_drop_current(); -} - -std::unique_ptr publish_otel_process_ctx( - const otel_process_ctx_data& data, Logger& logger) { -#ifndef __linux__ - // Feature is Linux-only, nothing to do elsewhere - (void)data; - (void)logger; - return nullptr; -#else - std::lock_guard lock(get_otel_context_mutex()); - const auto result = otel_process_ctx_publish(&data); - if (!result.success) { - logger.log_error([&](std::ostream& log) { - log << "Failed to publish OpenTelemetry process context: " - << result.error_message; - }); - return nullptr; - } - return std::make_unique(); -#endif -} - -} // namespace datadog::tracing diff --git a/src/datadog/otel_process_ctx_guard.h b/src/datadog/otel_process_ctx_guard.h deleted file mode 100644 index 1473418d7..000000000 --- a/src/datadog/otel_process_ctx_guard.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -#include "otel_process_ctx.h" - -namespace datadog::tracing { - -class Logger; - -// RAII handle for a published OpenTelemetry process context. Destroying the -// guard drops the process-wide context. -// -// Multi-instance behavior: the OTel context is a per-process singleton. -// A successful publish replaces any previously-published context, and -// destroying any guard drops whatever is current (last writer wins style). -// -// This global state is serialized via an internal mutex so this class is -// thread-safe. -class OtelCtxGuard { - public: - ~OtelCtxGuard(); -}; - -// Publish the OTel process context. Returns a guard whose destructor drops -// the context, or nullptr on failure (errors are logged via `logger`). -std::unique_ptr publish_otel_process_ctx( - const otel_process_ctx_data& data, Logger& logger); - -} // namespace datadog::tracing diff --git a/src/datadog/otel_process_ctx_registration.cpp b/src/datadog/otel_process_ctx_registration.cpp new file mode 100644 index 000000000..9143ab2dc --- /dev/null +++ b/src/datadog/otel_process_ctx_registration.cpp @@ -0,0 +1,143 @@ +#include "otel_process_ctx_registration.h" + +#include +#include + +#include +#include +#include +#include + +#include "otel_process_ctx.h" + +namespace datadog::tracing { +namespace { + +// Process-wide OTel context state, including the mutex that guards it. +// Accessed through the single `get_otel_context_state()` instance. +struct StaticOtelContextState { + std::mutex mutex; + // Shared by all coexisting registrations. Present iff + // `runtime_ids` is non-empty: established by the first live registration and + // dropped once the last one is released. + Optional common; + // The `service_instance_id` (runtime id) of each live registration; expected + // to be unique per registration (see `publish`). + std::set runtime_ids; +}; + +StaticOtelContextState& get_otel_context_state() { + static StaticOtelContextState state; + return state; +} + +// Removes `runtime_id` from `state`. Must be called with `state.mutex` held. +void unregister(StaticOtelContextState& state, const std::string& runtime_id) { + state.runtime_ids.erase(runtime_id); + if (state.runtime_ids.empty()) { + state.common.reset(); + } +} + +// (Re)publishes or drops the process context to reflect `state`. Must be called +// with `state.mutex` held. +otel_process_ctx_result upsert(const StaticOtelContextState& state) { + const std::set& runtime_ids = state.runtime_ids; + if (runtime_ids.empty()) { + otel_process_ctx_drop_current(); + return {true, nullptr}; + } + + const OtelCtxFields& common = *state.common; + // With a single live registration we publish its instance id; with several, + // no single id represents the process, so it is omitted (see class docs). + // When there is one entry it is necessarily the sole survivor. + const bool include_instance_id = runtime_ids.size() == 1; + + std::vector resource_attrs; + if (common.hostname) { + resource_attrs = {"host.name", common.hostname->c_str(), "container.id", + common.container_id.c_str(), nullptr}; + } else { + resource_attrs = {"container.id", common.container_id.c_str(), nullptr}; + } + std::vector extra_attrs = {"datadog.process_tags", + common.process_tags.c_str(), nullptr}; + + otel_process_ctx_data data = {}; + data.deployment_environment_name = common.service_env.c_str(); + data.service_instance_id = + include_instance_id ? runtime_ids.begin()->c_str() : ""; + data.service_name = common.service_name.c_str(); + data.service_version = common.service_version.c_str(); + data.telemetry_sdk_language = common.tracer_language.c_str(); + data.telemetry_sdk_version = common.tracer_version.c_str(); + data.telemetry_sdk_name = tracer_library_name; + data.resource_attributes = resource_attrs.data(); + data.extra_attributes = extra_attrs.data(); + data.thread_ctx_config = nullptr; + + return otel_process_ctx_publish(&data); +} + +} // namespace + +OtelCtxRegistration::~OtelCtxRegistration() { + StaticOtelContextState& state = get_otel_context_state(); + std::lock_guard lock(state.mutex); + unregister(state, runtime_id_); + upsert(state); +} + +#ifndef __linux__ + +std::unique_ptr OtelCtxRegistration::publish( + const OtelCtxFields&, const std::string&, Logger&) { + // Feature is Linux-only, nothing to do + return nullptr; +} + +#else + +std::unique_ptr OtelCtxRegistration::publish( + const OtelCtxFields& fields, const std::string& runtime_id, + Logger& logger) { + StaticOtelContextState& state = get_otel_context_state(); + std::lock_guard lock(state.mutex); + + if (!state.common) { + // First registration establishes the process-wide fields + state.common = fields; + } else if (!(*state.common == fields)) { + logger.log_error([](std::ostream& log) { + log << "OpenTelemetry process context fields differ between coexisting " + "tracers; keeping the previously-published values"; + }); + } + + if (!state.runtime_ids.insert(runtime_id).second) { + // Runtime ids are expected to be unique per tracer + logger.log_error([](std::ostream& log) { + log << "Two tracers share a runtime id; skipping OpenTelemetry " + "context update"; + }); + return nullptr; + } + + const otel_process_ctx_result result = upsert(state); + if (!result.success) { + logger.log_error([&](std::ostream& log) { + log << "Failed to publish OpenTelemetry process context: " + << result.error_message; + }); + unregister(state, runtime_id); + return nullptr; + } + + return std::unique_ptr( + new OtelCtxRegistration(runtime_id)); +} + +#endif + +} // namespace datadog::tracing diff --git a/src/datadog/otel_process_ctx_registration.h b/src/datadog/otel_process_ctx_registration.h new file mode 100644 index 000000000..ac4364957 --- /dev/null +++ b/src/datadog/otel_process_ctx_registration.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include +#include +#include + +namespace datadog::tracing { + +class Logger; + +struct OtelCtxFields { + std::string service_env; + std::string service_name; + std::string service_version; + std::string tracer_language; + std::string tracer_version; + Optional hostname; + std::string container_id; + std::string process_tags; + + bool operator==(const OtelCtxFields& other) const { + return service_env == other.service_env && + service_name == other.service_name && + service_version == other.service_version && + tracer_language == other.tracer_language && + tracer_version == other.tracer_version && + hostname == other.hostname && container_id == other.container_id && + process_tags == other.process_tags; + } +}; + +// RAII handle representing one Tracer's contribution to the published +// OpenTelemetry process context. Destroying it withdraws that contribution. +// +// The OTel context is a per-process singleton, but several Tracers can be alive +// at once in a single process. For instance, the Envoy integration creates one +// Tracer per worker thread. +// We validate that config fields stay the same between all tracer instances, +// which is how the known integrations behave today -- the only field that's +// expected to differ is the `runtime_id`. +// +// The published context is reference-counted across all live tracer instances: +// +// * While exactly one registration is alive, the context is published in +// full, including its `runtime_id` +// * While two or more registrations are alive, the `runtime_id` is +// omitted, since this field is expected to differ between tracer instances. +// +// This class is thread-safe (takes care of protecting any global state). +class OtelCtxRegistration { + public: + // Publish the OTel process context built from `fields`, for a tracer with the + // given `runtime_id` (its `service_instance_id`). Returns a registration + // whose destruction updates or drops the process-wide context. This is + // nullptr outside of Linux or on failure. + static std::unique_ptr publish( + const OtelCtxFields& fields, const std::string& runtime_id, + Logger& logger); + + ~OtelCtxRegistration(); + + OtelCtxRegistration(const OtelCtxRegistration&) = delete; + OtelCtxRegistration& operator=(const OtelCtxRegistration&) = delete; + OtelCtxRegistration(OtelCtxRegistration&&) = delete; + OtelCtxRegistration& operator=(OtelCtxRegistration&&) = delete; + + private: + explicit OtelCtxRegistration(std::string runtime_id) + : runtime_id_(std::move(runtime_id)) {} + + std::string runtime_id_; +}; + +} // namespace datadog::tracing diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 7df7c465e..4c7823f09 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -23,7 +23,7 @@ #include "hex.h" #include "json.hpp" #include "msgpack.h" -#include "otel_process_ctx_guard.h" +#include "otel_process_ctx_registration.h" #include "platform_util.h" #include "random.h" #include "root_session_id.h" @@ -153,24 +153,6 @@ std::string Tracer::config() const { return config.dump(); } -namespace { - -std::vector otel_resource_attrs( - const Optional& hostname, const std::string& container_id) { - if (hostname) { - return {"host.name", hostname->c_str(), "container.id", - container_id.c_str(), nullptr}; - } - return {"container.id", container_id.c_str(), nullptr}; -} - -std::vector otel_extra_attrs( - const std::string& process_tags_joined) { - return {"datadog.process_tags", process_tags_joined.c_str(), nullptr}; -} - -} // namespace - void Tracer::store_config( const std::unordered_map& process_tags) { auto maybe_file = @@ -223,22 +205,20 @@ void Tracer::store_config( return; } - auto resource_attrs = otel_resource_attrs(hostname_, container_id); - auto extra_attrs = otel_extra_attrs(process_tags_joined); - - otel_process_ctx_data otel_data = {}; - otel_data.deployment_environment_name = service_env.c_str(); - otel_data.service_instance_id = runtime_id_string.c_str(); - otel_data.service_name = service_name.c_str(); - otel_data.service_version = service_version.c_str(); - otel_data.telemetry_sdk_language = tracer_language.c_str(); - otel_data.telemetry_sdk_version = tracer_version_value.c_str(); - otel_data.telemetry_sdk_name = tracer_library_name; - otel_data.resource_attributes = resource_attrs.data(); - otel_data.extra_attributes = extra_attrs.data(); - otel_data.thread_ctx_config = nullptr; - - otel_context_guard_ = publish_otel_process_ctx(otel_data, *logger_); + // Publish the same metadata as OTel Process Context. + // We explicitly opted to publish this only when the above tracer info file + // was successful. + OtelCtxFields otel_fields; + otel_fields.service_env = service_env; + otel_fields.service_name = service_name; + otel_fields.service_version = service_version; + otel_fields.tracer_language = tracer_language; + otel_fields.tracer_version = tracer_version_value; + otel_fields.hostname = hostname_; + otel_fields.container_id = container_id; + otel_fields.process_tags = process_tags_joined; + otel_context_registration_ = + OtelCtxRegistration::publish(otel_fields, runtime_id_string, *logger_); } Span Tracer::create_span() { return create_span(SpanConfig{}); } diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index c557ea830..23a4d7950 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -23,12 +23,38 @@ std::map to_map(const char** key_value_array) { return out; } +#ifdef __linux__ +std::unique_ptr make_tracer( + const RuntimeID& runtime_id, const std::string& service = "otel-ctx-svc", + std::shared_ptr logger = std::make_shared()) { + TracerConfig config; + config.service = service; + config.runtime_id = runtime_id; + config.collector = std::make_shared(); + config.logger = std::move(logger); + + auto finalized = finalize_config(config); + REQUIRE(finalized); + return std::make_unique(*finalized); +} + +Optional current_instance_id() { + auto read_result = otel_process_ctx_read(); + if (!read_result.success) return nullopt; + std::string instance_id(read_result.data.service_instance_id); + otel_process_ctx_read_drop(&read_result); + return instance_id; +} +#endif + } // namespace OTEL_CTX_TEST("Tracer construction publishes OTel process context") { #ifndef __linux__ SUCCEED("OpenTelemetry process context is Linux-only"); #else + REQUIRE(current_instance_id() == nullopt); // no context leaked from earlier + std::string expected_container_id; if (auto id = container::get_id()) { expected_container_id = id->value; @@ -91,6 +117,8 @@ OTEL_CTX_TEST("host.name is omitted when report_hostname is false") { #ifndef __linux__ SUCCEED("OpenTelemetry process context is Linux-only"); #else + REQUIRE(current_instance_id() == nullopt); // no context leaked from earlier + TracerConfig config; config.service = "otel-ctx-svc"; config.report_hostname = false; @@ -113,3 +141,76 @@ OTEL_CTX_TEST("host.name is omitted when report_hostname is false") { REQUIRE(otel_process_ctx_read_drop(&read_result)); #endif } + +OTEL_CTX_TEST( + "service_instance_id is omitted while multiple Tracers are alive") { +#ifndef __linux__ + SUCCEED("OpenTelemetry process context is Linux-only"); +#else + REQUIRE(current_instance_id() == nullopt); // no context leaked from earlier + + const RuntimeID runtime_id_1 = RuntimeID::generate(); + const RuntimeID runtime_id_2 = RuntimeID::generate(); + + auto tracer1 = make_tracer(runtime_id_1); + CHECK(current_instance_id() == runtime_id_1.string()); + + auto tracer2 = make_tracer(runtime_id_2); + CHECK(current_instance_id() == ""); + + tracer2.reset(); + CHECK(current_instance_id() == runtime_id_1.string()); + + tracer1.reset(); + CHECK(current_instance_id() == nullopt); +#endif +} + +OTEL_CTX_TEST("service_instance_id returns only when a single Tracer remains") { +#ifndef __linux__ + SUCCEED("OpenTelemetry process context is Linux-only"); +#else + REQUIRE(current_instance_id() == nullopt); // no context leaked from earlier + + const RuntimeID runtime_id_1 = RuntimeID::generate(); + const RuntimeID runtime_id_2 = RuntimeID::generate(); + const RuntimeID runtime_id_3 = RuntimeID::generate(); + + auto tracer1 = make_tracer(runtime_id_1); + auto tracer2 = make_tracer(runtime_id_2); + auto tracer3 = make_tracer(runtime_id_3); + + CHECK(current_instance_id() == ""); + + tracer1.reset(); + CHECK(current_instance_id() == ""); + + tracer2.reset(); + CHECK(current_instance_id() == runtime_id_3.string()); +#endif +} + +OTEL_CTX_TEST( + "a later Tracer with different config fields is logged and ignored") { +#ifndef __linux__ + SUCCEED("OpenTelemetry process context is Linux-only"); +#else + REQUIRE(current_instance_id() == nullopt); // no context leaked from earlier + + const RuntimeID runtime_id_1 = RuntimeID::generate(); + const RuntimeID runtime_id_2 = RuntimeID::generate(); + + auto tracer1 = make_tracer(runtime_id_1, "svc-one"); + + auto logger2 = std::make_shared(); + auto tracer2 = make_tracer(runtime_id_2, "svc-two", logger2); + + CHECK(logger2->error_count() == 1); + { + auto read_result = otel_process_ctx_read(); + REQUIRE(read_result.success); + CHECK(std::string(read_result.data.service_name) == "svc-one"); + REQUIRE(otel_process_ctx_read_drop(&read_result)); + } +#endif +} From d9b66ed9c22d20f43e93634f9311ac5cbd28861b Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 29 Jul 2026 05:18:21 +0000 Subject: [PATCH 52/59] Add entry for vendored otel_process_ctx library --- LICENSE-3rdparty.csv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index 143b14995..1dc243874 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -2,4 +2,5 @@ Component,Origin,License,Copyright vendored,nlohmann/json,MIT,Copyright (c) 2013-2022 Niels Lohmann vendored,Catch2,Boost,Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. vendored,picosha2,MIT,Copyright (C) 2017 okdshin -vendored,cpp-httplib,MIT,Copyright (c) 2023 Yuji Hirose. All rights reserved. \ No newline at end of file +vendored,cpp-httplib,MIT,Copyright (c) 2023 Yuji Hirose. All rights reserved. +vendored,open-telemetry/sig-profiling (process-context),Apache-2.0,"Copyright 2025 Datadog, Inc." \ No newline at end of file From abfd29dd1c9887b25d47462acc13579b9d14aa87 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 29 Jul 2026 05:29:40 +0000 Subject: [PATCH 53/59] Assert on expected error, not just on error count --- test/test_otel_process_ctx.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index 23a4d7950..d3e9a8879 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -205,7 +205,9 @@ OTEL_CTX_TEST( auto logger2 = std::make_shared(); auto tracer2 = make_tracer(runtime_id_2, "svc-two", logger2); - CHECK(logger2->error_count() == 1); + REQUIRE(logger2->error_count() == 1); + CHECK_THAT(std::get(logger2->entries.back().payload), + Catch::Matchers::Contains("fields differ between coexisting")); { auto read_result = otel_process_ctx_read(); REQUIRE(read_result.success); From 3f6591383078040924ebc6624c9d2feee98567fd Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 29 Jul 2026 05:52:48 +0000 Subject: [PATCH 54/59] Support multiple tracers with the same runtime id --- src/datadog/otel_process_ctx_registration.cpp | 38 ++++++++++--------- src/datadog/otel_process_ctx_registration.h | 12 +++--- test/test_otel_process_ctx.cpp | 26 +++++++++++++ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/datadog/otel_process_ctx_registration.cpp b/src/datadog/otel_process_ctx_registration.cpp index 9143ab2dc..064f682e4 100644 --- a/src/datadog/otel_process_ctx_registration.cpp +++ b/src/datadog/otel_process_ctx_registration.cpp @@ -21,9 +21,10 @@ struct StaticOtelContextState { // `runtime_ids` is non-empty: established by the first live registration and // dropped once the last one is released. Optional common; - // The `service_instance_id` (runtime id) of each live registration; expected - // to be unique per registration (see `publish`). - std::set runtime_ids; + // The `service_instance_id` (runtime id) of each live registration. This is a + // multiset because several tracers may share one runtime id and each of them + // counts separately. + std::multiset runtime_ids; }; StaticOtelContextState& get_otel_context_state() { @@ -31,9 +32,15 @@ StaticOtelContextState& get_otel_context_state() { return state; } -// Removes `runtime_id` from `state`. Must be called with `state.mutex` held. +// Removes one registration for `runtime_id` from `state`. Must be called with +// `state.mutex` held. void unregister(StaticOtelContextState& state, const std::string& runtime_id) { - state.runtime_ids.erase(runtime_id); + // Erase only one runtime id, leaving copies, if any + const std::multiset::iterator entry = + state.runtime_ids.find(runtime_id); + if (entry != state.runtime_ids.end()) { + state.runtime_ids.erase(entry); + } if (state.runtime_ids.empty()) { state.common.reset(); } @@ -42,17 +49,19 @@ void unregister(StaticOtelContextState& state, const std::string& runtime_id) { // (Re)publishes or drops the process context to reflect `state`. Must be called // with `state.mutex` held. otel_process_ctx_result upsert(const StaticOtelContextState& state) { - const std::set& runtime_ids = state.runtime_ids; + const std::multiset& runtime_ids = state.runtime_ids; if (runtime_ids.empty()) { otel_process_ctx_drop_current(); return {true, nullptr}; } const OtelCtxFields& common = *state.common; - // With a single live registration we publish its instance id; with several, - // no single id represents the process, so it is omitted (see class docs). - // When there is one entry it is necessarily the sole survivor. - const bool include_instance_id = runtime_ids.size() == 1; + // While all live registrations report one runtime id, that id represents the + // process and we publish it; once ids differ, none does, so it is omitted + // (see class docs). The multiset is sorted, so the first and last entries are + // equal exactly when every entry is. + const bool include_instance_id = + *runtime_ids.begin() == *runtime_ids.rbegin(); std::vector resource_attrs; if (common.hostname) { @@ -115,14 +124,7 @@ std::unique_ptr OtelCtxRegistration::publish( }); } - if (!state.runtime_ids.insert(runtime_id).second) { - // Runtime ids are expected to be unique per tracer - logger.log_error([](std::ostream& log) { - log << "Two tracers share a runtime id; skipping OpenTelemetry " - "context update"; - }); - return nullptr; - } + state.runtime_ids.insert(runtime_id); const otel_process_ctx_result result = upsert(state); if (!result.success) { diff --git a/src/datadog/otel_process_ctx_registration.h b/src/datadog/otel_process_ctx_registration.h index ac4364957..239962d6b 100644 --- a/src/datadog/otel_process_ctx_registration.h +++ b/src/datadog/otel_process_ctx_registration.h @@ -41,12 +41,14 @@ struct OtelCtxFields { // which is how the known integrations behave today -- the only field that's // expected to differ is the `runtime_id`. // -// The published context is reference-counted across all live tracer instances: +// The published context is reference-counted across all live tracer instances, +// and the `runtime_id` is published based on how many unique ids we observe: // -// * While exactly one registration is alive, the context is published in -// full, including its `runtime_id` -// * While two or more registrations are alive, the `runtime_id` is -// omitted, since this field is expected to differ between tracer instances. +// * While every live registration reports the same `runtime_id`, the context +// is published in full, including that `runtime_id`: a single id does +// represent the whole process. +// * While two or more distinct `runtime_id`s are alive, the `runtime_id` is +// omitted, since no single id represents the process. // // This class is thread-safe (takes care of protecting any global state). class OtelCtxRegistration { diff --git a/test/test_otel_process_ctx.cpp b/test/test_otel_process_ctx.cpp index d3e9a8879..65efcc8f3 100644 --- a/test/test_otel_process_ctx.cpp +++ b/test/test_otel_process_ctx.cpp @@ -190,6 +190,32 @@ OTEL_CTX_TEST("service_instance_id returns only when a single Tracer remains") { #endif } +OTEL_CTX_TEST("service_instance_id is published while all Tracers share it") { +#ifndef __linux__ + SUCCEED("OpenTelemetry process context is Linux-only"); +#else + REQUIRE(current_instance_id() == nullopt); // no context leaked from earlier + + const RuntimeID shared_runtime_id = RuntimeID::generate(); + const auto logger = std::make_shared(); + + auto worker1 = make_tracer(shared_runtime_id, "otel-ctx-svc", logger); + auto worker2 = make_tracer(shared_runtime_id, "otel-ctx-svc", logger); + auto worker3 = make_tracer(shared_runtime_id, "otel-ctx-svc", logger); + + CHECK(current_instance_id() == shared_runtime_id.string()); + + worker1.reset(); + CHECK(current_instance_id() == shared_runtime_id.string()); + + worker2.reset(); + CHECK(current_instance_id() == shared_runtime_id.string()); + + worker3.reset(); + CHECK(current_instance_id() == nullopt); +#endif +} + OTEL_CTX_TEST( "a later Tracer with different config fields is logged and ignored") { #ifndef __linux__ From b76b9c9a61fdb4afada3cedd8ccfd7ad3adbb070 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Wed, 29 Jul 2026 05:57:16 +0000 Subject: [PATCH 55/59] Make linter happy --- test/test_tracer_config.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index c83d47ed1..28754c862 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -6,7 +6,8 @@ #include #if defined(__linux__) -// Used to test writing to the `datadog-tracer-info` file; this is a Linux-only feature. +// Used to test writing to the `datadog-tracer-info` file; this is a Linux-only +// feature. #include #include @@ -36,7 +37,8 @@ #include "test.h" #if defined(__linux__) -// Used to test writing to the `datadog-tracer-info` file; this is a Linux-only feature. +// Used to test writing to the `datadog-tracer-info` file; this is a Linux-only +// feature. #include "common/ctx_sharing_helpers.h" #include "platform_util.h" #include "string_util.h" From e40b70b87e2d9b6263b6b6d735323dc65667a149 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Mon, 10 Aug 2026 05:20:52 +0000 Subject: [PATCH 56/59] Minor: Remove redundant include (already pulled indirectly) --- src/datadog/tracer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index e330f0984..8c0e6bd76 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include "config_manager.h" #include "datadog_agent.h" From add3c88bdf71762753094e88f094611ae23f9a13 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Mon, 10 Aug 2026 05:22:33 +0000 Subject: [PATCH 57/59] Minor: Rename `StaticOtelContextState` -> `StaticOtelCtxState` Also `get_otel_context_state()` to `get_otel_ctx_state()` to match. --- src/datadog/otel_process_ctx_registration.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/datadog/otel_process_ctx_registration.cpp b/src/datadog/otel_process_ctx_registration.cpp index 064f682e4..a3dcece27 100644 --- a/src/datadog/otel_process_ctx_registration.cpp +++ b/src/datadog/otel_process_ctx_registration.cpp @@ -14,8 +14,8 @@ namespace datadog::tracing { namespace { // Process-wide OTel context state, including the mutex that guards it. -// Accessed through the single `get_otel_context_state()` instance. -struct StaticOtelContextState { +// Accessed through the single `get_otel_ctx_state()` instance. +struct StaticOtelCtxState { std::mutex mutex; // Shared by all coexisting registrations. Present iff // `runtime_ids` is non-empty: established by the first live registration and @@ -27,14 +27,14 @@ struct StaticOtelContextState { std::multiset runtime_ids; }; -StaticOtelContextState& get_otel_context_state() { - static StaticOtelContextState state; +StaticOtelCtxState& get_otel_ctx_state() { + static StaticOtelCtxState state; return state; } // Removes one registration for `runtime_id` from `state`. Must be called with // `state.mutex` held. -void unregister(StaticOtelContextState& state, const std::string& runtime_id) { +void unregister(StaticOtelCtxState& state, const std::string& runtime_id) { // Erase only one runtime id, leaving copies, if any const std::multiset::iterator entry = state.runtime_ids.find(runtime_id); @@ -48,7 +48,7 @@ void unregister(StaticOtelContextState& state, const std::string& runtime_id) { // (Re)publishes or drops the process context to reflect `state`. Must be called // with `state.mutex` held. -otel_process_ctx_result upsert(const StaticOtelContextState& state) { +otel_process_ctx_result upsert(const StaticOtelCtxState& state) { const std::multiset& runtime_ids = state.runtime_ids; if (runtime_ids.empty()) { otel_process_ctx_drop_current(); @@ -92,7 +92,7 @@ otel_process_ctx_result upsert(const StaticOtelContextState& state) { } // namespace OtelCtxRegistration::~OtelCtxRegistration() { - StaticOtelContextState& state = get_otel_context_state(); + StaticOtelCtxState& state = get_otel_ctx_state(); std::lock_guard lock(state.mutex); unregister(state, runtime_id_); upsert(state); @@ -111,7 +111,7 @@ std::unique_ptr OtelCtxRegistration::publish( std::unique_ptr OtelCtxRegistration::publish( const OtelCtxFields& fields, const std::string& runtime_id, Logger& logger) { - StaticOtelContextState& state = get_otel_context_state(); + StaticOtelCtxState& state = get_otel_ctx_state(); std::lock_guard lock(state.mutex); if (!state.common) { From 73d3ec78cfa9213d11ddf1ca49b74326d64659c1 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Mon, 10 Aug 2026 05:34:18 +0000 Subject: [PATCH 58/59] Release `StaticOtelContextState` mutex before logging This avoids holding the lock while logging. --- src/datadog/otel_process_ctx_registration.cpp | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/datadog/otel_process_ctx_registration.cpp b/src/datadog/otel_process_ctx_registration.cpp index a3dcece27..4f3cb29b1 100644 --- a/src/datadog/otel_process_ctx_registration.cpp +++ b/src/datadog/otel_process_ctx_registration.cpp @@ -112,27 +112,40 @@ std::unique_ptr OtelCtxRegistration::publish( const OtelCtxFields& fields, const std::string& runtime_id, Logger& logger) { StaticOtelCtxState& state = get_otel_ctx_state(); - std::lock_guard lock(state.mutex); - if (!state.common) { - // First registration establishes the process-wide fields - state.common = fields; - } else if (!(*state.common == fields)) { + bool fields_differ = false; + Optional publish_error; + { + std::lock_guard lock(state.mutex); + + if (!state.common) { + // First registration establishes the process-wide fields + state.common = fields; + } else if (!(*state.common == fields)) { + fields_differ = true; + } + + state.runtime_ids.insert(runtime_id); + + const otel_process_ctx_result result = upsert(state); + if (!result.success) { + unregister(state, runtime_id); + publish_error = result; + } + } + + if (fields_differ) { logger.log_error([](std::ostream& log) { log << "OpenTelemetry process context fields differ between coexisting " "tracers; keeping the previously-published values"; }); } - state.runtime_ids.insert(runtime_id); - - const otel_process_ctx_result result = upsert(state); - if (!result.success) { + if (publish_error) { logger.log_error([&](std::ostream& log) { log << "Failed to publish OpenTelemetry process context: " - << result.error_message; + << publish_error->error_message; }); - unregister(state, runtime_id); return nullptr; } From fe98617f3a8f398a3d9573a7a234dd90f0905529 Mon Sep 17 00:00:00 2001 From: Ivo Anjo Date: Mon, 10 Aug 2026 07:51:15 +0100 Subject: [PATCH 59/59] Minor: Fix duplicate test from merge conflict handling --- test/test_tracer.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/test/test_tracer.cpp b/test/test_tracer.cpp index 3c2c7830e..55f8d15c7 100644 --- a/test/test_tracer.cpp +++ b/test/test_tracer.cpp @@ -2150,29 +2150,6 @@ TEST_TRACER("APM tracing enabled") { CHECK(span.numeric_tags.count(tags::internal::apm_enabled) == 0); } -TEST_TRACER("APM tracing enabled") { - TracerConfig config; - config.service = "testsvc"; - config.name = "test.op"; - const std::shared_ptr collector = - std::make_shared(); - config.collector = collector; - config.logger = std::make_shared(); - config.tracing_enabled = true; - - Expected finalized_config = finalize_config(config); - REQUIRE(finalized_config); - Tracer tracer{*finalized_config}; - - tracer.create_span(); - - REQUIRE(collector->chunks.size() == 1); - REQUIRE(collector->chunks.front().size() == 1); - const SpanData& span = *collector->chunks.front().front(); - // tracing needs to be disabled for this tag to be set - CHECK(span.numeric_tags.count(tags::internal::apm_enabled) == 0); -} - TEST_TRACER("APM tracing disabled") { TracerConfig config; config.service = "testsvc";