diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage')
3 files changed, 392 insertions, 0 deletions
diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/baggage.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/baggage.h new file mode 100644 index 000000000..eb5e4dcc7 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/baggage.h @@ -0,0 +1,299 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include <cctype> + +#include "opentelemetry/common/kv_properties.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace baggage +{ + +class Baggage +{ +public: + static constexpr size_t kMaxKeyValuePairs = 180; + static constexpr size_t kMaxKeyValueSize = 4096; + static constexpr size_t kMaxSize = 8192; + static constexpr char kKeyValueSeparator = '='; + static constexpr char kMembersSeparator = ','; + static constexpr char kMetadataSeparator = ';'; + + Baggage() noexcept : kv_properties_(new opentelemetry::common::KeyValueProperties()) {} + Baggage(size_t size) noexcept + : kv_properties_(new opentelemetry::common::KeyValueProperties(size)){}; + + template <class T> + Baggage(const T &keys_and_values) noexcept + : kv_properties_(new opentelemetry::common::KeyValueProperties(keys_and_values)) + {} + + static nostd::shared_ptr<Baggage> GetDefault() + { + static nostd::shared_ptr<Baggage> baggage{new Baggage()}; + return baggage; + } + + /* Get value for key in the baggage + @returns true if key is found, false otherwise + */ + bool GetValue(nostd::string_view key, std::string &value) const noexcept + { + return kv_properties_->GetValue(key, value); + } + + /* Returns shared_ptr of new baggage object which contains new key-value pair. If key or value is + invalid, copy of current baggage is returned + */ + nostd::shared_ptr<Baggage> Set(const nostd::string_view &key, + const nostd::string_view &value) noexcept + { + + nostd::shared_ptr<Baggage> baggage(new Baggage(kv_properties_->Size() + 1)); + const bool valid_kv = IsValidKey(key) && IsValidValue(value); + + if (valid_kv) + { + baggage->kv_properties_->AddEntry(key, value); + } + + // add rest of the fields. + kv_properties_->GetAllEntries( + [&baggage, &key, &valid_kv](nostd::string_view e_key, nostd::string_view e_value) { + // if key or value was not valid, add all the entries. Add only remaining entries + // otherwise. + if (!valid_kv || key != e_key) + { + baggage->kv_properties_->AddEntry(e_key, e_value); + } + + return true; + }); + + return baggage; + } + + // @return all key-values entries by repeatedly invoking the function reference passed as argument + // for each entry + bool GetAllEntries( + nostd::function_ref<bool(nostd::string_view, nostd::string_view)> callback) const noexcept + { + return kv_properties_->GetAllEntries(callback); + } + + // delete key from the baggage if it exists. Returns shared_ptr of new baggage object. + // if key does not exist, copy of current baggage is returned. + // Validity of key is not checked as invalid keys should never be populated in baggage in the + // first place. + nostd::shared_ptr<Baggage> Delete(nostd::string_view key) noexcept + { + // keeping size of baggage same as key might not be found in it + nostd::shared_ptr<Baggage> baggage(new Baggage(kv_properties_->Size())); + kv_properties_->GetAllEntries( + [&baggage, &key](nostd::string_view e_key, nostd::string_view e_value) { + if (key != e_key) + baggage->kv_properties_->AddEntry(e_key, e_value); + return true; + }); + return baggage; + } + + // Returns shared_ptr of baggage after extracting key-value pairs from header + static nostd::shared_ptr<Baggage> FromHeader(nostd::string_view header) noexcept + { + if (header.size() > kMaxSize) + { + // header size exceeds maximum threshold, return empty baggage + return GetDefault(); + } + + common::KeyValueStringTokenizer kv_str_tokenizer(header); + size_t cnt = kv_str_tokenizer.NumTokens(); // upper bound on number of kv pairs + if (cnt > kMaxKeyValuePairs) + { + cnt = kMaxKeyValuePairs; + } + + nostd::shared_ptr<Baggage> baggage(new Baggage(cnt)); + bool kv_valid; + nostd::string_view key, value; + + while (kv_str_tokenizer.next(kv_valid, key, value) && baggage->kv_properties_->Size() < cnt) + { + if (!kv_valid || (key.size() + value.size() > kMaxKeyValueSize)) + { + // if kv pair is not valid, skip it + continue; + } + + // NOTE : metadata is kept as part of value only as it does not have any semantic meaning. + // but, we need to extract it (else Decode on value will return error) + nostd::string_view metadata; + auto metadata_separator = value.find(kMetadataSeparator); + if (metadata_separator != std::string::npos) + { + metadata = value.substr(metadata_separator); + value = value.substr(0, metadata_separator); + } + + bool err = 0; + auto key_str = UrlDecode(common::StringUtil::Trim(key), err); + auto value_str = UrlDecode(common::StringUtil::Trim(value), err); + + if (err == false && IsValidKey(key_str) && IsValidValue(value_str)) + { + if (!metadata.empty()) + { + value_str.append(metadata.data(), metadata.size()); + } + baggage->kv_properties_->AddEntry(key_str, value_str); + } + } + + return baggage; + } + + // Creates string from baggage object. + std::string ToHeader() const noexcept + { + std::string header_s; + bool first = true; + kv_properties_->GetAllEntries([&](nostd::string_view key, nostd::string_view value) { + if (!first) + { + header_s.push_back(kMembersSeparator); + } + else + { + first = false; + } + header_s.append(UrlEncode(key)); + header_s.push_back(kKeyValueSeparator); + + // extracting metadata from value. We do not encode metadata + auto metadata_separator = value.find(kMetadataSeparator); + if (metadata_separator != std::string::npos) + { + header_s.append(UrlEncode(value.substr(0, metadata_separator))); + auto metadata = value.substr(metadata_separator); + header_s.append(std::string(metadata.data(), metadata.size())); + } + else + { + header_s.append(UrlEncode(value)); + } + return true; + }); + return header_s; + } + +private: + static bool IsPrintableString(nostd::string_view str) + { + for (const auto ch : str) + { + if (ch < ' ' || ch > '~') + { + return false; + } + } + + return true; + } + + static bool IsValidKey(nostd::string_view key) { return key.size() && IsPrintableString(key); } + + static bool IsValidValue(nostd::string_view value) { return IsPrintableString(value); } + + // Uri encode key value pairs before injecting into header + // Implementation inspired from : https://golang.org/src/net/url/url.go?s=7851:7884#L264 + static std::string UrlEncode(nostd::string_view str) + { + auto to_hex = [](char c) -> char { + static const char *hex = "0123456789ABCDEF"; + return hex[c & 15]; + }; + + std::string ret; + + for (auto c : str) + { + if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') + { + ret.push_back(c); + } + else if (c == ' ') + { + ret.push_back('+'); + } + else + { + ret.push_back('%'); + ret.push_back(to_hex(c >> 4)); + ret.push_back(to_hex(c & 15)); + } + } + + return ret; + } + + // Uri decode key value pairs after extracting from header + static std::string UrlDecode(nostd::string_view str, bool &err) + { + auto IsHex = [](char c) { + return std::isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); + }; + + auto from_hex = [](char c) -> char { + // c - '0' produces integer type which could trigger error/warning when casting to char, + // but the cast is safe here. + return static_cast<char>(std::isdigit(c) ? c - '0' : std::toupper(c) - 'A' + 10); + }; + + std::string ret; + + for (size_t i = 0; i < str.size(); i++) + { + if (str[i] == '%') + { + if (i + 2 >= str.size() || !IsHex(str[i + 1]) || !IsHex(str[i + 2])) + { + err = 1; + return ""; + } + ret.push_back(from_hex(str[i + 1]) << 4 | from_hex(str[i + 2])); + i += 2; + } + else if (str[i] == '+') + { + ret.push_back(' '); + } + else if (std::isalnum(str[i]) || str[i] == '-' || str[i] == '_' || str[i] == '.' || + str[i] == '~') + { + ret.push_back(str[i]); + } + else + { + err = 1; + return ""; + } + } + + return ret; + } + +private: + // Store entries in a C-style array to avoid using std::array or std::vector. + nostd::unique_ptr<opentelemetry::common::KeyValueProperties> kv_properties_; +}; + +} // namespace baggage + +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/baggage_context.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/baggage_context.h new file mode 100644 index 000000000..9a92bac77 --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/baggage_context.h @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/context/context.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE + +namespace baggage +{ + +static const std::string kBaggageHeader = "baggage"; + +inline nostd::shared_ptr<opentelemetry::baggage::Baggage> GetBaggage( + const opentelemetry::context::Context &context) noexcept +{ + context::ContextValue context_value = context.GetValue(kBaggageHeader); + if (nostd::holds_alternative<nostd::shared_ptr<opentelemetry::baggage::Baggage>>(context_value)) + { + return nostd::get<nostd::shared_ptr<opentelemetry::baggage::Baggage>>(context_value); + } + static nostd::shared_ptr<opentelemetry::baggage::Baggage> empty_baggage{ + new opentelemetry::baggage::Baggage()}; + return empty_baggage; +} + +inline context::Context SetBaggage( + opentelemetry::context::Context &context, + nostd::shared_ptr<opentelemetry::baggage::Baggage> baggage) noexcept +{ + return context.SetValue(kBaggageHeader, baggage); +} + +} // namespace baggage +OPENTELEMETRY_END_NAMESPACE diff --git a/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/propagation/baggage_propagator.h b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/propagation/baggage_propagator.h new file mode 100644 index 000000000..3de60860b --- /dev/null +++ b/src/jaegertracing/opentelemetry-cpp/api/include/opentelemetry/baggage/propagation/baggage_propagator.h @@ -0,0 +1,54 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/baggage/baggage.h" +#include "opentelemetry/baggage/baggage_context.h" +#include "opentelemetry/context/propagation/text_map_propagator.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace baggage +{ +namespace propagation +{ + +class BaggagePropagator : public opentelemetry::context::propagation::TextMapPropagator +{ +public: + void Inject(opentelemetry::context::propagation::TextMapCarrier &carrier, + const opentelemetry::context::Context &context) noexcept override + { + auto baggage = opentelemetry::baggage::GetBaggage(context); + auto header = baggage->ToHeader(); + if (header.size()) + { + carrier.Set(kBaggageHeader, header); + } + } + + context::Context Extract(const opentelemetry::context::propagation::TextMapCarrier &carrier, + opentelemetry::context::Context &context) noexcept override + { + nostd::string_view baggage_str = carrier.Get(opentelemetry::baggage::kBaggageHeader); + auto baggage = opentelemetry::baggage::Baggage::FromHeader(baggage_str); + + if (baggage->ToHeader().size()) + { + return opentelemetry::baggage::SetBaggage(context, baggage); + } + else + { + return context; + } + } + + bool Fields(nostd::function_ref<bool(nostd::string_view)> callback) const noexcept override + { + return callback(kBaggageHeader); + } +}; +} // namespace propagation +} // namespace baggage +OPENTELEMETRY_END_NAMESPACE |