diff --git a/BUILD.bazel b/BUILD.bazel index 500c56e5..91fd94d5 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -4,6 +4,7 @@ cc_library( "src/datadog/base64.cpp", "src/datadog/cerr_logger.cpp", "src/datadog/clock.cpp", + "src/datadog/config_manager.cpp", "src/datadog/collector_response.cpp", # "src/datadog/curl.cpp", no libcurl "src/datadog/datadog_agent_config.cpp", diff --git a/CMakeLists.txt b/CMakeLists.txt index b03ad992..29fa8618 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ target_sources(dd_trace_cpp-objects PRIVATE src/datadog/base64.cpp src/datadog/cerr_logger.cpp src/datadog/clock.cpp + src/datadog/config_manager.cpp src/datadog/collector_response.cpp src/datadog/curl.cpp src/datadog/datadog_agent_config.cpp diff --git a/bin/cmake-build b/bin/cmake-build index 1ba61e27..34926942 100755 --- a/bin/cmake-build +++ b/bin/cmake-build @@ -6,5 +6,5 @@ cd "$(dirname "$0")"/.. mkdir -p .build cd .build -cmake .. +cmake .. "$@" make -j "$(nproc)" diff --git a/fuzz/README.md b/fuzz/README.md index 3f0181c3..648d3e40 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -3,24 +3,19 @@ Fuzzers Each subdirectory here contains the source of an executable that [fuzz tests][1] some part of the library using [LLVM's libfuzzer][2]. -There is a toplevel CMake boolean option associated with each fuzzer. The naming -convention is `FUZZ_`, e.g. -`FUZZ_W3C_PROPAGATION` for the fuzzer defined in -[fuzz/w3c-propagation/](./w3c-propagation/). The resulting binary is called -`fuzz` by convention. +There is a toplevel CMake boolean option that adds all of the fuzzer +executables to the build: `BUILD_FUZZERS`. -When building a fuzzer, the toolchain must be clang-based. For example, this -is how to build the fuzzer in [fuzz/w3c-propagation](./w3c-propagation/) from -the root of the repository: +When building the fuzzers, the toolchain must be clang-based. For example: ```console -$ rm -rf .build && mkdir .build # if toolchain or test setup need clearing -$ cd .build -$ CC=clang CXX=clang++ cmake .. -DFUZZ_W3C_PROPAGATION=ON -$ make -j $(nproc) -$ fuzz/w3c-propagation/fuzz +$ rm -rf .build # if toolchain needs clearing +$ bin/with-toolchain llvm bin/cmake-build -DBUILD_FUZZERS=1 +$ .build/fuzz/w3c-propagation/w3c-propagation-fuzz [... fuzzer output ...] ``` +The fuzzer executables are named `.build/fuzz/*/*-fuzz` by convention. + [1]: https://en.wikipedia.org/wiki/Fuzzing [2]: https://llvm.org/docs/LibFuzzer.html diff --git a/fuzz/base64/main.cpp b/fuzz/base64/main.cpp index 805a36c0..bd0e9712 100644 --- a/fuzz/base64/main.cpp +++ b/fuzz/base64/main.cpp @@ -1,9 +1,11 @@ #include #include +#include + namespace dd = datadog::tracing; extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, size_t size) { - dd::base64::decode(dd::StringView{(char*)data, size}); + dd::base64_decode(dd::StringView{(const char*)data, size}); return 0; } diff --git a/src/datadog/base64.cpp b/src/datadog/base64.cpp index c134a7dd..515dab67 100644 --- a/src/datadog/base64.cpp +++ b/src/datadog/base64.cpp @@ -1,109 +1,100 @@ #include "base64.h" -#include +#include +#include namespace datadog { namespace tracing { -namespace base64 { -#define _ 255 -#define SENTINEL_VALUE _ -#define EOL 0 +constexpr uint8_t k_sentinel = 255; +constexpr uint8_t _ = k_sentinel; // for brevity +constexpr uint8_t k_eol = 0; -/* - * Lookup table mapping the base64 table. Invalid inputs are mapped - * to the value 255. - * `=` map to 0. - */ +// Invalid inputs are mapped to the value 255. '=' maps to 0. constexpr uint8_t k_base64_table[]{ - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, 62, _, _, _, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, _, _, _, EOL, _, _, _, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, _, _, _, _, - _, _, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _}; - -// TODO: support input without padding? -std::string decode(StringView in) { - const std::size_t in_size = in.size(); - - std::string out; - out.reserve(in_size); + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, 62, _, _, _, 63, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, _, _, _, k_eol, _, _, _, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, _, _, _, _, _, _, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, + _, _, _, _}; + +std::string base64_decode(StringView input) { + const size_t in_size = input.size(); + + std::string output; + output.reserve(in_size); union { uint32_t buffer; uint8_t bytes[4]; } decoder; - std::size_t i = 0; + size_t i = 0; for (; i + 4 < in_size;) { - auto c0 = k_base64_table[static_cast(in[i++])]; - auto c1 = k_base64_table[static_cast(in[i++])]; - auto c2 = k_base64_table[static_cast(in[i++])]; - auto c3 = k_base64_table[static_cast(in[i++])]; + uint32_t c0 = k_base64_table[static_cast(input[i++])]; + uint32_t c1 = k_base64_table[static_cast(input[i++])]; + uint32_t c2 = k_base64_table[static_cast(input[i++])]; + uint32_t c3 = k_base64_table[static_cast(input[i++])]; - if (c0 == SENTINEL_VALUE || c1 == SENTINEL_VALUE || c2 == SENTINEL_VALUE || - c3 == SENTINEL_VALUE) { + if (c0 == k_sentinel || c1 == k_sentinel || c2 == k_sentinel || + c3 == k_sentinel) { return ""; } - decoder.buffer = - static_cast(0) | static_cast(c0) << 26 | - static_cast(c1) << 20 | static_cast(c2) << 14 | - static_cast(c3) << 8; + decoder.buffer = 0 | c0 << (32 - 6 * 1) | c1 << (32 - 6 * 2) | + c2 << (32 - 6 * 3) | c3 << (32 - 6 * 4); - // NOTE(@dmehala): It might seem confusion to read those bytes in reverse + // NOTE(@dmehala): It might seem confusing to read those bytes input reverse // order. It is related to the architecture endianess. For now the set of // architecture we support (x86_64 and arm64) are all little-endian. - out.push_back(decoder.bytes[3]); - out.push_back(decoder.bytes[2]); - out.push_back(decoder.bytes[1]); + // TODO(@dgoffredo): I'd prefer an endian-agnostic implementation. + // nginx-datadog targets x86_64 and arm64 in its binary releases, but + // dd-trace-cpp targets any standard C++17 compiler. + output.push_back(decoder.bytes[3]); + output.push_back(decoder.bytes[2]); + output.push_back(decoder.bytes[1]); } - if ((in_size - i) < 4) return ""; // not padded input is not supported + // If padding is missing, return the empty string in lieu of an Error. + if ((in_size - i) < 4) return ""; - auto c0 = k_base64_table[static_cast(in[i++])]; - auto c1 = k_base64_table[static_cast(in[i++])]; - auto c2 = k_base64_table[static_cast(in[i++])]; - auto c3 = k_base64_table[static_cast(in[i++])]; + uint32_t c0 = k_base64_table[static_cast(input[i++])]; + uint32_t c1 = k_base64_table[static_cast(input[i++])]; + uint32_t c2 = k_base64_table[static_cast(input[i++])]; + uint32_t c3 = k_base64_table[static_cast(input[i++])]; - if (c0 == SENTINEL_VALUE || c1 == SENTINEL_VALUE || c2 == SENTINEL_VALUE || - c3 == SENTINEL_VALUE) { + if (c0 == k_sentinel || c1 == k_sentinel || c2 == k_sentinel || + c3 == k_sentinel) { return ""; } - decoder.buffer = static_cast(0) | static_cast(c0) << 26 | - static_cast(c1) << 20 | - static_cast(c2) << 14 | - static_cast(c3) << 8; + decoder.buffer = 0 | c0 << (32 - 6 * 1) | c1 << (32 - 6 * 2) | + c2 << (32 - 6 * 3) | c3 << (32 - 6 * 4); - if (c2 == EOL) { - out.push_back(decoder.bytes[3]); - } else if (c3 == EOL) { - out.push_back(decoder.bytes[3]); - out.push_back(decoder.bytes[2]); + if (c2 == k_eol) { + output.push_back(decoder.bytes[3]); + } else if (c3 == k_eol) { + output.push_back(decoder.bytes[3]); + output.push_back(decoder.bytes[2]); } else { - out.push_back(decoder.bytes[3]); - out.push_back(decoder.bytes[2]); - out.push_back(decoder.bytes[1]); + output.push_back(decoder.bytes[3]); + output.push_back(decoder.bytes[2]); + output.push_back(decoder.bytes[1]); } - return out; + return output; } -#undef EOL -#undef SENTINEL_VALUE -#undef _ - -} // namespace base64 } // namespace tracing } // namespace datadog diff --git a/src/datadog/base64.h b/src/datadog/base64.h index a594f1df..f2539872 100644 --- a/src/datadog/base64.h +++ b/src/datadog/base64.h @@ -1,19 +1,15 @@ #pragma once +#include + #include "string_view.h" namespace datadog { namespace tracing { -namespace base64 { -/* - * Decode a base64-encoded string and returns the decoded data. - * - * It only supported padded base64-encoded string. Providing an unpadded - * input will return an empty string. - */ -std::string decode(StringView in); +// Return the result of decoding the specified padded base64-encoded `input`. If +// `input` is not padded, then return the empty string instead. +std::string base64_decode(StringView input); -} // namespace base64 } // namespace tracing } // namespace datadog diff --git a/src/datadog/config_manager.cpp b/src/datadog/config_manager.cpp new file mode 100644 index 00000000..cb441bf7 --- /dev/null +++ b/src/datadog/config_manager.cpp @@ -0,0 +1,45 @@ +#include "config_manager.h" + +namespace datadog { +namespace tracing { + +ConfigManager::ConfigManager(const FinalizedTracerConfig& config) + : clock_(config.clock), + default_trace_sampler_( + std::make_shared(config.trace_sampler, clock_)), + current_trace_sampler_(default_trace_sampler_) {} + +std::shared_ptr ConfigManager::get_trace_sampler() { + std::lock_guard lock(mutex_); + return current_trace_sampler_; +} + +void ConfigManager::update(const ConfigManager::Update& conf) { + std::lock_guard lock(mutex_); + + if (conf.trace_sampler) { + if (auto finalized_trace_sampler_cfg = + finalize_config(*conf.trace_sampler)) { + current_trace_sampler_ = + std::make_shared(*finalized_trace_sampler_cfg, clock_); + } else { + // TODO: report error + } + } else { + current_trace_sampler_ = default_trace_sampler_; + } +} + +void ConfigManager::reset() { + std::lock_guard lock(mutex_); + current_trace_sampler_ = default_trace_sampler_; +} + +nlohmann::json ConfigManager::config_json() const { + std::lock_guard lock(mutex_); + return nlohmann::json{ + {"trace_sampler", current_trace_sampler_->config_json()}}; +} + +} // namespace tracing +} // namespace datadog diff --git a/src/datadog/config_manager.h b/src/datadog/config_manager.h index 61fa88cd..f1dcf98d 100644 --- a/src/datadog/config_manager.h +++ b/src/datadog/config_manager.h @@ -1,5 +1,7 @@ #pragma once +// TODO: Document + #include #include "clock.h" @@ -10,10 +12,6 @@ namespace datadog { namespace tracing { -struct ConfigUpdate { - Optional trace_sampler; -}; - class ConfigManager { mutable std::mutex mutex_; Clock clock_; @@ -21,43 +19,25 @@ class ConfigManager { std::shared_ptr current_trace_sampler_; public: - ConfigManager(const FinalizedTracerConfig& config) - : clock_(config.clock), - default_trace_sampler_( - std::make_shared(config.trace_sampler, clock_)), - current_trace_sampler_(default_trace_sampler_) {} + struct Update { + Optional trace_sampler; + }; - std::shared_ptr get_trace_sampler() { - std::lock_guard lock(mutex_); - return current_trace_sampler_; - } + ConfigManager(const FinalizedTracerConfig& config); - void update(const ConfigUpdate& conf) { - std::lock_guard lock(mutex_); + // Return the `TraceSampler` consistent with the most recent configuration. + std::shared_ptr get_trace_sampler(); - if (conf.trace_sampler) { - if (auto finalized_trace_sampler_cfg = - finalize_config(*conf.trace_sampler)) { - current_trace_sampler_ = std::make_shared( - *finalized_trace_sampler_cfg, clock_); - } else { - // TODO: report error - } - } else { - current_trace_sampler_ = default_trace_sampler_; - } - } + // Apply the specified `conf` update. + void update(const Update& conf); - void reset() { - std::lock_guard lock(mutex_); - current_trace_sampler_ = default_trace_sampler_; - } + // Restore the configuration that was passed to this object's constructor, + // overriding any previous calls to `update`. + void reset(); - nlohmann::json config_json() const { - std::lock_guard lock(mutex_); - return nlohmann::json{ - {"trace_sampler", current_trace_sampler_->config_json()}}; - } + // Return a JSON representation of the current configuration managed by this + // object. + nlohmann::json config_json() const; }; } // namespace tracing diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index ca8d6d2d..0d5adcad 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -28,6 +28,10 @@ constexpr StringView traces_api_path = "/v0.4/traces"; constexpr StringView telemetry_v2_path = "/telemetry/proxy/api/v2/apmtelemetry"; constexpr StringView remote_configuration_path = "/v0.7/config"; +void set_content_type_json(DictWriter& headers) { + headers.set("Content-Type", "application/json"); +} + HTTPClient::URL traces_endpoint(const HTTPClient::URL& agent_url) { auto traces_url = agent_url; append(traces_url.path, traces_api_path); @@ -145,7 +149,7 @@ std::variant parse_agent_traces_response( DatadogAgent::DatadogAgent( const FinalizedDatadogAgentConfig& config, const std::shared_ptr& tracer_telemetry, - const std::shared_ptr& logger, const TracerId& tracer_id, + const std::shared_ptr& logger, const TracerID& tracer_id, ConfigManager& config_manager) : tracer_telemetry_(tracer_telemetry), clock_(config.clock), @@ -357,10 +361,10 @@ void DatadogAgent::flush() { void DatadogAgent::send_app_started() { auto payload = tracer_telemetry_->app_started(); - auto post_result = http_client_->post( - telemetry_endpoint_, httputil::header::json_content_type_setter, - std::move(payload), telemetry_on_response_, telemetry_on_error_, - clock_().tick + request_timeout_); + auto post_result = + http_client_->post(telemetry_endpoint_, set_content_type_json, + std::move(payload), telemetry_on_response_, + telemetry_on_error_, clock_().tick + request_timeout_); if (auto* error = post_result.if_error()) { logger_->log_error(error->with_prefix( "Unexpected error submitting telemetry app-started event: ")); @@ -369,10 +373,10 @@ void DatadogAgent::send_app_started() { void DatadogAgent::send_heartbeat_and_telemetry() { auto payload = tracer_telemetry_->heartbeat_and_telemetry(); - auto post_result = http_client_->post( - telemetry_endpoint_, httputil::header::json_content_type_setter, - std::move(payload), telemetry_on_response_, telemetry_on_error_, - clock_().tick + request_timeout_); + auto post_result = + http_client_->post(telemetry_endpoint_, set_content_type_json, + std::move(payload), telemetry_on_response_, + telemetry_on_error_, clock_().tick + request_timeout_); if (auto* error = post_result.if_error()) { logger_->log_error(error->with_prefix( "Unexpected error submitting telemetry app-heartbeat event: ")); @@ -381,10 +385,10 @@ void DatadogAgent::send_heartbeat_and_telemetry() { void DatadogAgent::send_app_closing() { auto payload = tracer_telemetry_->app_closing(); - auto post_result = http_client_->post( - telemetry_endpoint_, httputil::header::json_content_type_setter, - std::move(payload), telemetry_on_response_, telemetry_on_error_, - clock_().tick + request_timeout_); + auto post_result = + http_client_->post(telemetry_endpoint_, set_content_type_json, + std::move(payload), telemetry_on_response_, + telemetry_on_error_, clock_().tick + request_timeout_); if (auto* error = post_result.if_error()) { logger_->log_error(error->with_prefix( "Unexpected error submitting telemetry app-closing event: ")); @@ -441,8 +445,7 @@ void DatadogAgent::get_and_apply_remote_configuration_updates() { }; auto post_result = http_client_->post( - remote_configuration_endpoint_, - httputil::header::json_content_type_setter, + remote_configuration_endpoint_, set_content_type_json, remote_config_.make_request_payload().dump(), remote_configuration_on_response, remote_configuration_on_error, clock_().tick + request_timeout_); diff --git a/src/datadog/datadog_agent.h b/src/datadog/datadog_agent.h index cfc8ddf0..6aa11440 100644 --- a/src/datadog/datadog_agent.h +++ b/src/datadog/datadog_agent.h @@ -26,7 +26,7 @@ class FinalizedDatadogAgentConfig; class Logger; struct SpanData; class TraceSampler; -struct TracerId; +struct TracerID; class DatadogAgent : public Collector { public: @@ -65,7 +65,7 @@ class DatadogAgent : public Collector { public: DatadogAgent(const FinalizedDatadogAgentConfig&, const std::shared_ptr&, - const std::shared_ptr&, const TracerId& id, + const std::shared_ptr&, const TracerID& id, ConfigManager& config_manager); ~DatadogAgent(); diff --git a/src/datadog/datadog_agent_config.cpp b/src/datadog/datadog_agent_config.cpp index f19f356e..ad7154c9 100644 --- a/src/datadog/datadog_agent_config.cpp +++ b/src/datadog/datadog_agent_config.cpp @@ -133,7 +133,7 @@ Expected finalize_config( } if (rc_poll_interval_seconds <= 0) { - return Error{Error::DATADOG_AGENT_INVALID_CONFIGURATION, + return Error{Error::DATADOG_AGENT_INVALID_REMOTE_CONFIG_POLL_INTERVAL, "DatadogAgent: Remote Configuration poll interval must be a " "positive number of seconds."}; } diff --git a/src/datadog/error.h b/src/datadog/error.h index cce99e23..67accc6a 100644 --- a/src/datadog/error.h +++ b/src/datadog/error.h @@ -73,7 +73,7 @@ struct Error { CURL_DEADLINE_EXCEEDED_BEFORE_REQUEST_START = 48, DATADOG_AGENT_INVALID_REQUEST_TIMEOUT = 49, DATADOG_AGENT_INVALID_SHUTDOWN_TIMEOUT = 50, - DATADOG_AGENT_INVALID_CONFIGURATION = 51, + DATADOG_AGENT_INVALID_REMOTE_CONFIG_POLL_INTERVAL = 51, }; Code code; diff --git a/src/datadog/http_client.h b/src/datadog/http_client.h index 5d77610d..2931dde3 100644 --- a/src/datadog/http_client.h +++ b/src/datadog/http_client.h @@ -11,7 +11,6 @@ #include #include -#include "dict_writer.h" #include "error.h" #include "expected.h" #include "json_fwd.hpp" @@ -67,13 +66,5 @@ class HTTPClient { virtual ~HTTPClient() = default; }; -namespace httputil::header { - -inline void json_content_type_setter(DictWriter& headers) { - headers.set("Content-Type", "application/json"); -} - -} // namespace httputil::header - } // namespace tracing } // namespace datadog diff --git a/src/datadog/remote_config.cpp b/src/datadog/remote_config.cpp index 58784c84..d81dd6e8 100644 --- a/src/datadog/remote_config.cpp +++ b/src/datadog/remote_config.cpp @@ -1,12 +1,12 @@ #include "remote_config.h" -#include - +#include #include #include #include "base64.h" #include "json.hpp" +#include "random.h" #include "version.h" using namespace nlohmann::literals; @@ -15,6 +15,16 @@ namespace datadog { namespace tracing { namespace { +// The ".client.capabilities" field of the remote config request payload +// describes which parts of the library's configuration are supported for remote +// configuration. +// +// It's a bitset, 64 bits wide, where each bit indicates whether the library +// supports a particular feature for remote configuration. +// +// The bitset is encoded in the request as a JSON array of 8 integers, where +// each integer is one byte from the 64 bits. The bytes are in big-endian order +// within the array. enum CapabilitiesFlag : uint64_t { APM_TRACING_SAMPLE_RATE = 1 << 12, }; @@ -30,14 +40,15 @@ constexpr std::array capabilities_byte_array( return res; } -constexpr StringView k_apm_product = "APM_TRACING"; - constexpr std::array k_apm_capabilities = - capabilities_byte_array((uint64_t)0 | APM_TRACING_SAMPLE_RATE); + capabilities_byte_array(APM_TRACING_SAMPLE_RATE); + +constexpr StringView k_apm_product_path_substring = "/APM_TRACING/"; +constexpr StringView k_apm_product = "APM_TRACING"; } // namespace -void from_json(const nlohmann::json& j, ConfigUpdate& out) { +void from_json(const nlohmann::json& j, ConfigManager::Update& out) { if (auto sampling_rate_it = j.find("tracing_sampling_rate"); sampling_rate_it != j.cend()) { TraceSamplerConfig trace_sampler_cfg; @@ -47,10 +58,10 @@ void from_json(const nlohmann::json& j, ConfigUpdate& out) { } RemoteConfigurationManager::RemoteConfigurationManager( - const TracerId& tracer_id, ConfigManager& config_manager) + const TracerID& tracer_id, ConfigManager& config_manager) : tracer_id_(tracer_id), config_manager_(config_manager), - rc_id_(RuntimeID::generate()) {} + client_id_(uuid()) {} bool RemoteConfigurationManager::is_new_config( StringView config_path, const nlohmann::json& config_meta) { @@ -65,7 +76,7 @@ nlohmann::json RemoteConfigurationManager::make_request_payload() { // clang-format off auto j = nlohmann::json{ {"client", { - {"id", rc_id_.string()}, + {"id", client_id_}, {"products", nlohmann::json::array({k_apm_product})}, {"is_tracer", true}, {"capabilities", k_apm_capabilities}, @@ -109,7 +120,7 @@ void RemoteConfigurationManager::process_response(const nlohmann::json& json) { try { const auto targets = nlohmann::json::parse( - base64::decode(json.at("targets").get())); + base64_decode(json.at("targets").get())); state_.targets_version = targets.at("/signed/version"_json_pointer); state_.opaque_backend_state = @@ -138,18 +149,16 @@ void RemoteConfigurationManager::process_response(const nlohmann::json& json) { const auto& config_metadata = targets.at("/signed/targets"_json_pointer).at(config_path); - if (!contains(config_path, k_apm_product) || + if (!contains(config_path, k_apm_product_path_substring) || !is_new_config(config_path, config_metadata)) { continue; } - // NOTE(@dmehala): is it worth indexing first? const auto& target_files = json.at("/target_files"_json_pointer); auto target_it = std::find_if( target_files.cbegin(), target_files.cend(), - [&config_path](const auto& j) { - return j.at("/path"_json_pointer).template get() == - config_path; + [&config_path](const nlohmann::json& j) { + return j.at("/path"_json_pointer).get() == config_path; }); if (target_it == target_files.cend()) { @@ -159,7 +168,7 @@ void RemoteConfigurationManager::process_response(const nlohmann::json& json) { } const auto config_json = nlohmann::json::parse( - base64::decode(target_it.value().at("raw").get())); + base64_decode(target_it.value().at("raw").get())); const auto& targeted_service = config_json.at("service_target"); if (targeted_service.at("service").get() != @@ -173,7 +182,7 @@ void RemoteConfigurationManager::process_response(const nlohmann::json& json) { new_config.hash = config_metadata.at("/hashes/sha256"_json_pointer); new_config.id = config_json.at("id"); new_config.version = config_json.at("revision"); - new_config.content = ConfigUpdate(config_json.at("lib_config")); + new_config.content = ConfigManager::Update(config_json.at("lib_config")); apply_config(new_config); applied_config_[std::string{config_path}] = new_config; diff --git a/src/datadog/remote_config.h b/src/datadog/remote_config.h index b30ce7f6..7e29da53 100644 --- a/src/datadog/remote_config.h +++ b/src/datadog/remote_config.h @@ -1,5 +1,7 @@ #pragma once +// TODO: Document + #include #include "config_manager.h" @@ -24,18 +26,18 @@ class RemoteConfigurationManager { std::string id; std::string hash; std::size_t version; - ConfigUpdate content; + ConfigManager::Update content; }; - TracerId tracer_id_; + TracerID tracer_id_; ConfigManager& config_manager_; - RuntimeID rc_id_; + std::string client_id_; State state_; std::unordered_map applied_config_; public: - RemoteConfigurationManager(const TracerId& tracer_id, + RemoteConfigurationManager(const TracerID& tracer_id, ConfigManager& config_manager); nlohmann::json make_request_payload(); diff --git a/src/datadog/tracer.h b/src/datadog/tracer.h index d2556ee9..6c72faea 100644 --- a/src/datadog/tracer.h +++ b/src/datadog/tracer.h @@ -28,14 +28,14 @@ class DictReader; struct SpanConfig; class TraceSampler; class SpanSampler; -struct TracerId; +struct TracerID; class Tracer { std::shared_ptr logger_; std::shared_ptr collector_; std::shared_ptr defaults_; RuntimeID runtime_id_; - TracerId id_; + TracerID id_; std::shared_ptr tracer_telemetry_; std::shared_ptr span_sampler_; std::shared_ptr generator_; diff --git a/src/datadog/tracer_id.h b/src/datadog/tracer_id.h index e89f5534..dd4caf00 100644 --- a/src/datadog/tracer_id.h +++ b/src/datadog/tracer_id.h @@ -6,7 +6,7 @@ namespace datadog { namespace tracing { // Identify a tracer -struct TracerId { +struct TracerID { RuntimeID runtime_id; std::string service; std::string environment; diff --git a/src/datadog/tracer_telemetry.cpp b/src/datadog/tracer_telemetry.cpp index 88a01b6c..79bbb01c 100644 --- a/src/datadog/tracer_telemetry.cpp +++ b/src/datadog/tracer_telemetry.cpp @@ -10,7 +10,7 @@ namespace tracing { TracerTelemetry::TracerTelemetry(bool enabled, const Clock& clock, const std::shared_ptr& logger, - const TracerId& tracer_id) + const TracerID& tracer_id) : enabled_(enabled), clock_(clock), logger_(logger), diff --git a/src/datadog/tracer_telemetry.h b/src/datadog/tracer_telemetry.h index f40ec878..3cc64e57 100644 --- a/src/datadog/tracer_telemetry.h +++ b/src/datadog/tracer_telemetry.h @@ -44,7 +44,7 @@ class TracerTelemetry { bool debug_ = false; Clock clock_; std::shared_ptr logger_; - TracerId tracer_id_; + TracerID tracer_id_; std::string hostname_; uint64_t seq_id_ = 0; // This structure contains all the metrics that are exposed by tracer @@ -100,7 +100,7 @@ class TracerTelemetry { public: TracerTelemetry(bool enabled, const Clock& clock, const std::shared_ptr& logger, - const TracerId& tracer_id); + const TracerID& tracer_id); bool enabled() { return enabled_; }; // Provides access to the telemetry metrics for updating the values. // This value should not be stored. diff --git a/test/test_base64.cpp b/test/test_base64.cpp index 7c2b1f13..298b6577 100644 --- a/test/test_base64.cpp +++ b/test/test_base64.cpp @@ -5,28 +5,28 @@ #define BASE64_TEST(x) TEST_CASE(x, "[base64]") -namespace base64 = datadog::tracing::base64; +using namespace datadog::tracing; -BASE64_TEST("empty input") { CHECK(base64::decode("") == ""); } +BASE64_TEST("empty input") { CHECK(base64_decode("") == ""); } BASE64_TEST("invalid inputs") { SECTION("invalid characters") { - CHECK(base64::decode("InvalidData@") == ""); - CHECK(base64::decode("In@#*!^validData") == ""); + CHECK(base64_decode("InvalidData@") == ""); + CHECK(base64_decode("In@#*!^validData") == ""); } SECTION("single character without padding") { - CHECK(base64::decode("V") == ""); + CHECK(base64_decode("V") == ""); } } BASE64_TEST("unpadded input") { - CHECK(base64::decode("VGVzdGluZyBtdWx0aXBsZSBvZiA0IHBhZGRpbmcu") == + CHECK(base64_decode("VGVzdGluZyBtdWx0aXBsZSBvZiA0IHBhZGRpbmcu") == "Testing multiple of 4 padding."); } BASE64_TEST("padding") { - CHECK(base64::decode("bGlnaHQgdw==") == "light w"); - CHECK(base64::decode("bGlnaHQgd28=") == "light wo"); - CHECK(base64::decode("bGlnaHQgd29y") == "light wor"); + CHECK(base64_decode("bGlnaHQgdw==") == "light w"); + CHECK(base64_decode("bGlnaHQgd28=") == "light wo"); + CHECK(base64_decode("bGlnaHQgd29y") == "light wor"); } diff --git a/test/test_remote_config.cpp b/test/test_remote_config.cpp index 3b15ee1a..4e015c46 100644 --- a/test/test_remote_config.cpp +++ b/test/test_remote_config.cpp @@ -11,7 +11,7 @@ using namespace datadog::tracing; #define REMOTE_CONFIG_TEST(x) TEST_CASE(x, "[remote_config]") REMOTE_CONFIG_TEST("first payload") { - const TracerId tracer_id{/* runtime_id = */ RuntimeID::generate(), + const TracerID tracer_id{/* runtime_id = */ RuntimeID::generate(), /* service = */ "testsvc", /* environment = */ "test"}; @@ -43,7 +43,7 @@ REMOTE_CONFIG_TEST("first payload") { } REMOTE_CONFIG_TEST("response processing") { - const TracerId tracer_id{/* runtime_id = */ RuntimeID::generate(), + const TracerID tracer_id{/* runtime_id = */ RuntimeID::generate(), /* service = */ "testsvc", /* environment = */ "test"}; diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index 8ec4e300..7f0df1a1 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -410,7 +410,7 @@ TEST_CASE("TracerConfig::agent") { auto finalized = finalize_config(config); REQUIRE(!finalized); REQUIRE(finalized.error().code == - Error::DATADOG_AGENT_INVALID_CONFIGURATION); + Error::DATADOG_AGENT_INVALID_REMOTE_CONFIG_POLL_INTERVAL); } SECTION("cannot be negative") { @@ -418,7 +418,7 @@ TEST_CASE("TracerConfig::agent") { auto finalized = finalize_config(config); REQUIRE(!finalized); REQUIRE(finalized.error().code == - Error::DATADOG_AGENT_INVALID_CONFIGURATION); + Error::DATADOG_AGENT_INVALID_REMOTE_CONFIG_POLL_INTERVAL); } SECTION("override default value") { diff --git a/test/test_tracer_telemetry.cpp b/test/test_tracer_telemetry.cpp index 8affb195..9e691ad3 100644 --- a/test/test_tracer_telemetry.cpp +++ b/test/test_tracer_telemetry.cpp @@ -22,7 +22,7 @@ TEST_CASE("Tracer telemetry") { }; auto logger = std::make_shared(); - const TracerId tracer_id{/* runtime_id = */ RuntimeID::generate(), + const TracerID tracer_id{/* runtime_id = */ RuntimeID::generate(), /* service = */ "testsvc", /* environment = */ "test"};