From e668abe1224bbe0e57214114fec1d1e669ae84d6 Mon Sep 17 00:00:00 2001 From: easy Date: Mon, 2 Mar 2020 17:39:09 +1100 Subject: [PATCH 1/3] [WIP] Add TraceState. --- api/include/opentelemetry/trace/trace_state.h | 95 +++++++++++++++++++ api/test/trace/BUILD | 11 +++ api/test/trace/trace_state_test.cc | 17 ++++ 3 files changed, 123 insertions(+) create mode 100644 api/include/opentelemetry/trace/trace_state.h create mode 100644 api/test/trace/trace_state_test.cc diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h new file mode 100644 index 0000000000..18258caa47 --- /dev/null +++ b/api/include/opentelemetry/trace/trace_state.h @@ -0,0 +1,95 @@ +// 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" + +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. +// +// Implementation is optimized for a small list of key-value pairs. +// +// Key is opaque string up to 256 characters printable. It MUST begin with a lowercase letter, +// and can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and +// forward slashes /. +// +// Value is opaque string up to 256 characters, of printable ASCII RFC0020 characters (i.e. the +// range 0x20 to 0x7E) except comma , and equals =. +class TraceState +{ +public: + static constexpr int kKeyMaxSize = 256; + static constexpr int kValueMaxSize = 256; + static constexpr int kMaxKeyValuePairs = 32; + + class Entry { + public: + virtual ~Entry() {} + + virtual nostd::string_view key() = 0; + virtual nostd::string_view value() = 0; + }; + + // An empty TraceState. + TraceState() noexcept = default; + + // Returns false if no such key, otherwise returns true and populates value. + virtual bool Get(nostd::string_view key, nostd::string_view* value) const noexcept { return false; } + + // Returns true if there are no keys. + virtual bool empty() const noexcept { return true; } + + // Returns a span of all the entries. The TraceState object must outlive the span. + virtual nostd::span entries() const noexcept { return {}; } + + // Key is opaque string up to 256 characters printable. It MUST begin with a lowercase letter, and + // can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and + // forward slashes /. For multi-tenant vendor scenarios, an at sign (@) can be used to prefix the + // vendor name. + static bool IsValidKey(nostd::string_view key) { + if (key.empty() || key.length() > kKeyMaxSize || !IsNumberOrDigit(key[0])) { + return false; + } + int ats = 0; + const int n = key.length(); + for (int i = 0; i < n; ++i) { + char c = key[i]; + if (!IsNumberOrDigit(c) && c != '_' && c != '-' && c != '@' && c != '*' && c != '/') { + return false; + } + if ((c == '@') && (++ats > 1)) { + return false; + } + } + return true; + } + + private: + static bool IsNumberOrDigit(char c) { + return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); + } +}; + +} // namespace trace +} // namespace opentelemetry diff --git a/api/test/trace/BUILD b/api/test/trace/BUILD index a8e8507e4e..eb1b635066 100644 --- a/api/test/trace/BUILD +++ b/api/test/trace/BUILD @@ -49,3 +49,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 0000000000..2dd9263f80 --- /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("key", nullptr)); + EXPECT_TRUE(s.empty()); + EXPECT_EQ(0, s.entries().size()); +} +} // namespace From d9450f7d154ace6979c68e8d1cf74eb76cc51bcb Mon Sep 17 00:00:00 2001 From: easy Date: Mon, 2 Mar 2020 17:53:27 +1100 Subject: [PATCH 2/3] Add SpanContext. --- .../opentelemetry/trace/span_context.h | 65 +++++++++++++++++++ api/include/opentelemetry/trace/trace_state.h | 4 ++ api/test/trace/BUILD | 11 ++++ api/test/trace/span_context_test.cc | 15 +++++ 4 files changed, 95 insertions(+) create mode 100644 api/include/opentelemetry/trace/span_context.h create mode 100644 api/test/trace/span_context_test.cc diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h new file mode 100644 index 0000000000..c1171f5e9a --- /dev/null +++ b/api/include/opentelemetry/trace/span_context.h @@ -0,0 +1,65 @@ +// 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/unique_ptr.h" +#include "opentelemetry/trace/trace_id.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/trace_flags.h" +#include "opentelemetry/trace/trace_state.h" + +namespace opentelemetry +{ +namespace trace +{ + +// SpanContext contains the state that must propagate to child Spans and across +// process boundaries. It contains the identifiers TraceId and SpanId, +// TraceFlags, TraceState, and whether it has a remote parent. +class SpanContext final +{ +public: + // An invalid SpanContext. + SpanContext() noexcept : trace_state_(new TraceState) {} + + // TODO + // + // static SpanContext Create(TraceId traceId, SpanId spanId, TraceFlags traceFlags, TraceState traceState); + // static SpanContext CreateFromRemoteParent(...); + + const TraceId& trace_id() const noexcept { return trace_id_; } + const SpanId& span_id() const noexcept { return span_id_; } + const TraceFlags& trace_flags() const noexcept { return trace_flags_; } + const TraceState& trace_state() const noexcept { return *trace_state_; } + + bool IsValid() const noexcept { + return trace_id_.IsValid() && span_id_.IsValid(); + } + + bool HasRemoteParent() const noexcept { return remote_parent_; } + +private: + const TraceId trace_id_; + const SpanId span_id_; + const TraceFlags trace_flags_; + const nostd::unique_ptr trace_state_; // Never nullptr. + const bool remote_parent_ = false; +}; + +} // namespace trace +} // namespace opentelemetry diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h index 18258caa47..45e13fdda0 100644 --- a/api/include/opentelemetry/trace/trace_state.h +++ b/api/include/opentelemetry/trace/trace_state.h @@ -54,6 +54,8 @@ class TraceState // An empty TraceState. TraceState() noexcept = default; + virtual ~TraceState() = default; + // Returns false if no such key, otherwise returns true and populates value. virtual bool Get(nostd::string_view key, nostd::string_view* value) const noexcept { return false; } @@ -85,6 +87,8 @@ class TraceState return true; } + // TODO: IsValidValue + private: static bool IsNumberOrDigit(char c) { return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); diff --git a/api/test/trace/BUILD b/api/test/trace/BUILD index eb1b635066..14debe4e12 100644 --- a/api/test/trace/BUILD +++ b/api/test/trace/BUILD @@ -17,6 +17,17 @@ otel_cc_benchmark( deps = ["//api"], ) +cc_test( + name = "span_context_test", + srcs = [ + "span_context_test.cc", + ], + deps = [ + "//api", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "span_id_test", srcs = [ diff --git a/api/test/trace/span_context_test.cc b/api/test/trace/span_context_test.cc new file mode 100644 index 0000000000..3326a0c318 --- /dev/null +++ b/api/test/trace/span_context_test.cc @@ -0,0 +1,15 @@ +#include "opentelemetry/trace/span_context.h" + +#include + +namespace +{ + +using opentelemetry::trace::SpanContext; + +TEST(SpanContextTest, DefaultConstruction) +{ + SpanContext ctx; +} + +} // namespace From c4b6338338b1f58c158213f6de6b505226841373 Mon Sep 17 00:00:00 2001 From: easy Date: Mon, 2 Mar 2020 17:53:53 +1100 Subject: [PATCH 3/3] format --- .../opentelemetry/trace/span_context.h | 18 ++++--- api/include/opentelemetry/trace/trace_state.h | 48 +++++++++++-------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/api/include/opentelemetry/trace/span_context.h b/api/include/opentelemetry/trace/span_context.h index c1171f5e9a..3469ce845b 100644 --- a/api/include/opentelemetry/trace/span_context.h +++ b/api/include/opentelemetry/trace/span_context.h @@ -18,9 +18,9 @@ //#include #include "opentelemetry/nostd/unique_ptr.h" -#include "opentelemetry/trace/trace_id.h" #include "opentelemetry/trace/span_id.h" #include "opentelemetry/trace/trace_flags.h" +#include "opentelemetry/trace/trace_id.h" #include "opentelemetry/trace/trace_state.h" namespace opentelemetry @@ -39,17 +39,15 @@ class SpanContext final // TODO // - // static SpanContext Create(TraceId traceId, SpanId spanId, TraceFlags traceFlags, TraceState traceState); - // static SpanContext CreateFromRemoteParent(...); + // static SpanContext Create(TraceId traceId, SpanId spanId, TraceFlags traceFlags, TraceState + // traceState); static SpanContext CreateFromRemoteParent(...); - const TraceId& trace_id() const noexcept { return trace_id_; } - const SpanId& span_id() const noexcept { return span_id_; } - const TraceFlags& trace_flags() const noexcept { return trace_flags_; } - const TraceState& trace_state() const noexcept { return *trace_state_; } + const TraceId &trace_id() const noexcept { return trace_id_; } + const SpanId &span_id() const noexcept { return span_id_; } + const TraceFlags &trace_flags() const noexcept { return trace_flags_; } + const TraceState &trace_state() const noexcept { return *trace_state_; } - bool IsValid() const noexcept { - return trace_id_.IsValid() && span_id_.IsValid(); - } + bool IsValid() const noexcept { return trace_id_.IsValid() && span_id_.IsValid(); } bool HasRemoteParent() const noexcept { return remote_parent_; } diff --git a/api/include/opentelemetry/trace/trace_state.h b/api/include/opentelemetry/trace/trace_state.h index 45e13fdda0..f039a3d143 100644 --- a/api/include/opentelemetry/trace/trace_state.h +++ b/api/include/opentelemetry/trace/trace_state.h @@ -25,8 +25,9 @@ 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. +// 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. // // Implementation is optimized for a small list of key-value pairs. // @@ -39,15 +40,16 @@ namespace trace class TraceState { public: - static constexpr int kKeyMaxSize = 256; - static constexpr int kValueMaxSize = 256; - static constexpr int kMaxKeyValuePairs = 32; + static constexpr int kKeyMaxSize = 256; + static constexpr int kValueMaxSize = 256; + static constexpr int kMaxKeyValuePairs = 32; - class Entry { - public: + class Entry + { + public: virtual ~Entry() {} - virtual nostd::string_view key() = 0; + virtual nostd::string_view key() = 0; virtual nostd::string_view value() = 0; }; @@ -57,30 +59,38 @@ class TraceState virtual ~TraceState() = default; // Returns false if no such key, otherwise returns true and populates value. - virtual bool Get(nostd::string_view key, nostd::string_view* value) const noexcept { return false; } + virtual bool Get(nostd::string_view key, nostd::string_view *value) const noexcept + { + return false; + } // Returns true if there are no keys. virtual bool empty() const noexcept { return true; } // Returns a span of all the entries. The TraceState object must outlive the span. - virtual nostd::span entries() const noexcept { return {}; } + virtual nostd::span entries() const noexcept { return {}; } // Key is opaque string up to 256 characters printable. It MUST begin with a lowercase letter, and // can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and // forward slashes /. For multi-tenant vendor scenarios, an at sign (@) can be used to prefix the // vendor name. - static bool IsValidKey(nostd::string_view key) { - if (key.empty() || key.length() > kKeyMaxSize || !IsNumberOrDigit(key[0])) { + static bool IsValidKey(nostd::string_view key) + { + if (key.empty() || key.length() > kKeyMaxSize || !IsNumberOrDigit(key[0])) + { return false; } - int ats = 0; + int ats = 0; const int n = key.length(); - for (int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) + { char c = key[i]; - if (!IsNumberOrDigit(c) && c != '_' && c != '-' && c != '@' && c != '*' && c != '/') { + if (!IsNumberOrDigit(c) && c != '_' && c != '-' && c != '@' && c != '*' && c != '/') + { return false; } - if ((c == '@') && (++ats > 1)) { + if ((c == '@') && (++ats > 1)) + { return false; } } @@ -89,10 +99,8 @@ class TraceState // TODO: IsValidValue - private: - static bool IsNumberOrDigit(char c) { - return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); - } +private: + static bool IsNumberOrDigit(char c) { return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); } }; } // namespace trace