99
1010#include " json.hpp"
1111#include " json_serializer.h"
12+ #include " stable_config.h"
1213
1314namespace datadog {
1415namespace tracing {
1516namespace {
1617
17- std::string to_string (const std::vector<SpanSamplerConfig::Rule> & rules) {
18+ std::string to_string (const std::vector<SpanSamplerConfig::Rule>& rules) {
1819 nlohmann::json res;
19- for (const auto & r : rules) {
20+ for (const auto & r : rules) {
2021 nlohmann::json j = r;
2122 j[" sample_rate" ] = r.sample_rate ;
2223 if (r.max_per_second ) {
@@ -37,7 +38,7 @@ Expected<std::vector<SpanSamplerConfig::Rule>> parse_rules(StringView rules_raw,
3738
3839 try {
3940 json_rules = nlohmann::json::parse (rules_raw);
40- } catch (const nlohmann::json::parse_error & error) {
41+ } catch (const nlohmann::json::parse_error& error) {
4142 std::string message;
4243 message += " Unable to parse JSON from " ;
4344 append (message, env_var);
@@ -63,9 +64,9 @@ Expected<std::vector<SpanSamplerConfig::Rule>> parse_rules(StringView rules_raw,
6364 const std::unordered_set<std::string> allowed_properties{
6465 " service" , " name" , " resource" , " tags" , " sample_rate" , " max_per_second" };
6566
66- for (const auto & json_rule : json_rules) {
67+ for (const auto & json_rule : json_rules) {
6768 auto matcher = from_json (json_rule);
68- if (auto * error = matcher.if_error ()) {
69+ if (auto * error = matcher.if_error ()) {
6970 std::string prefix;
7071 prefix += " Unable to create a rule from " ;
7172 append (prefix, env_var);
@@ -118,7 +119,7 @@ Expected<std::vector<SpanSamplerConfig::Rule>> parse_rules(StringView rules_raw,
118119 }
119120
120121 // Look for unexpected properties.
121- for (const auto & [key, value] : json_rule.items ()) {
122+ for (const auto & [key, value] : json_rule.items ()) {
122123 if (allowed_properties.count (key)) {
123124 continue ;
124125 }
@@ -143,14 +144,14 @@ Expected<std::vector<SpanSamplerConfig::Rule>> parse_rules(StringView rules_raw,
143144 return rules;
144145}
145146
146- Expected<SpanSamplerConfig> load_span_sampler_env_config (Logger & logger) {
147+ Expected<SpanSamplerConfig> load_span_sampler_env_config (Logger& logger) {
147148 SpanSamplerConfig env_config;
148149
149150 auto rules_env = lookup (environment::DD_SPAN_SAMPLING_RULES);
150151 if (rules_env) {
151152 auto maybe_rules =
152153 parse_rules (*rules_env, name (environment::DD_SPAN_SAMPLING_RULES));
153- if (auto * error = maybe_rules.if_error ()) {
154+ if (auto * error = maybe_rules.if_error ()) {
154155 return std::move (*error);
155156 }
156157 env_config.rules = std::move (*maybe_rules);
@@ -174,7 +175,7 @@ Expected<SpanSamplerConfig> load_span_sampler_env_config(Logger &logger) {
174175 } else {
175176 const auto span_rules_file = std::string (*file_env);
176177
177- const auto file_error = [&](const char * operation) {
178+ const auto file_error = [&](const char * operation) {
178179 std::string message;
179180 message += " Unable to " ;
180181 message += operation;
@@ -199,7 +200,7 @@ Expected<SpanSamplerConfig> load_span_sampler_env_config(Logger &logger) {
199200
200201 auto maybe_rules = parse_rules (
201202 rules_stream.str (), name (environment::DD_SPAN_SAMPLING_RULES_FILE));
202- if (auto * error = maybe_rules.if_error ()) {
203+ if (auto * error = maybe_rules.if_error ()) {
203204 std::string prefix;
204205 prefix += " With " ;
205206 append (prefix, name (environment::DD_SPAN_SAMPLING_RULES_FILE));
@@ -218,10 +219,11 @@ Expected<SpanSamplerConfig> load_span_sampler_env_config(Logger &logger) {
218219
219220} // namespace
220221
221- SpanSamplerConfig::Rule::Rule (const SpanMatcher & base) : SpanMatcher(base) {}
222+ SpanSamplerConfig::Rule::Rule (const SpanMatcher& base) : SpanMatcher(base) {}
222223
223224Expected<FinalizedSpanSamplerConfig> finalize_config (
224- const SpanSamplerConfig &user_config, Logger &logger) {
225+ const SpanSamplerConfig& user_config, Logger& logger,
226+ const StableConfigs* stable_configs) {
225227 Expected<SpanSamplerConfig> env_config = load_span_sampler_env_config (logger);
226228 if (auto error = env_config.if_error ()) {
227229 return *error;
@@ -237,15 +239,52 @@ Expected<FinalizedSpanSamplerConfig> finalize_config(
237239 user_rules = user_config.rules ;
238240 }
239241
242+ Optional<std::vector<SpanSamplerConfig::Rule>> fleet_rules;
243+ Optional<std::vector<SpanSamplerConfig::Rule>> local_rules;
244+ if (stable_configs) {
245+ auto parse_span_rules = [](const StableConfig& cfg, const std::string& key)
246+ -> Optional<std::vector<SpanSamplerConfig::Rule>> {
247+ auto val = cfg.lookup (key);
248+ if (!val || val->empty ()) return nullopt ;
249+ try {
250+ auto json_rules = nlohmann::json::parse (*val);
251+ if (!json_rules.is_array ()) return nullopt ;
252+ std::vector<SpanSamplerConfig::Rule> rules;
253+ for (const auto & json_rule : json_rules) {
254+ auto matcher = from_json (json_rule);
255+ if (matcher.if_error ()) return nullopt ;
256+ SpanSamplerConfig::Rule rule{*matcher};
257+ if (auto sr = json_rule.find (" sample_rate" );
258+ sr != json_rule.end () && sr->is_number ()) {
259+ rule.sample_rate = *sr;
260+ }
261+ if (auto mps = json_rule.find (" max_per_second" );
262+ mps != json_rule.end () && mps->is_number ()) {
263+ rule.max_per_second = *mps;
264+ }
265+ rules.emplace_back (std::move (rule));
266+ }
267+ return rules;
268+ } catch (...) {
269+ return nullopt ;
270+ }
271+ };
272+ fleet_rules =
273+ parse_span_rules (stable_configs->fleet , " DD_SPAN_SAMPLING_RULES" );
274+ local_rules =
275+ parse_span_rules (stable_configs->local , " DD_SPAN_SAMPLING_RULES" );
276+ }
277+
240278 std::vector<SpanSamplerConfig::Rule> rules = resolve_and_record_config (
241- env_rules, user_rules, &result.metadata , ConfigName::SPAN_SAMPLING_RULES,
242- nullptr , [](const std::vector<SpanSamplerConfig::Rule> &r) {
279+ fleet_rules, env_rules, user_rules, local_rules, &result.metadata ,
280+ ConfigName::SPAN_SAMPLING_RULES, nullptr ,
281+ [](const std::vector<SpanSamplerConfig::Rule>& r) {
243282 return to_string (r);
244283 });
245284
246- for (const auto & rule : rules) {
285+ for (const auto & rule : rules) {
247286 auto maybe_rate = Rate::from (rule.sample_rate );
248- if (auto * error = maybe_rate.if_error ()) {
287+ if (auto * error = maybe_rate.if_error ()) {
249288 std::string prefix;
250289 prefix +=
251290 " Unable to parse sample_rate in span sampling rule with span "
@@ -272,17 +311,17 @@ Expected<FinalizedSpanSamplerConfig> finalize_config(
272311 }
273312
274313 FinalizedSpanSamplerConfig::Rule finalized;
275- static_cast <SpanMatcher &>(finalized) = rule;
314+ static_cast <SpanMatcher&>(finalized) = rule;
276315 finalized.sample_rate = *maybe_rate;
277316 finalized.max_per_second = rule.max_per_second ;
278317 result.rules .push_back (std::move (finalized));
279318 }
280319 return result;
281320}
282321
283- std::string to_string (const FinalizedSpanSamplerConfig::Rule & rule) {
322+ std::string to_string (const FinalizedSpanSamplerConfig::Rule& rule) {
284323 // Get the base class's fields, then add our own.
285- nlohmann::json result = static_cast <const SpanMatcher &>(rule);
324+ nlohmann::json result = static_cast <const SpanMatcher&>(rule);
286325 result[" sample_rate" ] = double (rule.sample_rate );
287326 if (rule.max_per_second ) {
288327 result[" max_per_second" ] = *rule.max_per_second ;
0 commit comments