diff --git a/BUILD.bazel b/BUILD.bazel index 585e6f21..5573b39b 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -24,6 +24,7 @@ cc_library( "src/datadog/msgpack.cpp", "src/datadog/net_util.cpp", "src/datadog/null_collector.cpp", + "src/datadog/optional.cpp", "src/datadog/parse_util.cpp", "src/datadog/propagation_styles.cpp", "src/datadog/rate.cpp", @@ -38,6 +39,7 @@ cc_library( "src/datadog/span_matcher.cpp", "src/datadog/span_sampler_config.cpp", "src/datadog/span_sampler.cpp", + "src/datadog/string_view.cpp", "src/datadog/tag_propagation.cpp", "src/datadog/tags.cpp", "src/datadog/threaded_event_scheduler.cpp", @@ -73,6 +75,7 @@ cc_library( "src/datadog/msgpack.h", "src/datadog/net_util.h", "src/datadog/null_collector.h", + "src/datadog/optional.h", "src/datadog/parse_util.h", "src/datadog/propagation_styles.h", "src/datadog/rate.h", @@ -87,6 +90,7 @@ cc_library( "src/datadog/span_matcher.h", "src/datadog/span_sampler_config.h", "src/datadog/span_sampler.h", + "src/datadog/string_view.h", "src/datadog/tag_propagation.h", "src/datadog/tags.h", "src/datadog/threaded_event_scheduler.h", @@ -103,7 +107,12 @@ cc_library( "-Werror", "-pedantic", "-std=c++17", + "-DDD_USE_ABSEIL_FOR_ENVOY", ], strip_include_prefix = "src/", visibility = ["//visibility:public"], + deps = [ + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:optional", + ], ) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 13f2b15a..a584ea4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ target_sources(dd_trace_cpp PRIVATE src/datadog/msgpack.cpp src/datadog/net_util.cpp src/datadog/null_collector.cpp + src/datadog/optional.cpp src/datadog/parse_util.cpp src/datadog/propagation_styles.cpp src/datadog/rate.cpp @@ -90,6 +91,7 @@ target_sources(dd_trace_cpp PRIVATE src/datadog/span_matcher.cpp src/datadog/span_sampler_config.cpp src/datadog/span_sampler.cpp + src/datadog/string_view.cpp src/datadog/tag_propagation.cpp src/datadog/tags.cpp src/datadog/threaded_event_scheduler.cpp @@ -131,6 +133,7 @@ target_sources(dd_trace_cpp PUBLIC src/datadog/msgpack.h src/datadog/net_util.h src/datadog/null_collector.h + src/datadog/optional.h src/datadog/parse_util.h src/datadog/propagation_styles.h src/datadog/rate.h @@ -145,6 +148,7 @@ target_sources(dd_trace_cpp PUBLIC src/datadog/span_matcher.h src/datadog/span_sampler_config.h src/datadog/span_sampler.h + src/datadog/string_view.h src/datadog/tag_propagation.h src/datadog/tags.h src/datadog/threaded_event_scheduler.h diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 00000000..6fe24089 --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,27 @@ +# The Bazel build is primarily for use by Envoy. +# +# Envoy forbids use of std::string_view and std::optional, preferring use of +# Abseil's absl::string_view and absl::optional instead. +# +# In the context of an Envoy build, the Abseil libraries point to whatever +# versions Envoy uses. +# +# To test this library's Bazel build independent of Envoy, we need to specify +# versions of the Abseil libraries. That is what this file is for. + +# These rules are based on , +# accessed December 6, 2022. +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "com_google_absl", + urls = ["https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip"], + sha256 = "aabf6c57e3834f8dc3873a927f37eaf69975d4b28117fc7427dfb1c661542a87", + strip_prefix = "abseil-cpp-98eb410c93ad059f9bba1bf43f5bb916fc92a5ea", +) + +http_archive( + name = "bazel_skylib", + urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz"], + sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728", +) diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel deleted file mode 100644 index e69de29b..00000000 diff --git a/src/datadog/collector.h b/src/datadog/collector.h index 97b3f0c4..64de43c0 100644 --- a/src/datadog/collector.h +++ b/src/datadog/collector.h @@ -11,11 +11,11 @@ // `response_handler` parameter to `Collector::send`. #include -#include #include #include "expected.h" #include "json_fwd.hpp" +#include "optional.h" namespace datadog { namespace tracing { diff --git a/src/datadog/collector_response.cpp b/src/datadog/collector_response.cpp index 523abec9..0b61a249 100644 --- a/src/datadog/collector_response.cpp +++ b/src/datadog/collector_response.cpp @@ -3,8 +3,7 @@ namespace datadog { namespace tracing { -std::string CollectorResponse::key(std::string_view service, - std::string_view environment) { +std::string CollectorResponse::key(StringView service, StringView environment) { std::string result; result += "service:"; result += service; diff --git a/src/datadog/collector_response.h b/src/datadog/collector_response.h index 76800d4b..7d72e8d5 100644 --- a/src/datadog/collector_response.h +++ b/src/datadog/collector_response.h @@ -14,17 +14,16 @@ // information. #include -#include #include #include "rate.h" +#include "string_view.h" namespace datadog { namespace tracing { struct CollectorResponse { - static std::string key(std::string_view service, - std::string_view environment); + static std::string key(StringView service, StringView environment); static const std::string key_of_default_rate; std::unordered_map sample_rate_by_key; }; diff --git a/src/datadog/curl.cpp b/src/datadog/curl.cpp index de66e5ee..c825490f 100644 --- a/src/datadog/curl.cpp +++ b/src/datadog/curl.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -22,6 +21,7 @@ #include "json.hpp" #include "logger.h" #include "parse_util.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -61,7 +61,7 @@ class CurlImpl { public: ~HeaderWriter(); curl_slist *release(); - void set(std::string_view key, std::string_view value) override; + void set(StringView key, StringView value) override; }; class HeaderReader : public DictReader { @@ -71,10 +71,9 @@ class CurlImpl { public: explicit HeaderReader( std::unordered_map *response_headers_lower); - std::optional lookup(std::string_view key) const override; - void visit( - const std::function - &visitor) const override; + Optional lookup(StringView key) const override; + void visit(const std::function + &visitor) const override; }; void run(); @@ -88,7 +87,7 @@ class CurlImpl { void *user_data); static bool is_non_whitespace(unsigned char); static char to_lower(unsigned char); - static std::string_view trim(std::string_view); + static StringView trim(StringView); public: explicit CurlImpl(const std::shared_ptr &logger); @@ -426,7 +425,7 @@ curl_slist *CurlImpl::HeaderWriter::release() { return list; } -void CurlImpl::HeaderWriter::set(std::string_view key, std::string_view value) { +void CurlImpl::HeaderWriter::set(StringView key, StringView value) { buffer_.clear(); buffer_ += key; buffer_ += ": "; @@ -439,8 +438,7 @@ CurlImpl::HeaderReader::HeaderReader( std::unordered_map *response_headers_lower) : response_headers_lower_(response_headers_lower) {} -std::optional CurlImpl::HeaderReader::lookup( - std::string_view key) const { +Optional CurlImpl::HeaderReader::lookup(StringView key) const { buffer_.clear(); std::transform(key.begin(), key.end(), std::back_inserter(buffer_), &to_lower); @@ -453,8 +451,8 @@ std::optional CurlImpl::HeaderReader::lookup( } void CurlImpl::HeaderReader::visit( - const std::function - &visitor) const { + const std::function &visitor) + const { for (const auto &[key, value] : *response_headers_lower_) { visitor(key, value); } diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index 659ea268..59e45186 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -21,7 +21,7 @@ namespace datadog { namespace tracing { namespace { -const std::string_view traces_api_path = "/v0.4/traces"; +const StringView traces_api_path = "/v0.4/traces"; HTTPClient::URL traces_endpoint(const HTTPClient::URL& agent_url) { auto traces_url = agent_url; @@ -49,10 +49,10 @@ Expected msgpack_encode( } std::variant parse_agent_traces_response( - std::string_view body) try { + StringView body) try { nlohmann::json response = nlohmann::json::parse(body); - std::string_view type = response.type_name(); + StringView type = response.type_name(); if (type != "object") { std::string message; message += @@ -66,7 +66,7 @@ std::variant parse_agent_traces_response( return message; } - const std::string_view sample_rates_property = "rate_by_service"; + const StringView sample_rates_property = "rate_by_service"; const auto found = response.find(sample_rates_property); if (found == response.end()) { return CollectorResponse{}; diff --git a/src/datadog/datadog_agent_config.cpp b/src/datadog/datadog_agent_config.cpp index b122e180..822031c0 100644 --- a/src/datadog/datadog_agent_config.cpp +++ b/src/datadog/datadog_agent_config.cpp @@ -11,8 +11,8 @@ namespace datadog { namespace tracing { -Expected DatadogAgentConfig::parse(std::string_view input) { - const std::string_view separator = "://"; +Expected DatadogAgentConfig::parse(StringView input) { + const StringView separator = "://"; const auto after_scheme = std::search(input.begin(), input.end(), separator.begin(), separator.end()); if (after_scheme == input.end()) { @@ -23,9 +23,9 @@ Expected DatadogAgentConfig::parse(std::string_view input) { return Error{Error::URL_MISSING_SEPARATOR, std::move(message)}; } - const std::string_view scheme = range(input.begin(), after_scheme); - const std::string_view supported[] = {"http", "https", "unix", "http+unix", - "https+unix"}; + const StringView scheme = range(input.begin(), after_scheme); + const StringView supported[] = {"http", "https", "unix", "http+unix", + "https+unix"}; const auto found = std::find(std::begin(supported), std::end(supported), scheme); if (found == std::end(supported)) { @@ -42,7 +42,7 @@ Expected DatadogAgentConfig::parse(std::string_view input) { return Error{Error::URL_UNSUPPORTED_SCHEME, std::move(message)}; } - const std::string_view authority_and_path = + const StringView authority_and_path = range(after_scheme + separator.size(), input.end()); // If the scheme is for unix domain sockets, then there's no way to // distinguish the path-to-socket from the path-to-resource. Some diff --git a/src/datadog/datadog_agent_config.h b/src/datadog/datadog_agent_config.h index b4c69a6e..18b1e690 100644 --- a/src/datadog/datadog_agent_config.h +++ b/src/datadog/datadog_agent_config.h @@ -14,11 +14,11 @@ #include #include #include -#include #include #include "expected.h" #include "http_client.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -50,7 +50,7 @@ struct DatadogAgentConfig { // How often, in milliseconds, to send batches of traces to the Datadog Agent. int flush_interval_milliseconds = 2000; - static Expected parse(std::string_view); + static Expected parse(StringView); }; class FinalizedDatadogAgentConfig { diff --git a/src/datadog/dict_reader.h b/src/datadog/dict_reader.h index 83195183..33452158 100644 --- a/src/datadog/dict_reader.h +++ b/src/datadog/dict_reader.h @@ -5,8 +5,9 @@ // context from externalized formats: HTTP headers, gRPC metadata, etc. #include -#include -#include + +#include "optional.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -17,13 +18,12 @@ class DictReader { // Return the value at the specified `key`, or return `std::nullopt` if there // is no value at `key`. - virtual std::optional lookup( - std::string_view key) const = 0; + virtual Optional lookup(StringView key) const = 0; // Invoke the specified `visitor` once for each key/value pair in this object. virtual void visit( - const std::function& - visitor) const = 0; + const std::function& visitor) + const = 0; }; } // namespace tracing diff --git a/src/datadog/dict_writer.h b/src/datadog/dict_writer.h index 05535151..572acdd0 100644 --- a/src/datadog/dict_writer.h +++ b/src/datadog/dict_writer.h @@ -8,7 +8,7 @@ // permitted to result from repeated invocations of `DictWriter::set` with the // same key. -#include +#include "string_view.h" namespace datadog { namespace tracing { @@ -20,7 +20,7 @@ class DictWriter { // Associate the specified `value` with the specified `key`. An // implementation may, but is not required to, overwrite any previous value at // `key`. - virtual void set(std::string_view key, std::string_view value) = 0; + virtual void set(StringView key, StringView value) = 0; }; } // namespace tracing diff --git a/src/datadog/environment.cpp b/src/datadog/environment.cpp index d9434c8b..571fbc69 100644 --- a/src/datadog/environment.cpp +++ b/src/datadog/environment.cpp @@ -8,15 +8,15 @@ namespace datadog { namespace tracing { namespace environment { -std::string_view name(Variable variable) { return variable_names[variable]; } +StringView name(Variable variable) { return variable_names[variable]; } -std::optional lookup(Variable variable) { +Optional lookup(Variable variable) { const char *name = variable_names[variable]; const char *value = std::getenv(name); if (!value) { return std::nullopt; } - return std::string_view{value}; + return StringView{value}; } nlohmann::json to_json() { diff --git a/src/datadog/environment.h b/src/datadog/environment.h index 133375a0..9e878af9 100644 --- a/src/datadog/environment.h +++ b/src/datadog/environment.h @@ -14,10 +14,9 @@ // // `lookup` retrieves the value of `Variable` in the environment. -#include -#include - #include "json_fwd.hpp" +#include "optional.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -66,11 +65,11 @@ inline const char* const variable_names[] = { #undef LIST_ENVIRONMENT_VARIABLES // Return the name of the specified environment `variable`. -std::string_view name(Variable variable); +StringView name(Variable variable); // Return the value of the specified environment `variable`, or return // `std::nullptr` if that variable is not set in the environment. -std::optional lookup(Variable variable); +Optional lookup(Variable variable); nlohmann::json to_json(); diff --git a/src/datadog/error.cpp b/src/datadog/error.cpp index 1e0f62e8..7f318595 100644 --- a/src/datadog/error.cpp +++ b/src/datadog/error.cpp @@ -10,7 +10,7 @@ std::ostream& operator<<(std::ostream& stream, const Error& error) { return stream << "[error code " << int(error.code) << "] " << error.message; } -Error Error::with_prefix(std::string_view prefix) const { +Error Error::with_prefix(StringView prefix) const { std::string new_message{prefix.begin(), prefix.end()}; new_message += message; return Error{code, std::move(new_message)}; diff --git a/src/datadog/error.h b/src/datadog/error.h index 76a79c24..f19eae01 100644 --- a/src/datadog/error.h +++ b/src/datadog/error.h @@ -12,7 +12,8 @@ #include #include -#include + +#include "string_view.h" namespace datadog { namespace tracing { @@ -71,7 +72,7 @@ struct Error { Code code; std::string message; - Error with_prefix(std::string_view) const; + Error with_prefix(StringView) const; }; std::ostream& operator<<(std::ostream&, const Error&); diff --git a/src/datadog/expected.h b/src/datadog/expected.h index 7ac20d42..4597cc2a 100644 --- a/src/datadog/expected.h +++ b/src/datadog/expected.h @@ -10,7 +10,7 @@ // ------------- // The following excerpt demonstrates the intended usage of `Expected`: // -// Expected parse_integer(std::string_view name); +// Expected parse_integer(StringView name); // // // int main() { @@ -35,12 +35,12 @@ // // `Expected` is like `Expected`, except that if the value is not an // error then it cannot be "dereferenced" with `operator*`, i.e. it is analogous -// to `std::optional` (and is implemented as such). +// to `Optional` (and is implemented as such). -#include #include #include "error.h" +#include "optional.h" namespace datadog { namespace tracing { @@ -189,7 +189,7 @@ const Error* Expected::if_error() const& { template <> class Expected { - std::optional data_; + Optional data_; public: Expected() = default; diff --git a/src/datadog/glob.cpp b/src/datadog/glob.cpp index 29925793..2f3c4975 100644 --- a/src/datadog/glob.cpp +++ b/src/datadog/glob.cpp @@ -5,7 +5,7 @@ namespace datadog { namespace tracing { -bool glob_match(std::string_view pattern, std::string_view subject) { +bool glob_match(StringView pattern, StringView subject) { // This is a backtracking implementation of the glob matching algorithm. // The glob pattern language supports `*` and `?`, but no escape sequences. // diff --git a/src/datadog/glob.h b/src/datadog/glob.h index 7d8fdaff..77dcb574 100644 --- a/src/datadog/glob.h +++ b/src/datadog/glob.h @@ -11,7 +11,7 @@ // The patterns are here called "glob patterns," though they are different from // the patterns used in Unix shells. -#include +#include "string_view.h" namespace datadog { namespace tracing { @@ -19,7 +19,7 @@ namespace tracing { // Return whether the specified `subject` matches the specified glob `pattern`, // i.e. whether `subject` is a member of the set of strings represented by the // glob `pattern`. -bool glob_match(std::string_view pattern, std::string_view subject); +bool glob_match(StringView pattern, StringView subject); } // namespace tracing } // namespace datadog diff --git a/src/datadog/http_client.h b/src/datadog/http_client.h index 6b7decd7..df340d43 100644 --- a/src/datadog/http_client.h +++ b/src/datadog/http_client.h @@ -10,11 +10,11 @@ #include #include -#include #include "error.h" #include "expected.h" #include "json_fwd.hpp" +#include "optional.h" namespace datadog { namespace tracing { diff --git a/src/datadog/logger.cpp b/src/datadog/logger.cpp index 71e8c388..db459d60 100644 --- a/src/datadog/logger.cpp +++ b/src/datadog/logger.cpp @@ -9,7 +9,7 @@ void Logger::log_error(const Error& error) { log_error([&](auto& stream) { stream << error; }); } -void Logger::log_error(std::string_view message) { +void Logger::log_error(StringView message) { log_error([&](auto& stream) { stream << message; }); } diff --git a/src/datadog/logger.h b/src/datadog/logger.h index de2396ea..bd5c5400 100644 --- a/src/datadog/logger.h +++ b/src/datadog/logger.h @@ -32,7 +32,7 @@ // return; // } // -// The other overload accepts a `std::string_view`: +// The other overload accepts a `StringView`: // // if (!success) { // logger.log_error("Something went wrong with the frobnication."); @@ -41,7 +41,8 @@ #include #include -#include + +#include "string_view.h" namespace datadog { namespace tracing { @@ -58,7 +59,7 @@ class Logger { virtual void log_startup(const LogFunc&) = 0; virtual void log_error(const Error&); - virtual void log_error(std::string_view); + virtual void log_error(StringView); }; } // namespace tracing diff --git a/src/datadog/msgpack.cpp b/src/datadog/msgpack.cpp index 6ea5fc7a..05bef574 100644 --- a/src/datadog/msgpack.cpp +++ b/src/datadog/msgpack.cpp @@ -20,7 +20,7 @@ constexpr auto STR32 = std::byte(0xDB); constexpr auto UINT64 = std::byte(0xCF); } // namespace types -std::string make_overflow_message(std::string_view type, std::size_t actual, +std::string make_overflow_message(StringView type, std::size_t actual, std::size_t max) { std::string message; message += "Cannot msgpack encode "; @@ -93,7 +93,7 @@ void pack_double(std::string& buffer, double value) { push_number_big_endian(buffer, memory.as_integer); } -Expected pack_string(std::string& buffer, std::string_view value) { +Expected pack_string(std::string& buffer, StringView value) { const auto size = value.size(); const auto max = std::numeric_limits::max(); if (size > max) { diff --git a/src/datadog/msgpack.h b/src/datadog/msgpack.h index 812a6c57..85510beb 100644 --- a/src/datadog/msgpack.h +++ b/src/datadog/msgpack.h @@ -14,10 +14,10 @@ #include #include #include -#include #include #include "expected.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -29,7 +29,7 @@ void pack_integer(std::string& buffer, std::int32_t value); void pack_double(std::string& buffer, double value); -Expected pack_string(std::string& buffer, std::string_view value); +Expected pack_string(std::string& buffer, StringView value); Expected pack_array(std::string& buffer, std::size_t size); diff --git a/src/datadog/net_util.cpp b/src/datadog/net_util.cpp index ab4127de..9c6e6e58 100644 --- a/src/datadog/net_util.cpp +++ b/src/datadog/net_util.cpp @@ -9,7 +9,7 @@ namespace datadog { namespace tracing { -std::optional get_hostname() { +Optional get_hostname() { char buffer[256]; if (::gethostname(buffer, sizeof buffer)) { return std::nullopt; diff --git a/src/datadog/net_util.h b/src/datadog/net_util.h index e44486c7..97dce891 100644 --- a/src/datadog/net_util.h +++ b/src/datadog/net_util.h @@ -2,13 +2,14 @@ // This component provides networking-related miscellanea. -#include #include +#include "optional.h" + namespace datadog { namespace tracing { -std::optional get_hostname(); +Optional get_hostname(); } // namespace tracing } // namespace datadog diff --git a/src/datadog/optional.cpp b/src/datadog/optional.cpp new file mode 100644 index 00000000..16d841e3 --- /dev/null +++ b/src/datadog/optional.cpp @@ -0,0 +1 @@ +#include "optional.h" diff --git a/src/datadog/optional.h b/src/datadog/optional.h new file mode 100644 index 00000000..d1fc76f9 --- /dev/null +++ b/src/datadog/optional.h @@ -0,0 +1,48 @@ +#pragma once + +// One of the clients of this library is Envoy, a service (HTTP) proxy. +// +// Envoy uses Abseil as its base C++ library, and additionally builds in C++17 +// mode. Abseil has a build option to forward its `std::string_view` and +// `std::optional` equivalents to the actual standard types when C++17 is +// available. +// +// Envoy does not use this Abseil build option, due to incomplete support for +// the C++17 standard library on iOS 11. +// +// As a result, Envoy forbids use of `std::string_view` and `std::optional`, +// instead preferring Abseil's `absl::string_view` and `absl::optional`. +// +// This presents a problem for this library, since we use `std::string_view` +// and `std::optional` in the exported interface, i.e. in header files. +// +// As a workaround, Bazel (the build tool used by Envoy) builds of this library +// will define the `DD_USE_ABSEIL_FOR_ENVOY` preprocessor macro. When this +// macro is defined, the library-specific `StringView` and `Optional` aliases +// will refer to the Abseil types. When the macro is not defined, the +// library-specific aliases will refer to the standard types. +// +// This file defines `datadog::tracing::Optional`, a type template that is an +// alias for either `std::optional` or `absl::optional`. + +#ifdef DD_USE_ABSEIL_FOR_ENVOY +// Abseil examples, including usage in Envoy, include Abseil headers in quoted +// style instead of angle bracket style, per Bazel's default build behavior. +#include "absl/types/optional.h" +#else +#include +#endif // defined DD_USE_ABSEIL_FOR_ENVOY + +namespace datadog { +namespace tracing { + +#ifdef DD_USE_ABSEIL_FOR_ENVOY +template +using Optional = absl::optional; +#else +template +using Optional = std::optional; +#endif // defined DD_USE_ABSEIL_FOR_ENVOY + +} // namespace tracing +} // namespace datadog diff --git a/src/datadog/parse_util.cpp b/src/datadog/parse_util.cpp index 21e714c1..23731963 100644 --- a/src/datadog/parse_util.cpp +++ b/src/datadog/parse_util.cpp @@ -15,8 +15,7 @@ namespace tracing { namespace { template -Expected parse_integer(std::string_view input, int base, - std::string_view kind) { +Expected parse_integer(StringView input, int base, StringView kind) { Integer value; input = strip(input); const auto status = std::from_chars(input.begin(), input.end(), value, base); @@ -45,7 +44,7 @@ Expected parse_integer(std::string_view input, int base, } // namespace -std::string_view strip(std::string_view input) { +StringView strip(StringView input) { const auto not_whitespace = [](unsigned char ch) { return !std::isspace(ch); }; @@ -58,18 +57,18 @@ std::string_view strip(std::string_view input) { assert(begin <= end); - return std::string_view{begin, std::size_t(end - begin)}; + return StringView{begin, std::size_t(end - begin)}; } -Expected parse_uint64(std::string_view input, int base) { +Expected parse_uint64(StringView input, int base) { return parse_integer(input, base, "64-bit unsigned"); } -Expected parse_int(std::string_view input, int base) { +Expected parse_int(StringView input, int base) { return parse_integer(input, base, "int"); } -Expected parse_double(std::string_view input) { +Expected parse_double(StringView input) { // This function uses a different technique from `parse_integer`, because // some compilers with _partial_ support for C++17 do not implement the // floating point portions of `std::from_chars`: @@ -100,7 +99,7 @@ Expected parse_double(std::string_view input) { return value; } -bool starts_with(std::string_view subject, std::string_view prefix) { +bool starts_with(StringView subject, StringView prefix) { if (prefix.size() > subject.size()) { return false; } diff --git a/src/datadog/parse_util.h b/src/datadog/parse_util.h index 718834b0..38df4bd5 100644 --- a/src/datadog/parse_util.h +++ b/src/datadog/parse_util.h @@ -4,37 +4,37 @@ #include #include -#include #include "expected.h" +#include "string_view.h" namespace datadog { namespace tracing { // Return a `string_view` over the specified range of characters `[begin, end)`. -inline std::string_view range(const char* begin, const char* end) { - return std::string_view{begin, std::size_t(end - begin)}; +inline StringView range(const char* begin, const char* end) { + return StringView{begin, std::size_t(end - begin)}; } // Remove leading and trailing whitespace (as determined by `std::isspace`) from // the specified `input`. -std::string_view strip(std::string_view input); +StringView strip(StringView input); // Return a non-negative integer parsed from the specified `input` with respect // to the specified `base`, or return an `Error` if no such integer can be // parsed. It is an error unless all of `input` is consumed by the parse. // Leading and trailing whitespace are not ignored. -Expected parse_uint64(std::string_view input, int base); -Expected parse_int(std::string_view input, int base); +Expected parse_uint64(StringView input, int base); +Expected parse_int(StringView input, int base); // Return a floating point number parsed from the specified `input`, or return // an `Error` if not such number can be parsed. It is an error unless all of // `input` is consumed by the parse. Leading and trailing whitespace are not // ignored. -Expected parse_double(std::string_view input); +Expected parse_double(StringView input); // Return whether the specified `prefix` is a prefix of the specified `subject`. -bool starts_with(std::string_view subject, std::string_view prefix); +bool starts_with(StringView subject, StringView prefix); } // namespace tracing } // namespace datadog diff --git a/src/datadog/sampling_decision.h b/src/datadog/sampling_decision.h index 6addfab0..0e2fe1cf 100644 --- a/src/datadog/sampling_decision.h +++ b/src/datadog/sampling_decision.h @@ -4,8 +4,7 @@ // keep/drop sampling decision (for either trace sampling or span sampling) and // contains supporting information about the reason for the decision. -#include - +#include "optional.h" #include "rate.h" #include "sampling_mechanism.h" @@ -33,15 +32,15 @@ struct SamplingDecision { // "drop." int priority; // See `sampling_mechanism.h`. - std::optional mechanism; + Optional mechanism; // The sample rate associated with this decision, if any. - std::optional configured_rate; + Optional configured_rate; // The effective rate of the limiter consulted in this decision, if any. A // limiter's effective rate is `num_allowed / num_asked`. - std::optional limiter_effective_rate; + Optional limiter_effective_rate; // The per-second maximum allowed number of "keeps" configured for the limiter // consulted in this decision, if any. - std::optional limiter_max_per_second; + Optional limiter_max_per_second; // The provenance of this decision. Origin origin; }; diff --git a/src/datadog/span.cpp b/src/datadog/span.cpp index 1c75e061..ce3f4984 100644 --- a/src/datadog/span.cpp +++ b/src/datadog/span.cpp @@ -1,13 +1,13 @@ #include "span.h" #include -#include #include -#include #include "dict_writer.h" +#include "optional.h" #include "span_config.h" #include "span_data.h" +#include "string_view.h" #include "tags.h" #include "trace_segment.h" @@ -64,7 +64,7 @@ std::uint64_t Span::id() const { return data_->span_id; } std::uint64_t Span::trace_id() const { return data_->trace_id; } -std::optional Span::parent_id() const { +Optional Span::parent_id() const { if (data_->parent_id == 0) { return std::nullopt; } @@ -75,7 +75,7 @@ TimePoint Span::start_time() const { return data_->start; } bool Span::error() const { return data_->error; } -std::optional Span::lookup_tag(std::string_view name) const { +Optional Span::lookup_tag(StringView name) const { if (tags::is_internal(name)) { return std::nullopt; } @@ -87,27 +87,23 @@ std::optional Span::lookup_tag(std::string_view name) const { return found->second; } -void Span::set_tag(std::string_view name, std::string_view value) { +void Span::set_tag(StringView name, StringView value) { if (!tags::is_internal(name)) { data_->tags.insert_or_assign(std::string(name), std::string(value)); } } -void Span::remove_tag(std::string_view name) { +void Span::remove_tag(StringView name) { if (!tags::is_internal(name)) { data_->tags.erase(std::string(name)); } } -void Span::set_service_name(std::string_view service) { - data_->service = service; -} +void Span::set_service_name(StringView service) { data_->service = service; } -void Span::set_service_type(std::string_view type) { - data_->service_type = type; -} +void Span::set_service_type(StringView type) { data_->service_type = type; } -void Span::set_resource_name(std::string_view resource) { +void Span::set_resource_name(StringView resource) { data_->resource = resource; } @@ -119,22 +115,22 @@ void Span::set_error(bool is_error) { } } -void Span::set_error_message(std::string_view message) { +void Span::set_error_message(StringView message) { data_->error = true; data_->tags.insert_or_assign("error.msg", std::string(message)); } -void Span::set_error_type(std::string_view type) { +void Span::set_error_type(StringView type) { data_->error = true; data_->tags.insert_or_assign("error.type", std::string(type)); } -void Span::set_error_stack(std::string_view type) { +void Span::set_error_stack(StringView type) { data_->error = true; data_->tags.insert_or_assign("error.stack", std::string(type)); } -void Span::set_name(std::string_view value) { data_->name = value; } +void Span::set_name(StringView value) { data_->name = value; } void Span::set_end_time(std::chrono::steady_clock::time_point end_time) { end_time_ = end_time; diff --git a/src/datadog/span.h b/src/datadog/span.h index bba41190..4d7512fe 100644 --- a/src/datadog/span.h +++ b/src/datadog/span.h @@ -43,12 +43,12 @@ #include #include #include -#include -#include #include "clock.h" #include "error.h" #include "id_generator.h" +#include "optional.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -63,7 +63,7 @@ class Span { SpanData* data_; IDGenerator generate_span_id_; Clock clock_; - std::optional end_time_; + Optional end_time_; public: // Create a span whose properties are stored in the specified `data` and that @@ -98,7 +98,7 @@ class Span { std::uint64_t trace_id() const; // Return the ID of this span's parent span, or return null if this span has // no parent. - std::optional parent_id() const; + Optional parent_id() const; // Return the start time of this span. TimePoint start_time() const; // Return whether this span has been marked as an error having occurred during @@ -107,36 +107,36 @@ class Span { // Return the value of the tag having the specified `name`, or return null if // there is no such tag. - std::optional lookup_tag(std::string_view name) const; + Optional lookup_tag(StringView name) const; // Overwrite the tag having the specified `name` so that it has the specified // `value`, or create a new tag. - void set_tag(std::string_view name, std::string_view value); + void set_tag(StringView name, StringView value); // Delete the tag having the specified `name` if it exists. - void remove_tag(std::string_view name); + void remove_tag(StringView name); // Set the name of the service associated with this span, e.g. // "ingress-nginx-useast1". - void set_service_name(std::string_view); + void set_service_name(StringView); // Set the type of the service associated with this span, e.g. "web". - void set_service_type(std::string_view); + void set_service_type(StringView); // Set the name of the operation that this span represents, e.g. // "handle.request", "execute.query", or "healthcheck". - void set_name(std::string_view); + void set_name(StringView); // Set the name of the resource associated with the operation that this span // represents, e.g. "/api/v1/info" or "select count(*) from users". - void set_resource_name(std::string_view); + void set_resource_name(StringView); // Set whether an error occurred during the extent of this span. If `false`, // then error-related tags will be removed from this span as well. void set_error(bool); // Associate a message with the error that occurred during the extent of this // span. This also has the effect of calling `set_error(true)`. - void set_error_message(std::string_view); + void set_error_message(StringView); // Associate an error type with the error that occurred during the extent of // this span. This also has the effect of calling `set_error(true)`. - void set_error_type(std::string_view); + void set_error_type(StringView); // Associate a call stack with the error that occurred during the extent of // this span. This also has the effect of calling `set_error(true)`. - void set_error_stack(std::string_view); + void set_error_stack(StringView); // Set end time of this span. Doing so will override the default behavior of // using the current time in the destructor. void set_end_time(std::chrono::steady_clock::time_point); diff --git a/src/datadog/span_config.h b/src/datadog/span_config.h index f9675e41..3fb0fc1d 100644 --- a/src/datadog/span_config.h +++ b/src/datadog/span_config.h @@ -13,24 +13,24 @@ // when no corresponding property is specified in a `SpanConfig` argument. // See `SpanData::apply_config`. -#include #include #include #include #include "clock.h" +#include "optional.h" namespace datadog { namespace tracing { struct SpanConfig { - std::optional service; - std::optional service_type; - std::optional version; - std::optional environment; - std::optional name; - std::optional resource; - std::optional start; + Optional service; + Optional service_type; + Optional version; + Optional environment; + Optional name; + Optional resource; + Optional start; std::unordered_map tags; }; diff --git a/src/datadog/span_data.cpp b/src/datadog/span_data.cpp index 2b701223..538886af 100644 --- a/src/datadog/span_data.cpp +++ b/src/datadog/span_data.cpp @@ -1,19 +1,19 @@ #include "span_data.h" #include -#include #include "error.h" #include "msgpack.h" #include "span_config.h" #include "span_defaults.h" +#include "string_view.h" #include "tags.h" namespace datadog { namespace tracing { namespace { -std::optional lookup( +Optional lookup( const std::string& key, const std::unordered_map& map) { const auto found = map.find(key); @@ -25,11 +25,11 @@ std::optional lookup( } // namespace -std::optional SpanData::environment() const { +Optional SpanData::environment() const { return lookup(tags::environment, tags); } -std::optional SpanData::version() const { +Optional SpanData::version() const { return lookup(tags::version, tags); } diff --git a/src/datadog/span_data.h b/src/datadog/span_data.h index aa1b2fc3..3e9b00fa 100644 --- a/src/datadog/span_data.h +++ b/src/datadog/span_data.h @@ -5,13 +5,13 @@ #include #include -#include #include -#include #include #include "clock.h" #include "expected.h" +#include "optional.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -33,8 +33,8 @@ struct SpanData { std::unordered_map tags; std::unordered_map numeric_tags; - std::optional environment() const; - std::optional version() const; + Optional environment() const; + Optional version() const; // Modify the properties of this object to honor the specified `config` and // `defaults`. The properties of `config`, if set, override the properties of diff --git a/src/datadog/span_matcher.cpp b/src/datadog/span_matcher.cpp index 0121be1e..7778ab5c 100644 --- a/src/datadog/span_matcher.cpp +++ b/src/datadog/span_matcher.cpp @@ -1,18 +1,18 @@ #include "span_matcher.h" #include -#include #include "error.h" #include "glob.h" #include "json.hpp" +#include "optional.h" #include "span_data.h" namespace datadog { namespace tracing { namespace { -bool is_match(std::string_view pattern, std::string_view subject) { +bool is_match(StringView pattern, StringView subject) { // Since "*" is the default pattern, optimize for that case. return pattern == "*" || glob_match(pattern, subject); } @@ -52,8 +52,8 @@ Expected SpanMatcher::from_json(const nlohmann::json& json) { } const auto check_property_type = - [&](std::string_view property, const nlohmann::json& value, - std::string_view expected_type) -> std::optional { + [&](StringView property, const nlohmann::json& value, + StringView expected_type) -> Optional { type = value.type_name(); if (type == expected_type) { return std::nullopt; diff --git a/src/datadog/span_sampler_config.cpp b/src/datadog/span_sampler_config.cpp index 7e767381..e6da8200 100644 --- a/src/datadog/span_sampler_config.cpp +++ b/src/datadog/span_sampler_config.cpp @@ -16,8 +16,8 @@ namespace { // `env_var` is the name of the environment variable from which `rules_raw` was // obtained. It's used for error messages. -Expected> parse_rules( - std::string_view rules_raw, std::string_view env_var) { +Expected> parse_rules(StringView rules_raw, + StringView env_var) { std::vector rules; nlohmann::json json_rules; @@ -46,7 +46,7 @@ Expected> parse_rules( return Error{Error::SPAN_SAMPLING_RULES_WRONG_TYPE, std::move(message)}; } - const std::unordered_set allowed_properties{ + const std::unordered_set allowed_properties{ "service", "name", "resource", "tags", "sample_rate", "max_per_second"}; for (const auto &json_rule : json_rules) { diff --git a/src/datadog/span_sampler_config.h b/src/datadog/span_sampler_config.h index eb8de135..0eaa81e1 100644 --- a/src/datadog/span_sampler_config.h +++ b/src/datadog/span_sampler_config.h @@ -7,11 +7,11 @@ // `SpanSamplerConfig` is specified as the `span_sampler` property of // `TracerConfig`. -#include #include #include "expected.h" #include "json_fwd.hpp" +#include "optional.h" #include "rate.h" #include "span_matcher.h" @@ -23,7 +23,7 @@ class Logger; struct SpanSamplerConfig { struct Rule : public SpanMatcher { double sample_rate = 1.0; - std::optional max_per_second; + Optional max_per_second; Rule(const SpanMatcher&); Rule() = default; @@ -45,7 +45,7 @@ class FinalizedSpanSamplerConfig { public: struct Rule : public SpanMatcher { Rate sample_rate; - std::optional max_per_second; + Optional max_per_second; }; std::vector rules; diff --git a/src/datadog/string_view.cpp b/src/datadog/string_view.cpp new file mode 100644 index 00000000..fa834413 --- /dev/null +++ b/src/datadog/string_view.cpp @@ -0,0 +1 @@ +#include "string_view.h" diff --git a/src/datadog/string_view.h b/src/datadog/string_view.h new file mode 100644 index 00000000..306fd233 --- /dev/null +++ b/src/datadog/string_view.h @@ -0,0 +1,46 @@ +#pragma once + +// One of the clients of this library is Envoy, a service (HTTP) proxy. +// +// Envoy uses Abseil as its base C++ library, and additionally builds in C++17 +// mode. Abseil has a build option to forward its `std::string_view` and +// `std::optional` equivalents to the actual standard types when C++17 is +// available. +// +// Envoy does not use this Abseil build option, due to incomplete support for +// the C++17 standard library on iOS 11. +// +// As a result, Envoy forbids use of `std::string_view` and `std::optional`, +// instead preferring Abseil's `absl::string_view` and `absl::optional`. +// +// This presents a problem for this library, since we use `std::string_view` +// and `std::optional` in the exported interface, i.e. in header files. +// +// As a workaround, Bazel (the build tool used by Envoy) builds of this library +// will define the `DD_USE_ABSEIL_FOR_ENVOY` preprocessor macro. When this +// macro is defined, the library-specific `StringView` and `Optional` aliases +// will refer to the Abseil types. When the macro is not defined, the +// library-specific aliases will refer to the standard types. +// +// This file defines `datadog::tracing::StringView`, a type that is an alias +// for either `std::string_view` or `absl::string_view`. + +#ifdef DD_USE_ABSEIL_FOR_ENVOY +// Abseil examples, including usage in Envoy, include Abseil headers in quoted +// style instead of angle bracket style, per Bazel's default build behavior. +#include "absl/strings/string_view.h" +#else +#include +#endif // defined DD_USE_ABSEIL_FOR_ENVOY + +namespace datadog { +namespace tracing { + +#ifdef DD_USE_ABSEIL_FOR_ENVOY +using StringView = absl::string_view; +#else +using StringView = std::string_view; +#endif // defined DD_USE_ABSEIL_FOR_ENVOY + +} // namespace tracing +} // namespace datadog diff --git a/src/datadog/tag_propagation.cpp b/src/datadog/tag_propagation.cpp index c740d0e4..03dbb70b 100644 --- a/src/datadog/tag_propagation.cpp +++ b/src/datadog/tag_propagation.cpp @@ -33,7 +33,7 @@ namespace { // `entry`. Return an `Error` if an error occurs. Expected decode_tag( std::unordered_map& destination, - std::string_view entry) { + StringView entry) { const auto separator = std::find(entry.begin(), entry.end(), '='); if (separator == entry.end()) { std::string message; @@ -42,16 +42,16 @@ Expected decode_tag( return Error{Error::MALFORMED_TRACE_TAGS, std::move(message)}; } - const std::string_view key = range(entry.begin(), separator); - const std::string_view value = range(separator + 1, entry.end()); + const StringView key = range(entry.begin(), separator); + const StringView value = range(separator + 1, entry.end()); // Among duplicate keys, most recent value wins. destination.insert_or_assign(std::string(key), std::string(value)); return std::nullopt; } -void append_tag(std::string& serialized_tags, std::string_view tag_key, - std::string_view tag_value) { +void append_tag(std::string& serialized_tags, StringView tag_key, + StringView tag_value) { serialized_tags.append(tag_key.begin(), tag_key.end()); serialized_tags += '='; serialized_tags.append(tag_value.begin(), tag_value.end()); @@ -60,7 +60,7 @@ void append_tag(std::string& serialized_tags, std::string_view tag_key, } // namespace Expected> decode_tags( - std::string_view header_value) { + StringView header_value) { std::unordered_map tags; auto iter = header_value.begin(); diff --git a/src/datadog/tag_propagation.h b/src/datadog/tag_propagation.h index 696c9105..b518716d 100644 --- a/src/datadog/tag_propagation.h +++ b/src/datadog/tag_propagation.h @@ -12,10 +12,10 @@ // "x-datadog-tags" header format. #include -#include #include #include "expected.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -23,7 +23,7 @@ namespace tracing { // Return a name->value mapping of tags parsed from the specified // `header_value`, or return an `Error` if an error occurs. Expected> decode_tags( - std::string_view header_value); + StringView header_value); // Serialize the specified `trace_tags` into the propagation format and return // the resulting string. diff --git a/src/datadog/tags.cpp b/src/datadog/tags.cpp index 538a6796..4a3ebdd0 100644 --- a/src/datadog/tags.cpp +++ b/src/datadog/tags.cpp @@ -31,9 +31,7 @@ const std::string span_sampling_limit = "_dd.span_sampling.max_per_second"; } // namespace internal -bool is_internal(std::string_view tag_name) { - return starts_with(tag_name, "_dd."); -} +bool is_internal(StringView tag_name) { return starts_with(tag_name, "_dd."); } } // namespace tags } // namespace tracing diff --git a/src/datadog/tags.h b/src/datadog/tags.h index 43bad9ab..ad79c866 100644 --- a/src/datadog/tags.h +++ b/src/datadog/tags.h @@ -4,7 +4,8 @@ // meaning. #include -#include + +#include "string_view.h" namespace datadog { namespace tracing { @@ -35,7 +36,7 @@ extern const std::string span_sampling_limit; // Return whether the specified `tag_name` is reserved for use internal to this // library. -bool is_internal(std::string_view tag_name); +bool is_internal(StringView tag_name); } // namespace tags } // namespace tracing diff --git a/src/datadog/trace_sampler.h b/src/datadog/trace_sampler.h index d48a36c0..f93f9b14 100644 --- a/src/datadog/trace_sampler.h +++ b/src/datadog/trace_sampler.h @@ -84,13 +84,13 @@ // `DD_TRACE_RATE_LIMIT` environment variable. #include -#include #include #include #include "clock.h" #include "json_fwd.hpp" #include "limiter.h" +#include "optional.h" #include "rate.h" #include "trace_sampler_config.h" @@ -104,7 +104,7 @@ struct SpanData; class TraceSampler { std::mutex mutex_; - std::optional collector_default_sample_rate_; + Optional collector_default_sample_rate_; std::unordered_map collector_sample_rates_; std::vector rules_; diff --git a/src/datadog/trace_sampler_config.cpp b/src/datadog/trace_sampler_config.cpp index bc2c3334..d0676603 100644 --- a/src/datadog/trace_sampler_config.cpp +++ b/src/datadog/trace_sampler_config.cpp @@ -47,7 +47,7 @@ Expected finalize_config( return Error{Error::TRACE_SAMPLING_RULES_WRONG_TYPE, std::move(message)}; } - const std::unordered_set allowed_properties{ + const std::unordered_set allowed_properties{ "service", "name", "resource", "tags", "sample_rate"}; for (const auto &json_rule : json_rules) { diff --git a/src/datadog/trace_sampler_config.h b/src/datadog/trace_sampler_config.h index efcac75f..80b35e9c 100644 --- a/src/datadog/trace_sampler_config.h +++ b/src/datadog/trace_sampler_config.h @@ -7,11 +7,11 @@ // `TraceSamplerConfig` is specified as the `trace_sampler` property of // `TracerConfig`. -#include #include #include "expected.h" #include "json_fwd.hpp" +#include "optional.h" #include "rate.h" #include "span_matcher.h" @@ -26,7 +26,7 @@ struct TraceSamplerConfig { Rule() = default; }; - std::optional sample_rate; + Optional sample_rate; std::vector rules; double max_per_second = 200; }; diff --git a/src/datadog/trace_segment.cpp b/src/datadog/trace_segment.cpp index 9d658b7f..9253ae19 100644 --- a/src/datadog/trace_segment.cpp +++ b/src/datadog/trace_segment.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -14,6 +13,7 @@ #include "dict_writer.h" #include "error.h" #include "logger.h" +#include "optional.h" #include "span_data.h" #include "span_sampler.h" #include "tag_propagation.h" @@ -46,10 +46,10 @@ TraceSegment::TraceSegment( const std::shared_ptr& span_sampler, const std::shared_ptr& defaults, const PropagationStyles& injection_styles, - const std::optional& hostname, - std::optional origin, std::size_t tags_header_max_size, + const Optional& hostname, Optional origin, + std::size_t tags_header_max_size, std::unordered_map trace_tags, - std::optional sampling_decision, + Optional sampling_decision, std::unique_ptr local_root) : logger_(logger), collector_(collector), @@ -74,15 +74,13 @@ TraceSegment::TraceSegment( const SpanDefaults& TraceSegment::defaults() const { return *defaults_; } -const std::optional& TraceSegment::hostname() const { +const Optional& TraceSegment::hostname() const { return hostname_; } -const std::optional& TraceSegment::origin() const { - return origin_; -} +const Optional& TraceSegment::origin() const { return origin_; } -std::optional TraceSegment::sampling_decision() const { +Optional TraceSegment::sampling_decision() const { // `sampling_decision_` can change, so we need a lock. std::lock_guard lock(mutex_); return sampling_decision_; diff --git a/src/datadog/trace_segment.h b/src/datadog/trace_segment.h index bf3530c3..2e095b18 100644 --- a/src/datadog/trace_segment.h +++ b/src/datadog/trace_segment.h @@ -29,11 +29,11 @@ #include #include #include -#include #include #include #include "expected.h" +#include "optional.h" #include "propagation_styles.h" #include "sampling_decision.h" @@ -59,14 +59,14 @@ class TraceSegment { std::shared_ptr defaults_; const PropagationStyles injection_styles_; - const std::optional hostname_; - const std::optional origin_; + const Optional hostname_; + const Optional origin_; const std::size_t tags_header_max_size_; std::unordered_map trace_tags_; std::vector> spans_; std::size_t num_finished_spans_; - std::optional sampling_decision_; + Optional sampling_decision_; bool awaiting_delegated_sampling_decision_ = false; public: @@ -76,17 +76,16 @@ class TraceSegment { const std::shared_ptr& span_sampler, const std::shared_ptr& defaults, const PropagationStyles& injection_styles, - const std::optional& hostname, - std::optional origin, - std::size_t tags_header_max_size, + const Optional& hostname, + Optional origin, std::size_t tags_header_max_size, std::unordered_map trace_tags, - std::optional sampling_decision, + Optional sampling_decision, std::unique_ptr local_root); const SpanDefaults& defaults() const; - const std::optional& hostname() const; - const std::optional& origin() const; - std::optional sampling_decision() const; + const Optional& hostname() const; + const Optional& origin() const; + Optional sampling_decision() const; Logger& logger() const; diff --git a/src/datadog/tracer.cpp b/src/datadog/tracer.cpp index 96c83bad..b5434e0e 100644 --- a/src/datadog/tracer.cpp +++ b/src/datadog/tracer.cpp @@ -26,20 +26,19 @@ namespace { class ExtractionPolicy { public: - virtual Expected> trace_id( + virtual Expected> trace_id( const DictReader& headers) = 0; - virtual Expected> parent_id( + virtual Expected> parent_id( const DictReader& headers) = 0; - virtual Expected> sampling_priority( + virtual Expected> sampling_priority( const DictReader& headers) = 0; - virtual std::optional origin(const DictReader& headers) = 0; - virtual std::optional trace_tags(const DictReader&) = 0; + virtual Optional origin(const DictReader& headers) = 0; + virtual Optional trace_tags(const DictReader&) = 0; }; class DatadogExtractionPolicy : public ExtractionPolicy { - Expected> id(const DictReader& headers, - std::string_view header, - std::string_view kind) { + Expected> id(const DictReader& headers, + StringView header, StringView kind) { auto found = headers.lookup(header); if (!found) { return std::nullopt; @@ -60,19 +59,19 @@ class DatadogExtractionPolicy : public ExtractionPolicy { } public: - Expected> trace_id( + Expected> trace_id( const DictReader& headers) override { return id(headers, "x-datadog-trace-id", "trace"); } - Expected> parent_id( + Expected> parent_id( const DictReader& headers) override { return id(headers, "x-datadog-parent-id", "parent span"); } - Expected> sampling_priority( + Expected> sampling_priority( const DictReader& headers) override { - const std::string_view header = "x-datadog-sampling-priority"; + const StringView header = "x-datadog-sampling-priority"; auto found = headers.lookup(header); if (!found) { return std::nullopt; @@ -90,7 +89,7 @@ class DatadogExtractionPolicy : public ExtractionPolicy { return *result; } - std::optional origin(const DictReader& headers) override { + Optional origin(const DictReader& headers) override { auto found = headers.lookup("x-datadog-origin"); if (found) { return std::string(*found); @@ -98,7 +97,7 @@ class DatadogExtractionPolicy : public ExtractionPolicy { return std::nullopt; } - std::optional trace_tags(const DictReader& headers) override { + Optional trace_tags(const DictReader& headers) override { auto found = headers.lookup("x-datadog-tags"); if (found) { return std::string(*found); @@ -108,9 +107,8 @@ class DatadogExtractionPolicy : public ExtractionPolicy { }; class B3ExtractionPolicy : public DatadogExtractionPolicy { - Expected> id(const DictReader& headers, - std::string_view header, - std::string_view kind) { + Expected> id(const DictReader& headers, + StringView header, StringView kind) { auto found = headers.lookup(header); if (!found) { return std::nullopt; @@ -131,19 +129,19 @@ class B3ExtractionPolicy : public DatadogExtractionPolicy { } public: - Expected> trace_id( + Expected> trace_id( const DictReader& headers) override { return id(headers, "x-b3-traceid", "trace"); } - Expected> parent_id( + Expected> parent_id( const DictReader& headers) override { return id(headers, "x-b3-spanid", "parent span"); } - Expected> sampling_priority( + Expected> sampling_priority( const DictReader& headers) override { - const std::string_view header = "x-b3-sampled"; + const StringView header = "x-b3-sampled"; auto found = headers.lookup(header); if (!found) { return std::nullopt; @@ -163,11 +161,11 @@ class B3ExtractionPolicy : public DatadogExtractionPolicy { }; struct ExtractedData { - std::optional trace_id; - std::optional parent_id; - std::optional origin; - std::optional trace_tags; - std::optional sampling_priority; + Optional trace_id; + Optional parent_id; + Optional origin; + Optional trace_tags; + Optional sampling_priority; }; bool operator!=(const ExtractedData& left, const ExtractedData& right) { @@ -208,14 +206,14 @@ Expected extract_data(ExtractionPolicy& extract, return extracted_data; } -void log_startup_message(Logger& logger, std::string_view tracer_version_string, +void log_startup_message(Logger& logger, StringView tracer_version_string, const Collector& collector, const SpanDefaults& defaults, const TraceSampler& trace_sampler, const SpanSampler& span_sampler, const PropagationStyles& injection_styles, const PropagationStyles& extraction_styles, - const std::optional& hostname, + const Optional& hostname, std::size_t tags_header_max_size) { // clang-format off auto config = nlohmann::json::object({ @@ -305,7 +303,7 @@ Expected Tracer::extract_span(const DictReader& reader, const SpanConfig& config) { assert(extraction_styles_.datadog || extraction_styles_.b3); - std::optional extracted_data; + Optional extracted_data; const char* extracted_by; if (extraction_styles_.datadog) { @@ -391,7 +389,7 @@ Expected Tracer::extract_span(const DictReader& reader, span_data->trace_id = *trace_id; span_data->parent_id = *parent_id; - std::optional sampling_decision; + Optional sampling_decision; if (sampling_priority) { SamplingDecision decision; decision.priority = *sampling_priority; diff --git a/src/datadog/tracer.h b/src/datadog/tracer.h index cb328da7..d3a6f0ae 100644 --- a/src/datadog/tracer.h +++ b/src/datadog/tracer.h @@ -10,12 +10,11 @@ // obtained from a `TracerConfig` via the `finalize_config` function. See // `tracer_config.h`. -#include - #include "clock.h" #include "error.h" #include "expected.h" #include "id_generator.h" +#include "optional.h" #include "span.h" #include "tracer_config.h" @@ -37,7 +36,7 @@ class Tracer { std::shared_ptr defaults_; PropagationStyles injection_styles_; PropagationStyles extraction_styles_; - std::optional hostname_; + Optional hostname_; std::size_t tags_header_max_size_; public: diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index a5ba75e6..d3441572 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -13,6 +12,7 @@ #include "environment.h" #include "null_collector.h" #include "parse_util.h" +#include "string_view.h" namespace datadog { namespace tracing { @@ -23,7 +23,7 @@ void to_lower(std::string &text) { [](unsigned char ch) { return std::tolower(ch); }); } -bool falsy(std::string_view text) { +bool falsy(StringView text) { auto lower = std::string{text}; to_lower(lower); return lower == "0" || lower == "false" || lower == "no"; @@ -32,11 +32,11 @@ bool falsy(std::string_view text) { // List items are separated by an optional comma (",") and any amount of // whitespace. // Leading and trailing whitespace is ignored. -std::vector parse_list(std::string_view input) { +std::vector parse_list(StringView input) { using uchar = unsigned char; input = strip(input); - std::vector items; + std::vector items; if (input.empty()) { return items; } @@ -67,11 +67,11 @@ std::vector parse_list(std::string_view input) { return items; } -Expected parse_propagation_styles(std::string_view input) { +Expected parse_propagation_styles(StringView input) { PropagationStyles styles{false, false}; // Style names are separated by spaces, or a comma, or some combination. - for (const std::string_view &item : parse_list(input)) { + for (const StringView &item : parse_list(input)) { auto token = std::string(item); to_lower(token); if (token == "datadog") { @@ -93,11 +93,11 @@ Expected parse_propagation_styles(std::string_view input) { } Expected> parse_tags( - std::string_view input) { + StringView input) { std::unordered_map tags; // Within a tag, the key and value are separated by a colon (":"). - for (const std::string_view &token : parse_list(input)) { + for (const StringView &token : parse_list(input)) { const auto separator = std::find(token.begin(), token.end(), ':'); if (separator == token.end()) { std::string message; diff --git a/src/datadog/version.h b/src/datadog/version.h index 1c673db2..413e3fb3 100644 --- a/src/datadog/version.h +++ b/src/datadog/version.h @@ -2,7 +2,7 @@ // This component provides the release version of this library. -#include +#include "string_view.h" namespace datadog { namespace tracing { diff --git a/test/glob.cpp b/test/glob.cpp index a99cbe2c..eaddfd77 100644 --- a/test/glob.cpp +++ b/test/glob.cpp @@ -2,8 +2,7 @@ // `glob_match`, defined in `glob.h`. #include - -#include +#include #include "test.h" @@ -11,8 +10,8 @@ using namespace datadog::tracing; TEST_CASE("glob") { struct TestCase { - std::string_view pattern; - std::string_view subject; + StringView pattern; + StringView subject; bool expected; }; diff --git a/test/mocks/dict_readers.h b/test/mocks/dict_readers.h index 48202916..707e9ed7 100644 --- a/test/mocks/dict_readers.h +++ b/test/mocks/dict_readers.h @@ -15,7 +15,7 @@ class MockDictReader : public DictReader { const std::unordered_map& map) : map_(&map) {} - std::optional lookup(std::string_view key) const override { + Optional lookup(StringView key) const override { auto found = map_->find(std::string(key)); if (found == map_->end()) { return std::nullopt; @@ -23,9 +23,8 @@ class MockDictReader : public DictReader { return found->second; } - void visit( - const std::function& - visitor) const override { + void visit(const std::function& + visitor) const override { for (const auto& [key, value] : *map_) { visitor(key, value); } diff --git a/test/mocks/dict_writers.h b/test/mocks/dict_writers.h index aa1f25dc..eb68a1be 100644 --- a/test/mocks/dict_writers.h +++ b/test/mocks/dict_writers.h @@ -1,9 +1,9 @@ #pragma once #include +#include #include -#include #include using namespace datadog::tracing; @@ -11,7 +11,7 @@ using namespace datadog::tracing; struct MockDictWriter : public DictWriter { std::unordered_map items; - void set(std::string_view key, std::string_view value) override { + void set(StringView key, StringView value) override { items.insert_or_assign(std::string(key), std::string(value)); } }; diff --git a/test/mocks/event_schedulers.h b/test/mocks/event_schedulers.h index 2a0d5065..4149797e 100644 --- a/test/mocks/event_schedulers.h +++ b/test/mocks/event_schedulers.h @@ -1,17 +1,17 @@ #pragma once #include +#include #include #include #include -#include using namespace datadog::tracing; struct MockEventScheduler : public EventScheduler { std::function event_callback; - std::optional recurrence_interval; + Optional recurrence_interval; bool cancelled = false; Cancel schedule_recurring_event(std::chrono::steady_clock::duration interval, diff --git a/test/mocks/http_clients.h b/test/mocks/http_clients.h index 0610ace3..4170ac03 100644 --- a/test/mocks/http_clients.h +++ b/test/mocks/http_clients.h @@ -2,10 +2,10 @@ #include #include +#include #include #include -#include #include #include #include @@ -29,11 +29,11 @@ using namespace datadog::tracing; // If `response_error` is not null, then it will be delivered instead of the // `response_body`. struct MockHTTPClient : public HTTPClient { - std::optional post_error; + Optional post_error; std::ostringstream response_body; int response_status = -1; std::unordered_map response_headers; - std::optional response_error; + Optional response_error; MockDictWriter request_headers; std::mutex mutex_; ResponseHandler on_response_; diff --git a/test/mocks/loggers.h b/test/mocks/loggers.h index ae671465..5364a1c4 100644 --- a/test/mocks/loggers.h +++ b/test/mocks/loggers.h @@ -18,7 +18,7 @@ struct NullLogger : public Logger { void log_error(const LogFunc&) override {} void log_startup(const LogFunc&) override {} void log_error(const Error&) override {} - void log_error(std::string_view) override {} + void log_error(StringView) override {} }; struct MockLogger : public Logger { @@ -64,7 +64,7 @@ struct MockLogger : public Logger { entries.push_back(Entry{Entry::ERROR, error}); } - void log_error(std::string_view message) override { + void log_error(StringView message) override { if (echo) { *echo << message << '\n'; } diff --git a/test/span.cpp b/test/span.cpp index 5959856f..c35cc155 100644 --- a/test/span.cpp +++ b/test/span.cpp @@ -3,6 +3,7 @@ // for propagation. #include +#include #include #include #include @@ -14,7 +15,6 @@ #include #include #include -#include #include #include "matchers.h" @@ -228,9 +228,9 @@ TEST_CASE(".error() and .set_error*()") { std::string name; std::function mutate; bool expected_error; - std::optional expected_error_message; - std::optional expected_error_type; - std::optional expected_error_stack; + Optional expected_error_message; + Optional expected_error_type; + Optional expected_error_stack; }; auto test_case = GENERATE(values( diff --git a/test/span_sampler.cpp b/test/span_sampler.cpp index 145b4645..8f60fd02 100644 --- a/test/span_sampler.cpp +++ b/test/span_sampler.cpp @@ -1,10 +1,10 @@ +#include #include #include #include #include #include -#include #include #include #include @@ -18,7 +18,7 @@ using namespace datadog::tracing; namespace std { -std::ostream& operator<<(std::ostream& stream, std::optional value) { +std::ostream& operator<<(std::ostream& stream, Optional value) { if (value) { return stream << *value; } @@ -46,9 +46,9 @@ std::ostream& operator<<( namespace { struct SpanSamplingTags { - std::optional mechanism; - std::optional rule_rate; - std::optional max_per_second; + Optional mechanism; + Optional rule_rate; + Optional max_per_second; }; SpanSamplingTags span_sampling_tags(const SpanData& span) { @@ -70,19 +70,19 @@ SpanSamplingTags span_sampling_tags(const SpanData& span) { return result; } -SpanSamplerConfig::Rule by_service(std::string_view service) { +SpanSamplerConfig::Rule by_service(StringView service) { SpanSamplerConfig::Rule rule; rule.service = service; return rule; } -SpanSamplerConfig::Rule by_name(std::string_view name) { +SpanSamplerConfig::Rule by_name(StringView name) { SpanSamplerConfig::Rule rule; rule.name = name; return rule; } -SpanSamplerConfig::Rule by_resource(std::string_view resource) { +SpanSamplerConfig::Rule by_resource(StringView resource) { SpanSamplerConfig::Rule rule; rule.resource = resource; return rule; @@ -96,7 +96,7 @@ SpanSamplerConfig::Rule by_tags( } SpanSamplerConfig::Rule by_name_and_tags( - std::string_view name, std::unordered_map tags) { + StringView name, std::unordered_map tags) { SpanSamplerConfig::Rule rule; rule.name = name; rule.tags = std::move(tags); @@ -292,7 +292,7 @@ TEST_CASE("span rule limiter") { struct TestCase { std::string name; std::size_t num_spans; - std::optional max_per_second; + Optional max_per_second; std::size_t expected_count; }; diff --git a/test/tracer.cpp b/test/tracer.cpp index f5fdbea7..71226c35 100644 --- a/test/tracer.cpp +++ b/test/tracer.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,7 +15,6 @@ #include #include -#include #include "matchers.h" #include "mocks/collectors.h" @@ -26,7 +26,7 @@ namespace datadog { namespace tracing { std::ostream& operator<<(std::ostream& stream, - const std::optional& code) { + const Optional& code) { if (code) { return stream << "Error::Code(" << int(*code) << ")"; } @@ -263,7 +263,7 @@ TEST_CASE("span extraction") { bool extract_b3; std::unordered_map headers; // Null means "don't expect an error." - std::optional expected_error; + Optional expected_error; }; auto test_case = GENERATE(values({ @@ -453,8 +453,8 @@ TEST_CASE("span extraction") { bool extract_b3; std::unordered_map headers; std::uint64_t expected_trace_id; - std::optional expected_parent_id; - std::optional expected_sampling_priority; + Optional expected_parent_id; + Optional expected_sampling_priority; }; auto test_case = GENERATE(values({ diff --git a/test/tracer_config.cpp b/test/tracer_config.cpp index df31a016..37c56c84 100644 --- a/test/tracer_config.cpp +++ b/test/tracer_config.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -10,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -55,7 +55,7 @@ namespace { // Restore any previous value (or unset the value if it was unset) afterward. class EnvGuard { std::string name_; - std::optional former_value_; + Optional former_value_; public: EnvGuard(std::string name, std::string value) : name_(std::move(name)) { @@ -93,7 +93,7 @@ class EnvGuard { }; // For brevity when we're tabulating a lot of test cases with parse -// `std::optional<...>` data members. +// `Optional<...>` data members. const auto x = std::nullopt; // Here's an attempt at a portable secure temporary file. @@ -194,7 +194,7 @@ TEST_CASE("TracerConfig::defaults") { std::string name; std::string dd_tags; std::unordered_map expected_tags; - std::optional expected_error; + Optional expected_error; }; auto test_case = GENERATE(values({ @@ -416,7 +416,7 @@ TEST_CASE("TracerConfig::agent") { SECTION("parsing") { struct TestCase { std::string url; - std::optional expected_error; + Optional expected_error; std::string expected_scheme = ""; std::string expected_authority = ""; std::string expected_path = ""; @@ -459,9 +459,9 @@ TEST_CASE("TracerConfig::agent") { SECTION("environment variables override") { struct TestCase { std::string name; - std::optional env_host; - std::optional env_port; - std::optional env_url; + Optional env_host; + Optional env_port; + Optional env_url; std::string expected_scheme; std::string expected_authority; }; @@ -490,15 +490,15 @@ TEST_CASE("TracerConfig::agent") { })); CAPTURE(test_case.name); - std::optional host_guard; + Optional host_guard; if (test_case.env_host) { host_guard.emplace("DD_AGENT_HOST", *test_case.env_host); } - std::optional port_guard; + Optional port_guard; if (test_case.env_port) { port_guard.emplace("DD_TRACE_AGENT_PORT", *test_case.env_port); } - std::optional url_guard; + Optional url_guard; if (test_case.env_url) { url_guard.emplace("DD_TRACE_AGENT_URL", *test_case.env_url); } @@ -1018,7 +1018,7 @@ TEST_CASE("TracerConfig propagation styles") { struct TestCase { int line; std::string env_value; - std::optional expected_error; + Optional expected_error; PropagationStyles expected_styles = PropagationStyles{}; };