Skip to content

Commit 8c3969c

Browse files
authored
feat: support DD_TAGS dynamic configuration (#94)
1 parent 6605685 commit 8c3969c

File tree

7 files changed

+78
-11
lines changed

7 files changed

+78
-11
lines changed

src/datadog/config_manager.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,20 @@ ConfigManager::ConfigManager(const FinalizedTracerConfig& config)
99
: clock_(config.clock),
1010
default_trace_sampler_(
1111
std::make_shared<TraceSampler>(config.trace_sampler, clock_)),
12-
current_trace_sampler_(default_trace_sampler_) {}
12+
current_trace_sampler_(default_trace_sampler_),
13+
default_span_defaults_(std::make_shared<SpanDefaults>(config.defaults)),
14+
current_span_defaults_(default_span_defaults_) {}
1315

1416
std::shared_ptr<TraceSampler> ConfigManager::get_trace_sampler() {
1517
std::lock_guard<std::mutex> lock(mutex_);
1618
return current_trace_sampler_;
1719
}
1820

21+
std::shared_ptr<const SpanDefaults> ConfigManager::get_span_defaults() {
22+
std::lock_guard<std::mutex> lock(mutex_);
23+
return current_span_defaults_;
24+
}
25+
1926
void ConfigManager::update(const ConfigUpdate& conf) {
2027
std::lock_guard<std::mutex> lock(mutex_);
2128

@@ -30,16 +37,28 @@ void ConfigManager::update(const ConfigUpdate& conf) {
3037
} else {
3138
current_trace_sampler_ = default_trace_sampler_;
3239
}
40+
41+
if (conf.tags) {
42+
auto new_span_defaults =
43+
std::make_shared<SpanDefaults>(*current_span_defaults_);
44+
new_span_defaults->tags = std::move(*conf.tags);
45+
46+
current_span_defaults_ = new_span_defaults;
47+
} else {
48+
current_span_defaults_ = default_span_defaults_;
49+
}
3350
}
3451

3552
void ConfigManager::reset() {
3653
std::lock_guard<std::mutex> lock(mutex_);
3754
current_trace_sampler_ = default_trace_sampler_;
55+
current_span_defaults_ = default_span_defaults_;
3856
}
3957

4058
nlohmann::json ConfigManager::config_json() const {
4159
std::lock_guard<std::mutex> lock(mutex_);
4260
return nlohmann::json{
61+
{"default", to_json(*current_span_defaults_)},
4362
{"trace_sampler", current_trace_sampler_->config_json()}};
4463
}
4564

src/datadog/config_manager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "clock.h"
1111
#include "config_update.h"
1212
#include "json.hpp"
13+
#include "span_defaults.h"
1314
#include "tracer_config.h"
1415

1516
namespace datadog {
@@ -21,12 +22,18 @@ class ConfigManager {
2122
std::shared_ptr<TraceSampler> default_trace_sampler_;
2223
std::shared_ptr<TraceSampler> current_trace_sampler_;
2324

25+
std::shared_ptr<const SpanDefaults> default_span_defaults_;
26+
std::shared_ptr<const SpanDefaults> current_span_defaults_;
27+
2428
public:
2529
ConfigManager(const FinalizedTracerConfig& config);
2630

2731
// Return the `TraceSampler` consistent with the most recent configuration.
2832
std::shared_ptr<TraceSampler> get_trace_sampler();
2933

34+
// Return the `SpanDefaults` consistent with the most recent configuration.
35+
std::shared_ptr<const SpanDefaults> get_span_defaults();
36+
3037
// Apply the specified `conf` update.
3138
void update(const ConfigUpdate& conf);
3239

src/datadog/config_update.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <unordered_map>
4+
35
#include "optional"
46
#include "trace_sampler_config.h"
57

@@ -13,6 +15,7 @@ namespace tracing {
1315
// remote configuration value.
1416
struct ConfigUpdate {
1517
Optional<TraceSamplerConfig> trace_sampler;
18+
Optional<std::unordered_map<std::string, std::string>> tags;
1619
};
1720

1821
} // namespace tracing

src/datadog/remote_config.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace {
2929
// within the array.
3030
enum CapabilitiesFlag : uint64_t {
3131
APM_TRACING_SAMPLE_RATE = 1 << 12,
32+
APM_TRACING_TAGS = 1 << 15
3233
};
3334

3435
constexpr std::array<uint8_t, sizeof(uint64_t)> capabilities_byte_array(
@@ -43,11 +44,36 @@ constexpr std::array<uint8_t, sizeof(uint64_t)> capabilities_byte_array(
4344
}
4445

4546
constexpr std::array<uint8_t, sizeof(uint64_t)> k_apm_capabilities =
46-
capabilities_byte_array(APM_TRACING_SAMPLE_RATE);
47+
capabilities_byte_array(APM_TRACING_SAMPLE_RATE | APM_TRACING_TAGS);
4748

4849
constexpr StringView k_apm_product = "APM_TRACING";
4950
constexpr StringView k_apm_product_path_substring = "/APM_TRACING/";
5051

52+
Expected<std::unordered_map<std::string, std::string>> parse_tags(
53+
const std::vector<StringView>& list_of_tags) {
54+
std::unordered_map<std::string, std::string> tags;
55+
56+
// Within a tag, the key and value are separated by a colon (":").
57+
for (const StringView& token : list_of_tags) {
58+
const auto separator = std::find(token.begin(), token.end(), ':');
59+
if (separator == token.end()) {
60+
std::string message;
61+
message += "Unable to parse a key/value from the tag text \"";
62+
append(message, token);
63+
message +=
64+
"\" because it does not contain the separator character \":\".";
65+
return Error{Error::TAG_MISSING_SEPARATOR, std::move(message)};
66+
}
67+
68+
std::string key{token.begin(), separator};
69+
std::string value{separator + 1, token.end()};
70+
// If there are duplicate values, then the last one wins.
71+
tags.insert_or_assign(std::move(key), std::move(value));
72+
}
73+
74+
return tags;
75+
}
76+
5177
ConfigUpdate parse_dynamic_config(const nlohmann::json& j) {
5278
ConfigUpdate config_update;
5379

@@ -59,6 +85,15 @@ ConfigUpdate parse_dynamic_config(const nlohmann::json& j) {
5985
config_update.trace_sampler = trace_sampler_cfg;
6086
}
6187

88+
if (auto tags_it = j.find("tracing_tags"); tags_it != j.cend()) {
89+
auto parsed_tags = parse_tags(*tags_it);
90+
if (parsed_tags.if_error()) {
91+
// TODO: report to telemetry
92+
} else {
93+
config_update.tags = std::move(*parsed_tags);
94+
}
95+
}
96+
6297
return config_update;
6398
}
6499

src/datadog/tracer.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
3838
: logger_(config.logger),
3939
config_manager_(std::make_shared<ConfigManager>(config)),
4040
collector_(/* see constructor body */),
41-
defaults_(std::make_shared<SpanDefaults>(config.defaults)),
4241
runtime_id_(config.runtime_id ? *config.runtime_id
4342
: RuntimeID::generate()),
4443
signature_{runtime_id_, config.defaults.service,
@@ -83,7 +82,6 @@ nlohmann::json Tracer::config_json() const {
8382
// clang-format off
8483
auto config = nlohmann::json::object({
8584
{"version", tracer_version_string},
86-
{"defaults", to_json(*defaults_)},
8785
{"runtime_id", runtime_id_.string()},
8886
{"collector", collector_->config_json()},
8987
{"span_sampler", span_sampler_->config_json()},
@@ -106,8 +104,9 @@ nlohmann::json Tracer::config_json() const {
106104
Span Tracer::create_span() { return create_span(SpanConfig{}); }
107105

108106
Span Tracer::create_span(const SpanConfig& config) {
107+
auto defaults = config_manager_->get_span_defaults();
109108
auto span_data = std::make_unique<SpanData>();
110-
span_data->apply_config(*defaults_, config, clock_);
109+
span_data->apply_config(*defaults, config, clock_);
111110
span_data->trace_id = generator_->trace_id(span_data->start);
112111
span_data->span_id = span_data->trace_id.low;
113112
span_data->parent_id = 0;
@@ -122,7 +121,7 @@ Span Tracer::create_span(const SpanConfig& config) {
122121
tracer_telemetry_->metrics().tracer.trace_segments_created_new.inc();
123122
const auto segment = std::make_shared<TraceSegment>(
124123
logger_, collector_, tracer_telemetry_,
125-
config_manager_->get_trace_sampler(), span_sampler_, defaults_,
124+
config_manager_->get_trace_sampler(), span_sampler_, defaults,
126125
runtime_id_, sampling_delegation_enabled_,
127126
false /* sampling_decision_was_delegated_to_me */, injection_styles_,
128127
hostname_, nullopt /* origin */, tags_header_max_size_,
@@ -241,7 +240,8 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
241240

242241
// We're done extracting fields. Now create the span.
243242
// This is similar to what we do in `create_span`.
244-
span_data->apply_config(*defaults_, config, clock_);
243+
span_data->apply_config(*config_manager_->get_span_defaults(), config,
244+
clock_);
245245
span_data->span_id = generator_->span_id();
246246
span_data->trace_id = *trace_id;
247247
span_data->parent_id = *parent_id;
@@ -293,8 +293,9 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
293293
tracer_telemetry_->metrics().tracer.trace_segments_created_continued.inc();
294294
const auto segment = std::make_shared<TraceSegment>(
295295
logger_, collector_, tracer_telemetry_,
296-
config_manager_->get_trace_sampler(), span_sampler_, defaults_,
297-
runtime_id_, sampling_delegation_enabled_, delegate_sampling_decision,
296+
config_manager_->get_trace_sampler(), span_sampler_,
297+
config_manager_->get_span_defaults(), runtime_id_,
298+
sampling_delegation_enabled_, delegate_sampling_decision,
298299
injection_styles_, hostname_, std::move(origin), tags_header_max_size_,
299300
std::move(trace_tags), std::move(sampling_decision),
300301
std::move(additional_w3c_tracestate),

src/datadog/tracer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class Tracer {
3737
std::shared_ptr<Logger> logger_;
3838
std::shared_ptr<ConfigManager> config_manager_;
3939
std::shared_ptr<Collector> collector_;
40-
std::shared_ptr<const SpanDefaults> defaults_;
4140
RuntimeID runtime_id_;
4241
TracerSignature signature_;
4342
std::shared_ptr<TracerTelemetry> tracer_telemetry_;

test/test_remote_config.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ REMOTE_CONFIG_TEST("response processing") {
166166
"target_files": [
167167
{
168168
"path": "foo/APM_TRACING/30",
169-
"raw": "eyAiaWQiOiAiODI3ZWFjZjhkYmMzYWIxNDM0ZDMyMWNiODFkZmJmN2FmZTY1NGE0YjYxMTFjZjE2NjBiNzFjY2Y4OTc4MTkzOCIsICJyZXZpc2lvbiI6IDE2OTgxNjcxMjYwNjQsICJzY2hlbWFfdmVyc2lvbiI6ICJ2MS4wLjAiLCAiYWN0aW9uIjogImVuYWJsZSIsICJsaWJfY29uZmlnIjogeyAibGlicmFyeV9sYW5ndWFnZSI6ICJhbGwiLCAibGlicmFyeV92ZXJzaW9uIjogImxhdGVzdCIsICJzZXJ2aWNlX25hbWUiOiAidGVzdHN2YyIsICJlbnYiOiAidGVzdCIsICJ0cmFjaW5nX2VuYWJsZWQiOiB0cnVlLCAidHJhY2luZ19zYW1wbGluZ19yYXRlIjogMC42IH0sICJzZXJ2aWNlX3RhcmdldCI6IHsgInNlcnZpY2UiOiAidGVzdHN2YyIsICJlbnYiOiAidGVzdCIgfSB9"
169+
"raw": "eyAiaWQiOiAiODI3ZWFjZjhkYmMzYWIxNDM0ZDMyMWNiODFkZmJmN2FmZTY1NGE0YjYxMTFjZjE2NjBiNzFjY2Y4OTc4MTkzOCIsICJyZXZpc2lvbiI6IDE2OTgxNjcxMjYwNjQsICJzY2hlbWFfdmVyc2lvbiI6ICJ2MS4wLjAiLCAiYWN0aW9uIjogImVuYWJsZSIsICJsaWJfY29uZmlnIjogeyAibGlicmFyeV9sYW5ndWFnZSI6ICJhbGwiLCAibGlicmFyeV92ZXJzaW9uIjogImxhdGVzdCIsICJzZXJ2aWNlX25hbWUiOiAidGVzdHN2YyIsICJlbnYiOiAidGVzdCIsICJ0cmFjaW5nX2VuYWJsZWQiOiB0cnVlLCAidHJhY2luZ19zYW1wbGluZ19yYXRlIjogMC42LCAidHJhY2luZ190YWdzIjogWyJoZWxsbzp3b3JsZCIsICJmb286YmFyIl0gfSwgInNlcnZpY2VfdGFyZ2V0IjogeyAic2VydmljZSI6ICJ0ZXN0c3ZjIiwgImVudiI6ICJ0ZXN0IiB9IH0="
170170
}
171171
]
172172
})";
@@ -180,10 +180,13 @@ REMOTE_CONFIG_TEST("response processing") {
180180
REQUIRE(!response_json.is_discarded());
181181

182182
const auto old_trace_sampler = config_manager->get_trace_sampler();
183+
const auto old_span_defaults = config_manager->get_span_defaults();
183184
rc.process_response(response_json);
184185
const auto new_trace_sampler = config_manager->get_trace_sampler();
186+
const auto new_span_defaults = config_manager->get_span_defaults();
185187

186188
CHECK(new_trace_sampler != old_trace_sampler);
189+
CHECK(new_span_defaults != old_span_defaults);
187190

188191
SECTION("reset confguration") {
189192
SECTION(

0 commit comments

Comments
 (0)