Skip to content

Commit f3958f3

Browse files
authored
refactor: Remote Configuration (#130)
Refactor the Remote Configuration (RC) as a standalone module, enabling its use independently of the tracer. Additionally, ensure that external listeners can register and receive configuration updates when RC is embedded in the tracer. Changes: - Move APM_TRACING updates handling to the configuration manager. - Expose the `remote_configuration_listeners` field in datadog agent config to allow registration of external listeners. - Improve the robustness of config path parsing and ensure an error is reported if parsing fails. - Add `to_upper` utility function. - Increase test coverage for RC and the new configuration manager behaviour.
1 parent f1c90ec commit f3958f3

28 files changed

+1351
-739
lines changed

BUILD.bazel

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ cc_library(
2727
"src/datadog/propagation_style.cpp",
2828
"src/datadog/random.cpp",
2929
"src/datadog/rate.cpp",
30-
"src/datadog/remote_config.cpp",
30+
"src/datadog/remote_config/remote_config.cpp",
3131
"src/datadog/runtime_id.cpp",
3232
"src/datadog/span.cpp",
3333
"src/datadog/span_data.cpp",
@@ -55,7 +55,6 @@ cc_library(
5555
"src/datadog/config.h",
5656
"src/datadog/clock.h",
5757
"src/datadog/config_manager.h",
58-
"src/datadog/config_update.h",
5958
"src/datadog/collector.h",
6059
"src/datadog/collector_response.h",
6160
# "src/datadog/curl.h", no libcurl
@@ -88,7 +87,10 @@ cc_library(
8887
"src/datadog/propagation_style.h",
8988
"src/datadog/random.h",
9089
"src/datadog/rate.h",
91-
"src/datadog/remote_config.h",
90+
"src/datadog/remote_config/capability.h",
91+
"src/datadog/remote_config/listener.h",
92+
"src/datadog/remote_config/product.h",
93+
"src/datadog/remote_config/remote_config.h",
9294
"src/datadog/runtime_id.h",
9395
"src/datadog/sampling_decision.h",
9496
"src/datadog/sampling_mechanism.h",
@@ -118,6 +120,7 @@ cc_library(
118120
"src/datadog/w3c_propagation.h",
119121
],
120122
strip_include_prefix = "src/",
123+
copts = ["-Isrc/datadog"],
121124
visibility = ["//visibility:public"],
122125
deps = [
123126
"@com_google_absl//absl/strings",

CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ target_sources(dd_trace_cpp-objects
103103
src/datadog/propagation_style.cpp
104104
src/datadog/random.cpp
105105
src/datadog/rate.cpp
106-
src/datadog/remote_config.cpp
106+
src/datadog/remote_config/remote_config.cpp
107107
src/datadog/runtime_id.cpp
108108
src/datadog/span.cpp
109109
src/datadog/span_data.cpp
@@ -137,7 +137,6 @@ target_sources(dd_trace_cpp-objects PUBLIC
137137
src/datadog/cerr_logger.h
138138
src/datadog/clock.h
139139
src/datadog/config_manager.h
140-
src/datadog/config_update.h
141140
src/datadog/collector.h
142141
src/datadog/collector_response.h
143142
# src/datadog/curl.h except for curl.h
@@ -170,7 +169,9 @@ target_sources(dd_trace_cpp-objects PUBLIC
170169
src/datadog/propagation_style.h
171170
src/datadog/random.h
172171
src/datadog/rate.h
173-
src/datadog/remote_config.h
172+
src/datadog/remote_config/remote_config.h
173+
src/datadog/remote_config/capability.h
174+
src/datadog/remote_config/listener.h
174175
src/datadog/runtime_id.h
175176
src/datadog/sampling_decision.h
176177
src/datadog/sampling_mechanism.h
@@ -204,12 +205,11 @@ target_sources(dd_trace_cpp-objects PUBLIC
204205
# or installing the library.
205206
target_include_directories(dd_trace_cpp-objects
206207
PUBLIC
207-
$<INSTALL_INTERFACE:src>
208+
$<INSTALL_INTERFACE:src/datadog>
208209
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
210+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/datadog>
209211
)
210212

211-
add_dependencies(dd_trace_cpp-objects Threads::Threads)
212-
213213
target_link_libraries(dd_trace_cpp-objects
214214
PUBLIC
215215
Threads::Threads

src/datadog/config_manager.cpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,71 @@ Expected<Rules> parse_trace_sampling_rules(const nlohmann::json& json_rules) {
7777
return parsed_rules;
7878
}
7979

80+
ConfigManager::Update parse_dynamic_config(const nlohmann::json& j) {
81+
ConfigManager::Update config_update;
82+
83+
if (auto sampling_rate_it = j.find("tracing_sampling_rate");
84+
sampling_rate_it != j.cend() && sampling_rate_it->is_number()) {
85+
config_update.trace_sampling_rate = sampling_rate_it->get<double>();
86+
}
87+
88+
if (auto tags_it = j.find("tracing_tags");
89+
tags_it != j.cend() && tags_it->is_array()) {
90+
config_update.tags = tags_it->get<std::vector<StringView>>();
91+
}
92+
93+
if (auto tracing_enabled_it = j.find("tracing_enabled");
94+
tracing_enabled_it != j.cend() && tracing_enabled_it->is_boolean()) {
95+
config_update.report_traces = tracing_enabled_it->get<bool>();
96+
}
97+
98+
if (auto tracing_sampling_rules_it = j.find("tracing_sampling_rules");
99+
tracing_sampling_rules_it != j.cend() &&
100+
tracing_sampling_rules_it->is_array()) {
101+
config_update.trace_sampling_rules = &(*tracing_sampling_rules_it);
102+
}
103+
104+
return config_update;
105+
}
106+
80107
} // namespace
81108

82-
ConfigManager::ConfigManager(const FinalizedTracerConfig& config)
109+
namespace rc = datadog::remote_config;
110+
111+
ConfigManager::ConfigManager(const FinalizedTracerConfig& config,
112+
const std::shared_ptr<TracerTelemetry>& telemetry)
83113
: clock_(config.clock),
84114
default_metadata_(config.metadata),
85115
trace_sampler_(
86116
std::make_shared<TraceSampler>(config.trace_sampler, clock_)),
87117
rules_(config.trace_sampler.rules),
88118
span_defaults_(std::make_shared<SpanDefaults>(config.defaults)),
89-
report_traces_(config.report_traces) {}
119+
report_traces_(config.report_traces),
120+
telemetry_(telemetry) {}
121+
122+
rc::Products ConfigManager::get_products() { return rc::product::APM_TRACING; }
123+
124+
rc::Capabilities ConfigManager::get_capabilities() {
125+
using namespace rc::capability;
126+
return APM_TRACING_SAMPLE_RATE | APM_TRACING_TAGS | APM_TRACING_ENABLED |
127+
APM_TRACING_SAMPLE_RULES;
128+
}
129+
130+
Optional<std::string> ConfigManager::on_update(const Configuration& config) {
131+
const auto config_json = nlohmann::json::parse(config.content);
132+
auto config_update = parse_dynamic_config(config_json.at("lib_config"));
133+
134+
auto config_metadata = apply_update(config_update);
135+
telemetry_->capture_configuration_change(config_metadata);
136+
137+
// TODO:
138+
return nullopt;
139+
}
140+
141+
void ConfigManager::on_revert(const Configuration&) {
142+
auto config_metadata = apply_update({});
143+
telemetry_->capture_configuration_change(config_metadata);
144+
}
90145

91146
std::shared_ptr<TraceSampler> ConfigManager::trace_sampler() {
92147
std::lock_guard<std::mutex> lock(mutex_);
@@ -103,7 +158,8 @@ bool ConfigManager::report_traces() {
103158
return report_traces_.value();
104159
}
105160

106-
std::vector<ConfigMetadata> ConfigManager::update(const ConfigUpdate& conf) {
161+
std::vector<ConfigMetadata> ConfigManager::apply_update(
162+
const ConfigManager::Update& conf) {
107163
std::vector<ConfigMetadata> metadata;
108164

109165
std::lock_guard<std::mutex> lock(mutex_);
@@ -210,8 +266,6 @@ void ConfigManager::reset_config(ConfigName name, T& conf,
210266
metadata.emplace_back(default_metadata_[name]);
211267
}
212268

213-
std::vector<ConfigMetadata> ConfigManager::reset() { return update({}); }
214-
215269
nlohmann::json ConfigManager::config_json() const {
216270
std::lock_guard<std::mutex> lock(mutex_);
217271
return nlohmann::json{{"defaults", to_json(*span_defaults_.value())},

src/datadog/config_manager.h

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,31 @@
88
#include <mutex>
99

1010
#include "clock.h"
11-
#include "config_update.h"
1211
#include "json.hpp"
1312
#include "optional.h"
13+
#include "remote_config/listener.h"
1414
#include "span_defaults.h"
1515
#include "tracer_config.h"
16+
#include "tracer_telemetry.h"
1617

1718
namespace datadog {
1819
namespace tracing {
1920

20-
class ConfigManager {
21+
class ConfigManager : public remote_config::Listener {
22+
public:
23+
// The `Update` struct serves as a container for configuration that can
24+
// exclusively be changed remotely.
25+
//
26+
// Configurations can be `nullopt` to signal the absence of a value from the
27+
// remote configuration value.
28+
struct Update {
29+
Optional<bool> report_traces;
30+
Optional<double> trace_sampling_rate;
31+
Optional<std::vector<StringView>> tags;
32+
const nlohmann::json* trace_sampling_rules = nullptr;
33+
};
34+
35+
private:
2136
// A class template for managing dynamic configuration values.
2237
//
2338
// This class allows storing and managing dynamic configuration values. It
@@ -60,13 +75,25 @@ class ConfigManager {
6075
DynamicConfig<std::shared_ptr<const SpanDefaults>> span_defaults_;
6176
DynamicConfig<bool> report_traces_;
6277

78+
std::shared_ptr<TracerTelemetry> telemetry_;
79+
6380
private:
6481
template <typename T>
6582
void reset_config(ConfigName name, T& conf,
6683
std::vector<ConfigMetadata>& metadata);
6784

6885
public:
69-
ConfigManager(const FinalizedTracerConfig& config);
86+
ConfigManager(const FinalizedTracerConfig& config,
87+
const std::shared_ptr<TracerTelemetry>& telemetry);
88+
~ConfigManager() override{};
89+
90+
remote_config::Products get_products() override;
91+
remote_config::Capabilities get_capabilities() override;
92+
93+
Optional<std::string> on_update(
94+
const Listener::Configuration& config) override;
95+
void on_revert(const Listener::Configuration& config) override;
96+
void on_post_process() override{};
7097

7198
// Return the `TraceSampler` consistent with the most recent configuration.
7299
std::shared_ptr<TraceSampler> trace_sampler();
@@ -77,16 +104,11 @@ class ConfigManager {
77104
// Return whether traces should be sent to the collector.
78105
bool report_traces();
79106

80-
// Apply the specified `conf` update.
81-
std::vector<ConfigMetadata> update(const ConfigUpdate& conf);
82-
83-
// Restore the configuration that was passed to this object's constructor,
84-
// overriding any previous calls to `update`.
85-
std::vector<ConfigMetadata> reset();
86-
87107
// Return a JSON representation of the current configuration managed by this
88108
// object.
89109
nlohmann::json config_json() const;
110+
111+
std::vector<ConfigMetadata> apply_update(const ConfigManager::Update& conf);
90112
};
91113

92114
} // namespace tracing

src/datadog/config_update.h

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/datadog/datadog_agent.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,14 @@ std::variant<CollectorResponse, std::string> parse_agent_traces_response(
145145

146146
} // namespace
147147

148+
namespace rc = datadog::remote_config;
149+
148150
DatadogAgent::DatadogAgent(
149151
const FinalizedDatadogAgentConfig& config,
150152
const std::shared_ptr<TracerTelemetry>& tracer_telemetry,
151153
const std::shared_ptr<Logger>& logger,
152154
const TracerSignature& tracer_signature,
153-
const std::shared_ptr<ConfigManager>& config_manager)
155+
const std::vector<std::shared_ptr<rc::Listener>>& rc_listeners)
154156
: tracer_telemetry_(tracer_telemetry),
155157
clock_(config.clock),
156158
logger_(logger),
@@ -162,7 +164,7 @@ DatadogAgent::DatadogAgent(
162164
flush_interval_(config.flush_interval),
163165
request_timeout_(config.request_timeout),
164166
shutdown_timeout_(config.shutdown_timeout),
165-
remote_config_(tracer_signature, config_manager),
167+
remote_config_(tracer_signature, rc_listeners, logger),
166168
tracer_signature_(tracer_signature) {
167169
assert(logger_);
168170
assert(tracer_telemetry_);
@@ -410,14 +412,13 @@ void DatadogAgent::send_heartbeat_and_telemetry() {
410412
send_telemetry("app-heartbeat", tracer_telemetry_->heartbeat_and_telemetry());
411413
}
412414

413-
void DatadogAgent::send_app_closing() {
414-
send_telemetry("app-closing", tracer_telemetry_->app_closing());
415+
void DatadogAgent::send_configuration_change() {
416+
send_telemetry("app-client-configuration-change",
417+
tracer_telemetry_->configuration_change());
415418
}
416419

417-
void DatadogAgent::send_configuration_change(
418-
const std::vector<ConfigMetadata>& config) {
419-
send_telemetry("app-client-configuration-change",
420-
tracer_telemetry_->configuration_change(config));
420+
void DatadogAgent::send_app_closing() {
421+
send_telemetry("app-closing", tracer_telemetry_->app_closing());
421422
}
422423

423424
void DatadogAgent::get_and_apply_remote_configuration_updates() {
@@ -457,11 +458,13 @@ void DatadogAgent::get_and_apply_remote_configuration_updates() {
457458
}
458459

459460
if (!response_json.empty()) {
460-
auto updated_configuration =
461-
remote_config_.process_response(response_json);
462-
if (!updated_configuration.empty()) {
463-
send_configuration_change(updated_configuration);
464-
}
461+
remote_config_.process_response(response_json);
462+
// NOTE(@dmehala): Not ideal but it mimics the old behavior.
463+
// In the future, I would prefer telemetry pushing to the agent
464+
// and not the agent pulling from telemetry. That way telemetry will
465+
// be more flexible and could support env var to customize how often
466+
// it captures metrics.
467+
send_configuration_change();
465468
}
466469
};
467470

src/datadog/datadog_agent.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "event_scheduler.h"
1717
#include "http_client.h"
1818
#include "metrics.h"
19-
#include "remote_config.h"
19+
#include "remote_config/remote_config.h"
2020
#include "tracer_signature.h"
2121
#include "tracer_telemetry.h"
2222

@@ -55,7 +55,7 @@ class DatadogAgent : public Collector {
5555
std::chrono::steady_clock::duration request_timeout_;
5656
std::chrono::steady_clock::duration shutdown_timeout_;
5757

58-
RemoteConfigurationManager remote_config_;
58+
remote_config::Manager remote_config_;
5959
TracerSignature tracer_signature_;
6060

6161
void flush();
@@ -67,7 +67,8 @@ class DatadogAgent : public Collector {
6767
DatadogAgent(const FinalizedDatadogAgentConfig&,
6868
const std::shared_ptr<TracerTelemetry>&,
6969
const std::shared_ptr<Logger>&, const TracerSignature& id,
70-
const std::shared_ptr<ConfigManager>& config_manager);
70+
const std::vector<std::shared_ptr<remote_config::Listener>>&
71+
rc_listeners);
7172
~DatadogAgent();
7273

7374
Expected<void> send(
@@ -77,7 +78,7 @@ class DatadogAgent : public Collector {
7778
void send_app_started(
7879
const std::unordered_map<ConfigName, ConfigMetadata>& config_metadata);
7980

80-
void send_configuration_change(const std::vector<ConfigMetadata>& config);
81+
void send_configuration_change();
8182

8283
void get_and_apply_remote_configuration_updates();
8384

src/datadog/datadog_agent_config.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ Expected<FinalizedDatadogAgentConfig> finalize_config(
7878
result.event_scheduler = user_config.event_scheduler;
7979
}
8080

81+
result.remote_configuration_listeners =
82+
user_config.remote_configuration_listeners;
83+
8184
if (auto flush_interval_milliseconds =
8285
value_or(env_config->flush_interval_milliseconds,
8386
user_config.flush_interval_milliseconds, 2000);

0 commit comments

Comments
 (0)