diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h new file mode 100644 index 00000000000..c827cd80e00 --- /dev/null +++ b/api/include/opentelemetry/trace/trace_state.h @@ -0,0 +1,96 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/unique_ptr.h" + +namespace opentelemetry +{ +namespace trace +{ + +/** + * TraceState carries tracing-system specific context in a list of key-value pairs. TraceState + * allows different vendors to propagate additional information and inter-operate with their legacy + * id formats. + * + * For more information, see the W3C Trace Context specification: + * https://www.w3.org/TR/trace-context + */ +class TraceState +{ +public: + static constexpr int kKeyMaxSize = 256; + static constexpr int kValueMaxSize = 256; + static constexpr int kMaxKeyValuePairs = 32; + + // Class to store key-value pairs. + class Entry + { + public: + Entry() noexcept = default; + + // Copy constructor. + Entry(const Entry ©); + + // Creates an Entry for a given key-value pair. + Entry(nostd::string_view key, nostd::string_view value) noexcept; + + nostd::string_view GetKey(); + nostd::string_view GetValue(); + + private: + // Store key and value as raw char pointers to avoid using std::string. + nostd::unique_ptr key_; + nostd::unique_ptr value_; + }; + + // An empty TraceState. + TraceState() noexcept : num_entries_(0) {} + + // Returns false if no such key, otherwise returns true and populates value. + bool Get(nostd::string_view key, nostd::string_view value) const noexcept { return false; } + + // Creates an Entry for the key-value pair and adds it to entries. + // If value is null, this function is a no-op. + void Set(nostd::string_view key, nostd::string_view value) const noexcept; + + // Returns true if there are no keys, false otherwise. + bool Empty() const noexcept { return true; } + + // Returns a span of all the entries. The TraceState object must outlive the span. + nostd::span Entries() const noexcept { return {}; } + + // Returns whether key is a valid key. See https://www.w3.org/TR/trace-context/#key + static bool IsValidKey(nostd::string_view key); + + // Returns whether value is a valid value. See https://www.w3.org/TR/trace-context/#value + static bool IsValidValue(nostd::string_view value); + +private: + // Store entries in a C-style array to avoid using std::array or std::vector. + Entry entries_[kMaxKeyValuePairs]; + + // Maintain the number of entries in entries_. Must be in the range [0, kMaxKeyValuePairs]. + int num_entries_; +}; + +} // namespace trace +} // namespace opentelemetry diff --git a/api/test/trace/BUILD b/api/test/trace/BUILD index b3f194baa0c..1fce77d6418 100644 --- a/api/test/trace/BUILD +++ b/api/test/trace/BUILD @@ -82,3 +82,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "trace_state_test", + srcs = [ + "trace_state_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/api/test/trace/trace_state_test.cc b/api/test/trace/trace_state_test.cc new file mode 100644 index 00000000000..e74beaa05b1 --- /dev/null +++ b/api/test/trace/trace_state_test.cc @@ -0,0 +1,17 @@ +#include "opentelemetry/trace/trace_state.h" + +#include + +namespace +{ + +using opentelemetry::trace::TraceState; + +TEST(TraceStateTest, DefaultConstruction) +{ + TraceState s; + EXPECT_FALSE(s.Get("missing_key", "value")); + EXPECT_TRUE(s.Empty()); + EXPECT_EQ(0, s.Entries().size()); +} +} // namespace