diff --git a/src/datadog/config_manager.cpp b/src/datadog/config_manager.cpp index b5f6498f..3789c34a 100644 --- a/src/datadog/config_manager.cpp +++ b/src/datadog/config_manager.cpp @@ -11,18 +11,25 @@ ConfigManager::ConfigManager(const FinalizedTracerConfig& config) std::make_shared(config.trace_sampler, clock_)), current_trace_sampler_(default_trace_sampler_), default_span_defaults_(std::make_shared(config.defaults)), - current_span_defaults_(default_span_defaults_) {} + current_span_defaults_(default_span_defaults_), + default_report_traces_(config.report_traces), + current_report_traces_(default_report_traces_) {} -std::shared_ptr ConfigManager::get_trace_sampler() { +std::shared_ptr ConfigManager::trace_sampler() { std::lock_guard lock(mutex_); return current_trace_sampler_; } -std::shared_ptr ConfigManager::get_span_defaults() { +std::shared_ptr ConfigManager::span_defaults() { std::lock_guard lock(mutex_); return current_span_defaults_; } +bool ConfigManager::report_traces() { + std::lock_guard lock(mutex_); + return current_report_traces_; +} + void ConfigManager::update(const ConfigUpdate& conf) { std::lock_guard lock(mutex_); @@ -47,19 +54,27 @@ void ConfigManager::update(const ConfigUpdate& conf) { } else { current_span_defaults_ = default_span_defaults_; } + + if (conf.report_traces) { + current_report_traces_ = *conf.report_traces; + } else { + current_report_traces_ = default_report_traces_; + } } void ConfigManager::reset() { std::lock_guard lock(mutex_); current_trace_sampler_ = default_trace_sampler_; current_span_defaults_ = default_span_defaults_; + current_report_traces_ = default_report_traces_; } nlohmann::json ConfigManager::config_json() const { std::lock_guard lock(mutex_); return nlohmann::json{ {"default", to_json(*current_span_defaults_)}, - {"trace_sampler", current_trace_sampler_->config_json()}}; + {"trace_sampler", current_trace_sampler_->config_json()}, + {"report_traces", current_report_traces_}}; } } // namespace tracing diff --git a/src/datadog/config_manager.h b/src/datadog/config_manager.h index e14ffee0..51b3c6b0 100644 --- a/src/datadog/config_manager.h +++ b/src/datadog/config_manager.h @@ -25,14 +25,20 @@ class ConfigManager { std::shared_ptr default_span_defaults_; std::shared_ptr current_span_defaults_; + bool default_report_traces_; + bool current_report_traces_; + public: ConfigManager(const FinalizedTracerConfig& config); // Return the `TraceSampler` consistent with the most recent configuration. - std::shared_ptr get_trace_sampler(); + std::shared_ptr trace_sampler(); // Return the `SpanDefaults` consistent with the most recent configuration. - std::shared_ptr get_span_defaults(); + std::shared_ptr span_defaults(); + + // Return whether traces should be sent to the collector. + bool report_traces(); // Apply the specified `conf` update. void update(const ConfigUpdate& conf); diff --git a/src/datadog/config_update.h b/src/datadog/config_update.h index 41aac51e..20001e22 100644 --- a/src/datadog/config_update.h +++ b/src/datadog/config_update.h @@ -14,6 +14,7 @@ namespace tracing { // Configurations can be `nullopt` to signal the absence of a value from the // remote configuration value. struct ConfigUpdate { + Optional report_traces; Optional trace_sampler; Optional> tags; }; diff --git a/src/datadog/remote_config.cpp b/src/datadog/remote_config.cpp index 746aada2..4afc5031 100644 --- a/src/datadog/remote_config.cpp +++ b/src/datadog/remote_config.cpp @@ -29,7 +29,8 @@ namespace { // within the array. enum CapabilitiesFlag : uint64_t { APM_TRACING_SAMPLE_RATE = 1 << 12, - APM_TRACING_TAGS = 1 << 15 + APM_TRACING_TAGS = 1 << 15, + APM_TRACING_ENABLED = 1 << 19 }; constexpr std::array capabilities_byte_array( @@ -44,7 +45,8 @@ constexpr std::array capabilities_byte_array( } constexpr std::array k_apm_capabilities = - capabilities_byte_array(APM_TRACING_SAMPLE_RATE | APM_TRACING_TAGS); + capabilities_byte_array(APM_TRACING_SAMPLE_RATE | APM_TRACING_TAGS | + APM_TRACING_ENABLED); constexpr StringView k_apm_product = "APM_TRACING"; constexpr StringView k_apm_product_path_substring = "/APM_TRACING/"; @@ -94,6 +96,15 @@ ConfigUpdate parse_dynamic_config(const nlohmann::json& j) { } } + if (auto tracing_enabled_it = j.find("tracing_enabled"); + tracing_enabled_it != j.cend()) { + if (tracing_enabled_it->is_boolean()) { + config_update.report_traces = tracing_enabled_it->get(); + } else { + // TODO: report to telemetry + } + } + return config_update; } diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index 7e948319..639411ca 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -107,6 +107,7 @@ TraceSegment::TraceSegment( const std::shared_ptr& trace_sampler, const std::shared_ptr& span_sampler, const std::shared_ptr& defaults, + const std::shared_ptr& config_manager, const RuntimeID& runtime_id, bool sampling_delegation_enabled, bool sampling_decision_was_delegated_to_me, const std::vector& injection_styles, @@ -133,13 +134,15 @@ TraceSegment::TraceSegment( sampling_decision_(std::move(sampling_decision)), additional_w3c_tracestate_(std::move(additional_w3c_tracestate)), additional_datadog_w3c_tracestate_( - std::move(additional_datadog_w3c_tracestate)) { + std::move(additional_datadog_w3c_tracestate)), + config_manager_(config_manager) { assert(logger_); assert(collector_); assert(tracer_telemetry_); assert(trace_sampler_); assert(span_sampler_); assert(defaults_); + assert(config_manager_); sampling_delegation_.enabled = sampling_delegation_enabled; sampling_delegation_.decision_was_delegated_to_me = @@ -264,10 +267,12 @@ void TraceSegment::span_finished() { span.tags[tags::internal::runtime_id] = runtime_id_.string(); } - const auto result = collector_->send(std::move(spans_), trace_sampler_); - if (auto* error = result.if_error()) { - logger_->log_error( - error->with_prefix("Error sending spans to collector: ")); + if (config_manager_->report_traces()) { + const auto result = collector_->send(std::move(spans_), trace_sampler_); + if (auto* error = result.if_error()) { + logger_->log_error( + error->with_prefix("Error sending spans to collector: ")); + } } tracer_telemetry_->metrics().tracer.trace_segments_closed.inc(); diff --git a/src/datadog/trace_segment.h b/src/datadog/trace_segment.h index cf2272a5..a89490e5 100644 --- a/src/datadog/trace_segment.h +++ b/src/datadog/trace_segment.h @@ -32,6 +32,7 @@ #include #include +#include "config_manager.h" #include "expected.h" #include "metrics.h" #include "optional.h" @@ -74,6 +75,9 @@ class TraceSegment { Optional sampling_decision_; Optional additional_w3c_tracestate_; Optional additional_datadog_w3c_tracestate_; + + std::shared_ptr config_manager_; + // See `doc/sampling-delegation.md` for more information about // `struct SamplingDelegation`. struct SamplingDelegation { @@ -100,6 +104,7 @@ class TraceSegment { const std::shared_ptr& trace_sampler, const std::shared_ptr& span_sampler, const std::shared_ptr& defaults, + const std::shared_ptr& config_manager, const RuntimeID& runtime_id, bool sampling_delegation_enabled, bool sampling_decision_was_delegated_to_me, const std::vector& injection_styles, diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 54c55b96..24dcf749 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -104,7 +104,7 @@ 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 defaults = config_manager_->span_defaults(); auto span_data = std::make_unique(); span_data->apply_config(*defaults, config, clock_); span_data->trace_id = generator_->trace_id(span_data->start); @@ -120,9 +120,9 @@ Span Tracer::create_span(const SpanConfig& config) { const auto span_data_ptr = span_data.get(); tracer_telemetry_->metrics().tracer.trace_segments_created_new.inc(); const auto segment = std::make_shared( - logger_, collector_, tracer_telemetry_, - config_manager_->get_trace_sampler(), span_sampler_, defaults, - runtime_id_, sampling_delegation_enabled_, + logger_, collector_, tracer_telemetry_, config_manager_->trace_sampler(), + span_sampler_, defaults, config_manager_, runtime_id_, + sampling_delegation_enabled_, false /* sampling_decision_was_delegated_to_me */, injection_styles_, hostname_, nullopt /* origin */, tags_header_max_size_, std::move(trace_tags), nullopt /* sampling_decision */, @@ -240,8 +240,7 @@ Expected 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(*config_manager_->get_span_defaults(), config, - clock_); + span_data->apply_config(*config_manager_->span_defaults(), config, clock_); span_data->span_id = generator_->span_id(); span_data->trace_id = *trace_id; span_data->parent_id = *parent_id; @@ -292,10 +291,9 @@ Expected Tracer::extract_span(const DictReader& reader, const auto span_data_ptr = span_data.get(); tracer_telemetry_->metrics().tracer.trace_segments_created_continued.inc(); const auto segment = std::make_shared( - logger_, collector_, tracer_telemetry_, - config_manager_->get_trace_sampler(), span_sampler_, - config_manager_->get_span_defaults(), runtime_id_, - sampling_delegation_enabled_, delegate_sampling_decision, + logger_, collector_, tracer_telemetry_, config_manager_->trace_sampler(), + span_sampler_, config_manager_->span_defaults(), config_manager_, + 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), diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 4c517af6..b7a726dc 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -12,7 +12,6 @@ #include "datadog_agent.h" #include "environment.h" #include "json.hpp" -#include "null_collector.h" #include "parse_util.h" #include "string_view.h" @@ -312,14 +311,12 @@ Expected finalize_config(const TracerConfig &config, result.log_on_startup = !falsy(*startup_env); } - bool report_traces = config.report_traces; + result.report_traces = config.report_traces; if (auto enabled_env = lookup(environment::DD_TRACE_ENABLED)) { - report_traces = !falsy(*enabled_env); + result.report_traces = !falsy(*enabled_env); } - if (!report_traces) { - result.collector = std::make_shared(); - } else if (!config.collector) { + if (!config.collector) { auto finalized = finalize_config(config.agent, result.logger, clock); if (auto *error = finalized.if_error()) { return std::move(*error); diff --git a/src/datadog/tracer_config.h b/src/datadog/tracer_config.h index 93546337..c9ed4dda 100644 --- a/src/datadog/tracer_config.h +++ b/src/datadog/tracer_config.h @@ -166,6 +166,7 @@ class FinalizedTracerConfig { std::string integration_name; std::string integration_version; bool delegate_trace_sampling; + bool report_traces; }; // Return a `FinalizedTracerConfig` from the specified `config` and from any diff --git a/test/test_remote_config.cpp b/test/test_remote_config.cpp index 984d64f5..0e7ff156 100644 --- a/test/test_remote_config.cpp +++ b/test/test_remote_config.cpp @@ -63,6 +63,7 @@ REMOTE_CONFIG_TEST("response processing") { config.defaults.service = "testsvc"; config.defaults.environment = "test"; config.trace_sampler.sample_rate = 1.0; + config.report_traces = true; const auto config_manager = std::make_shared(*finalize_config(config)); @@ -160,13 +161,31 @@ REMOTE_CONFIG_TEST("response processing") { SECTION("valid remote configuration") { // clang-format off + // { + // "lib_config": { + // "library_language": "all", + // "library_version": "latest", + // "service_name": "testsvc", + // "env": "test", + // "tracing_enabled": false, + // "tracing_sampling_rate": 0.6, + // "tracing_tags": [ + // "hello:world", + // "foo:bar" + // ] + // }, + // "service_target": { + // "service": "testsvc", + // "env": "test" + // } + // } const std::string json_input = R"({ "targets": "ewogICAgInNpZ25lZCI6IHsKICAgICAgICAiY3VzdG9tIjogewogICAgICAgICAgICAiYWdlbnRfcmVmcmVzaF9pbnRlcnZhbCI6IDUsCiAgICAgICAgICAgICJvcGFxdWVfYmFja2VuZF9zdGF0ZSI6ICJleUoyWlhKemFXOXVJam95TENKemRHRjBaU0k2ZXlKbWFXeGxYMmhoYzJobGN5STZleUprWVhSaFpHOW5MekV3TURBeE1qVTROREF2UVZCTlgxUlNRVU5KVGtjdk9ESTNaV0ZqWmpoa1ltTXpZV0l4TkRNMFpETXlNV05pT0RGa1ptSm1OMkZtWlRZMU5HRTBZall4TVRGalpqRTJOakJpTnpGalkyWTRPVGM0TVRrek9DOHlPVEE0Tm1Ka1ltVTFNRFpsTmpoaU5UQm1NekExTlRneU0yRXpaR0UxWTJVd05USTRaakUyTkRCa05USmpaamc0TmpFNE1UWmhZV0U1Wm1ObFlXWTBJanBiSW05WVpESnBlVU16ZUM5b1JXc3hlWFZoWTFoR04xbHFjWEpwVGs5QldVdHVaekZ0V0UwMU5WWktUSGM5SWwxOWZYMD0iCiAgICAgICAgfSwKICAgICAgICAic3BlY192ZXJzaW9uIjogIjEuMC4wIiwKICAgICAgICAidGFyZ2V0cyI6IHsKICAgICAgICAgICAgImZvby9BUE1fVFJBQ0lORy8zMCI6IHsKICAgICAgICAgICAgICAgICJoYXNoZXMiOiB7CiAgICAgICAgICAgICAgICAgICAgInNoYTI1NiI6ICJhMTc3NzY4YjIwYjdjN2Y4NDQ5MzVjYWU2OWM1YzVlZDg4ZWFhZTIzNGUwMTgyYTc4MzU5OTczMzllNTUyNGJjIgogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICJsZW5ndGgiOiAzNzQKICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgInZlcnNpb24iOiA2NjIwNDMyMAogICAgfQp9", "client_configs": ["foo/APM_TRACING/30"], "target_files": [ { "path": "foo/APM_TRACING/30", - "raw": "eyAiaWQiOiAiODI3ZWFjZjhkYmMzYWIxNDM0ZDMyMWNiODFkZmJmN2FmZTY1NGE0YjYxMTFjZjE2NjBiNzFjY2Y4OTc4MTkzOCIsICJyZXZpc2lvbiI6IDE2OTgxNjcxMjYwNjQsICJzY2hlbWFfdmVyc2lvbiI6ICJ2MS4wLjAiLCAiYWN0aW9uIjogImVuYWJsZSIsICJsaWJfY29uZmlnIjogeyAibGlicmFyeV9sYW5ndWFnZSI6ICJhbGwiLCAibGlicmFyeV92ZXJzaW9uIjogImxhdGVzdCIsICJzZXJ2aWNlX25hbWUiOiAidGVzdHN2YyIsICJlbnYiOiAidGVzdCIsICJ0cmFjaW5nX2VuYWJsZWQiOiB0cnVlLCAidHJhY2luZ19zYW1wbGluZ19yYXRlIjogMC42LCAidHJhY2luZ190YWdzIjogWyJoZWxsbzp3b3JsZCIsICJmb286YmFyIl0gfSwgInNlcnZpY2VfdGFyZ2V0IjogeyAic2VydmljZSI6ICJ0ZXN0c3ZjIiwgImVudiI6ICJ0ZXN0IiB9IH0=" + "raw": "eyAiaWQiOiAiODI3ZWFjZjhkYmMzYWIxNDM0ZDMyMWNiODFkZmJmN2FmZTY1NGE0YjYxMTFjZjE2NjBiNzFjY2Y4OTc4MTkzOCIsICJyZXZpc2lvbiI6IDE2OTgxNjcxMjYwNjQsICJzY2hlbWFfdmVyc2lvbiI6ICJ2MS4wLjAiLCAiYWN0aW9uIjogImVuYWJsZSIsICJsaWJfY29uZmlnIjogeyAibGlicmFyeV9sYW5ndWFnZSI6ICJhbGwiLCAibGlicmFyeV92ZXJzaW9uIjogImxhdGVzdCIsICJzZXJ2aWNlX25hbWUiOiAidGVzdHN2YyIsICJlbnYiOiAidGVzdCIsICJ0cmFjaW5nX2VuYWJsZWQiOiBmYWxzZSwgInRyYWNpbmdfc2FtcGxpbmdfcmF0ZSI6IDAuNiwgInRyYWNpbmdfdGFncyI6IFsiaGVsbG86d29ybGQiLCAiZm9vOmJhciJdIH0sICJzZXJ2aWNlX3RhcmdldCI6IHsgInNlcnZpY2UiOiAidGVzdHN2YyIsICJlbnYiOiAidGVzdCIgfSB9" } ] })"; @@ -179,14 +198,17 @@ REMOTE_CONFIG_TEST("response processing") { REQUIRE(!response_json.is_discarded()); - const auto old_trace_sampler = config_manager->get_trace_sampler(); - const auto old_span_defaults = config_manager->get_span_defaults(); + const auto old_trace_sampler = config_manager->trace_sampler(); + const auto old_span_defaults = config_manager->span_defaults(); + const auto old_report_traces = config_manager->report_traces(); rc.process_response(response_json); - const auto new_trace_sampler = config_manager->get_trace_sampler(); - const auto new_span_defaults = config_manager->get_span_defaults(); + const auto new_trace_sampler = config_manager->trace_sampler(); + const auto new_span_defaults = config_manager->span_defaults(); + const auto new_report_traces = config_manager->report_traces(); CHECK(new_trace_sampler != old_trace_sampler); CHECK(new_span_defaults != old_span_defaults); + CHECK(new_report_traces != old_report_traces); SECTION("reset confguration") { SECTION( @@ -206,8 +228,13 @@ REMOTE_CONFIG_TEST("response processing") { REQUIRE(!response_json.is_discarded()); rc.process_response(response_json); - const auto current_trace_sampler = config_manager->get_trace_sampler(); + const auto current_trace_sampler = config_manager->trace_sampler(); + const auto current_span_defaults = config_manager->span_defaults(); + const auto current_report_traces = config_manager->report_traces(); + CHECK(old_trace_sampler == current_trace_sampler); + CHECK(old_span_defaults == current_span_defaults); + CHECK(old_report_traces == current_report_traces); } SECTION("missing configuration field -> field should be reset") { @@ -232,7 +259,7 @@ REMOTE_CONFIG_TEST("response processing") { REQUIRE(!response_json.is_discarded()); rc.process_response(response_json); - const auto current_trace_sampler = config_manager->get_trace_sampler(); + const auto current_trace_sampler = config_manager->trace_sampler(); CHECK(old_trace_sampler == current_trace_sampler); } } @@ -275,9 +302,9 @@ REMOTE_CONFIG_TEST("response processing") { REQUIRE(!response_json.is_discarded()); - const auto old_sampling_rate = config_manager->get_trace_sampler(); + const auto old_sampling_rate = config_manager->trace_sampler(); rc.process_response(response_json); - const auto new_sampling_rate = config_manager->get_trace_sampler(); + const auto new_sampling_rate = config_manager->trace_sampler(); CHECK(new_sampling_rate == old_sampling_rate); }