Skip to content

Commit

Permalink
feat: support DD_TAGS dynamic configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
dmehala committed Jan 26, 2024
1 parent 0f508e1 commit fb95bc7
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 10 deletions.
21 changes: 20 additions & 1 deletion src/datadog/config_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@ ConfigManager::ConfigManager(const FinalizedTracerConfig& config)
: clock_(config.clock),
default_trace_sampler_(
std::make_shared<TraceSampler>(config.trace_sampler, clock_)),
current_trace_sampler_(default_trace_sampler_) {}
current_trace_sampler_(default_trace_sampler_),
default_span_defaults_(std::make_shared<SpanDefaults>(config.defaults)),
current_span_defaults_(default_span_defaults_) {}

std::shared_ptr<TraceSampler> ConfigManager::get_trace_sampler() {
std::lock_guard<std::mutex> lock(mutex_);
return current_trace_sampler_;
}

std::shared_ptr<const SpanDefaults> ConfigManager::get_span_defaults() {
std::lock_guard<std::mutex> lock(mutex_);
return current_span_defaults_;
}

void ConfigManager::update(const ConfigUpdate& conf) {
std::lock_guard<std::mutex> lock(mutex_);

Expand All @@ -30,16 +37,28 @@ void ConfigManager::update(const ConfigUpdate& conf) {
} else {
current_trace_sampler_ = default_trace_sampler_;
}

if (conf.tags) {
auto new_span_defaults =
std::make_shared<SpanDefaults>(*current_span_defaults_);
new_span_defaults->tags = std::move(*conf.tags);

current_span_defaults_ = new_span_defaults;
} else {
current_span_defaults_ = default_span_defaults_;
}
}

void ConfigManager::reset() {
std::lock_guard<std::mutex> lock(mutex_);
current_trace_sampler_ = default_trace_sampler_;
current_span_defaults_ = default_span_defaults_;
}

nlohmann::json ConfigManager::config_json() const {
std::lock_guard<std::mutex> lock(mutex_);
return nlohmann::json{
{"default", to_json(*current_span_defaults_)},
{"trace_sampler", current_trace_sampler_->config_json()}};
}

Expand Down
7 changes: 7 additions & 0 deletions src/datadog/config_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "clock.h"
#include "config_update.h"
#include "json.hpp"
#include "span_defaults.h"
#include "tracer_config.h"

namespace datadog {
Expand All @@ -21,12 +22,18 @@ class ConfigManager {
std::shared_ptr<TraceSampler> default_trace_sampler_;
std::shared_ptr<TraceSampler> current_trace_sampler_;

std::shared_ptr<const SpanDefaults> default_span_defaults_;
std::shared_ptr<const SpanDefaults> current_span_defaults_;

public:
ConfigManager(const FinalizedTracerConfig& config);

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

// Return the `SpanDefaults` consistent with the most recent configuration.
std::shared_ptr<const SpanDefaults> get_span_defaults();

// Apply the specified `conf` update.
void update(const ConfigUpdate& conf);

Expand Down
3 changes: 3 additions & 0 deletions src/datadog/config_update.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <unordered_map>

#include "optional"
#include "trace_sampler_config.h"

Expand All @@ -13,6 +15,7 @@ namespace tracing {
// remote configuration value.
struct ConfigUpdate {
Optional<TraceSamplerConfig> trace_sampler;
Optional<std::unordered_map<std::string, std::string>> tags;
};

} // namespace tracing
Expand Down
37 changes: 36 additions & 1 deletion src/datadog/remote_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace {
// within the array.
enum CapabilitiesFlag : uint64_t {
APM_TRACING_SAMPLE_RATE = 1 << 12,
APM_TRACING_TAGS = 1 << 15
};

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

constexpr std::array<uint8_t, sizeof(uint64_t)> k_apm_capabilities =
capabilities_byte_array(APM_TRACING_SAMPLE_RATE);
capabilities_byte_array(APM_TRACING_SAMPLE_RATE | APM_TRACING_TAGS);

constexpr StringView k_apm_product = "APM_TRACING";
constexpr StringView k_apm_product_path_substring = "/APM_TRACING/";

Expected<std::unordered_map<std::string, std::string>> parse_tags(
const std::vector<StringView>& list_of_tags) {
std::unordered_map<std::string, std::string> tags;

// Within a tag, the key and value are separated by a colon (":").
for (const StringView& token : list_of_tags) {
const auto separator = std::find(token.begin(), token.end(), ':');
if (separator == token.end()) {
std::string message;
message += "Unable to parse a key/value from the tag text \"";
append(message, token);
message +=
"\" because it does not contain the separator character \":\".";
return Error{Error::TAG_MISSING_SEPARATOR, std::move(message)};
}

std::string key{token.begin(), separator};
std::string value{separator + 1, token.end()};
// If there are duplicate values, then the last one wins.
tags.insert_or_assign(std::move(key), std::move(value));
}

return tags;
}

ConfigUpdate parse_dynamic_config(const nlohmann::json& j) {
ConfigUpdate config_update;

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

if (auto tags_it = j.find("tracing_tags"); tags_it != j.cend()) {
auto parsed_tags = parse_tags(*tags_it);
if (auto error = parsed_tags.if_error()) {
// TODO: report to telemetry
} else {
config_update.tags = std::move(*parsed_tags);
}
}

return config_update;
}

Expand Down
15 changes: 8 additions & 7 deletions src/datadog/tracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
: logger_(config.logger),
config_manager_(std::make_shared<ConfigManager>(config)),
collector_(/* see constructor body */),
defaults_(std::make_shared<SpanDefaults>(config.defaults)),
runtime_id_(config.runtime_id ? *config.runtime_id
: RuntimeID::generate()),
signature_{runtime_id_, config.defaults.service,
Expand Down Expand Up @@ -83,7 +82,6 @@ nlohmann::json Tracer::config_json() const {
// clang-format off
auto config = nlohmann::json::object({
{"version", tracer_version_string},
{"defaults", to_json(*defaults_)},
{"runtime_id", runtime_id_.string()},
{"collector", collector_->config_json()},
{"span_sampler", span_sampler_->config_json()},
Expand All @@ -106,8 +104,9 @@ nlohmann::json Tracer::config_json() const {
Span Tracer::create_span() { return create_span(SpanConfig{}); }

Span Tracer::create_span(const SpanConfig& config) {
auto defaults = config_manager_->get_span_defaults();
auto span_data = std::make_unique<SpanData>();
span_data->apply_config(*defaults_, config, clock_);
span_data->apply_config(*defaults, config, clock_);
span_data->trace_id = generator_->trace_id(span_data->start);
span_data->span_id = span_data->trace_id.low;
span_data->parent_id = 0;
Expand All @@ -122,7 +121,7 @@ Span Tracer::create_span(const SpanConfig& config) {
tracer_telemetry_->metrics().tracer.trace_segments_created_new.inc();
const auto segment = std::make_shared<TraceSegment>(
logger_, collector_, tracer_telemetry_,
config_manager_->get_trace_sampler(), span_sampler_, defaults_,
config_manager_->get_trace_sampler(), span_sampler_, defaults,
runtime_id_, sampling_delegation_enabled_,
false /* sampling_decision_was_delegated_to_me */, injection_styles_,
hostname_, nullopt /* origin */, tags_header_max_size_,
Expand Down Expand Up @@ -241,7 +240,8 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,

// We're done extracting fields. Now create the span.
// This is similar to what we do in `create_span`.
span_data->apply_config(*defaults_, config, clock_);
span_data->apply_config(*config_manager_->get_span_defaults(), config,
clock_);
span_data->span_id = generator_->span_id();
span_data->trace_id = *trace_id;
span_data->parent_id = *parent_id;
Expand Down Expand Up @@ -293,8 +293,9 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
tracer_telemetry_->metrics().tracer.trace_segments_created_continued.inc();
const auto segment = std::make_shared<TraceSegment>(
logger_, collector_, tracer_telemetry_,
config_manager_->get_trace_sampler(), span_sampler_, defaults_,
runtime_id_, sampling_delegation_enabled_, delegate_sampling_decision,
config_manager_->get_trace_sampler(), span_sampler_,
config_manager_->get_span_defaults(), runtime_id_,
sampling_delegation_enabled_, delegate_sampling_decision,
injection_styles_, hostname_, std::move(origin), tags_header_max_size_,
std::move(trace_tags), std::move(sampling_decision),
std::move(additional_w3c_tracestate),
Expand Down
1 change: 0 additions & 1 deletion src/datadog/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class Tracer {
std::shared_ptr<Logger> logger_;
std::shared_ptr<ConfigManager> config_manager_;
std::shared_ptr<Collector> collector_;
std::shared_ptr<const SpanDefaults> defaults_;
RuntimeID runtime_id_;
TracerSignature signature_;
std::shared_ptr<TracerTelemetry> tracer_telemetry_;
Expand Down

0 comments on commit fb95bc7

Please sign in to comment.