From a144119bd42548c1f2d30065c9ba054c821e8681 Mon Sep 17 00:00:00 2001 From: Anna Date: Mon, 5 Jan 2026 23:54:04 +0100 Subject: [PATCH 1/6] Report trace sampler --- include/datadog/trace_sampler_config.h | 8 +++++-- src/datadog/trace_sampler_config.cpp | 30 ++++++++------------------ src/datadog/tracer_config.cpp | 3 ++- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/include/datadog/trace_sampler_config.h b/include/datadog/trace_sampler_config.h index 094cceba..479cb19c 100644 --- a/include/datadog/trace_sampler_config.h +++ b/include/datadog/trace_sampler_config.h @@ -42,7 +42,9 @@ struct TraceSamplerConfig { class FinalizedTraceSamplerConfig { friend Expected finalize_config( - const TraceSamplerConfig& config); + const TraceSamplerConfig& config, + std::unordered_map>* + telemetry_configs); friend class FinalizedTracerConfig; FinalizedTraceSamplerConfig() = default; @@ -58,7 +60,9 @@ class FinalizedTraceSamplerConfig { }; Expected finalize_config( - const TraceSamplerConfig& config); + const TraceSamplerConfig& config, + std::unordered_map>* + telemetry_configs); } // namespace tracing } // namespace datadog diff --git a/src/datadog/trace_sampler_config.cpp b/src/datadog/trace_sampler_config.cpp index 2182c0ab..9252b847 100644 --- a/src/datadog/trace_sampler_config.cpp +++ b/src/datadog/trace_sampler_config.cpp @@ -150,7 +150,9 @@ std::string to_string(const std::vector &rules) { TraceSamplerConfig::Rule::Rule(const SpanMatcher &base) : SpanMatcher(base) {} Expected finalize_config( - const TraceSamplerConfig &config) { + const TraceSamplerConfig &config, + std::unordered_map> + *telemetry_configs) { Expected env_config = load_trace_sampler_env_config(); if (auto error = env_config.if_error()) { return *error; @@ -191,27 +193,15 @@ Expected finalize_config( result.rules.emplace_back(std::move(finalized_rule)); } - Optional sample_rate; - if (env_config->sample_rate) { - sample_rate = env_config->sample_rate; - result.metadata[ConfigName::TRACE_SAMPLING_RATE] = ConfigMetadata( - ConfigName::TRACE_SAMPLING_RATE, to_string(*sample_rate, 1), - ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); - } else if (config.sample_rate) { - sample_rate = config.sample_rate; - result.metadata[ConfigName::TRACE_SAMPLING_RATE] = ConfigMetadata( - ConfigName::TRACE_SAMPLING_RATE, to_string(*sample_rate, 1), - ConfigMetadata::Origin::CODE); - } else { - result.metadata[ConfigName::TRACE_SAMPLING_RATE] = - ConfigMetadata(ConfigName::TRACE_SAMPLING_RATE, "1.0", - ConfigMetadata::Origin::DEFAULT); - } + Optional sample_rate = resolve_and_record_config( + env_config->sample_rate, config.sample_rate, telemetry_configs, + &result.metadata, ConfigName::TRACE_SAMPLING_RATE, 1.0, + [](const double &d) { return to_string(d, 1); }); // If `sample_rate` was specified, then it translates to a "catch-all" rule // appended to the end of `rules`. First, though, we have to make sure the // sample rate is valid. - if (sample_rate) { + if (sample_rate && (env_config->sample_rate || config.sample_rate)) { auto maybe_rate = Rate::from(*sample_rate); if (auto *error = maybe_rate.if_error()) { return error->with_prefix( @@ -225,10 +215,8 @@ Expected finalize_config( result.rules.emplace_back(std::move(finalized_rule)); } - std::unordered_map> - telemetry_configs_tmp; double max_per_second = resolve_and_record_config( - env_config->max_per_second, config.max_per_second, &telemetry_configs_tmp, + env_config->max_per_second, config.max_per_second, telemetry_configs, &result.metadata, ConfigName::TRACE_SAMPLING_LIMIT, 100.0, [](const double &d) { return std::to_string(d); }); diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 7c9af617..3a951f71 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -421,7 +421,8 @@ Expected finalize_config(const TracerConfig &user_config, return std::move(*error); } - if (auto trace_sampler_config = finalize_config(user_config.trace_sampler)) { + if (auto trace_sampler_config = + finalize_config(user_config.trace_sampler, &all_sources_configs)) { final_config.metadata.merge(trace_sampler_config->metadata); final_config.trace_sampler = std::move(*trace_sampler_config); } else { From 85a5977c39101a33a90f8caa89264db37f2bc386 Mon Sep 17 00:00:00 2001 From: Anna Date: Mon, 5 Jan 2026 23:54:18 +0100 Subject: [PATCH 2/6] Report span sampler values --- include/datadog/span_sampler_config.h | 10 +++++++--- src/datadog/span_sampler_config.cpp | 28 ++++++++++++++++----------- src/datadog/tracer_config.cpp | 4 ++-- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/include/datadog/span_sampler_config.h b/include/datadog/span_sampler_config.h index d23228bd..ce1c8d2f 100644 --- a/include/datadog/span_sampler_config.h +++ b/include/datadog/span_sampler_config.h @@ -37,7 +37,9 @@ struct SpanSamplerConfig { class FinalizedSpanSamplerConfig { friend Expected finalize_config( - const SpanSamplerConfig&, Logger&); + const SpanSamplerConfig&, Logger&, + std::unordered_map>* + telemetry_configs); friend class FinalizedTracerConfig; FinalizedSpanSamplerConfig() = default; @@ -52,8 +54,10 @@ class FinalizedSpanSamplerConfig { std::unordered_map metadata; }; -Expected finalize_config(const SpanSamplerConfig&, - Logger&); +Expected finalize_config( + const SpanSamplerConfig&, Logger&, + std::unordered_map>* + telemetry_configs); std::string to_string(const FinalizedSpanSamplerConfig::Rule&); diff --git a/src/datadog/span_sampler_config.cpp b/src/datadog/span_sampler_config.cpp index f16c61b0..fdbf7833 100644 --- a/src/datadog/span_sampler_config.cpp +++ b/src/datadog/span_sampler_config.cpp @@ -221,7 +221,9 @@ Expected load_span_sampler_env_config(Logger &logger) { SpanSamplerConfig::Rule::Rule(const SpanMatcher &base) : SpanMatcher(base) {} Expected finalize_config( - const SpanSamplerConfig &user_config, Logger &logger) { + const SpanSamplerConfig &user_config, Logger &logger, + std::unordered_map> + *telemetry_configs) { Expected env_config = load_span_sampler_env_config(logger); if (auto error = env_config.if_error()) { return *error; @@ -229,19 +231,23 @@ Expected finalize_config( FinalizedSpanSamplerConfig result; - std::vector rules; + // Convert to Optional for resolve_and_record_config + Optional> env_rules; if (!env_config->rules.empty()) { - rules = env_config->rules; - result.metadata[ConfigName::SPAN_SAMPLING_RULES] = - ConfigMetadata(ConfigName::SPAN_SAMPLING_RULES, to_string(rules), - ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); - } else if (!user_config.rules.empty()) { - rules = user_config.rules; - result.metadata[ConfigName::SPAN_SAMPLING_RULES] = - ConfigMetadata(ConfigName::SPAN_SAMPLING_RULES, to_string(rules), - ConfigMetadata::Origin::CODE); + env_rules = env_config->rules; + } + Optional> user_rules; + if (!user_config.rules.empty()) { + user_rules = user_config.rules; } + std::vector rules = resolve_and_record_config( + env_rules, user_rules, telemetry_configs, &result.metadata, + ConfigName::SPAN_SAMPLING_RULES, nullptr, + [](const std::vector &r) { + return to_string(r); + }); + for (const auto &rule : rules) { auto maybe_rate = Rate::from(rule.sample_rate); if (auto *error = maybe_rate.if_error()) { diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 3a951f71..4fb3ceed 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -429,8 +429,8 @@ Expected finalize_config(const TracerConfig &user_config, return std::move(trace_sampler_config.error()); } - if (auto span_sampler_config = - finalize_config(user_config.span_sampler, *logger)) { + if (auto span_sampler_config = finalize_config( + user_config.span_sampler, *logger, &all_sources_configs)) { final_config.metadata.merge(span_sampler_config->metadata); final_config.span_sampler = std::move(*span_sampler_config); } else { From d26be779287211ed5c8d66fe26a695659e467e23 Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 7 Jan 2026 11:15:51 +0100 Subject: [PATCH 3/6] answer to comment, merge instead of passing by ref --- include/datadog/span_sampler_config.h | 11 ++++------- include/datadog/trace_sampler_config.h | 9 +++------ src/datadog/span_sampler_config.cpp | 10 +++------- src/datadog/trace_sampler_config.cpp | 11 +++++------ src/datadog/tracer_config.cpp | 9 +++++---- 5 files changed, 20 insertions(+), 30 deletions(-) diff --git a/include/datadog/span_sampler_config.h b/include/datadog/span_sampler_config.h index ce1c8d2f..c22f81f1 100644 --- a/include/datadog/span_sampler_config.h +++ b/include/datadog/span_sampler_config.h @@ -37,9 +37,7 @@ struct SpanSamplerConfig { class FinalizedSpanSamplerConfig { friend Expected finalize_config( - const SpanSamplerConfig&, Logger&, - std::unordered_map>* - telemetry_configs); + const SpanSamplerConfig&, Logger&); friend class FinalizedTracerConfig; FinalizedSpanSamplerConfig() = default; @@ -52,12 +50,11 @@ class FinalizedSpanSamplerConfig { std::vector rules; std::unordered_map metadata; + std::unordered_map> telemetry_configs; }; -Expected finalize_config( - const SpanSamplerConfig&, Logger&, - std::unordered_map>* - telemetry_configs); +Expected finalize_config(const SpanSamplerConfig&, + Logger&); std::string to_string(const FinalizedSpanSamplerConfig::Rule&); diff --git a/include/datadog/trace_sampler_config.h b/include/datadog/trace_sampler_config.h index 479cb19c..18981054 100644 --- a/include/datadog/trace_sampler_config.h +++ b/include/datadog/trace_sampler_config.h @@ -42,9 +42,7 @@ struct TraceSamplerConfig { class FinalizedTraceSamplerConfig { friend Expected finalize_config( - const TraceSamplerConfig& config, - std::unordered_map>* - telemetry_configs); + const TraceSamplerConfig& config); friend class FinalizedTracerConfig; FinalizedTraceSamplerConfig() = default; @@ -53,6 +51,7 @@ class FinalizedTraceSamplerConfig { double max_per_second; std::vector rules; std::unordered_map metadata; + std::unordered_map> telemetry_configs; public: /// Returns the trace sampler configuration when APM Tracing is disabled. @@ -60,9 +59,7 @@ class FinalizedTraceSamplerConfig { }; Expected finalize_config( - const TraceSamplerConfig& config, - std::unordered_map>* - telemetry_configs); + const TraceSamplerConfig& config); } // namespace tracing } // namespace datadog diff --git a/src/datadog/span_sampler_config.cpp b/src/datadog/span_sampler_config.cpp index fdbf7833..2594808b 100644 --- a/src/datadog/span_sampler_config.cpp +++ b/src/datadog/span_sampler_config.cpp @@ -221,28 +221,25 @@ Expected load_span_sampler_env_config(Logger &logger) { SpanSamplerConfig::Rule::Rule(const SpanMatcher &base) : SpanMatcher(base) {} Expected finalize_config( - const SpanSamplerConfig &user_config, Logger &logger, - std::unordered_map> - *telemetry_configs) { + const SpanSamplerConfig &user_config, Logger &logger) { Expected env_config = load_span_sampler_env_config(logger); if (auto error = env_config.if_error()) { return *error; } FinalizedSpanSamplerConfig result; - // Convert to Optional for resolve_and_record_config Optional> env_rules; + Optional> user_rules; if (!env_config->rules.empty()) { env_rules = env_config->rules; } - Optional> user_rules; if (!user_config.rules.empty()) { user_rules = user_config.rules; } std::vector rules = resolve_and_record_config( - env_rules, user_rules, telemetry_configs, &result.metadata, + env_rules, user_rules, &result.telemetry_configs, &result.metadata, ConfigName::SPAN_SAMPLING_RULES, nullptr, [](const std::vector &r) { return to_string(r); @@ -282,7 +279,6 @@ Expected finalize_config( finalized.max_per_second = rule.max_per_second; result.rules.push_back(std::move(finalized)); } - return result; } diff --git a/src/datadog/trace_sampler_config.cpp b/src/datadog/trace_sampler_config.cpp index 9252b847..871681ab 100644 --- a/src/datadog/trace_sampler_config.cpp +++ b/src/datadog/trace_sampler_config.cpp @@ -150,9 +150,7 @@ std::string to_string(const std::vector &rules) { TraceSamplerConfig::Rule::Rule(const SpanMatcher &base) : SpanMatcher(base) {} Expected finalize_config( - const TraceSamplerConfig &config, - std::unordered_map> - *telemetry_configs) { + const TraceSamplerConfig &config) { Expected env_config = load_trace_sampler_env_config(); if (auto error = env_config.if_error()) { return *error; @@ -194,7 +192,7 @@ Expected finalize_config( } Optional sample_rate = resolve_and_record_config( - env_config->sample_rate, config.sample_rate, telemetry_configs, + env_config->sample_rate, config.sample_rate, &result.telemetry_configs, &result.metadata, ConfigName::TRACE_SAMPLING_RATE, 1.0, [](const double &d) { return to_string(d, 1); }); @@ -216,8 +214,9 @@ Expected finalize_config( } double max_per_second = resolve_and_record_config( - env_config->max_per_second, config.max_per_second, telemetry_configs, - &result.metadata, ConfigName::TRACE_SAMPLING_LIMIT, 100.0, + env_config->max_per_second, config.max_per_second, + &result.telemetry_configs, &result.metadata, + ConfigName::TRACE_SAMPLING_LIMIT, 100.0, [](const double &d) { return std::to_string(d); }); const auto allowed_types = {FP_NORMAL, FP_SUBNORMAL}; diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 4fb3ceed..377243e8 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -421,17 +421,18 @@ Expected finalize_config(const TracerConfig &user_config, return std::move(*error); } - if (auto trace_sampler_config = - finalize_config(user_config.trace_sampler, &all_sources_configs)) { + if (auto trace_sampler_config = finalize_config(user_config.trace_sampler)) { final_config.metadata.merge(trace_sampler_config->metadata); + all_sources_configs.merge(trace_sampler_config->telemetry_configs); final_config.trace_sampler = std::move(*trace_sampler_config); } else { return std::move(trace_sampler_config.error()); } - if (auto span_sampler_config = finalize_config( - user_config.span_sampler, *logger, &all_sources_configs)) { + if (auto span_sampler_config = + finalize_config(user_config.span_sampler, *logger)) { final_config.metadata.merge(span_sampler_config->metadata); + all_sources_configs.merge(span_sampler_config->telemetry_configs); final_config.span_sampler = std::move(*span_sampler_config); } else { return std::move(span_sampler_config.error()); From c0a0489e5e707794c592669eea01bc0be458206e Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 7 Jan 2026 14:10:29 +0100 Subject: [PATCH 4/6] Add more asserts in unit tests --- test/test_span_sampler.cpp | 18 ++++++++++++++++++ test/test_trace_sampler.cpp | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/test/test_span_sampler.cpp b/test/test_span_sampler.cpp index 35fc2aa9..39ff63d1 100644 --- a/test/test_span_sampler.cpp +++ b/test/test_span_sampler.cpp @@ -271,6 +271,24 @@ TEST_CASE("span rule sample rate") { config.trace_sampler.sample_rate = 0.0; // drop the trace auto finalized = finalize_config(config); REQUIRE(finalized); + + // metadata should be populated right - check the full JSON representation + auto expected_rules = "[{\"name\":\"*\",\"resource\":\"*\",\"sample_rate\":" + + to_string(test_case.span_rule_rate, 1) + + ",\"service\":\"testsvc\",\"tags\":{}}]"; + REQUIRE(finalized->metadata[ConfigName::SPAN_SAMPLING_RULES].value == + expected_rules); + + auto tracing_product = finalized->telemetry.products[0]; + + // Verify the tracing product has the span sampling rules in telemetry configs + const auto& span_rules_configs = + tracing_product.configurations.at(ConfigName::SPAN_SAMPLING_RULES); + REQUIRE(span_rules_configs.size() == + 1); // Only CODE origin since rules were set in code + REQUIRE(span_rules_configs[0].value == expected_rules); + REQUIRE(span_rules_configs[0].origin == ConfigMetadata::Origin::CODE); + Tracer tracer{*finalized}; { auto span = tracer.create_span(); diff --git a/test/test_trace_sampler.cpp b/test/test_trace_sampler.cpp index 4070ee59..150aabc1 100644 --- a/test/test_trace_sampler.cpp +++ b/test/test_trace_sampler.cpp @@ -73,6 +73,21 @@ TEST_CASE("trace sampling rule sample rate") { auto finalized = finalize_config(config); REQUIRE(finalized); + + // metadata should be populated right + REQUIRE(finalized->metadata[ConfigName::TRACE_SAMPLING_RATE].value == + to_string(test_case.sample_rate, 1)); + + auto tracing_product = finalized->telemetry.products[0]; + // Verify the tracing product has the telemetry configs + const auto& rate_configs = + tracing_product.configurations.at(ConfigName::TRACE_SAMPLING_RATE); + REQUIRE(rate_configs.size() == 2); + REQUIRE(rate_configs[0].value == to_string(1, 1)); + REQUIRE(rate_configs[0].origin == ConfigMetadata::Origin::DEFAULT); + REQUIRE(rate_configs[1].value == to_string(test_case.sample_rate, 1)); + REQUIRE(rate_configs[1].origin == ConfigMetadata::Origin::CODE); + Tracer tracer{*finalized}; for (std::size_t i = 0; i < num_iterations; ++i) { From 842d4e81a5b69ccad5bb0822379de21caceb43d5 Mon Sep 17 00:00:00 2001 From: Anna Date: Mon, 12 Jan 2026 12:17:09 +0100 Subject: [PATCH 5/6] answer to comments --- src/datadog/span_sampler_config.cpp | 1 - src/datadog/trace_sampler_config.cpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/datadog/span_sampler_config.cpp b/src/datadog/span_sampler_config.cpp index 2594808b..f9cffdc1 100644 --- a/src/datadog/span_sampler_config.cpp +++ b/src/datadog/span_sampler_config.cpp @@ -228,7 +228,6 @@ Expected finalize_config( } FinalizedSpanSamplerConfig result; - // Convert to Optional for resolve_and_record_config Optional> env_rules; Optional> user_rules; if (!env_config->rules.empty()) { diff --git a/src/datadog/trace_sampler_config.cpp b/src/datadog/trace_sampler_config.cpp index 871681ab..f0cf301a 100644 --- a/src/datadog/trace_sampler_config.cpp +++ b/src/datadog/trace_sampler_config.cpp @@ -196,10 +196,11 @@ Expected finalize_config( &result.metadata, ConfigName::TRACE_SAMPLING_RATE, 1.0, [](const double &d) { return to_string(d, 1); }); + bool is_sample_rate_provided = env_config->sample_rate || config.sample_rate; // If `sample_rate` was specified, then it translates to a "catch-all" rule // appended to the end of `rules`. First, though, we have to make sure the // sample rate is valid. - if (sample_rate && (env_config->sample_rate || config.sample_rate)) { + if (sample_rate && is_sample_rate_provided) { auto maybe_rate = Rate::from(*sample_rate); if (auto *error = maybe_rate.if_error()) { return error->with_prefix( From 9000fef631e3f565f42c7b14e1202567c851d517 Mon Sep 17 00:00:00 2001 From: Anna Date: Fri, 16 Jan 2026 14:22:31 +0100 Subject: [PATCH 6/6] rename telemetry_configs to metadata and remove old metadata --- include/datadog/config.h | 31 +++++----- include/datadog/datadog_agent_config.h | 2 +- include/datadog/span_sampler_config.h | 3 +- include/datadog/trace_sampler_config.h | 3 +- include/datadog/tracer_config.h | 2 +- src/datadog/config_manager.cpp | 10 +++- src/datadog/datadog_agent_config.cpp | 4 +- src/datadog/span_sampler_config.cpp | 5 +- src/datadog/trace_sampler_config.cpp | 15 +++-- src/datadog/tracer_config.cpp | 79 +++++++++++++------------- test/test_span_sampler.cpp | 5 +- test/test_trace_sampler.cpp | 5 +- test/test_tracer_config.cpp | 35 +++++++----- 13 files changed, 104 insertions(+), 95 deletions(-) diff --git a/include/datadog/config.h b/include/datadog/config.h index c1a70319..c02dfd9f 100644 --- a/include/datadog/config.h +++ b/include/datadog/config.h @@ -63,11 +63,12 @@ struct ConfigMetadata { }; // Returns the final configuration value using the following -// precedence order: environment > user code > default, and populates two maps: -// 1. `telemetry_configs`: Records ALL configuration sources that were provided, -// ordered from lowest to highest precedence. -// 2. `metadata`: Records ONLY the winning configuration value (highest -// precedence). Template Parameters: +// precedence order: environment > user code > default, and populates metadata: +// `metadata`: Records ALL configuration sources that were provided, +// ordered from lowest to highest precedence. The last entry has the highest +// precedence and is the winning value. +// +// Template Parameters: // Value: The type of the configuration value // Stringifier: Optional function type to convert Value to string // (defaults to std::nullptr_t, which uses string construction) @@ -76,10 +77,8 @@ struct ConfigMetadata { // Parameters: // from_env: Optional value from environment variables (highest precedence) // from_user: Optional value from user code (middle precedence) -// telemetry_configs: Output map that will be populated with all config -// sources found for this config_name, in precedence order -// metadata: Output map that will be populated with the winning config value -// for this config_name +// metadata: Output map that will be populated with all config sources found +// for this config_name, in precedence order (last = highest) // config_name: The configuration parameter name identifier // fallback: Optional default value (lowest precedence). Pass nullptr to // indicate no default. @@ -94,9 +93,7 @@ template Value resolve_and_record_config( const Optional& from_env, const Optional& from_user, - std::unordered_map>* - telemetry_configs, - std::unordered_map* metadata, + std::unordered_map>* metadata, ConfigName config_name, DefaultValue fallback = nullptr, Stringifier to_string_fn = nullptr) { auto stringify = [&](const Value& v) -> std::string { @@ -111,13 +108,12 @@ Value resolve_and_record_config( } }; - std::vector telemetry_entries; + std::vector metadata_entries; Optional chosen_value; auto add_entry = [&](ConfigMetadata::Origin origin, const Value& val) { std::string val_str = stringify(val); - telemetry_entries.emplace_back( - ConfigMetadata{config_name, val_str, origin}); + metadata_entries.emplace_back(ConfigMetadata{config_name, val_str, origin}); chosen_value = val; }; @@ -134,9 +130,8 @@ Value resolve_and_record_config( add_entry(ConfigMetadata::Origin::ENVIRONMENT_VARIABLE, *from_env); } - (*telemetry_configs)[config_name] = std::move(telemetry_entries); - if (!(*telemetry_configs)[config_name].empty()) { - (*metadata)[config_name] = (*telemetry_configs)[config_name].back(); + if (!metadata_entries.empty()) { + (*metadata)[config_name] = std::move(metadata_entries); } return chosen_value.value_or(Value{}); diff --git a/include/datadog/datadog_agent_config.h b/include/datadog/datadog_agent_config.h index 7db0d651..a324f44f 100644 --- a/include/datadog/datadog_agent_config.h +++ b/include/datadog/datadog_agent_config.h @@ -85,7 +85,7 @@ class FinalizedDatadogAgentConfig { std::chrono::steady_clock::duration request_timeout; std::chrono::steady_clock::duration shutdown_timeout; std::chrono::steady_clock::duration remote_configuration_poll_interval; - std::unordered_map metadata; + std::unordered_map> metadata; // Origin detection Optional admission_controller_uid; diff --git a/include/datadog/span_sampler_config.h b/include/datadog/span_sampler_config.h index c22f81f1..7faaa8eb 100644 --- a/include/datadog/span_sampler_config.h +++ b/include/datadog/span_sampler_config.h @@ -49,8 +49,7 @@ class FinalizedSpanSamplerConfig { }; std::vector rules; - std::unordered_map metadata; - std::unordered_map> telemetry_configs; + std::unordered_map> metadata; }; Expected finalize_config(const SpanSamplerConfig&, diff --git a/include/datadog/trace_sampler_config.h b/include/datadog/trace_sampler_config.h index 18981054..685eeb82 100644 --- a/include/datadog/trace_sampler_config.h +++ b/include/datadog/trace_sampler_config.h @@ -50,8 +50,7 @@ class FinalizedTraceSamplerConfig { public: double max_per_second; std::vector rules; - std::unordered_map metadata; - std::unordered_map> telemetry_configs; + std::unordered_map> metadata; public: /// Returns the trace sampler configuration when APM Tracing is disabled. diff --git a/include/datadog/tracer_config.h b/include/datadog/tracer_config.h index e1d62597..2ee4cd02 100644 --- a/include/datadog/tracer_config.h +++ b/include/datadog/tracer_config.h @@ -229,7 +229,7 @@ class FinalizedTracerConfig final { std::string integration_name; std::string integration_version; bool report_traces; - std::unordered_map metadata; + std::unordered_map> metadata; Baggage::Options baggage_opts; HTTPClient::URL agent_url; std::shared_ptr event_scheduler; diff --git a/src/datadog/config_manager.cpp b/src/datadog/config_manager.cpp index ce6c51b9..3699c4cb 100644 --- a/src/datadog/config_manager.cpp +++ b/src/datadog/config_manager.cpp @@ -287,12 +287,18 @@ namespace rc = datadog::remote_config; ConfigManager::ConfigManager(const FinalizedTracerConfig& config) : clock_(config.clock), - default_metadata_(config.metadata), trace_sampler_( std::make_shared(config.trace_sampler, clock_)), rules_(config.trace_sampler.rules), span_defaults_(std::make_shared(config.defaults)), - report_traces_(config.report_traces) {} + report_traces_(config.report_traces) { + // Extract winning value (last entry) from each config's metadata history + for (const auto& [name, metadata_vec] : config.metadata) { + if (!metadata_vec.empty()) { + default_metadata_[name] = metadata_vec.back(); + } + } +} rc::Products ConfigManager::get_products() { return rc::product::APM_TRACING; } diff --git a/src/datadog/datadog_agent_config.cpp b/src/datadog/datadog_agent_config.cpp index 6656ae0f..05b3b065 100644 --- a/src/datadog/datadog_agent_config.cpp +++ b/src/datadog/datadog_agent_config.cpp @@ -142,8 +142,8 @@ Expected finalize_config( return std::move(*error); } result.url = *parsed_url; - result.metadata[ConfigName::AGENT_URL] = - ConfigMetadata(ConfigName::AGENT_URL, url, origin); + result.metadata[ConfigName::AGENT_URL] = { + ConfigMetadata(ConfigName::AGENT_URL, url, origin)}; // Starting Datadog Agent 7.62.0, the admission controller inject a unique // identifier through `DD_EXTERNAL_ENV`. This uid is used for origin diff --git a/src/datadog/span_sampler_config.cpp b/src/datadog/span_sampler_config.cpp index f9cffdc1..cf1b60fb 100644 --- a/src/datadog/span_sampler_config.cpp +++ b/src/datadog/span_sampler_config.cpp @@ -238,9 +238,8 @@ Expected finalize_config( } std::vector rules = resolve_and_record_config( - env_rules, user_rules, &result.telemetry_configs, &result.metadata, - ConfigName::SPAN_SAMPLING_RULES, nullptr, - [](const std::vector &r) { + env_rules, user_rules, &result.metadata, ConfigName::SPAN_SAMPLING_RULES, + nullptr, [](const std::vector &r) { return to_string(r); }); diff --git a/src/datadog/trace_sampler_config.cpp b/src/datadog/trace_sampler_config.cpp index f0cf301a..698731db 100644 --- a/src/datadog/trace_sampler_config.cpp +++ b/src/datadog/trace_sampler_config.cpp @@ -162,14 +162,14 @@ Expected finalize_config( if (!env_config->rules.empty()) { rules = std::move(env_config->rules); - result.metadata[ConfigName::TRACE_SAMPLING_RULES] = + result.metadata[ConfigName::TRACE_SAMPLING_RULES] = { ConfigMetadata(ConfigName::TRACE_SAMPLING_RULES, to_string(rules), - ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); + ConfigMetadata::Origin::ENVIRONMENT_VARIABLE)}; } else if (!config.rules.empty()) { rules = std::move(config.rules); - result.metadata[ConfigName::TRACE_SAMPLING_RULES] = + result.metadata[ConfigName::TRACE_SAMPLING_RULES] = { ConfigMetadata(ConfigName::TRACE_SAMPLING_RULES, to_string(rules), - ConfigMetadata::Origin::CODE); + ConfigMetadata::Origin::CODE)}; } for (const auto &rule : rules) { @@ -192,8 +192,8 @@ Expected finalize_config( } Optional sample_rate = resolve_and_record_config( - env_config->sample_rate, config.sample_rate, &result.telemetry_configs, - &result.metadata, ConfigName::TRACE_SAMPLING_RATE, 1.0, + env_config->sample_rate, config.sample_rate, &result.metadata, + ConfigName::TRACE_SAMPLING_RATE, 1.0, [](const double &d) { return to_string(d, 1); }); bool is_sample_rate_provided = env_config->sample_rate || config.sample_rate; @@ -215,8 +215,7 @@ Expected finalize_config( } double max_per_second = resolve_and_record_config( - env_config->max_per_second, config.max_per_second, - &result.telemetry_configs, &result.metadata, + env_config->max_per_second, config.max_per_second, &result.metadata, ConfigName::TRACE_SAMPLING_LIMIT, 100.0, [](const double &d) { return std::to_string(d); }); diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 377243e8..a10b17a8 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -284,13 +284,10 @@ Expected finalize_config(const TracerConfig &user_config, final_config.clock = clock; final_config.logger = logger; - std::unordered_map> - all_sources_configs; - // DD_SERVICE final_config.defaults.service = resolve_and_record_config( - env_config->service, user_config.service, &all_sources_configs, - &final_config.metadata, ConfigName::SERVICE_NAME, get_process_name()); + env_config->service, user_config.service, &final_config.metadata, + ConfigName::SERVICE_NAME, get_process_name()); // Service type final_config.defaults.service_type = @@ -298,22 +295,21 @@ Expected finalize_config(const TracerConfig &user_config, // DD_ENV final_config.defaults.environment = resolve_and_record_config( - env_config->environment, user_config.environment, &all_sources_configs, - &final_config.metadata, ConfigName::SERVICE_ENV); + env_config->environment, user_config.environment, &final_config.metadata, + ConfigName::SERVICE_ENV); // DD_VERSION final_config.defaults.version = resolve_and_record_config( - env_config->version, user_config.version, &all_sources_configs, - &final_config.metadata, ConfigName::SERVICE_VERSION); + env_config->version, user_config.version, &final_config.metadata, + ConfigName::SERVICE_VERSION); // Span name final_config.defaults.name = value_or(env_config->name, user_config.name, ""); // DD_TAGS final_config.defaults.tags = resolve_and_record_config( - env_config->tags, user_config.tags, &all_sources_configs, - &final_config.metadata, ConfigName::TAGS, - std::unordered_map{}, + env_config->tags, user_config.tags, &final_config.metadata, + ConfigName::TAGS, std::unordered_map{}, [](const auto &tags) { return join_tags(tags); }); // Extraction Styles @@ -323,8 +319,8 @@ Expected finalize_config(const TracerConfig &user_config, final_config.extraction_styles = resolve_and_record_config( env_config->extraction_styles, user_config.extraction_styles, - &all_sources_configs, &final_config.metadata, - ConfigName::EXTRACTION_STYLES, default_propagation_styles, + &final_config.metadata, ConfigName::EXTRACTION_STYLES, + default_propagation_styles, [](const std::vector &styles) { return join_propagation_styles(styles); }); @@ -337,8 +333,8 @@ Expected finalize_config(const TracerConfig &user_config, // Injection Styles final_config.injection_styles = resolve_and_record_config( env_config->injection_styles, user_config.injection_styles, - &all_sources_configs, &final_config.metadata, - ConfigName::INJECTION_STYLES, default_propagation_styles, + &final_config.metadata, ConfigName::INJECTION_STYLES, + default_propagation_styles, [](const std::vector &styles) { return join_propagation_styles(styles); }); @@ -351,14 +347,14 @@ Expected finalize_config(const TracerConfig &user_config, // Startup Logs final_config.log_on_startup = resolve_and_record_config( env_config->log_on_startup, user_config.log_on_startup, - &all_sources_configs, &final_config.metadata, ConfigName::STARTUP_LOGS, - true, [](const bool &b) { return to_string(b); }); + &final_config.metadata, ConfigName::STARTUP_LOGS, true, + [](const bool &b) { return to_string(b); }); // Report traces final_config.report_traces = resolve_and_record_config( env_config->report_traces, user_config.report_traces, - &all_sources_configs, &final_config.metadata, ConfigName::REPORT_TRACES, - true, [](const bool &b) { return to_string(b); }); + &final_config.metadata, ConfigName::REPORT_TRACES, true, + [](const bool &b) { return to_string(b); }); // Report hostname final_config.report_hostname = @@ -371,8 +367,8 @@ Expected finalize_config(const TracerConfig &user_config, // 128b Trace IDs final_config.generate_128bit_trace_ids = resolve_and_record_config( env_config->generate_128bit_trace_ids, - user_config.generate_128bit_trace_ids, &all_sources_configs, - &final_config.metadata, ConfigName::GENEREATE_128BIT_TRACE_IDS, true, + user_config.generate_128bit_trace_ids, &final_config.metadata, + ConfigName::GENEREATE_128BIT_TRACE_IDS, true, [](const bool &b) { return to_string(b); }); // Integration name & version @@ -385,15 +381,13 @@ Expected finalize_config(const TracerConfig &user_config, // Baggage - max items final_config.baggage_opts.max_items = resolve_and_record_config( env_config->baggage_max_items, user_config.baggage_max_items, - &all_sources_configs, &final_config.metadata, - ConfigName::TRACE_BAGGAGE_MAX_ITEMS, 64UL, + &final_config.metadata, ConfigName::TRACE_BAGGAGE_MAX_ITEMS, 64UL, [](const size_t &i) { return std::to_string(i); }); // Baggage - max bytes final_config.baggage_opts.max_bytes = resolve_and_record_config( env_config->baggage_max_bytes, user_config.baggage_max_bytes, - &all_sources_configs, &final_config.metadata, - ConfigName::TRACE_BAGGAGE_MAX_BYTES, 8192UL, + &final_config.metadata, ConfigName::TRACE_BAGGAGE_MAX_BYTES, 8192UL, [](const size_t &i) { return std::to_string(i); }); if (final_config.baggage_opts.max_items <= 0 || @@ -422,8 +416,11 @@ Expected finalize_config(const TracerConfig &user_config, } if (auto trace_sampler_config = finalize_config(user_config.trace_sampler)) { - final_config.metadata.merge(trace_sampler_config->metadata); - all_sources_configs.merge(trace_sampler_config->telemetry_configs); + // Merge metadata vectors + for (auto &[key, values] : trace_sampler_config->metadata) { + auto &dest = final_config.metadata[key]; + dest.insert(dest.end(), values.begin(), values.end()); + } final_config.trace_sampler = std::move(*trace_sampler_config); } else { return std::move(trace_sampler_config.error()); @@ -431,8 +428,11 @@ Expected finalize_config(const TracerConfig &user_config, if (auto span_sampler_config = finalize_config(user_config.span_sampler, *logger)) { - final_config.metadata.merge(span_sampler_config->metadata); - all_sources_configs.merge(span_sampler_config->telemetry_configs); + // Merge metadata vectors + for (auto &[key, values] : span_sampler_config->metadata) { + auto &dest = final_config.metadata[key]; + dest.insert(dest.end(), values.begin(), values.end()); + } final_config.span_sampler = std::move(*span_sampler_config); } else { return std::move(span_sampler_config.error()); @@ -455,7 +455,7 @@ Expected finalize_config(const TracerConfig &user_config, final_config.telemetry = std::move(*telemetry_final_config); final_config.telemetry.products.emplace_back(telemetry::Product{ telemetry::Product::Name::tracing, true, tracer_version, nullopt, - nullopt, all_sources_configs}); + nullopt, final_config.metadata}); } else { return std::move(telemetry_final_config.error()); } @@ -463,24 +463,23 @@ Expected finalize_config(const TracerConfig &user_config, // APM Tracing Enabled final_config.tracing_enabled = resolve_and_record_config( env_config->tracing_enabled, user_config.tracing_enabled, - &all_sources_configs, &final_config.metadata, - ConfigName::APM_TRACING_ENABLED, true, + &final_config.metadata, ConfigName::APM_TRACING_ENABLED, true, [](const bool &b) { return to_string(b); }); { // Resource Renaming Enabled const bool resource_renaming_enabled = resolve_and_record_config( env_config->resource_renaming_enabled, - user_config.resource_renaming_enabled, &all_sources_configs, - &final_config.metadata, ConfigName::TRACE_RESOURCE_RENAMING_ENABLED, - false, [](const bool &b) { return to_string(b); }); + user_config.resource_renaming_enabled, &final_config.metadata, + ConfigName::TRACE_RESOURCE_RENAMING_ENABLED, false, + [](const bool &b) { return to_string(b); }); // Resource Renaming Always Simplified Endpoint const bool resource_renaming_always_simplified_endpoint = resolve_and_record_config( env_config->resource_renaming_always_simplified_endpoint, user_config.resource_renaming_always_simplified_endpoint, - &all_sources_configs, &final_config.metadata, + &final_config.metadata, ConfigName::TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT, false, [](const bool &b) { return to_string(b); }); @@ -511,7 +510,11 @@ Expected finalize_config(const TracerConfig &user_config, if (!user_config.collector) { final_config.collector = *agent_finalized; - final_config.metadata.merge(agent_finalized->metadata); + // Merge metadata vectors + for (auto &[key, values] : agent_finalized->metadata) { + auto &dest = final_config.metadata[key]; + dest.insert(dest.end(), values.begin(), values.end()); + } } else { final_config.collector = user_config.collector; } diff --git a/test/test_span_sampler.cpp b/test/test_span_sampler.cpp index 39ff63d1..6b1dbe4e 100644 --- a/test/test_span_sampler.cpp +++ b/test/test_span_sampler.cpp @@ -276,8 +276,9 @@ TEST_CASE("span rule sample rate") { auto expected_rules = "[{\"name\":\"*\",\"resource\":\"*\",\"sample_rate\":" + to_string(test_case.span_rule_rate, 1) + ",\"service\":\"testsvc\",\"tags\":{}}]"; - REQUIRE(finalized->metadata[ConfigName::SPAN_SAMPLING_RULES].value == - expected_rules); + REQUIRE( + finalized->metadata.at(ConfigName::SPAN_SAMPLING_RULES).back().value == + expected_rules); auto tracing_product = finalized->telemetry.products[0]; diff --git a/test/test_trace_sampler.cpp b/test/test_trace_sampler.cpp index 150aabc1..de10f352 100644 --- a/test/test_trace_sampler.cpp +++ b/test/test_trace_sampler.cpp @@ -75,8 +75,9 @@ TEST_CASE("trace sampling rule sample rate") { REQUIRE(finalized); // metadata should be populated right - REQUIRE(finalized->metadata[ConfigName::TRACE_SAMPLING_RATE].value == - to_string(test_case.sample_rate, 1)); + REQUIRE( + finalized->metadata.at(ConfigName::TRACE_SAMPLING_RATE).back().value == + to_string(test_case.sample_rate, 1)); auto tracing_product = finalized->telemetry.products[0]; // Verify the tracing product has the telemetry configs diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index b08af36c..b6407f72 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -1372,10 +1372,12 @@ TRACER_CONFIG_TEST("baggage") { 1); REQUIRE(finalized->metadata.count(ConfigName::TRACE_BAGGAGE_MAX_BYTES) == 1); - CHECK(finalized->metadata[ConfigName::TRACE_BAGGAGE_MAX_ITEMS].origin == - ConfigMetadata::Origin::DEFAULT); - CHECK(finalized->metadata[ConfigName::TRACE_BAGGAGE_MAX_BYTES].origin == - ConfigMetadata::Origin::DEFAULT); + CHECK(finalized->metadata.at(ConfigName::TRACE_BAGGAGE_MAX_ITEMS) + .back() + .origin == ConfigMetadata::Origin::DEFAULT); + CHECK(finalized->metadata.at(ConfigName::TRACE_BAGGAGE_MAX_BYTES) + .back() + .origin == ConfigMetadata::Origin::DEFAULT); } SECTION("value overriden by environment variables") { @@ -1410,10 +1412,12 @@ TRACER_CONFIG_TEST("baggage") { 1); REQUIRE(finalized->metadata.count(ConfigName::TRACE_BAGGAGE_MAX_BYTES) == 1); - CHECK(finalized->metadata[ConfigName::TRACE_BAGGAGE_MAX_ITEMS].origin == - ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); - CHECK(finalized->metadata[ConfigName::TRACE_BAGGAGE_MAX_BYTES].origin == - ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); + CHECK(finalized->metadata.at(ConfigName::TRACE_BAGGAGE_MAX_ITEMS) + .back() + .origin == ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); + CHECK(finalized->metadata.at(ConfigName::TRACE_BAGGAGE_MAX_BYTES) + .back() + .origin == ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); } SECTION("value overriden by code") { @@ -1434,10 +1438,12 @@ TRACER_CONFIG_TEST("baggage") { 1); REQUIRE(finalized->metadata.count(ConfigName::TRACE_BAGGAGE_MAX_BYTES) == 1); - CHECK(finalized->metadata[ConfigName::TRACE_BAGGAGE_MAX_ITEMS].origin == - ConfigMetadata::Origin::CODE); - CHECK(finalized->metadata[ConfigName::TRACE_BAGGAGE_MAX_BYTES].origin == - ConfigMetadata::Origin::CODE); + CHECK(finalized->metadata.at(ConfigName::TRACE_BAGGAGE_MAX_ITEMS) + .back() + .origin == ConfigMetadata::Origin::CODE); + CHECK(finalized->metadata.at(ConfigName::TRACE_BAGGAGE_MAX_BYTES) + .back() + .origin == ConfigMetadata::Origin::CODE); } SECTION("disabled when `max_bytes` <= 3") { @@ -1490,7 +1496,7 @@ TRACER_CONFIG_TEST("telemetry products contain configuration precedence") { CHECK(configs[2].value == "env-service"); // Metadata contains final value (highest precedence) - CHECK(finalized->metadata.at(ConfigName::SERVICE_NAME).value == + CHECK(finalized->metadata.at(ConfigName::SERVICE_NAME).back().value == "env-service"); } @@ -1513,7 +1519,8 @@ TRACER_CONFIG_TEST("telemetry products contain configuration precedence") { CHECK(configs[1].origin == ConfigMetadata::Origin::ENVIRONMENT_VARIABLE); CHECK(configs[1].value == "prod"); - CHECK(finalized->metadata.at(ConfigName::SERVICE_ENV).value == "prod"); + CHECK(finalized->metadata.at(ConfigName::SERVICE_ENV).back().value == + "prod"); } SECTION("single source: CODE only") {