From 4e3270207d10b8ec00b70d5540fad54a633c5c59 Mon Sep 17 00:00:00 2001 From: Pengyuan Bian Date: Wed, 22 May 2019 17:24:57 -0700 Subject: [PATCH 1/3] opencensus library --- WORKSPACE | 13 ++ extensions/stackdriver/opencensus/BUILD | 15 ++ extensions/stackdriver/opencensus/README.md | 5 + .../opencensus/common/internal/BUILD | 60 +++++ .../opencensus/common/internal/hash_mix.h | 49 +++++ .../opencensus/common/internal/random.cc | 53 +++++ .../opencensus/common/internal/random.h | 77 +++++++ .../common/internal/string_vector_hash.h | 41 ++++ .../stackdriver/opencensus/context/BUILD | 42 ++++ .../stackdriver/opencensus/context/context.h | 74 +++++++ .../opencensus/context/internal/context.cc | 58 +++++ .../context/internal/with_context.cc | 56 +++++ .../opencensus/context/with_context.h | 61 ++++++ .../stackdriver/opencensus/opencensus.bzl | 30 +++ extensions/stackdriver/opencensus/stats/BUILD | 111 ++++++++++ .../opencensus/stats/aggregation.h | 87 ++++++++ .../opencensus/stats/bucket_boundaries.h | 85 +++++++ .../opencensus/stats/distribution.h | 78 +++++++ .../opencensus/stats/internal/aggregation.cc | 37 ++++ .../stats/internal/aggregation_window.cc | 35 +++ .../stats/internal/aggregation_window.h | 77 +++++++ .../stats/internal/bucket_boundaries.cc | 77 +++++++ .../stats/internal/delta_producer.cc | 118 ++++++++++ .../stats/internal/delta_producer.h | 110 ++++++++++ .../opencensus/stats/internal/distribution.cc | 50 +++++ .../opencensus/stats/internal/measure.cc | 60 +++++ .../opencensus/stats/internal/measure_data.cc | 107 +++++++++ .../opencensus/stats/internal/measure_data.h | 75 +++++++ .../stats/internal/measure_descriptor.cc | 29 +++ .../stats/internal/measure_registry.cc | 39 ++++ .../stats/internal/measure_registry_impl.cc | 150 +++++++++++++ .../stats/internal/measure_registry_impl.h | 108 +++++++++ .../opencensus/stats/internal/recording.cc | 40 ++++ .../stats/internal/set_aggregation_window.cc | 29 +++ .../stats/internal/set_aggregation_window.h | 34 +++ .../stats/internal/stats_exporter.cc | 87 ++++++++ .../stats/internal/stats_exporter_impl.h | 58 +++++ .../stats/internal/stats_manager.cc | 184 ++++++++++++++++ .../opencensus/stats/internal/stats_manager.h | 128 +++++++++++ .../opencensus/stats/internal/view.cc | 55 +++++ .../opencensus/stats/internal/view_data.cc | 82 +++++++ .../stats/internal/view_data_impl.cc | 207 ++++++++++++++++++ .../stats/internal/view_data_impl.h | 119 ++++++++++ .../stats/internal/view_descriptor.cc | 102 +++++++++ .../stackdriver/opencensus/stats/measure.h | 122 +++++++++++ .../opencensus/stats/measure_descriptor.h | 70 ++++++ .../opencensus/stats/measure_registry.h | 44 ++++ .../stackdriver/opencensus/stats/recording.h | 50 +++++ .../stackdriver/opencensus/stats/stats.h | 33 +++ .../opencensus/stats/stats_exporter.h | 65 ++++++ .../stackdriver/opencensus/stats/tag_key.h | 29 +++ .../stackdriver/opencensus/stats/tag_set.h | 29 +++ .../stackdriver/opencensus/stats/view.h | 63 ++++++ .../stackdriver/opencensus/stats/view_data.h | 79 +++++++ .../opencensus/stats/view_descriptor.h | 118 ++++++++++ extensions/stackdriver/opencensus/tags/BUILD | 57 +++++ .../opencensus/tags/context_util.h | 33 +++ .../opencensus/tags/internal/context_util.cc | 41 ++++ .../opencensus/tags/internal/tag_key.cc | 70 ++++++ .../opencensus/tags/internal/tag_map.cc | 79 +++++++ .../opencensus/tags/internal/with_tag_map.cc | 60 +++++ .../stackdriver/opencensus/tags/tag_key.h | 55 +++++ .../stackdriver/opencensus/tags/tag_map.h | 72 ++++++ .../opencensus/tags/with_tag_map.h | 62 ++++++ 64 files changed, 4423 insertions(+) create mode 100644 extensions/stackdriver/opencensus/BUILD create mode 100644 extensions/stackdriver/opencensus/README.md create mode 100644 extensions/stackdriver/opencensus/common/internal/BUILD create mode 100644 extensions/stackdriver/opencensus/common/internal/hash_mix.h create mode 100644 extensions/stackdriver/opencensus/common/internal/random.cc create mode 100644 extensions/stackdriver/opencensus/common/internal/random.h create mode 100644 extensions/stackdriver/opencensus/common/internal/string_vector_hash.h create mode 100644 extensions/stackdriver/opencensus/context/BUILD create mode 100644 extensions/stackdriver/opencensus/context/context.h create mode 100644 extensions/stackdriver/opencensus/context/internal/context.cc create mode 100644 extensions/stackdriver/opencensus/context/internal/with_context.cc create mode 100644 extensions/stackdriver/opencensus/context/with_context.h create mode 100644 extensions/stackdriver/opencensus/opencensus.bzl create mode 100644 extensions/stackdriver/opencensus/stats/BUILD create mode 100644 extensions/stackdriver/opencensus/stats/aggregation.h create mode 100644 extensions/stackdriver/opencensus/stats/bucket_boundaries.h create mode 100644 extensions/stackdriver/opencensus/stats/distribution.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/aggregation.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/aggregation_window.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/aggregation_window.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/bucket_boundaries.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/delta_producer.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/delta_producer.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/distribution.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure_data.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure_data.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure_descriptor.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure_registry.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/recording.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/stats_exporter.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/stats_exporter_impl.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/stats_manager.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/stats_manager.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/view.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/view_data.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/view_data_impl.cc create mode 100644 extensions/stackdriver/opencensus/stats/internal/view_data_impl.h create mode 100644 extensions/stackdriver/opencensus/stats/internal/view_descriptor.cc create mode 100644 extensions/stackdriver/opencensus/stats/measure.h create mode 100644 extensions/stackdriver/opencensus/stats/measure_descriptor.h create mode 100644 extensions/stackdriver/opencensus/stats/measure_registry.h create mode 100644 extensions/stackdriver/opencensus/stats/recording.h create mode 100644 extensions/stackdriver/opencensus/stats/stats.h create mode 100644 extensions/stackdriver/opencensus/stats/stats_exporter.h create mode 100644 extensions/stackdriver/opencensus/stats/tag_key.h create mode 100644 extensions/stackdriver/opencensus/stats/tag_set.h create mode 100644 extensions/stackdriver/opencensus/stats/view.h create mode 100644 extensions/stackdriver/opencensus/stats/view_data.h create mode 100644 extensions/stackdriver/opencensus/stats/view_descriptor.h create mode 100644 extensions/stackdriver/opencensus/tags/BUILD create mode 100644 extensions/stackdriver/opencensus/tags/context_util.h create mode 100644 extensions/stackdriver/opencensus/tags/internal/context_util.cc create mode 100644 extensions/stackdriver/opencensus/tags/internal/tag_key.cc create mode 100644 extensions/stackdriver/opencensus/tags/internal/tag_map.cc create mode 100644 extensions/stackdriver/opencensus/tags/internal/with_tag_map.cc create mode 100644 extensions/stackdriver/opencensus/tags/tag_key.h create mode 100644 extensions/stackdriver/opencensus/tags/tag_map.h create mode 100644 extensions/stackdriver/opencensus/tags/with_tag_map.h diff --git a/WORKSPACE b/WORKSPACE index 26248bd4a49..3c82adaf78d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -82,3 +82,16 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe go_rules_dependencies() go_register_toolchains(go_version = GO_VERSION) + +# TODO(bianpengyuan): remove this googleapis dep when upstream imports it in +# https://github.com/envoyproxy/envoy/pull/5387 +load("//extensions/stackdriver/opencensus:opencensus.bzl", "telemetry_googleapis") + +telemetry_googleapis() + +load("@telemetry_googleapis//:repository_rules.bzl", "switched_rules_by_language") + +switched_rules_by_language( + name = "com_google_googleapis_imports", + cc = True, +) diff --git a/extensions/stackdriver/opencensus/BUILD b/extensions/stackdriver/opencensus/BUILD new file mode 100644 index 00000000000..b79cfe1a282 --- /dev/null +++ b/extensions/stackdriver/opencensus/BUILD @@ -0,0 +1,15 @@ +# Copyright 2018, OpenCensus 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. + +licenses(["notice"]) # Apache 2.0 diff --git a/extensions/stackdriver/opencensus/README.md b/extensions/stackdriver/opencensus/README.md new file mode 100644 index 00000000000..fb8cb68cb39 --- /dev/null +++ b/extensions/stackdriver/opencensus/README.md @@ -0,0 +1,5 @@ +# Opencensus Library + +This folder includes opencensus library copied from with customization. Even though opencensus-cpp repo has already had bazel setup, the original code won't work out of box within a wasm sandbox or in an envoy worker silo, so we have to copy and customize it. + +The library is mainly used to do data aggregation for some predefined metrics and export them to Stackdriver. The code in this directory should mostly remain unchanged unless bug is found. \ No newline at end of file diff --git a/extensions/stackdriver/opencensus/common/internal/BUILD b/extensions/stackdriver/opencensus/common/internal/BUILD new file mode 100644 index 00000000000..917ad26a699 --- /dev/null +++ b/extensions/stackdriver/opencensus/common/internal/BUILD @@ -0,0 +1,60 @@ +# OpenCensus C++ internal libraries. +# +# Copyright 2017, OpenCensus 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. + +load( + "@envoy//bazel:envoy_build_system.bzl", + "envoy_cc_library", +) + +licenses(["notice"]) # Apache 2.0 + +envoy_cc_library( + name = "hash_mix", + hdrs = ["hash_mix.h"], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], +) + +envoy_cc_library( + name = "random_lib", + srcs = ["random.cc"], + hdrs = ["random.h"], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], + deps = [ + "@envoy//source/extensions/common/wasm/null:null_lib", + ], +) + +envoy_cc_library( + name = "string_vector_hash", + hdrs = ["string_vector_hash.h"], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], + deps = [":hash_mix"], +) diff --git a/extensions/stackdriver/opencensus/common/internal/hash_mix.h b/extensions/stackdriver/opencensus/common/internal/hash_mix.h new file mode 100644 index 00000000000..ed6e736adbd --- /dev/null +++ b/extensions/stackdriver/opencensus/common/internal/hash_mix.h @@ -0,0 +1,49 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_COMMON_INTERNAL_HASH_MIX_H_ +#define OPENCENSUS_COMMON_INTERNAL_HASH_MIX_H_ + +#include +#include + +namespace opencensus { +namespace common { + +// HashMix provides efficient mixing of hash values. +class HashMix final { + public: + HashMix() : hash_(1) {} + + // Mixes in another *hashed* value. + void Mix(std::size_t hash) { + // A multiplier that has been found to provide good mixing. + constexpr std::size_t kMul = + static_cast(0xdc3eb94af8ab4c93ULL); + hash_ *= kMul; + hash_ = + ((hash << 19) | (hash >> (std::numeric_limits::digits - 19))) + + hash; + } + + size_t get() const { return hash_; } + + private: + std::size_t hash_; +}; + +} // namespace common +} // namespace opencensus + +#endif // OPENCENSUS_COMMON_INTERNAL_HASH_MIX_H_ diff --git a/extensions/stackdriver/opencensus/common/internal/random.cc b/extensions/stackdriver/opencensus/common/internal/random.cc new file mode 100644 index 00000000000..5826f0f3391 --- /dev/null +++ b/extensions/stackdriver/opencensus/common/internal/random.cc @@ -0,0 +1,53 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/common/internal/random.h" + +#include + +namespace opencensus { +namespace common { + +uint64_t Generator::Random64() { return rng_(); } + +Random* Random::GetRandom() { + static auto* const global_random = new Random; + return global_random; +} + +uint32_t Random::GenerateRandom32() { return gen_.Random64(); } + +uint64_t Random::GenerateRandom64() { return gen_.Random64(); } + +float Random::GenerateRandomFloat() { + return static_cast(gen_.Random64()) / static_cast(UINT64_MAX); +} + +double Random::GenerateRandomDouble() { + return static_cast(gen_.Random64()) / static_cast(UINT64_MAX); +} + +void Random::GenerateRandomBuffer(uint8_t* buf, size_t buf_size) { + for (size_t i = 0; i < buf_size; i += sizeof(uint64_t)) { + uint64_t value = gen_.rng_(); + if (i + sizeof(uint64_t) <= buf_size) { + memcpy(&buf[i], &value, sizeof(uint64_t)); + } else { + memcpy(&buf[i], &value, buf_size - i); + } + } +} + +} // namespace common +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/common/internal/random.h b/extensions/stackdriver/opencensus/common/internal/random.h new file mode 100644 index 00000000000..d243abac9c2 --- /dev/null +++ b/extensions/stackdriver/opencensus/common/internal/random.h @@ -0,0 +1,77 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_COMMON_INTERNAL_RANDOM_H_ +#define OPENCENSUS_COMMON_INTERNAL_RANDOM_H_ + +#include +#include +#include + +#ifndef NULL_PLUGIN +#include "api/wasm/cpp/proxy_wasm_intrinsics.h" +#else +#include "extensions/common/wasm/null/null.h" +using namespace Envoy::Extensions::Common::Wasm::Null::Plugin; +#endif + +namespace opencensus { +namespace common { + +class Generator { + public: + Generator() : rng_(proxy_getCurrentTimeNanoseconds()) {} + explicit Generator(uint64_t seed) : rng_(seed) {} + + uint64_t Random64(); + + private: + friend class Random; + + std::mt19937_64 rng_; +}; + +class Random { + public: + // Initializes and returns a singleton Random generator. + static Random* GetRandom(); + + // Generating functions. + // Generates a random uint32_t + uint32_t GenerateRandom32(); + // Generates a random uint64_t + uint64_t GenerateRandom64(); + // Generates a random float between [0.0, 1.0] + float GenerateRandomFloat(); + // Generates a random double between [0.0, 1.0] + double GenerateRandomDouble(); + // Fills the given buffer with uniformly random bits. + void GenerateRandomBuffer(uint8_t* buf, size_t buf_size); + + private: + Random() = default; + + Random(const Random&) = delete; + Random(Random&&) = delete; + Random& operator=(const Random&) = delete; + Random& operator=(Random&&) = delete; + + uint64_t GenerateValue(); + Generator gen_; +}; + +} // namespace common +} // namespace opencensus + +#endif // OPENCENSUS_COMMON_INTERNAL_RANDOM_H_ diff --git a/extensions/stackdriver/opencensus/common/internal/string_vector_hash.h b/extensions/stackdriver/opencensus/common/internal/string_vector_hash.h new file mode 100644 index 00000000000..66d961a2aa4 --- /dev/null +++ b/extensions/stackdriver/opencensus/common/internal/string_vector_hash.h @@ -0,0 +1,41 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_COMMON_INTERNAL_STRING_VECTOR_HASH_H_ +#define OPENCENSUS_COMMON_INTERNAL_STRING_VECTOR_HASH_H_ + +#include +#include +#include + +#include "opencensus/common/internal/hash_mix.h" + +namespace opencensus { +namespace common { + +struct StringVectorHash { + std::size_t operator()(const std::vector& container) const { + std::hash hasher; + HashMix mixer; + for (const auto& elem : container) { + mixer.Mix(hasher(elem)); + } + return mixer.get(); + } +}; + +} // namespace common +} // namespace opencensus + +#endif // OPENCENSUS_COMMON_INTERNAL_STRING_VECTOR_HASH_H_ diff --git a/extensions/stackdriver/opencensus/context/BUILD b/extensions/stackdriver/opencensus/context/BUILD new file mode 100644 index 00000000000..b7e20f0dddb --- /dev/null +++ b/extensions/stackdriver/opencensus/context/BUILD @@ -0,0 +1,42 @@ +# OpenCensus C++ Context library. +# See context.h for details. +# +# Copyright 2018, OpenCensus 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. + +load( + "@envoy//bazel:envoy_build_system.bzl", + "envoy_cc_library", +) + +envoy_cc_library( + name = "context", + srcs = [ + "internal/context.cc", + "internal/with_context.cc", + ], + hdrs = [ + "context.h", + "with_context.h", + ], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], + deps = [ + "//extensions/stackdriver/opencensus/tags", + ], +) diff --git a/extensions/stackdriver/opencensus/context/context.h b/extensions/stackdriver/opencensus/context/context.h new file mode 100644 index 00000000000..73a87c61303 --- /dev/null +++ b/extensions/stackdriver/opencensus/context/context.h @@ -0,0 +1,74 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_CONTEXT_CONTEXT_H_ +#define OPENCENSUS_CONTEXT_CONTEXT_H_ + +#include +#include + +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace tags { +class ContextPeer; +class WithTagMap; +} // namespace tags +namespace context { + +// Context holds information specific to an operation, such as a TagMap and +// Span. Each thread has a currently active Context. Contexts are conceptually +// immutable: the contents of a Context cannot be modified in-place. +// +// This is a draft implementation of Context, and we chose to depend on TagMap +// and Span directly. In future, the implementation will change, so only rely +// on the public API for manipulating Contexts. In future we may support +// arbitrary keys and values. +class Context { + public: + // Returns a const reference to the current (thread local) Context. + static const Context& Current(); + + // Context is copiable and movable. + Context(const Context&) = default; + Context(Context&&) = default; + Context& operator=(const Context&) = default; + Context& operator=(Context&&) = default; + + // Returns an std::function wrapped to run with a copy of this Context. + std::function Wrap(std::function fn) const; + + // Returns a human-readable string for debugging. Do not rely on its format or + // try to parse it. Do not use the DebugString to retrieve Tags. + std::string DebugString() const; + + private: + // Creates a default Context. + Context(); + + static Context* InternalMutableCurrent(); + friend void swap(Context& a, Context& b); + + friend class ContextTestPeer; + friend class WithContext; + friend class ::opencensus::tags::ContextPeer; + friend class ::opencensus::tags::WithTagMap; + + opencensus::tags::TagMap tags_; +}; + +} // namespace context +} // namespace opencensus + +#endif // OPENCENSUS_CONTEXT_CONTEXT_H_ diff --git a/extensions/stackdriver/opencensus/context/internal/context.cc b/extensions/stackdriver/opencensus/context/internal/context.cc new file mode 100644 index 00000000000..11eefc11096 --- /dev/null +++ b/extensions/stackdriver/opencensus/context/internal/context.cc @@ -0,0 +1,58 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/context/context.h" + +#include +#include + +#include "absl/strings/str_cat.h" +#include "opencensus/context/with_context.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace context { + +Context::Context() : tags_(opencensus::tags::TagMap({})) {} + +// static +const Context& Context::Current() { return *InternalMutableCurrent(); } + +std::function Context::Wrap(std::function fn) const { + Context copy(Context::Current()); + return [fn, copy]() { + WithContext wc(copy); + fn(); + }; +} + +std::string Context::DebugString() const { + return absl::StrCat("ctx@", absl::Hex(this), + " tags=", tags_.DebugString()); +} + +// static +Context* Context::InternalMutableCurrent() { + static Context* thread_ctx = nullptr; + if (thread_ctx == nullptr) thread_ctx = new Context; + return thread_ctx; +} + +void swap(Context& a, Context& b) { + using std::swap; + swap(a.tags_, b.tags_); +} + +} // namespace context +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/context/internal/with_context.cc b/extensions/stackdriver/opencensus/context/internal/with_context.cc new file mode 100644 index 00000000000..97eaf29dcdf --- /dev/null +++ b/extensions/stackdriver/opencensus/context/internal/with_context.cc @@ -0,0 +1,56 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/context/with_context.h" + +#include + +#include "opencensus/context/context.h" + +namespace opencensus { +namespace context { + +WithContext::WithContext(const Context& ctx, bool cond) + : swapped_context_(cond ? ctx : Context()) +#ifndef NDEBUG + , + original_context_(Context::InternalMutableCurrent()) +#endif + , + cond_(cond) { + ConditionalSwap(); +} + +WithContext::WithContext(Context&& ctx, bool cond) + : swapped_context_(cond ? std::move(ctx) : Context()) +#ifndef NDEBUG + , + original_context_(Context::InternalMutableCurrent()) +#endif + , + cond_(cond) { + ConditionalSwap(); +} + +WithContext::~WithContext() { ConditionalSwap(); } + +void WithContext::ConditionalSwap() { + if (cond_) { + using std::swap; + swap(*Context::InternalMutableCurrent(), swapped_context_); + } +} + +} // namespace context +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/context/with_context.h b/extensions/stackdriver/opencensus/context/with_context.h new file mode 100644 index 00000000000..ba921102a7c --- /dev/null +++ b/extensions/stackdriver/opencensus/context/with_context.h @@ -0,0 +1,61 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_CONTEXT_WITH_CONTEXT_H_ +#define OPENCENSUS_CONTEXT_WITH_CONTEXT_H_ + +#include "opencensus/context/context.h" + +namespace opencensus { +namespace context { + +// WithContext is a scoped object that sets the current Context to the given +// one, until the WithContext object is destroyed. If the condition is false, it +// doesn't do anything. +// +// Because WithContext changes the current (thread local) context, NEVER +// allocate a WithContext in one thread and deallocate in another. A simple way +// to ensure this is to only ever stack-allocate it. +// +// Example usage: +// { +// WithContext wc(op.ctx_); +// // Do work. +// } +class WithContext { + public: + explicit WithContext(const Context& ctx, bool cond = true); + explicit WithContext(Context&& ctx, bool cond = true); + ~WithContext(); + + private: + WithContext() = delete; + WithContext(const WithContext&) = delete; + WithContext(WithContext&&) = delete; + WithContext& operator=(const WithContext&) = delete; + WithContext& operator=(WithContext&&) = delete; + + void ConditionalSwap(); + + Context swapped_context_; +#ifndef NDEBUG + const Context* original_context_; +#endif + const bool cond_; +}; + +} // namespace context +} // namespace opencensus + +#endif // OPENCENSUS_CONTEXT_WITH_CONTEXT_H_ diff --git a/extensions/stackdriver/opencensus/opencensus.bzl b/extensions/stackdriver/opencensus/opencensus.bzl new file mode 100644 index 00000000000..ca659113958 --- /dev/null +++ b/extensions/stackdriver/opencensus/opencensus.bzl @@ -0,0 +1,30 @@ +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# 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. +# +################################################################################ +# + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +TELEMETRY_GOOGLEAPIS_SHA="c39b7e880e6db2ce61704da2a55083ea17fdb14b" +TELEMETRY_GOOGLEAPIS_SHA256="ee05b85961aa721671d85c111c6287e9667e69b616d97959588b1a991ef44a2d" +TELEMETRY_GOOGLEAPIS_URLS=["https://github.com/googleapis/googleapis/archive/" + TELEMETRY_GOOGLEAPIS_SHA + ".tar.gz"] + +def telemetry_googleapis(): + http_archive( + name = "telemetry_googleapis", + urls = TELEMETRY_GOOGLEAPIS_URLS, + sha256 = TELEMETRY_GOOGLEAPIS_SHA256, + strip_prefix = "googleapis-" + TELEMETRY_GOOGLEAPIS_SHA, + ) diff --git a/extensions/stackdriver/opencensus/stats/BUILD b/extensions/stackdriver/opencensus/stats/BUILD new file mode 100644 index 00000000000..f52223a5d4d --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/BUILD @@ -0,0 +1,111 @@ +# OpenCensus C++ Stats library. +# +# Copyright 2017, OpenCensus 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. + +load( + "@envoy//bazel:envoy_build_system.bzl", + "envoy_cc_library", +) + +envoy_cc_library( + name = "stats", + hdrs = [ + "internal/aggregation_window.h", + "internal/set_aggregation_window.h", + "stats.h", + "stats_exporter.h", + ], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], + deps = [ + ":core", + ":recording", + ], +) + +envoy_cc_library( + name = "core", + srcs = [ + "internal/aggregation.cc", + "internal/aggregation_window.cc", + "internal/bucket_boundaries.cc", + "internal/delta_producer.cc", + "internal/distribution.cc", + "internal/measure.cc", + "internal/measure_data.cc", + "internal/measure_descriptor.cc", + "internal/measure_registry.cc", + "internal/measure_registry_impl.cc", + "internal/set_aggregation_window.cc", + "internal/stats_exporter.cc", + "internal/stats_manager.cc", + "internal/view.cc", + "internal/view_data.cc", + "internal/view_data_impl.cc", + "internal/view_descriptor.cc", + ], + hdrs = [ + "aggregation.h", + "bucket_boundaries.h", + "distribution.h", + "internal/aggregation_window.h", + "internal/delta_producer.h", + "internal/measure_data.h", + "internal/measure_registry_impl.h", + "internal/set_aggregation_window.h", + "internal/stats_exporter_impl.h", + "internal/stats_manager.h", + "internal/view_data_impl.h", + "measure.h", + "measure_descriptor.h", + "measure_registry.h", + "stats_exporter.h", + "tag_key.h", + "tag_set.h", + "view.h", + "view_data.h", + "view_descriptor.h", + ], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + deps = [ + "//extensions/stackdriver/opencensus/common/internal:string_vector_hash", + "//extensions/stackdriver/opencensus/tags", + "@envoy//source/extensions/common/wasm/null:null_lib", + ], +) + +envoy_cc_library( + name = "recording", + srcs = ["internal/recording.cc"], + hdrs = ["recording.h"], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + deps = [ + ":core", + "//extensions/stackdriver/opencensus/tags", + "//extensions/stackdriver/opencensus/tags:context_util", + ], +) diff --git a/extensions/stackdriver/opencensus/stats/aggregation.h b/extensions/stackdriver/opencensus/stats/aggregation.h new file mode 100644 index 00000000000..cff6ec1abd2 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/aggregation.h @@ -0,0 +1,87 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_AGGREGATION_H_ +#define OPENCENSUS_STATS_AGGREGATION_H_ + +#include +#include + +#include "opencensus/stats/bucket_boundaries.h" + +namespace opencensus { +namespace stats { + +// Aggregation defines how to aggregate data for each view. See the static +// constructors for details of the various options. +// Aggregation is immutable. +class Aggregation final { + public: + // Count aggregation counts the number of records, ignoring their individual + // values. Note that 'count' measures (e.g. the count of RPCs received) should + // use Sum() aggregation to correctly handle non-unit recorded values. + static Aggregation Count() { + return Aggregation(Type::kCount, BucketBoundaries::Explicit({})); + } + + // Sum aggregation sums all records. + static Aggregation Sum() { + return Aggregation(Type::kSum, BucketBoundaries::Explicit({})); + } + + // Distribution aggregation calculates distribution statistics (count, mean, + // range, and sum of squared deviation) and tracks a histogram of recorded + // values according to 'buckets'. + static Aggregation Distribution(BucketBoundaries buckets) { + return Aggregation(Type::kDistribution, std::move(buckets)); + } + + // LastValue aggregation returns the last value recorded. + static Aggregation LastValue() { + return Aggregation(Type::kLastValue, BucketBoundaries::Explicit({})); + } + + enum class Type { + kCount, + kSum, + kDistribution, + kLastValue, + }; + + Type type() const { return type_; } + const BucketBoundaries& bucket_boundaries() const { + return bucket_boundaries_; + } + + std::string DebugString() const; + + bool operator==(const Aggregation& other) const { + return type_ == other.type_ && + bucket_boundaries_ == other.bucket_boundaries_; + } + bool operator!=(const Aggregation& other) const { return !(*this == other); } + + private: + Aggregation(Type type, BucketBoundaries buckets) + : type_(type), bucket_boundaries_(std::move(buckets)) {} + + Type type_; + // Ignored except if type_ == kDistribution. + BucketBoundaries bucket_boundaries_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_AGGREGATION_H_ diff --git a/extensions/stackdriver/opencensus/stats/bucket_boundaries.h b/extensions/stackdriver/opencensus/stats/bucket_boundaries.h new file mode 100644 index 00000000000..ab3480bc54a --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/bucket_boundaries.h @@ -0,0 +1,85 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_BUCKET_BOUNDARIES_H_ +#define OPENCENSUS_STATS_BUCKET_BOUNDARIES_H_ + +#include +#include +#include + +namespace opencensus { +namespace stats { + +// BucketBoundaries defines the bucket boundaries for distribution +// aggregations. +// BucketBoundaries is a value type, and is thread-compatible. +class BucketBoundaries final { + public: + // Creates a BucketBoundaries with num_finite_buckets each 'width' wide, + // as well as an underflow and overflow bucket. 'offset' is the lower bound of + // the first finite bucket, so finite bucket i (1 <= i <= num_finite_buckets) + // covers the interval [offset + (i - 1) * width, offset + i * width). The + // underflow bucket covers [-inf, offset) and the overflow bucket [offset + + // num_finite_buckets * width, inf]. + static BucketBoundaries Linear(int num_finite_buckets, double offset, + double width); + + // Creates a BucketBoundaries with num_finite_buckets with exponentially + // increasing boundaries starting at zero (governed by growth_factor and + // scale), as well as an underflow and overflow bucket. Finite bucket i (1 <= + // i <= num_finite_buckets) covers the interval [scale * growth_factor ^ (i - + // 1), scale * growth_factor ^ i). The underflow bucket covers [-inf, 0) and + // the overflow bucket [scale * growth_factor ^ num_finite_buckets, inf]. + static BucketBoundaries Exponential(int num_finite_buckets, double scale, + double growth_factor); + + // Creates a BucketBoundaries from a monotonically increasing list of + // boundaries. This will create a bucket covering each interval of + // [boundaries[i], boundaries[i+1]), as well as an underflow bucket covering + // [-inf, boundaries[0]) and an overflow bucket covering + // [boundaries[boundaries.size()-1], inf]. + static BucketBoundaries Explicit(std::vector boundaries); + + // The number of buckets in a Distribution using this bucketer. + int num_buckets() const { return lower_boundaries_.size() + 1; } + // The index of the bucket for a given value, in [0, num_buckets() - 1]. + int BucketForValue(double value) const; + + const std::vector& lower_boundaries() const { + return lower_boundaries_; + } + + std::string DebugString() const; + + bool operator==(const BucketBoundaries& other) const { + return lower_boundaries_ == other.lower_boundaries_; + } + bool operator!=(const BucketBoundaries& other) const { + return !(*this == other); + } + + private: + BucketBoundaries(std::vector lower_boundaries) + : lower_boundaries_(std::move(lower_boundaries)) {} + + // The lower bound of each bucket, excluding the underflow bucket but + // including the overflow bucket. + std::vector lower_boundaries_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_BUCKET_BOUNDARIES_H_ diff --git a/extensions/stackdriver/opencensus/stats/distribution.h b/extensions/stackdriver/opencensus/stats/distribution.h new file mode 100644 index 00000000000..d575fd6f5a8 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/distribution.h @@ -0,0 +1,78 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_DISTRIBUTION_H_ +#define OPENCENSUS_STATS_DISTRIBUTION_H_ + +#include +#include +#include +#include + +#include "opencensus/stats/bucket_boundaries.h" + +namespace opencensus { +namespace stats { + +// A Distribution object holds a summary of a stream of double values (e.g. all +// values for one measure and set of tags). It stores both a statistical summary +// (mean, sum of squared deviation, and range) and a histogram recording the +// number of values in each bucket (as defined by a BucketBoundaries). +// This corresponds to a Stackdriver Distribution metric +// (https://cloud.google.com/monitoring/api/ref_v3/rest/v3/TypedValue#Distribution). +// Distribution is thread-compatible. +class Distribution final { + public: + const std::vector& bucket_counts() const { return bucket_counts_; } + + uint64_t count() const { return count_; } + double mean() const { return mean_; } + double sum_of_squared_deviation() const { return sum_of_squared_deviation_; } + double min() const { return min_; } + double max() const { return max_; } + + const BucketBoundaries& bucket_boundaries() const { return *buckets_; } + + // A string representation of the Distribution's data suitable for human + // consumption. + std::string DebugString() const; + + private: + friend class ViewDataImpl; // ViewDataImpl populates data directly. + friend class MeasureData; + + // buckets must outlive the Distribution. + explicit Distribution(const BucketBoundaries* buckets); + + // Adds 'value' to the distribution. 'value' does not need to be finite, but + // non-finite values may make statistics meaningless. + void Add(double value); + + const BucketBoundaries* const buckets_; // Never null; not owned. + + uint64_t count_ = 0; + double mean_ = 0; + double sum_of_squared_deviation_ = 0; + double min_ = std::numeric_limits::infinity(); + double max_ = -std::numeric_limits::infinity(); + + // The counts of values in the buckets listed in buckets_. Size is + // buckets_->num_buckets(). + std::vector bucket_counts_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_DISTRIBUTION_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/aggregation.cc b/extensions/stackdriver/opencensus/stats/internal/aggregation.cc new file mode 100644 index 00000000000..30a7751301d --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/aggregation.cc @@ -0,0 +1,37 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/aggregation.h" +#include "absl/strings/str_cat.h" + +namespace opencensus { +namespace stats { + +std::string Aggregation::DebugString() const { + switch (type_) { + case Type::kCount: + return "Count"; + case Type::kSum: + return "Sum"; + case Type::kDistribution: + return absl::StrCat("Distribution with ", + bucket_boundaries_.DebugString()); + case Type::kLastValue: + return "Last Value"; + } + return "BAD TYPE"; +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/aggregation_window.cc b/extensions/stackdriver/opencensus/stats/internal/aggregation_window.cc new file mode 100644 index 00000000000..5656d3de570 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/aggregation_window.cc @@ -0,0 +1,35 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/internal/aggregation_window.h" + +#include "absl/strings/str_cat.h" + +namespace opencensus { +namespace stats { + +std::string AggregationWindow::DebugString() const { + switch (type_) { + case Type::kCumulative: + return "Cumulative"; + case Type::kDelta: + return "Delta"; + case Type::kInterval: + return absl::StrCat("Interval (", duration_ / 1000, "s window)"); + } + return "BAD TYPE"; +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/aggregation_window.h b/extensions/stackdriver/opencensus/stats/internal/aggregation_window.h new file mode 100644 index 00000000000..7583f3ae131 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/aggregation_window.h @@ -0,0 +1,77 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_AGGREGATION_WINDOW_H_ +#define OPENCENSUS_STATS_INTERNAL_AGGREGATION_WINDOW_H_ + +#include +#include + +namespace opencensus { +namespace stats { + +// AggregationWindow defines the time range over which recorded data is +// aggregated for each view. +// AggregationWindow is immutable. +class AggregationWindow final { + public: + // Cumulative aggregation accumulates data over the lifetime of the process. + static AggregationWindow Cumulative() { + return AggregationWindow(Type::kCumulative, ULLONG_MAX); + } + + // Delta aggregation accumulates data until it is requested and then resets + // it, so that each recorded value appears in exactly one delta. + static AggregationWindow Delta() { + return AggregationWindow(Type::kDelta, ULLONG_MAX); + } + + // Interval aggregation keeps a rolling total of usage over the previous + // 'interval' of time. + static AggregationWindow Interval(uint64_t interval) { + return AggregationWindow(Type::kInterval, interval); + } + + enum class Type { + kCumulative, + kDelta, + kInterval, + }; + + Type type() const { return type_; } + uint64_t duration() const { return duration_; } + + std::string DebugString() const; + + bool operator==(const AggregationWindow& other) const { + return type_ == other.type_ && duration_ == other.duration_; + } + bool operator!=(const AggregationWindow& other) const { + return !(*this == other); + } + + private: + AggregationWindow(Type type, uint64_t duration) + : type_(type), duration_(duration) {} + + Type type_; + // Should always be InfiniteDuration if type_ == kCumulative, to simplify + // equality checking. + uint64_t duration_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_AGGREGATION_WINDOW_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/bucket_boundaries.cc b/extensions/stackdriver/opencensus/stats/internal/bucket_boundaries.cc new file mode 100644 index 00000000000..6b34726f0d4 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/bucket_boundaries.cc @@ -0,0 +1,77 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/bucket_boundaries.h" + +#include +#include + +#include "absl/base/macros.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" + +namespace opencensus { +namespace stats { + +// Class-level todos: +// TODO: Consider lazy generation of storage buckets, to save memory +// when few buckets are populated. +// TODO: Share bucketers, or at least the lower_boundaries_ vector, to +// reduce allocation/copying for copies of Aggregation objects. + +// static +BucketBoundaries BucketBoundaries::Linear(int num_finite_buckets, double offset, + double width) { + std::vector boundaries(num_finite_buckets + 1); + double boundary = offset; + for (int i = 0; i <= num_finite_buckets; ++i) { + boundaries[i] = boundary; + boundary += width; + } + return BucketBoundaries(std::move(boundaries)); +} + +// static +BucketBoundaries BucketBoundaries::Exponential(int num_finite_buckets, + double scale, + double growth_factor) { + std::vector boundaries(num_finite_buckets + 1); + double upper_bound = scale; + for (int i = 1; i <= num_finite_buckets; ++i) { + boundaries[i] = upper_bound; + upper_bound *= growth_factor; + } + return BucketBoundaries(std::move(boundaries)); +} + +// static +BucketBoundaries BucketBoundaries::Explicit(std::vector boundaries) { + if (!std::is_sorted(boundaries.begin(), boundaries.end())) { + return BucketBoundaries({}); + } + return BucketBoundaries(std::move(boundaries)); +} + +int BucketBoundaries::BucketForValue(double value) const { + return std::upper_bound(lower_boundaries_.begin(), lower_boundaries_.end(), + value) - + lower_boundaries_.begin(); +} + +std::string BucketBoundaries::DebugString() const { + return absl::StrCat("Buckets: ", absl::StrJoin(lower_boundaries_, ",")); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/delta_producer.cc b/extensions/stackdriver/opencensus/stats/internal/delta_producer.cc new file mode 100644 index 00000000000..3720ca7a860 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/delta_producer.cc @@ -0,0 +1,118 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/stats/internal/delta_producer.h" + +#include +#include +#include +#include + +#include "opencensus/stats/bucket_boundaries.h" +#include "opencensus/stats/internal/measure_data.h" +#include "opencensus/stats/internal/measure_registry_impl.h" +#include "opencensus/stats/internal/stats_manager.h" + +namespace opencensus { +namespace stats { + +void Delta::Record(std::initializer_list measurements, + opencensus::tags::TagMap tags) { + auto it = delta_.find(tags); + if (it == delta_.end()) { + it = delta_.emplace_hint(it, std::piecewise_construct, + std::make_tuple(std::move(tags)), + std::make_tuple(std::vector())); + it->second.reserve(registered_boundaries_.size()); + for (const auto& boundaries_for_measure : registered_boundaries_) { + it->second.emplace_back(boundaries_for_measure); + } + } + for (const auto& measurement : measurements) { + const uint64_t index = MeasureRegistryImpl::IdToIndex(measurement.id_); + switch (MeasureRegistryImpl::IdToType(measurement.id_)) { + case MeasureDescriptor::Type::kDouble: + it->second[index].Add(measurement.value_double_); + break; + case MeasureDescriptor::Type::kInt64: + it->second[index].Add(measurement.value_int_); + break; + } + } +} + +void Delta::clear() { + registered_boundaries_.clear(); + delta_.clear(); +} + +void Delta::SwapAndReset( + std::vector>& registered_boundaries, + Delta* other) { + registered_boundaries_.swap(other->registered_boundaries_); + delta_.swap(other->delta_); + delta_.clear(); + registered_boundaries_ = registered_boundaries; +} + +DeltaProducer* DeltaProducer::Get() { + static DeltaProducer* global_delta_producer = new DeltaProducer; + return global_delta_producer; +} + +void DeltaProducer::AddMeasure() { + registered_boundaries_.push_back({}); + SwapDeltas(); + ConsumeLastDelta(); +} + +void DeltaProducer::AddBoundaries(uint64_t index, + const BucketBoundaries& boundaries) { + auto& measure_boundaries = registered_boundaries_[index]; + if (std::find(measure_boundaries.begin(), measure_boundaries.end(), + boundaries) == measure_boundaries.end()) { + measure_boundaries.push_back(boundaries); + SwapDeltas(); + ConsumeLastDelta(); + } else { + } +} + +void DeltaProducer::Record(std::initializer_list measurements, + opencensus::tags::TagMap tags) { + active_delta_.Record(measurements, std::move(tags)); +} + +bool DeltaProducer::Flush() { + SwapDeltas(); + if (last_delta_.delta().size() == 0) { + return false; + } + ConsumeLastDelta(); + return true; +} + +DeltaProducer::DeltaProducer() {} + +void DeltaProducer::SwapDeltas() { + active_delta_.SwapAndReset(registered_boundaries_, &last_delta_); +} + +void DeltaProducer::ConsumeLastDelta() { + StatsManager::Get()->MergeDelta(last_delta_); + last_delta_.clear(); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/delta_producer.h b/extensions/stackdriver/opencensus/stats/internal/delta_producer.h new file mode 100644 index 00000000000..a99169c14c2 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/delta_producer.h @@ -0,0 +1,110 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_DELTA_PRODUCER_H_ +#define OPENCENSUS_STATS_INTERNAL_DELTA_PRODUCER_H_ + +#include +#include +#include +#include + +#include "opencensus/stats/bucket_boundaries.h" +#include "opencensus/stats/distribution.h" +#include "opencensus/stats/internal/measure_data.h" +#include "opencensus/stats/measure.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace stats { + +// Delta is thread-compatible. +class Delta final { + public: + void Record(std::initializer_list measurements, + opencensus::tags::TagMap tags); + + // Swaps registered_boundaries_ and delta_ with *other, clears delta_, and + // updates registered_boundaries_. + void SwapAndReset( + std::vector>& registered_boundaries, + Delta* other); + + // Clears registered_boundaries_ and delta_. + void clear(); + + const std::unordered_map, + opencensus::tags::TagMap::Hash>& + delta() const { + return delta_; + } + + private: + // A copy of registered_boundaries_ in the DeltaProducer as of when the + // delta was started. + std::vector> registered_boundaries_; + + // The actual data. Each MeasureData[] contains one element for each + // registered measure. + std::unordered_map, + opencensus::tags::TagMap::Hash> + delta_; +}; + +// DeltaProducer is thread-safe. +class DeltaProducer final { + public: + // Returns a pointer to the singleton DeltaProducer. + static DeltaProducer* Get(); + + // Adds a new Measure. + void AddMeasure(); + + // Adds a new BucketBoundaries for the measure 'index' if it does not already + // exist. + void AddBoundaries(uint64_t index, const BucketBoundaries& boundaries); + + void Record(std::initializer_list measurements, + opencensus::tags::TagMap tags); + + // Flushes the active delta and blocks until it is harvested. + // Returns true if there is measurement added since last flush, returns false + // if no measurement is added. + bool Flush(); + + private: + DeltaProducer(); + + // Flushing has two stages: swapping active_delta_ to last_delta_ and + // consuming last_delta_. Callers should release delta_mu_ before calling + // ConsumeLastDelta so that Record() is blocked for as little time as + // possible. SwapDeltas should never be called without then calling + // ConsumeLastDelta--otherwise the delta will be lost. + void SwapDeltas(); + void ConsumeLastDelta(); + + // The BucketBoundaries of each registered view with Distribution aggregation, + // by measure. Array indices in the outer array correspond to measure indices. + std::vector> registered_boundaries_; + Delta active_delta_; + + // TODO: consider making this a lockless queue to avoid blocking the main + // thread when calling a flush during harvesting. + Delta last_delta_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_DELTA_PRODUCER_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/distribution.cc b/extensions/stackdriver/opencensus/stats/internal/distribution.cc new file mode 100644 index 00000000000..82cd332f002 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/distribution.cc @@ -0,0 +1,50 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/distribution.h" + +#include + +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" + +namespace opencensus { +namespace stats { + +Distribution::Distribution(const BucketBoundaries* buckets) + : buckets_(buckets), bucket_counts_(buckets->num_buckets()) {} + +void Distribution::Add(double value) { + // Update using the method of provisional means. + ++count_; + const double new_mean = mean_ + (value - mean_) / count_; + sum_of_squared_deviation_ = + sum_of_squared_deviation_ + (value - mean_) * (value - new_mean); + mean_ = new_mean; + + min_ = std::min(value, min_); + max_ = std::max(value, max_); + + ++bucket_counts_[buckets_->BucketForValue(value)]; +} + +std::string Distribution::DebugString() const { + return absl::StrCat("count: ", count_, " mean: ", mean_, + " sum of squared deviation: ", sum_of_squared_deviation_, + " min: ", min_, " max: ", max_, "\nhistogram counts: ", + absl::StrJoin(bucket_counts_, ", ")); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/measure.cc b/extensions/stackdriver/opencensus/stats/internal/measure.cc new file mode 100644 index 00000000000..b4bba54b1ff --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure.cc @@ -0,0 +1,60 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/measure.h" + +#include "absl/strings/string_view.h" +#include "opencensus/stats/internal/measure_registry_impl.h" +#include "opencensus/stats/measure_registry.h" + +namespace opencensus { +namespace stats { + +// static +template +Measure Measure::Register(absl::string_view name, + absl::string_view description, + absl::string_view units) { + return MeasureRegistryImpl::Get()->Register(name, description, + units); +} + +template +const MeasureDescriptor& Measure::GetDescriptor() const { + return MeasureRegistryImpl::Get()->GetDescriptor(*this); +} + +// This is specialized so that we can also check whether the type matches the +// template type, in case an otherwise-valid measure in a union is being +// accessed via the wrong type. +template <> +bool MeasureDouble::IsValid() const { + return MeasureRegistryImpl::IdValid(id_) && + MeasureRegistryImpl::IdToType(id_) == MeasureDescriptor::Type::kDouble; +} + +template <> +bool MeasureInt64::IsValid() const { + return MeasureRegistryImpl::IdValid(id_) && + MeasureRegistryImpl::IdToType(id_) == MeasureDescriptor::Type::kInt64; +} + +template +Measure::Measure(uint64_t id) : id_(id) {} + +template class Measure; +template class Measure; + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/measure_data.cc b/extensions/stackdriver/opencensus/stats/internal/measure_data.cc new file mode 100644 index 00000000000..14fd70ef976 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure_data.cc @@ -0,0 +1,107 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/stats/internal/measure_data.h" + +#include +#include +#include +#include + +#include "absl/base/macros.h" +#include "absl/types/span.h" +#include "opencensus/stats/bucket_boundaries.h" +#include "opencensus/stats/distribution.h" + +namespace opencensus { +namespace stats { + +MeasureData::MeasureData(absl::Span boundaries) + : boundaries_(boundaries) { + histograms_.reserve(boundaries_.size()); + for (const auto& b : boundaries_) { + histograms_.emplace_back(b.num_buckets()); + } +} + +void MeasureData::Add(double value) { + last_value_ = value; + // Update using the method of provisional means. + ++count_; + const double old_mean = mean_; + mean_ += (value - mean_) / count_; + sum_of_squared_deviation_ = + sum_of_squared_deviation_ + (value - old_mean) * (value - mean_); + + min_ = std::min(value, min_); + max_ = std::max(value, max_); + + for (uint32_t i = 0; i < boundaries_.size(); ++i) { + ++histograms_[i][boundaries_[i].BucketForValue(value)]; + } +} + +void MeasureData::AddToDistribution(Distribution* distribution) const { + AddToDistribution(distribution->bucket_boundaries(), &distribution->count_, + &distribution->mean_, + &distribution->sum_of_squared_deviation_, + &distribution->min_, &distribution->max_, + absl::Span(distribution->bucket_counts_)); +} + +template +void MeasureData::AddToDistribution(const BucketBoundaries& boundaries, + T* count, double* mean, + double* sum_of_squared_deviation, + double* min, double* max, + absl::Span histogram_buckets) const { + // This uses the method of provisional means generalized for multiple values + // in both datasets. + const double new_count = *count + count_; + const double new_mean = *mean + (mean_ - *mean) * count_ / new_count; + *sum_of_squared_deviation += + sum_of_squared_deviation_ + *count * std::pow(*mean, 2) + + count_ * std::pow(mean_, 2) - new_count * std::pow(new_mean, 2); + *count = new_count; + *mean = new_mean; + + if (*count == count_) { + // Overwrite in case the destination was zero-initialized. + *min = min_; + *max = max_; + } else { + *min = std::min(*min, min_); + *max = std::max(*max, max_); + } + + uint32_t histogram_index = + std::find(boundaries_.begin(), boundaries_.end(), boundaries) - + boundaries_.begin(); + if (histogram_index >= histograms_.size()) { + // Add to the underflow bucket, to avoid downstream errors from the sum of + // bucket counts not matching the total count. + histogram_buckets[0] += count_; + } else { + for (uint32_t i = 0; i < histograms_[histogram_index].size(); ++i) { + histogram_buckets[i] += histograms_[histogram_index][i]; + } + } +} + +template void MeasureData::AddToDistribution(const BucketBoundaries&, double*, + double*, double*, double*, double*, + absl::Span) const; + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/measure_data.h b/extensions/stackdriver/opencensus/stats/internal/measure_data.h new file mode 100644 index 00000000000..8d2d4c7ad49 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure_data.h @@ -0,0 +1,75 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_MEASURE_DATA_H_ +#define OPENCENSUS_STATS_INTERNAL_MEASURE_DATA_H_ + +#include +#include +#include + +#include "absl/types/span.h" +#include "opencensus/stats/bucket_boundaries.h" +#include "opencensus/stats/distribution.h" + +namespace opencensus { +namespace stats { + +// MeasureData tracks all aggregations for a single measure, including +// histograms for a number of different BucketBoundaries. +// +// MeasureData is thread-compatible. +class MeasureData final { + public: + MeasureData(absl::Span boundaries); + + void Add(double value); + + double last_value() const { return last_value_; } + uint64_t count() const { return count_; } + double sum() const { return count_ * mean_; } + + // Adds this to 'distribution'. Requires that + // distribution->bucket_boundaries() be in the set of boundaries passed to + // this on construction. + void AddToDistribution(Distribution* distribution) const; + + // Adds this to a distribution by pointers to individual elements. + template + void AddToDistribution(const BucketBoundaries& boundaries, T* count, + double* mean, double* sum_of_squared_deviation, + double* min, double* max, + absl::Span histogram_buckets) const; + + private: + const absl::Span boundaries_; + + double last_value_ = std::numeric_limits::quiet_NaN(); + uint64_t count_ = 0; + double mean_ = 0; + double sum_of_squared_deviation_ = 0; + double min_ = std::numeric_limits::infinity(); + double max_ = -std::numeric_limits::infinity(); + std::vector> histograms_; +}; + +extern template void MeasureData::AddToDistribution(const BucketBoundaries&, + double*, double*, double*, + double*, double*, + absl::Span) const; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_MEASURE_DATA_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/measure_descriptor.cc b/extensions/stackdriver/opencensus/stats/internal/measure_descriptor.cc new file mode 100644 index 00000000000..eeb9eba6f04 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure_descriptor.cc @@ -0,0 +1,29 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/measure_descriptor.h" + +#include "absl/strings/str_cat.h" + +namespace opencensus { +namespace stats { + +std::string MeasureDescriptor::DebugString() const { + return absl::StrCat( + "name: \"", name_, "\"; units: \"", units_, "\"; description: \"", + description_, "\"; type: ", type_ == Type::kDouble ? "double" : "int64"); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/measure_registry.cc b/extensions/stackdriver/opencensus/stats/internal/measure_registry.cc new file mode 100644 index 00000000000..e342db042c6 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure_registry.cc @@ -0,0 +1,39 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/measure_registry.h" + +#include "opencensus/stats/internal/measure_registry_impl.h" + +namespace opencensus { +namespace stats { + +// static +const MeasureDescriptor& MeasureRegistry::GetDescriptorByName( + absl::string_view name) { + return MeasureRegistryImpl::Get()->GetDescriptorByName(name); +} + +// static +MeasureDouble MeasureRegistry::GetMeasureDoubleByName(absl::string_view name) { + return MeasureRegistryImpl::Get()->GetMeasureDoubleByName(name); +} + +// static +MeasureInt64 MeasureRegistry::GetMeasureInt64ByName(absl::string_view name) { + return MeasureRegistryImpl::Get()->GetMeasureInt64ByName(name); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.cc b/extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.cc new file mode 100644 index 00000000000..aab32de3f6e --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.cc @@ -0,0 +1,150 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/internal/measure_registry_impl.h" + +#include "opencensus/stats/internal/delta_producer.h" +#include "opencensus/stats/internal/stats_manager.h" +#include "opencensus/stats/measure_descriptor.h" + +namespace opencensus { +namespace stats { + +namespace { + +// Constants for constructing/deconstructing ids. +constexpr uint64_t kIndexMask = 0x3FFFFFFFFFFFFFFFLL; +constexpr uint64_t kValid = 0x8000000000000000ull; +constexpr uint64_t kInvalid = 0x0000000000000000ull; +constexpr uint64_t kTypeMask = 0x4000000000000000ull; +constexpr uint64_t kDoubleType = 0x0000000000000000ull; +constexpr uint64_t kIntType = 0x4000000000000000ull; + +} // namespace + +// static +MeasureRegistryImpl* MeasureRegistryImpl::Get() { + static MeasureRegistryImpl* global_measure_registry_impl = + new MeasureRegistryImpl(); + return global_measure_registry_impl; +} + +template <> +MeasureDouble MeasureRegistryImpl::Register(absl::string_view name, + absl::string_view description, + absl::string_view units) { + MeasureDouble measure(RegisterImpl(MeasureDescriptor( + name, description, units, MeasureDescriptor::Type::kDouble))); + if (measure.IsValid()) { + StatsManager::Get()->AddMeasure(measure); + DeltaProducer::Get()->AddMeasure(); + } + return measure; +} + +template <> +MeasureInt64 MeasureRegistryImpl::Register(absl::string_view name, + absl::string_view description, + absl::string_view units) { + MeasureInt64 measure(RegisterImpl(MeasureDescriptor( + name, description, units, MeasureDescriptor::Type::kInt64))); + if (measure.IsValid()) { + StatsManager::Get()->AddMeasure(measure); + DeltaProducer::Get()->AddMeasure(); + } + return measure; +} + +uint64_t MeasureRegistryImpl::RegisterImpl(MeasureDescriptor descriptor) { + if (descriptor.name().empty()) { + return CreateMeasureId(0, false, descriptor.type()); + } + const auto it = id_map_.find(descriptor.name()); + if (it != id_map_.end()) { + return CreateMeasureId(0, false, descriptor.type()); + } + const uint64_t id = + CreateMeasureId(registered_descriptors_.size(), true, descriptor.type()); + id_map_.emplace_hint(it, descriptor.name(), id); + registered_descriptors_.push_back(std::move(descriptor)); + return id; +} + +const MeasureDescriptor& MeasureRegistryImpl::GetDescriptorByName( + absl::string_view name) const { + const auto it = id_map_.find(std::string(name)); + if (it == id_map_.end()) { + static const MeasureDescriptor default_descriptor = + MeasureDescriptor("", "", "", MeasureDescriptor::Type::kDouble); + return default_descriptor; + } else { + return registered_descriptors_[IdToIndex(it->second)]; + } +} + +MeasureDouble MeasureRegistryImpl::GetMeasureDoubleByName( + absl::string_view name) const { + const auto it = id_map_.find(std::string(name)); + if (it == id_map_.end()) { + return MeasureDouble( + CreateMeasureId(0, false, MeasureDescriptor::Type::kDouble)); + } else { + return MeasureDouble(it->second); + } +} + +MeasureInt64 MeasureRegistryImpl::GetMeasureInt64ByName( + absl::string_view name) const { + const auto it = id_map_.find(std::string(name)); + if (it == id_map_.end()) { + return MeasureInt64( + CreateMeasureId(0, false, MeasureDescriptor::Type::kDouble)); + } else { + return MeasureInt64(it->second); + } +} + +uint64_t MeasureRegistryImpl::GetIdByName(absl::string_view name) const { + const auto it = id_map_.find(std::string(name)); + if (it == id_map_.end()) { + return CreateMeasureId(0, false, MeasureDescriptor::Type::kDouble); + } else { + return it->second; + } +} + +// static +bool MeasureRegistryImpl::IdValid(uint64_t id) { return id & kValid; } + +// static +uint64_t MeasureRegistryImpl::IdToIndex(uint64_t id) { return id & kIndexMask; } + +// static +MeasureDescriptor::Type MeasureRegistryImpl::IdToType(uint64_t id) { + if ((id & kTypeMask) == kDoubleType) { + return MeasureDescriptor::Type::kDouble; + } else { + return MeasureDescriptor::Type::kInt64; + } +} + +// static +uint64_t MeasureRegistryImpl::CreateMeasureId(uint64_t index, bool is_valid, + MeasureDescriptor::Type type) { + return index | (is_valid ? kValid : kInvalid) | + (type == MeasureDescriptor::Type::kDouble ? kDoubleType : kIntType); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.h b/extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.h new file mode 100644 index 00000000000..2e4a8460876 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/measure_registry_impl.h @@ -0,0 +1,108 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_MEASURE_REGISTRY_IMPL_H_ +#define OPENCENSUS_STATS_INTERNAL_MEASURE_REGISTRY_IMPL_H_ + +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/stats/measure.h" +#include "opencensus/stats/measure_descriptor.h" + +namespace opencensus { +namespace stats { + +// MeasureRegistryImpl implements MeasureRegistry and holds internal-only +// helpers for Measure. +// MeasureRegistryImpl is thread-safe. +class MeasureRegistryImpl { + public: + static MeasureRegistryImpl* Get(); + + template + Measure Register(absl::string_view name, + absl::string_view description, + absl::string_view units); + + const MeasureDescriptor& GetDescriptorByName(absl::string_view name) const; + + MeasureDouble GetMeasureDoubleByName(absl::string_view name) const; + MeasureInt64 GetMeasureInt64ByName(absl::string_view name) const; + + // The following methods are for internal use by the library, and not exposed + // in the public MeasureRegistry. + uint64_t GetIdByName(absl::string_view name) const; + + template + const MeasureDescriptor& GetDescriptor(Measure measure) const; + + // Measure ids contain a sequential index, a validity bit, and a + // type bit; these functions access the individual parts. + static bool IdValid(uint64_t id); + static uint64_t IdToIndex(uint64_t id); + static MeasureDescriptor::Type IdToType(uint64_t id); + + template + static uint64_t MeasureToIndex(Measure measure); + + private: + MeasureRegistryImpl() = default; + + uint64_t RegisterImpl(MeasureDescriptor descriptor); + + static uint64_t CreateMeasureId(uint64_t index, bool is_valid, + MeasureDescriptor::Type type); + + // The registered MeasureDescriptors. Measure id are indexes into this + // vector plus some flags in the high bits. + std::vector registered_descriptors_; + // A map from measure names to IDs. + std::unordered_map id_map_; +}; + +template <> +MeasureDouble MeasureRegistryImpl::Register(absl::string_view name, + absl::string_view description, + absl::string_view units); + +template <> +MeasureInt64 MeasureRegistryImpl::Register(absl::string_view name, + absl::string_view description, + absl::string_view units); + +template +const MeasureDescriptor& MeasureRegistryImpl::GetDescriptor( + Measure measure) const { + if (!measure.IsValid()) { + static const MeasureDescriptor default_descriptor = + MeasureDescriptor("", "", "", MeasureDescriptor::Type::kDouble); + return default_descriptor; + } + return registered_descriptors_[IdToIndex(measure.id_)]; +} + +// static +template +uint64_t MeasureRegistryImpl::MeasureToIndex(Measure measure) { + return IdToIndex(measure.id_); +} + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_MEASURE_REGISTRY_IMPL_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/recording.cc b/extensions/stackdriver/opencensus/stats/internal/recording.cc new file mode 100644 index 00000000000..dc3b171ad43 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/recording.cc @@ -0,0 +1,40 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/recording.h" + +#include + +#include "opencensus/stats/internal/delta_producer.h" +#include "opencensus/stats/measure.h" +#include "opencensus/tags/context_util.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace stats { + +void Record(std::initializer_list measurements) { + DeltaProducer::Get()->Record(measurements, + opencensus::tags::GetCurrentTagMap()); +} + +void Record(std::initializer_list measurements, + opencensus::tags::TagMap tags) { + DeltaProducer::Get()->Record(measurements, std::move(tags)); +} + +bool Flush() { return DeltaProducer::Get()->Flush(); } + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.cc b/extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.cc new file mode 100644 index 00000000000..6917689e022 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.cc @@ -0,0 +1,29 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/stats/internal/set_aggregation_window.h" + +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +void SetAggregationWindow(const AggregationWindow& window, + ViewDescriptor* descriptor) { + descriptor->aggregation_window_ = window; +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.h b/extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.h new file mode 100644 index 00000000000..c021fadf3a8 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/set_aggregation_window.h @@ -0,0 +1,34 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_SET_AGGREGATION_WINDOW_H_ +#define OPENCENSUS_STATS_INTERNAL_SET_AGGREGATION_WINDOW_H_ + +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +// You probably do not need this: ViewDescriptor has a Cumulative aggregation +// window by default, and that is what most exporters expect. Interval +// aggregation is mainly useful for on-task purposes, such as server status +// displays. +void SetAggregationWindow(const AggregationWindow& window, + ViewDescriptor* descriptor); + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_SET_AGGREGATION_WINDOW_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/stats_exporter.cc b/extensions/stackdriver/opencensus/stats/internal/stats_exporter.cc new file mode 100644 index 00000000000..15bb5bc88cf --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/stats_exporter.cc @@ -0,0 +1,87 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/stats_exporter.h" +#include "opencensus/stats/internal/stats_exporter_impl.h" + +#include +#include + +#include "absl/memory/memory.h" +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/view_data.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +// static +StatsExporterImpl* StatsExporterImpl::Get() { + static StatsExporterImpl* global_stats_exporter_impl = + new StatsExporterImpl(); + return global_stats_exporter_impl; +} + +void StatsExporterImpl::AddView(const ViewDescriptor& view) { + views_[view.name()] = absl::make_unique(view); +} + +void StatsExporterImpl::RemoveView(absl::string_view name) { + views_.erase(std::string(name)); +} + +void StatsExporterImpl::RegisterPushHandler( + std::unique_ptr handler) { + handlers_.push_back(std::move(handler)); +} + +std::vector> +StatsExporterImpl::GetViewData() { + std::vector> data; + data.reserve(views_.size()); + for (const auto& view : views_) { + data.emplace_back(view.second->descriptor(), view.second->GetData()); + } + return data; +} + +void StatsExporterImpl::Export() { + std::vector> data; + data.reserve(views_.size()); + for (const auto& view : views_) { + data.emplace_back(view.second->descriptor(), view.second->GetData()); + } + for (auto& handler : handlers_) { + handler->ExportViewData(data); + } +} + +void StatsExporterImpl::ClearHandlersForTesting() { handlers_.clear(); } + +void StatsExporter::RemoveView(absl::string_view name) { + StatsExporterImpl::Get()->RemoveView(name); +} + +void StatsExporter::RegisterPushHandler(std::unique_ptr handler) { + StatsExporterImpl::Get()->RegisterPushHandler(std::move(handler)); +} + +std::vector> StatsExporter::GetViewData() { + return StatsExporterImpl::Get()->GetViewData(); +} + +void StatsExporter::ExportViewData() { StatsExporterImpl::Get()->Export(); } + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/stats_exporter_impl.h b/extensions/stackdriver/opencensus/stats/internal/stats_exporter_impl.h new file mode 100644 index 00000000000..35aef87c976 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/stats_exporter_impl.h @@ -0,0 +1,58 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_STATS_EXPORTER_IMPL_H_ +#define OPENCENSUS_STATS_INTERNAL_STATS_EXPORTER_IMPL_H_ + +#include +#include + +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/stats_exporter.h" +#include "opencensus/stats/view_data.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +class StatsExporterImpl { + public: + static StatsExporterImpl* Get(); + + void AddView(const ViewDescriptor& view); + + void RemoveView(absl::string_view name); + + // Adds a handler, which cannot be subsequently removed (except by + // ClearHandlersForTesting()). The background thread is started when the + // first handler is registered. + void RegisterPushHandler(std::unique_ptr handler); + + std::vector> GetViewData(); + + void Export(); + + void ClearHandlersForTesting(); + + private: + StatsExporterImpl() {} + + std::vector> handlers_; + std::unordered_map> views_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_STATS_EXPORTER_IMPL_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/stats_manager.cc b/extensions/stackdriver/opencensus/stats/internal/stats_manager.cc new file mode 100644 index 00000000000..db36ef6f321 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/stats_manager.cc @@ -0,0 +1,184 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/internal/stats_manager.h" + +#include + +#include "absl/base/macros.h" +#include "absl/memory/memory.h" +#include "opencensus/stats/aggregation.h" +#include "opencensus/stats/bucket_boundaries.h" +#include "opencensus/stats/internal/delta_producer.h" +#include "opencensus/stats/internal/measure_data.h" +#include "opencensus/stats/internal/measure_registry_impl.h" +#include "opencensus/stats/view_descriptor.h" +#include "opencensus/tags/tag_key.h" +#include "opencensus/tags/tag_map.h" + +#ifndef NULL_PLUGIN +#include "api/wasm/cpp/proxy_wasm_intrinsics.h" +#else +#include "extensions/common/wasm/null/null.h" +using namespace Envoy::Extensions::Common::Wasm::Null::Plugin; +#endif + +namespace opencensus { +namespace stats { + +// TODO: See if it is possible to replace AssertHeld() with function +// annotations. +// TODO: Optimize selecting/sorting tag values for each view. + +// ========================================================================== // +// StatsManager::ViewInformation + +StatsManager::ViewInformation::ViewInformation(const ViewDescriptor& descriptor) + : descriptor_(descriptor), + data_(proxy_getCurrentTimeNanoseconds(), descriptor) {} + +bool StatsManager::ViewInformation::Matches( + const ViewDescriptor& descriptor) const { + return descriptor.aggregation() == descriptor_.aggregation() && + descriptor.aggregation_window_ == descriptor_.aggregation_window_ && + descriptor.columns() == descriptor_.columns(); +} + +int StatsManager::ViewInformation::num_consumers() const { + return num_consumers_; +} + +void StatsManager::ViewInformation::AddConsumer() { ++num_consumers_; } + +int StatsManager::ViewInformation::RemoveConsumer() { return --num_consumers_; } + +void StatsManager::ViewInformation::MergeMeasureData( + const opencensus::tags::TagMap& tags, const MeasureData& data, + uint64_t now) { + std::vector tag_values(descriptor_.columns().size()); + for (uint32_t i = 0; i < tag_values.size(); ++i) { + const opencensus::tags::TagKey column = descriptor_.columns()[i]; + for (const auto& tag : tags.tags()) { + if (tag.first == column) { + tag_values[i] = std::string(tag.second); + break; + } + } + } + data_.Merge(tag_values, data, now); +} + +std::unique_ptr StatsManager::ViewInformation::GetData() { + if (descriptor_.aggregation_window_.type() == + AggregationWindow::Type::kDelta) { + return data_.GetDeltaAndReset(proxy_getCurrentTimeNanoseconds()); + } else { + return absl::make_unique(data_); + } +} + +// ========================================================================== +// // StatsManager::MeasureInformation + +void StatsManager::MeasureInformation::MergeMeasureData( + const opencensus::tags::TagMap& tags, const MeasureData& data, + uint64_t now) { + for (auto& view : views_) { + view->MergeMeasureData(tags, data, now); + } +} + +StatsManager::ViewInformation* StatsManager::MeasureInformation::AddConsumer( + const ViewDescriptor& descriptor) { + for (auto& view : views_) { + if (view->Matches(descriptor)) { + view->AddConsumer(); + return view.get(); + } + } + views_.emplace_back(new ViewInformation(descriptor)); + return views_.back().get(); +} + +void StatsManager::MeasureInformation::RemoveView( + const ViewInformation* handle) { + for (auto it = views_.begin(); it != views_.end(); ++it) { + if (it->get() == handle) { + views_.erase(it); + return; + } + } +} + +// ========================================================================== +// // StatsManager + +// static +StatsManager* StatsManager::Get() { + static StatsManager* global_stats_manager = new StatsManager(); + return global_stats_manager; +} + +void StatsManager::MergeDelta(const Delta& delta) { + uint64_t now = proxy_getCurrentTimeNanoseconds(); + // Measures are added to the StatsManager before the DeltaProducer, so there + // should never be measures in the delta missing from measures_. + for (const auto& data_for_tagset : delta.delta()) { + for (uint32_t i = 0; i < data_for_tagset.second.size(); ++i) { + // Only add data if there is data for this tagset/measure combination, to + // avoid creating spurious empty rows. + if (data_for_tagset.second[i].count() != 0) { + measures_[i].MergeMeasureData(data_for_tagset.first, + data_for_tagset.second[i], now); + } + } + } +} + +template +void StatsManager::AddMeasure(Measure /* measure */) { + measures_.emplace_back(MeasureInformation()); +} + +template void StatsManager::AddMeasure(MeasureDouble measure); +template void StatsManager::AddMeasure(MeasureInt64 measure); + +StatsManager::ViewInformation* StatsManager::AddConsumer( + const ViewDescriptor& descriptor) { + if (!MeasureRegistryImpl::IdValid(descriptor.measure_id_)) { + return nullptr; + } + const uint64_t index = MeasureRegistryImpl::IdToIndex(descriptor.measure_id_); + // We need to call this outside of the locked portion to avoid a deadlock when + // the DeltaProducer flushes the old delta. We call it before adding the view + // to avoid errors from the old delta not having a histogram for the new view. + if (descriptor.aggregation().type() == Aggregation::Type::kDistribution) { + DeltaProducer::Get()->AddBoundaries( + index, descriptor.aggregation().bucket_boundaries()); + } + return measures_[index].AddConsumer(descriptor); +} + +void StatsManager::RemoveConsumer(ViewInformation* handle) { + const int num_consumers_remaining = handle->RemoveConsumer(); + if (num_consumers_remaining == 0) { + const auto& descriptor = handle->view_descriptor(); + const uint64_t index = + MeasureRegistryImpl::IdToIndex(descriptor.measure_id_); + measures_[index].RemoveView(handle); + } +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/stats_manager.h b/extensions/stackdriver/opencensus/stats/internal/stats_manager.h new file mode 100644 index 00000000000..2fb77c904c4 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/stats_manager.h @@ -0,0 +1,128 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_STATS_MANAGER_H_ +#define OPENCENSUS_STATS_INTERNAL_STATS_MANAGER_H_ + +#include + +#include "absl/types/span.h" +#include "opencensus/stats/distribution.h" +#include "opencensus/stats/internal/delta_producer.h" +#include "opencensus/stats/internal/measure_data.h" +#include "opencensus/stats/internal/view_data_impl.h" +#include "opencensus/stats/measure.h" +#include "opencensus/stats/view_descriptor.h" +#include "opencensus/tags/tag_key.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace stats { + +// StatsManager is a singleton class that stores data for active views, adding +// values from Record() events. +class StatsManager final { + public: + // ViewInformation stores part of the data of a ViewDescriptor + // (measure, aggregation, and columns), along with the data for the view. + // ViewInformation is thread-compatible; its non-const data is protected by an + // external mutex, which most non-const member functions require holding. + class ViewInformation { + public: + ViewInformation(const ViewDescriptor& descriptor); + + // Returns true if this ViewInformation can be used to provide data for + // 'descriptor' (i.e. shares measure, aggregation, aggregation window, and + // columns; this does not compare view name and description). + bool Matches(const ViewDescriptor& descriptor) const; + + int num_consumers() const; + // Increments the consumer count. Requires holding *mu_. + void AddConsumer(); + // Decrements the consumer count and returns the resulting count. Requires + // holding *mu_. + int RemoveConsumer(); + + // Adds 'data' under 'tags' as of 'now'. Requires holding *mu_; + void MergeMeasureData(const opencensus::tags::TagMap& tags, + const MeasureData& data, uint64_t now); + + // Retrieves a copy of the data. + std::unique_ptr GetData(); + + const ViewDescriptor& view_descriptor() const { return descriptor_; } + + private: + const ViewDescriptor descriptor_; + + // The number of View objects backed by this ViewInformation, for + // reference-counted GC. + int num_consumers_ = 1; + + // Possible types of stored data. + enum class DataType { kDouble, kUint64, kDistribution, kInterval }; + static DataType DataTypeForDescriptor(const ViewDescriptor& descriptor); + + ViewDataImpl data_; + }; + + public: + static StatsManager* Get(); + + // Merges all data from 'delta' at the present time. + void MergeDelta(const Delta& delta); + + // Adds a measure--this is necessary for views to be added under that measure. + template + void AddMeasure(Measure measure); + + // Returns a handle that can be used to retrieve data for 'descriptor' (which + // may point to a new or re-used ViewInformation). + ViewInformation* AddConsumer(const ViewDescriptor& descriptor); + + // Removes a consumer from the ViewInformation 'handle', and deletes it if + // that was the last consumer. + void RemoveConsumer(ViewInformation* handle); + + private: + // MeasureInformation stores all ViewInformation objects for a given measure. + class MeasureInformation { + public: + explicit MeasureInformation() {} + + // Merges measure_data into all views under this measure. Requires holding + // *mu_; + void MergeMeasureData(const opencensus::tags::TagMap& tags, + const MeasureData& data, uint64_t now); + + ViewInformation* AddConsumer(const ViewDescriptor& descriptor); + void RemoveView(const ViewInformation* handle); + + private: + // View objects hold a pointer to ViewInformation directly, so we do not + // need fast lookup--lookup is only needed for view removal. + std::vector> views_; + }; + + // All registered measures. + std::vector measures_; +}; + +extern template void StatsManager::AddMeasure(MeasureDouble measure); +extern template void StatsManager::AddMeasure(MeasureInt64 measure); + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_STATS_MANAGER_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/view.cc b/extensions/stackdriver/opencensus/stats/internal/view.cc new file mode 100644 index 00000000000..fda3491a5fd --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/view.cc @@ -0,0 +1,55 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/view.h" + +#include + +#include "absl/base/macros.h" +#include "absl/memory/memory.h" +#include "opencensus/stats/distribution.h" +#include "opencensus/stats/internal/view_data_impl.h" + +#ifndef NULL_PLUGIN +#include "api/wasm/cpp/proxy_wasm_intrinsics.h" +#else +#include "extensions/common/wasm/null/null.h" +using namespace Envoy::Extensions::Common::Wasm::Null::Plugin; +#endif + +namespace opencensus { +namespace stats { + +View::View(const ViewDescriptor& descriptor) + : descriptor_(descriptor), + handle_(StatsManager::Get()->AddConsumer(descriptor)) {} + +View::~View() { + if (IsValid()) { + StatsManager::Get()->RemoveConsumer(handle_); + } +} + +bool View::IsValid() const { return handle_ != nullptr; } + +const ViewData View::GetData() { + if (!IsValid()) { + return ViewData(absl::make_unique( + proxy_getCurrentTimeNanoseconds(), descriptor_)); + } + return ViewData(handle_->GetData()); +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/view_data.cc b/extensions/stackdriver/opencensus/stats/internal/view_data.cc new file mode 100644 index 00000000000..577caff3c9b --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/view_data.cc @@ -0,0 +1,82 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/view_data.h" + +#include "absl/base/macros.h" +#include "absl/memory/memory.h" +#include "opencensus/stats/internal/view_data_impl.h" + +namespace opencensus { +namespace stats { + +const Aggregation& ViewData::aggregation() const { + return impl_->aggregation(); +} + +ViewData::Type ViewData::type() const { + switch (impl_->type()) { + case ViewDataImpl::Type::kDouble: + return Type::kDouble; + case ViewDataImpl::Type::kInt64: + return Type::kInt64; + case ViewDataImpl::Type::kDistribution: + return Type::kDistribution; + case ViewDataImpl::Type::kStatsObject: + // This DCHECKs in the constructor. Returning kDouble here is + // safe, albeit incorrect--the double_data() accessor will return an empty + // map. + return Type::kDouble; + } + return Type::kDouble; +} + +const ViewData::DataMap& ViewData::double_data() const { + if (impl_->type() == ViewDataImpl::Type::kDouble) { + return impl_->double_data(); + } else { + static DataMap empty_map; + return empty_map; + } +} + +const ViewData::DataMap& ViewData::int_data() const { + if (impl_->type() == ViewDataImpl::Type::kInt64) { + return impl_->int_data(); + } else { + static DataMap empty_map; + return empty_map; + } +} + +const ViewData::DataMap& ViewData::distribution_data() const { + if (impl_->type() == ViewDataImpl::Type::kDistribution) { + return impl_->distribution_data(); + } else { + static DataMap empty_map; + return empty_map; + } +} + +uint64_t ViewData::start_time() const { return impl_->start_time(); } +uint64_t ViewData::end_time() const { return impl_->end_time(); } + +ViewData::ViewData(const ViewData& other) + : impl_(absl::make_unique(*other.impl_)) {} + +ViewData::ViewData(std::unique_ptr data) + : impl_(std::move(data)) {} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/view_data_impl.cc b/extensions/stackdriver/opencensus/stats/internal/view_data_impl.cc new file mode 100644 index 00000000000..0b9de8f871c --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/view_data_impl.cc @@ -0,0 +1,207 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/internal/view_data_impl.h" + +#include +#include + +#include "absl/base/macros.h" +#include "absl/memory/memory.h" +#include "opencensus/stats/distribution.h" +#include "opencensus/stats/measure_descriptor.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +ViewDataImpl::Type ViewDataImpl::TypeForDescriptor( + const ViewDescriptor& descriptor) { + switch (descriptor.aggregation_window_.type()) { + case AggregationWindow::Type::kCumulative: + case AggregationWindow::Type::kDelta: + switch (descriptor.aggregation().type()) { + case Aggregation::Type::kSum: + case Aggregation::Type::kLastValue: + switch (descriptor.measure_descriptor().type()) { + case MeasureDescriptor::Type::kDouble: + return ViewDataImpl::Type::kDouble; + case MeasureDescriptor::Type::kInt64: + return ViewDataImpl::Type::kInt64; + } + case Aggregation::Type::kCount: + return ViewDataImpl::Type::kInt64; + case Aggregation::Type::kDistribution: + return ViewDataImpl::Type::kDistribution; + } + case AggregationWindow::Type::kInterval: + return ViewDataImpl::Type::kStatsObject; + } + return ViewDataImpl::Type::kDouble; +} + +ViewDataImpl::ViewDataImpl(uint64_t start_time, + const ViewDescriptor& descriptor) + : aggregation_(descriptor.aggregation()), + aggregation_window_(descriptor.aggregation_window_), + type_(TypeForDescriptor(descriptor)), + start_time_(start_time), + end_time_(start_time + 1) { + switch (type_) { + case Type::kDouble: { + new (&double_data_) DataMap(); + break; + } + case Type::kInt64: { + new (&int_data_) DataMap(); + break; + } + case Type::kDistribution: { + new (&distribution_data_) DataMap(); + break; + } + case Type::kStatsObject: { + break; + } + } +} + +ViewDataImpl::~ViewDataImpl() { + switch (type_) { + case Type::kDouble: { + double_data_.~DataMap(); + break; + } + case Type::kInt64: { + int_data_.~DataMap(); + break; + } + case Type::kDistribution: { + distribution_data_.~DataMap(); + break; + } + case Type::kStatsObject: { + break; + } + } +} + +std::unique_ptr ViewDataImpl::GetDeltaAndReset(uint64_t now) { + // Need to use wrap_unique because this is a private constructor. + return absl::WrapUnique(new ViewDataImpl(this, now)); +} + +ViewDataImpl::ViewDataImpl(const ViewDataImpl& other) + : aggregation_(other.aggregation_), + aggregation_window_(other.aggregation_window_), + type_(other.type()), + start_time_(other.start_time_), + end_time_(other.end_time_) { + switch (type_) { + case Type::kDouble: { + new (&double_data_) DataMap(other.double_data_); + break; + } + case Type::kInt64: { + new (&int_data_) DataMap(other.int_data_); + break; + } + case Type::kDistribution: { + new (&distribution_data_) DataMap(other.distribution_data_); + break; + } + case Type::kStatsObject: { + break; + } + } +} + +void ViewDataImpl::Merge(const std::vector& tag_values, + const MeasureData& data, uint64_t now) { + end_time_ = std::max(end_time_, now); + switch (type_) { + case Type::kDouble: { + if (aggregation_.type() == Aggregation::Type::kSum) { + double_data_[tag_values] += data.sum(); + } else { + double_data_[tag_values] = data.last_value(); + } + break; + } + case Type::kInt64: { + switch (aggregation_.type()) { + case Aggregation::Type::kCount: { + int_data_[tag_values] += data.count(); + break; + } + case Aggregation::Type::kSum: { + int_data_[tag_values] += data.sum(); + break; + } + case Aggregation::Type::kLastValue: { + int_data_[tag_values] = data.last_value(); + break; + } + default: + break; + } + break; + } + case Type::kDistribution: { + DataMap::iterator it = distribution_data_.find(tag_values); + if (it == distribution_data_.end()) { + it = distribution_data_.emplace_hint( + it, tag_values, Distribution(&aggregation_.bucket_boundaries())); + } + data.AddToDistribution(&it->second); + break; + } + case Type::kStatsObject: { + break; + } + } +} + +ViewDataImpl::ViewDataImpl(ViewDataImpl* source, uint64_t now) + : aggregation_(source->aggregation_), + aggregation_window_(source->aggregation_window_), + type_(source->type_), + start_time_(source->start_time_), + end_time_(now) { + switch (type_) { + case Type::kDouble: { + new (&double_data_) DataMap(); + double_data_.swap(source->double_data_); + break; + } + case Type::kInt64: { + new (&int_data_) DataMap(); + int_data_.swap(source->int_data_); + break; + } + case Type::kDistribution: { + new (&distribution_data_) DataMap(); + distribution_data_.swap(source->distribution_data_); + break; + } + case Type::kStatsObject: { + break; + } + } + source->start_time_ = now; + source->end_time_ = now; +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/internal/view_data_impl.h b/extensions/stackdriver/opencensus/stats/internal/view_data_impl.h new file mode 100644 index 00000000000..bbedff0aeeb --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/view_data_impl.h @@ -0,0 +1,119 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_INTERNAL_VIEW_DATA_IMPL_H_ +#define OPENCENSUS_STATS_INTERNAL_VIEW_DATA_IMPL_H_ + +#include +#include +#include +#include + +#include "absl/base/macros.h" +#include "absl/strings/string_view.h" +#include "opencensus/common/internal/string_vector_hash.h" +#include "opencensus/stats/aggregation.h" +#include "opencensus/stats/distribution.h" +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/internal/measure_data.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +// ViewDataImpl contains a snapshot of data for a particular View. DataValueT is +// the type of the returned data, with possibilities listed in +// data_value_type.h. Which value type is returned for a view is determined by +// the view's aggregation and aggregation window. +// +// Thread-compatible. +class ViewDataImpl { + public: + // A convenience alias for the type of the map from tags to data. + template + using DataMap = std::unordered_map, DataValueT, + common::StringVectorHash>; + + // Constructs an empty ViewDataImpl for internal use from the descriptor. A + // ViewData can be constructed directly from such a ViewDataImpl for + // snapshotting cumulative data; ViewDataImpls for interval views must be + // converted using the following constructor before snapshotting. + ViewDataImpl(uint64_t start_time, const ViewDescriptor& descriptor); + + ViewDataImpl(const ViewDataImpl& other); + ~ViewDataImpl(); + + // Returns a copy of the present state of the object and resets data() and + // start_time(). + std::unique_ptr GetDeltaAndReset(uint64_t now); + + const Aggregation& aggregation() const { return aggregation_; } + const AggregationWindow& aggregation_window() const { + return aggregation_window_; + } + + enum class Type { + kDouble, + kInt64, + kDistribution, + kStatsObject, // Used for aggregating data, should not be exported. + }; + Type type() const { return type_; } + + // A map from tag values (corresponding to the keys in the ViewDescriptor, in + // that order) to the data for those tags. What data is contained depends on + // the View's Aggregation and AggregationWindow. + // Only one of these is valid for any ViewDataImpl (which is indicated by + // type()); + const DataMap& double_data() const { return double_data_; } + const DataMap& int_data() const { return int_data_; } + const DataMap& distribution_data() const { + return distribution_data_; + } + + uint64_t start_time() const { return start_time_; } + uint64_t end_time() const { return end_time_; } + + // Merges bulk data for the given tag values at 'now'. tag_values must be + // ordered according to the order of keys in the ViewDescriptor. + // TODO: Change to take Span when heterogenous lookup is + // supported. + void Merge(const std::vector& tag_values, + const MeasureData& data, uint64_t now); + + private: + // Implements GetDeltaAndReset(), copying aggregation_ and swapping data_ and + // start/end times. This is private so that it can be given a more descriptive + // name in the public API. + ViewDataImpl(ViewDataImpl* source, uint64_t now); + + Type TypeForDescriptor(const ViewDescriptor& descriptor); + + const Aggregation aggregation_; + const AggregationWindow aggregation_window_; + const Type type_; + union { + DataMap double_data_; + DataMap int_data_; + DataMap distribution_data_; + }; + + uint64_t start_time_; + uint64_t end_time_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_INTERNAL_VIEW_DATA_IMPL_H_ diff --git a/extensions/stackdriver/opencensus/stats/internal/view_descriptor.cc b/extensions/stackdriver/opencensus/stats/internal/view_descriptor.cc new file mode 100644 index 00000000000..3cda64419e9 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/internal/view_descriptor.cc @@ -0,0 +1,102 @@ +// Copyright 2017, OpenCensus 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. + +#include "opencensus/stats/view_descriptor.h" + +#include +#include + +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "opencensus/stats/aggregation.h" +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/internal/measure_registry_impl.h" +#include "opencensus/stats/internal/stats_exporter_impl.h" +#include "opencensus/stats/measure_descriptor.h" +#include "opencensus/stats/view.h" +#include "opencensus/tags/tag_key.h" + +namespace opencensus { +namespace stats { + +// TODO: NICETH: Allow inserting views without an id (autogenerating one +// based on measure/aggregation/columns). +// TODO: FIXME: Distinguish never-set values, and add an IsValid() +// method checking required fields. + +ViewDescriptor::ViewDescriptor() + : aggregation_(Aggregation::Sum()), + aggregation_window_(AggregationWindow::Cumulative()) {} + +ViewDescriptor& ViewDescriptor::set_name(absl::string_view name) { + name_ = std::string(name); + return *this; +} + +ViewDescriptor& ViewDescriptor::set_measure(absl::string_view name) { + measure_name_ = std::string(name); + measure_id_ = MeasureRegistryImpl::Get()->GetIdByName(name); + return *this; +} + +const MeasureDescriptor& ViewDescriptor::measure_descriptor() const { + return MeasureRegistryImpl::Get()->GetDescriptorByName(measure_name_); +} + +ViewDescriptor& ViewDescriptor::set_aggregation( + const Aggregation& aggregation) { + aggregation_ = aggregation; + return *this; +} + +ViewDescriptor& ViewDescriptor::add_column(opencensus::tags::TagKey tag_key) { + columns_.emplace_back(tag_key); + return *this; +} + +ViewDescriptor& ViewDescriptor::set_description(absl::string_view description) { + description_ = std::string(description); + return *this; +} + +void ViewDescriptor::RegisterForExport() const { + if (aggregation_window_.type() == AggregationWindow::Type::kCumulative) { + StatsExporterImpl::Get()->AddView(*this); + } +} + +std::string ViewDescriptor::DebugString() const { + return absl::StrCat( + "\n name: \"", name_, + "\"\n measure: ", measure_descriptor().DebugString(), + "\n aggregation: ", aggregation_.DebugString(), + "\n aggregation window: ", aggregation_window_.DebugString(), + "\n columns: ", + absl::StrJoin(columns_, ":", + [](std::string* out, opencensus::tags::TagKey key) { + return out->append(key.name()); + }), + "\n description: \"", description_, "\""); +} + +bool ViewDescriptor::operator==(const ViewDescriptor& other) const { + return name_ == other.name_ && measure_id_ == other.measure_id_ && + aggregation_ == other.aggregation_ && + aggregation_window_ == other.aggregation_window_ && + columns_ == other.columns_ && description_ == other.description_; +} + +} // namespace stats +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/stats/measure.h b/extensions/stackdriver/opencensus/stats/measure.h new file mode 100644 index 00000000000..de364473b45 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/measure.h @@ -0,0 +1,122 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_MEASURE_H_ +#define OPENCENSUS_STATS_MEASURE_H_ + +#include +#include + +#include "opencensus/stats/measure_descriptor.h" + +namespace opencensus { +namespace stats { + +// A Measure represents a certain type of record, such as the latency of a +// request. Value events are recorded against measures, and a view specifying +// that measure can retrieve the data for those events. Measures can only be +// obtained from the static functions MeasureRegistry::Register() and +// MeasureRegistry::GetMeasureByName(). +// Measure is immutable, and should be passed by value. It has a trivial +// destructor and can be safely used as a local static variable. +template +class Measure final { + public: + // Registers a MeasureDescriptor, returning a Measure that can be used to + // record values for or create views on that measure. Only one Measure may be + // registered under a certain name; subsequent registrations will fail, + // returning an invalid measure. Register* functions should only be called by + // the owner of a measure--other users should use GetMeasureByName. If there + // are multiple competing owners (e.g. for a generic resource such as "RPC + // latency" shared between RPC libraries) check whether the measure is + // registered with MeasureRegistry::GetMeasure*ByName before registering it. + // + // 'name' should be a globally unique identifier. It is recommended that this + // be in the format "/", e.g. "example.com/client/foo_usage". + // 'description' is a human-readable description of what the measure's + // values represent. + // 'units' are the units of recorded values. The recommended grammar is: + // - Expression = Component { "." Component } {"/" Component } + // - Component = [ PREFIX ] UNIT [ Annotation ] | Annotation | "1" + // - Annotation = "{" NAME "}" + // For example, string “MBy{transmitted}/ms” stands for megabytes per + // milliseconds, and the annotation transmitted inside {} is just a comment + // of the unit. + // By convention: + // - Latencies are measures in milliseconds, denoted "ms". + // - Sizes are measured in bytes, denoted "By". + // - Dimensionless values have unit "1". + static Measure Register(absl::string_view name, + absl::string_view description, + absl::string_view units); + + // Retrieves a copy of the Measure's descriptor. This is expensive, requiring + // a lookup in the MeasureRegistry. + const MeasureDescriptor& GetDescriptor() const; + + // Returns true if the measure is valid and false otherwise. Recording with an + // invalid Measure logs an error and assert-fails in debug mode. + bool IsValid() const; + + Measure(const Measure& other) : id_(other.id_) {} + bool operator==(Measure other) const { return id_ == other.id_; } + + private: + friend class Measurement; + friend class MeasureRegistryImpl; + explicit Measure(uint64_t id); + + const uint64_t id_; +}; + +typedef Measure MeasureDouble; +typedef Measure MeasureInt64; + +// Measurement is an immutable pair of a Measure and corresponding value to +// record--refer to comments in recording.h for further information. +// TODO: Write a non-compilation test. +// TODO: Make mismatching types produce a more informative error. +class Measurement final { + public: + template ::value>::type* = nullptr> + Measurement(MeasureDouble measure, T value) + : id_(measure.id_), value_double_(value) {} + template ::value>::type* = nullptr> + Measurement(MeasureInt64 measure, T value) + : id_(measure.id_), value_int_(value) {} + + private: + friend class StatsManager; + friend class Delta; + + const uint64_t id_; + union { + const double value_double_; + const int64_t value_int_; + }; +}; + +template <> +bool MeasureDouble::IsValid() const; +template <> +bool MeasureInt64::IsValid() const; +extern template class Measure; +extern template class Measure; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_MEASURE_H_ diff --git a/extensions/stackdriver/opencensus/stats/measure_descriptor.h b/extensions/stackdriver/opencensus/stats/measure_descriptor.h new file mode 100644 index 00000000000..5a2c8c25d48 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/measure_descriptor.h @@ -0,0 +1,70 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_MEASURE_DESCRIPTOR_H_ +#define OPENCENSUS_STATS_MEASURE_DESCRIPTOR_H_ + +#include + +#include "absl/strings/string_view.h" + +namespace opencensus { +namespace stats { + +// MeasureDescriptor is system-stable metadata (or a subset of it) for a +// Measure. +// MeasureDescriptor is immutable. +class MeasureDescriptor final { + public: + // The type of values recorded under this Measure. + enum class Type { + kDouble, + kInt64, + }; + + // See documentation on MeasureRegistry::Register*() for details of these + // fields. + const std::string& name() const { return name_; } + const std::string& description() const { return description_; } + const std::string& units() const { return units_; } + Type type() const { return type_; } + + std::string DebugString() const; + + bool operator==(const MeasureDescriptor& other) const { + return name_ == other.name_ && description_ == other.description_ && + units_ == other.units_ && type_ == other.type_; + } + bool operator!=(const MeasureDescriptor& other) const { + return !(*this == other); + } + + private: + // Only MeasureRegistryImpl can construct this--users should call the + // MeasureRegistry::Register*() functions. + friend class MeasureRegistryImpl; + MeasureDescriptor(absl::string_view name, absl::string_view description, + absl::string_view units, Type type) + : name_(name), description_(description), units_(units), type_(type) {} + + const std::string name_; + const std::string description_; + const std::string units_; + const Type type_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_MEASURE_DESCRIPTOR_H_ diff --git a/extensions/stackdriver/opencensus/stats/measure_registry.h b/extensions/stackdriver/opencensus/stats/measure_registry.h new file mode 100644 index 00000000000..2605828c89f --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/measure_registry.h @@ -0,0 +1,44 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_MEASURE_REGISTRY_H_ +#define OPENCENSUS_STATS_MEASURE_REGISTRY_H_ + +#include "absl/strings/string_view.h" +#include "opencensus/stats/measure.h" +#include "opencensus/stats/measure_descriptor.h" + +namespace opencensus { +namespace stats { + +// The MeasureRegistry keeps a record of all MeasureDescriptors registered, +// providing functions for querying their metadata by name or handle. Use +// Measure::Register() to register a measure with the registry. +// MeasureRegistry is thread-safe. +class MeasureRegistry final { + public: + // Returns the descriptor of the measure registered under 'name' if one is + // registered, and a descriptor with an empty name otherwise. + static const MeasureDescriptor& GetDescriptorByName(absl::string_view name); + + // Returns a measure for the registered MeasureDescriptor with the + // provided name, if one exists, and an invalid Measure otherwise. + static MeasureDouble GetMeasureDoubleByName(absl::string_view name); + static MeasureInt64 GetMeasureInt64ByName(absl::string_view name); +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_MEASURE_REGISTRY_H_ diff --git a/extensions/stackdriver/opencensus/stats/recording.h b/extensions/stackdriver/opencensus/stats/recording.h new file mode 100644 index 00000000000..d470a95f65f --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/recording.h @@ -0,0 +1,50 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_RECORDING_H_ +#define OPENCENSUS_STATS_RECORDING_H_ + +#include + +#include "opencensus/stats/measure.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace stats { + +// Records a list of Measurements under the current Context's tags. The +// recommended style is to create Measurements as an initializer list, e.g.: +// +// Record({{measure_double, 2.5}, {measure_int, 1ll}}); +// +// Only floating point values may be recorded against MeasureDoubles and only +// integral values against MeasureInt64s, to prevent silent loss of precision. +// If a record call fails to compile, ensure that all types match (using +// static_cast to double or int64_t if necessary). +void Record(std::initializer_list measurements); + +// Records a list of Measurements under the specified 'tags'. The current +// Context's tags are ignored. e.g: +// +// Record({{measure_double, 2.5}}, {{key, "value"}}); +void Record(std::initializer_list measurements, + opencensus::tags::TagMap tags); + +// Flushs all recorded Measurements. +bool Flush(); + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_RECORDING_H_ diff --git a/extensions/stackdriver/opencensus/stats/stats.h b/extensions/stackdriver/opencensus/stats/stats.h new file mode 100644 index 00000000000..f89cb5c8000 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/stats.h @@ -0,0 +1,33 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_STATS_H_ +#define OPENCENSUS_STATS_STATS_H_ + +// Re-export the public headers for stats so that users do not need to maintain +// a long include list. +#include "opencensus/stats/aggregation.h" // IWYU pragma: export +#include "opencensus/stats/bucket_boundaries.h" // IWYU pragma: export +#include "opencensus/stats/measure.h" // IWYU pragma: export +#include "opencensus/stats/measure_descriptor.h" // IWYU pragma: export +#include "opencensus/stats/measure_registry.h" // IWYU pragma: export +#include "opencensus/stats/recording.h" // IWYU pragma: export +#include "opencensus/stats/stats_exporter.h" // IWYU pragma: export +#include "opencensus/stats/tag_key.h" // IWYU pragma: export +#include "opencensus/stats/tag_set.h" // IWYU pragma: export +#include "opencensus/stats/view.h" // IWYU pragma: export +#include "opencensus/stats/view_data.h" // IWYU pragma: export +#include "opencensus/stats/view_descriptor.h" // IWYU pragma: export + +#endif // OPENCENSUS_STATS_STATS_H_ diff --git a/extensions/stackdriver/opencensus/stats/stats_exporter.h b/extensions/stackdriver/opencensus/stats/stats_exporter.h new file mode 100644 index 00000000000..7d616f8d3e7 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/stats_exporter.h @@ -0,0 +1,65 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_STATS_EXPORTER_H_ +#define OPENCENSUS_STATS_STATS_EXPORTER_H_ + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/stats/view.h" +#include "opencensus/stats/view_data.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +// StatsExporter manages views for export, and export handlers. New views can be +// registered with ViewDescriptor::RegisterForExport(). +// StatsExporter is thread-safe. +class StatsExporter final { + public: + // Removes the view with 'name' from the registry, if one is registered. + static void RemoveView(absl::string_view name); + + // StatsExporter::Handler is the interface for push exporters that export + // recorded data for registered views. The exporter should provide a static + // Register() method that takes any arguments needed by the exporter (e.g. a + // URL to export to) and calls StatsExporter::RegisterHandler itself. + class Handler { + public: + virtual ~Handler() = default; + virtual void ExportViewData( + const std::vector>& data) = 0; + }; + + // Registers a new handler. Every few seconds, each registered handler will be + // called with the present data for each registered view. This should only be + // called by push exporters' Register() methods. + static void RegisterPushHandler(std::unique_ptr handler); + + // Retrieves current data for all registered views, for implementing pull + // exporters. + static std::vector> GetViewData(); + + // Exports view data to backend handlers. + static void ExportViewData(); +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_STATS_EXPORTER_H_ diff --git a/extensions/stackdriver/opencensus/stats/tag_key.h b/extensions/stackdriver/opencensus/stats/tag_key.h new file mode 100644 index 00000000000..a3cc2afacea --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/tag_key.h @@ -0,0 +1,29 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_TAG_KEY_H_ +#define OPENCENSUS_STATS_TAG_KEY_H_ + +#include "absl/base/macros.h" +#include "opencensus/tags/tag_key.h" + +namespace opencensus { +namespace stats { + +typedef opencensus::tags::TagKey TagKey; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_TAG_KEY_H_ diff --git a/extensions/stackdriver/opencensus/stats/tag_set.h b/extensions/stackdriver/opencensus/stats/tag_set.h new file mode 100644 index 00000000000..a5dbd3673d0 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/tag_set.h @@ -0,0 +1,29 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_TAG_SET_H_ +#define OPENCENSUS_STATS_TAG_SET_H_ + +#include "absl/base/macros.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace stats { + +typedef opencensus::tags::TagMap TagSet; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_TAG_SET_H_ diff --git a/extensions/stackdriver/opencensus/stats/view.h b/extensions/stackdriver/opencensus/stats/view.h new file mode 100644 index 00000000000..04b30cd7306 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/view.h @@ -0,0 +1,63 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_VIEW_H_ +#define OPENCENSUS_STATS_VIEW_H_ + +#include "opencensus/stats/internal/stats_manager.h" +#include "opencensus/stats/view_data.h" +#include "opencensus/stats/view_descriptor.h" + +namespace opencensus { +namespace stats { + +// View is an RAII handle for on-task data collection--once a View is +// instantiated, OpenCensus will collect data for it, which can be accessed with +// View::GetData(). To register a view for export, rather than on-task +// collection, use ViewDescriptor::RegisterForExport() instead. +// +// View objects are thread-safe. +class View { + public: + // Creates a view, starting data collection for it. If descriptor.measure() + // has not been registered, IsValid() on the returned object will return + // false and GetData() will return an empty ViewData. + View(const ViewDescriptor& descriptor); + + // Not copyable, since views are RAII handles for resource collection. + View(const View& view) = delete; + View& operator=(const View& view) = delete; + + // Stops data collection. + ~View(); + + // Returns true if this object is valid and data can be collected. + bool IsValid() const; + + // Returns a snapshot of the View's data. + const ViewData GetData(); + + // TODO: Consider a means of querying one tagset to avoid copying. + + const ViewDescriptor& descriptor() { return descriptor_; } + + private: + const ViewDescriptor descriptor_; + StatsManager::ViewInformation* const handle_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_VIEW_H_ diff --git a/extensions/stackdriver/opencensus/stats/view_data.h b/extensions/stackdriver/opencensus/stats/view_data.h new file mode 100644 index 00000000000..e0288451560 --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/view_data.h @@ -0,0 +1,79 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_VIEW_DATA_H_ +#define OPENCENSUS_STATS_VIEW_DATA_H_ + +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/common/internal/string_vector_hash.h" +#include "opencensus/stats/aggregation.h" +#include "opencensus/stats/distribution.h" + +namespace opencensus { +namespace stats { + +// Forward declarations of friends. +class ViewDataImpl; + +// ViewData is an immutable snapshot of data for a particular View, aggregated +// according to the View's Aggregation and AggregationWindow. +class ViewData { + public: + // Maps a vector of tag values (corresponding to the columns of the + // ViewDescriptor of the View generating this ViewData, in that order) to + // data. + template + using DataMap = std::unordered_map, DataValueT, + common::StringVectorHash>; + + const Aggregation& aggregation() const; + + enum class Type { + kDouble, + kInt64, + kDistribution, + }; + Type type() const; + + // A map from tag values (corresponding to the keys in the ViewDescriptor, in + // that order) to the data for those tags. What data is contained depends on + // the View's Aggregation and AggregationWindow. + // Only one of these is valid for any ViewData (which is valid is indicated by + // type()). Calling the wrong one DCHECKs and returns an empty map. + const DataMap& double_data() const; + const DataMap& int_data() const; + const DataMap& distribution_data() const; + + uint64_t start_time() const; + uint64_t end_time() const; + + ViewData(const ViewData& other); + + private: + friend class View; // Allowed to call the private constructor. + explicit ViewData(std::unique_ptr data); + + const std::unique_ptr impl_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_VIEW_DATA_H_ diff --git a/extensions/stackdriver/opencensus/stats/view_descriptor.h b/extensions/stackdriver/opencensus/stats/view_descriptor.h new file mode 100644 index 00000000000..2969b6f944d --- /dev/null +++ b/extensions/stackdriver/opencensus/stats/view_descriptor.h @@ -0,0 +1,118 @@ +// Copyright 2017, OpenCensus 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. + +#ifndef OPENCENSUS_STATS_VIEW_DESCRIPTOR_H_ +#define OPENCENSUS_STATS_VIEW_DESCRIPTOR_H_ + +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/stats/aggregation.h" +#include "opencensus/stats/internal/aggregation_window.h" +#include "opencensus/stats/measure_descriptor.h" +#include "opencensus/tags/tag_key.h" + +namespace opencensus { +namespace stats { + +// ViewDescriptor provides metadata for a view: a unique name, the measure to +// collect data for, how to aggregate that data, and what tag keys to break it +// down by. +// In order to collect data for a ViewDescriptor, it must either be registered +// for export (by calling RegisterForExport() on the fully-defined descriptor) +// or converted into a View to collect data on-task (see view.h). +// +// ViewDescriptor is a value type, and is thread-compatible. +class ViewDescriptor final { + public: + ////////////////////////////////////////////////////////////////////////////// + // View definition + + // Creates a ViewDescriptor with Cumulative aggregation. + ViewDescriptor(); + + // Sets the name of the ViewDescriptor. Names must be unique within the + // library; it is recommended that it be in the format "/", + // where "" uniquely specifies the measure, aggregation, and columns + // (e.g. "example.com/Foo/FooUsage-sum-key1-key2"). + ViewDescriptor& set_name(absl::string_view name); + const std::string& name() const { return name_; } + + // Sets the measure. If no measure is registered under 'name' any View created + // with the descriptor will be invalid. + ViewDescriptor& set_measure(absl::string_view name); + // Accesses the descriptor of the view's measure. If no measure has been + // registered under the name set using set_measure(), this returns an invalid + // descriptor with blank fields. + const MeasureDescriptor& measure_descriptor() const; + + // Sets and retrieves the ViewDescriptor's aggregation. See aggregation.h for + // details of the options. + ViewDescriptor& set_aggregation(const Aggregation& aggregation); + const Aggregation& aggregation() const { return aggregation_; } + + // Adds a dimension to the view's data. When data is recorded it can specify a + // number of tags, key-value pairs; the aggregated data for each view will be + // broken down by the distinct values of each tag key matching one of the + // view's columns. + ViewDescriptor& add_column(opencensus::tags::TagKey tag_key); + size_t num_columns() const { return columns_.size(); } + const std::vector& columns() const { + return columns_; + } + + // Sets a human-readable description for the view. + ViewDescriptor& set_description(absl::string_view description); + const std::string& description() const { return description_; } + + ////////////////////////////////////////////////////////////////////////////// + // View registration + + // Registers this ViewDescriptor for export, replacing any already registered + // view with the same name.; requires that aggregation_window() == + // AggregationWindow::kCumulative() (the default). Future changes to this + // ViewDescriptor will not update the registered view. + void RegisterForExport() const; + + ////////////////////////////////////////////////////////////////////////////// + // Utilities + + std::string DebugString() const; + + bool operator==(const ViewDescriptor& other) const; + bool operator!=(const ViewDescriptor& other) const { + return !(*this == other); + } + + private: + friend class StatsManager; + friend class ViewDataImpl; + friend void SetAggregationWindow(const AggregationWindow&, ViewDescriptor*); + + std::string name_; + std::string measure_name_; + uint64_t measure_id_; + Aggregation aggregation_; + AggregationWindow aggregation_window_; + std::vector columns_; + std::string description_; +}; + +} // namespace stats +} // namespace opencensus + +#endif // OPENCENSUS_STATS_VIEW_DESCRIPTOR_H_ diff --git a/extensions/stackdriver/opencensus/tags/BUILD b/extensions/stackdriver/opencensus/tags/BUILD new file mode 100644 index 00000000000..e886173be2c --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/BUILD @@ -0,0 +1,57 @@ +# OpenCensus C++ Tags library. +# +# Copyright 2018, OpenCensus 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. + +load( + "@envoy//bazel:envoy_build_system.bzl", + "envoy_cc_library", +) + +envoy_cc_library( + name = "tags", + srcs = [ + "internal/tag_key.cc", + "internal/tag_map.cc", + ], + hdrs = [ + "tag_key.h", + "tag_map.h", + ], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], + deps = [ + "//extensions/stackdriver/opencensus/common/internal:hash_mix", + ], +) + +envoy_cc_library( + name = "context_util", + srcs = ["internal/context_util.cc"], + hdrs = ["context_util.h"], + copts = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", + ], + repository = "@envoy", + visibility = ["//extensions/stackdriver:__subpackages__"], + deps = [ + ":tags", + "//extensions/stackdriver/opencensus/context", + ], +) diff --git a/extensions/stackdriver/opencensus/tags/context_util.h b/extensions/stackdriver/opencensus/tags/context_util.h new file mode 100644 index 00000000000..42e5d0f10c6 --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/context_util.h @@ -0,0 +1,33 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_TAGS_CONTEXT_UTIL_H_ +#define OPENCENSUS_TAGS_CONTEXT_UTIL_H_ + +#include "opencensus/context/context.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace tags { + +// Returns the TagMap from the current Context. +const TagMap& GetCurrentTagMap(); + +// Returns the TagMap from the given Context. +const TagMap& GetTagMapFromContext(const opencensus::context::Context& ctx); + +} // namespace tags +} // namespace opencensus + +#endif // OPENCENSUS_TAGS_CONTEXT_UTIL_H_ diff --git a/extensions/stackdriver/opencensus/tags/internal/context_util.cc b/extensions/stackdriver/opencensus/tags/internal/context_util.cc new file mode 100644 index 00000000000..a3cc05dfaf3 --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/internal/context_util.cc @@ -0,0 +1,41 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/tags/context_util.h" + +#include "opencensus/context/context.h" +#include "opencensus/tags/tag_map.h" + +using ::opencensus::context::Context; + +namespace opencensus { +namespace tags { + +class ContextPeer { + public: + static const TagMap& GetTagMapFromContext(const Context& ctx) { + return ctx.tags_; + } +}; + +const TagMap& GetCurrentTagMap() { + return GetTagMapFromContext(Context::Current()); +} + +const TagMap& GetTagMapFromContext(const Context& ctx) { + return ContextPeer::GetTagMapFromContext(ctx); +} + +} // namespace tags +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/tags/internal/tag_key.cc b/extensions/stackdriver/opencensus/tags/internal/tag_key.cc new file mode 100644 index 00000000000..ec8c3c26379 --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/internal/tag_key.cc @@ -0,0 +1,70 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/tags/tag_key.h" + +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" + +namespace opencensus { +namespace tags { + +class TagKeyRegistry { + public: + static TagKeyRegistry* Get() { + static TagKeyRegistry* global_tag_key_registry = new TagKeyRegistry; + return global_tag_key_registry; + } + + TagKey Register(absl::string_view name); + + const std::string& TagKeyName(TagKey key) const { + return registered_tag_keys_[key.id_]; + } + + private: + // The registered tag keys. Tag key ids are indices into this vector. + std::vector registered_tag_keys_; + // A map from names to IDs. + // TODO: change to string_view when a suitable hash is available. + std::unordered_map id_map_; +}; + +TagKey TagKeyRegistry::Register(absl::string_view name) { + const std::string string_name(name); + const auto it = id_map_.find(string_name); + if (it == id_map_.end()) { + const uint64_t id = registered_tag_keys_.size(); + registered_tag_keys_.emplace_back(name); + id_map_.emplace_hint(it, string_name, id); + return TagKey(id); + } + return TagKey(it->second); +} + +TagKey TagKey::Register(absl::string_view name) { + return TagKeyRegistry::Get()->Register(name); +} + +const std::string& TagKey::name() const { + return TagKeyRegistry::Get()->TagKeyName(*this); +} + +} // namespace tags +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/tags/internal/tag_map.cc b/extensions/stackdriver/opencensus/tags/internal/tag_map.cc new file mode 100644 index 00000000000..d492d40e9e4 --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/internal/tag_map.cc @@ -0,0 +1,79 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/tags/tag_map.h" + +#include +#include +#include +#include +#include + +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "opencensus/common/internal/hash_mix.h" +#include "opencensus/tags/tag_key.h" + +namespace opencensus { +namespace tags { + +TagMap::TagMap( + std::initializer_list> tags) { + tags_.reserve(tags.size()); + for (const auto& tag : tags) { + tags_.emplace_back(tag.first, std::string(tag.second)); + } + Initialize(); +} + +TagMap::TagMap(std::vector> tags) + : tags_(std::move(tags)) { + Initialize(); +} + +void TagMap::Initialize() { + std::sort(tags_.begin(), tags_.end()); + + std::hash hasher; + common::HashMix mixer; + for (const auto& tag : tags_) { + mixer.Mix(tag.first.hash()); + mixer.Mix(hasher(tag.second)); + } + hash_ = mixer.get(); +} + +std::size_t TagMap::Hash::operator()(const TagMap& tags) const { + return tags.hash_; +} + +bool TagMap::operator==(const TagMap& other) const { + return tags_ == other.tags_; +} + +std::string TagMap::DebugString() const { + return absl::StrCat( + "{", + absl::StrJoin( + tags_, ", ", + [](std::string* o, std::pair kv) { + absl::StrAppend(o, "\"", kv.first.name(), "\": \"", kv.second, + "\""); + }), + "}"); +} + +} // namespace tags +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/tags/internal/with_tag_map.cc b/extensions/stackdriver/opencensus/tags/internal/with_tag_map.cc new file mode 100644 index 00000000000..ef66bb82e6e --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/internal/with_tag_map.cc @@ -0,0 +1,60 @@ +// Copyright 2018, OpenCensus 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. + +#include "opencensus/tags/with_tag_map.h" + +#include + +#include "opencensus/context/context.h" +#include "opencensus/tags/tag_map.h" + +using ::opencensus::context::Context; +using ::opencensus::tags::TagMap; + +namespace opencensus { +namespace tags { + +WithTagMap::WithTagMap(const TagMap& tags, bool cond) + : swapped_tags_(tags) +#ifndef NDEBUG + , + original_context_(Context::InternalMutableCurrent()) +#endif + , + cond_(cond) { + ConditionalSwap(); +} + +WithTagMap::WithTagMap(TagMap&& tags, bool cond) + : swapped_tags_(std::move(tags)) +#ifndef NDEBUG + , + original_context_(Context::InternalMutableCurrent()) +#endif + , + cond_(cond) { + ConditionalSwap(); +} + +WithTagMap::~WithTagMap() { ConditionalSwap(); } + +void WithTagMap::ConditionalSwap() { + if (cond_) { + using std::swap; + swap(Context::InternalMutableCurrent()->tags_, swapped_tags_); + } +} + +} // namespace tags +} // namespace opencensus diff --git a/extensions/stackdriver/opencensus/tags/tag_key.h b/extensions/stackdriver/opencensus/tags/tag_key.h new file mode 100644 index 00000000000..2b44297a16b --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/tag_key.h @@ -0,0 +1,55 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_TAGS_TAG_KEY_H_ +#define OPENCENSUS_TAGS_TAG_KEY_H_ + +#include +#include +#include + +#include "absl/strings/string_view.h" + +namespace opencensus { +namespace tags { + +// TagKey is a lightweight, immutable representation of a tag key. It has a +// trivial destructor and can be safely used as a local static variable. +// TagKey is thread-safe. +class TagKey final { + public: + // Registers a tag key with 'name'. Registering the same name twice produces + // equal TagKeys. + static TagKey Register(absl::string_view name); + + const std::string& name() const; + + bool operator==(TagKey other) const { return id_ == other.id_; } + bool operator!=(TagKey other) const { return id_ != other.id_; } + bool operator<(TagKey other) const { return id_ < other.id_; } + + // Returns a suitable hash of the TagKey. The implementation may change. + std::size_t hash() const { return id_; } + + private: + friend class TagKeyRegistry; + explicit TagKey(uint64_t id) : id_(id) {} + + uint64_t id_; +}; + +} // namespace tags +} // namespace opencensus + +#endif // OPENCENSUS_TAGS_TAG_KEY_H_ diff --git a/extensions/stackdriver/opencensus/tags/tag_map.h b/extensions/stackdriver/opencensus/tags/tag_map.h new file mode 100644 index 00000000000..5c648a738cc --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/tag_map.h @@ -0,0 +1,72 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_TAGS_TAG_MAP_H_ +#define OPENCENSUS_TAGS_TAG_MAP_H_ + +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/tags/tag_key.h" + +namespace opencensus { +namespace tags { + +// TagMap represents an immutable map of TagKeys to tag values (strings), and +// provides efficient equality and hash operations. A TagMap is expensive to +// construct, and should be shared between uses where possible. +class TagMap final { + public: + // Both constructors are not explicit so that Record({}, {{"k", "v"}}) works. + // This constructor is needed because even though we copy to a vector + // internally because c++ cannot deduce the conversion needed. + TagMap(std::initializer_list> tags); + + // This constructor is needed so that callers can dynamically construct + // TagMaps. It takes the argument by value to allow it to be moved. + TagMap(std::vector> tags); + + // Accesses the tags sorted by key (in an implementation-defined, not + // lexicographic, order). + const std::vector>& tags() const { + return tags_; + } + + struct Hash { + std::size_t operator()(const TagMap& tags) const; + }; + + bool operator==(const TagMap& other) const; + bool operator!=(const TagMap& other) const { return !(*this == other); } + + // Returns a human-readable string for debugging. Do not rely on its format or + // try to parse it. Do not use it to retrieve tags. + std::string DebugString() const; + + private: + void Initialize(); + + std::size_t hash_; + // TODO: add an option to store string_views to avoid copies. + std::vector> tags_; +}; + +} // namespace tags +} // namespace opencensus + +#endif // OPENCENSUS_TAGS_TAG_MAP_H_ diff --git a/extensions/stackdriver/opencensus/tags/with_tag_map.h b/extensions/stackdriver/opencensus/tags/with_tag_map.h new file mode 100644 index 00000000000..4ad9e5d6f57 --- /dev/null +++ b/extensions/stackdriver/opencensus/tags/with_tag_map.h @@ -0,0 +1,62 @@ +// Copyright 2018, OpenCensus 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. + +#ifndef OPENCENSUS_TAGS_WITH_TAG_MAP_H_ +#define OPENCENSUS_TAGS_WITH_TAG_MAP_H_ + +#include "opencensus/context/context.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace tags { + +// WithTagMap is a scoped object that sets the current TagMap to the given one, +// until the WithTagMap object is destroyed. If the condition is false, it +// doesn't do anything. +// +// Because WithTagMap changes the current (thread local) context, NEVER allocate +// a WithTagMap in one thread and deallocate in another. A simple way to ensure +// this is to only ever stack-allocate it. +// +// Example usage: +// { +// WithTagMap wt(tags); +// // Do work. +// } +class WithTagMap { + public: + explicit WithTagMap(const TagMap& tags, bool cond = true); + explicit WithTagMap(TagMap&& tags, bool cond = true); + ~WithTagMap(); + + private: + WithTagMap() = delete; + WithTagMap(const WithTagMap&) = delete; + WithTagMap(WithTagMap&&) = delete; + WithTagMap& operator=(const WithTagMap&) = delete; + WithTagMap& operator=(WithTagMap&&) = delete; + + void ConditionalSwap(); + + TagMap swapped_tags_; +#ifndef NDEBUG + const ::opencensus::context::Context* original_context_; +#endif + const bool cond_; +}; + +} // namespace tags +} // namespace opencensus + +#endif // OPENCENSUS_TAGS_WITH_TAG_MAP_H_ From 06d34adc438b72232353c34392f59cbd9a840ee4 Mon Sep 17 00:00:00 2001 From: Pengyuan Bian Date: Thu, 13 Jun 2019 11:19:18 -0700 Subject: [PATCH 2/3] add more text --- WORKSPACE | 2 +- extensions/stackdriver/opencensus/README.md | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 3c82adaf78d..0c19ce8aacd 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -83,7 +83,7 @@ go_rules_dependencies() go_register_toolchains(go_version = GO_VERSION) -# TODO(bianpengyuan): remove this googleapis dep when upstream imports it in +# TODO(bianpengyuan): remove this googleapis dep when upstream envoy-wasm repo merges # https://github.com/envoyproxy/envoy/pull/5387 load("//extensions/stackdriver/opencensus:opencensus.bzl", "telemetry_googleapis") diff --git a/extensions/stackdriver/opencensus/README.md b/extensions/stackdriver/opencensus/README.md index fb8cb68cb39..ca2993efd16 100644 --- a/extensions/stackdriver/opencensus/README.md +++ b/extensions/stackdriver/opencensus/README.md @@ -1,5 +1,9 @@ # Opencensus Library -This folder includes opencensus library copied from with customization. Even though opencensus-cpp repo has already had bazel setup, the original code won't work out of box within a wasm sandbox or in an envoy worker silo, so we have to copy and customize it. +This folder includes opencensus library copied from with customization. Even though opencensus-cpp repo has already had bazel setup, the original code won't work out of box within a wasm sandbox or in an envoy worker silo, so we have to copy and customize it. Customization includes: + +* Remove threading and thread annotations due to silo thread contrain. +* Remove assertion and stdio since they are not yet well supported by the emscripten ABI. All assertions and logs are about checking and logging misuse of opencensus library. It should not be a concern here since the library code is used in a certain way. +* Customized stackdriver exporter using WASM sandbox gRPC API. The library is mainly used to do data aggregation for some predefined metrics and export them to Stackdriver. The code in this directory should mostly remain unchanged unless bug is found. \ No newline at end of file From fa90de7c41b18f4736562d6cd617cb64fa6d63a3 Mon Sep 17 00:00:00 2001 From: Pengyuan Bian Date: Sun, 16 Jun 2019 13:57:31 -0700 Subject: [PATCH 3/3] extract out copts --- .../opencensus/common/internal/BUILD | 20 +++++++--------- .../stackdriver/opencensus/context/BUILD | 10 ++++---- extensions/stackdriver/opencensus/copts.bzl | 23 +++++++++++++++++++ .../stackdriver/opencensus/opencensus.bzl | 2 +- extensions/stackdriver/opencensus/stats/BUILD | 20 +++++++--------- extensions/stackdriver/opencensus/tags/BUILD | 15 ++++++------ 6 files changed, 53 insertions(+), 37 deletions(-) create mode 100644 extensions/stackdriver/opencensus/copts.bzl diff --git a/extensions/stackdriver/opencensus/common/internal/BUILD b/extensions/stackdriver/opencensus/common/internal/BUILD index 917ad26a699..6d78bb76946 100644 --- a/extensions/stackdriver/opencensus/common/internal/BUILD +++ b/extensions/stackdriver/opencensus/common/internal/BUILD @@ -19,15 +19,17 @@ load( "envoy_cc_library", ) +load( + "//extensions/stackdriver/opencensus:copts.bzl", + "DEFAULT_COPTS", +) + licenses(["notice"]) # Apache 2.0 envoy_cc_library( name = "hash_mix", hdrs = ["hash_mix.h"], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], ) @@ -36,10 +38,7 @@ envoy_cc_library( name = "random_lib", srcs = ["random.cc"], hdrs = ["random.h"], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], deps = [ @@ -50,10 +49,7 @@ envoy_cc_library( envoy_cc_library( name = "string_vector_hash", hdrs = ["string_vector_hash.h"], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], deps = [":hash_mix"], diff --git a/extensions/stackdriver/opencensus/context/BUILD b/extensions/stackdriver/opencensus/context/BUILD index b7e20f0dddb..1cc0e48a177 100644 --- a/extensions/stackdriver/opencensus/context/BUILD +++ b/extensions/stackdriver/opencensus/context/BUILD @@ -20,6 +20,11 @@ load( "envoy_cc_library", ) +load( + "//extensions/stackdriver/opencensus:copts.bzl", + "DEFAULT_COPTS", +) + envoy_cc_library( name = "context", srcs = [ @@ -30,10 +35,7 @@ envoy_cc_library( "context.h", "with_context.h", ], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], deps = [ diff --git a/extensions/stackdriver/opencensus/copts.bzl b/extensions/stackdriver/opencensus/copts.bzl new file mode 100644 index 00000000000..fe4162f0eda --- /dev/null +++ b/extensions/stackdriver/opencensus/copts.bzl @@ -0,0 +1,23 @@ +# Copyright 2019 Istio Authors. All Rights Reserved. +# +# 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. +# +################################################################################ +# + +WERROR = ["-Werror=return-type", "-Werror=switch"] + +DEFAULT_COPTS = [ + "-DNULL_PLUGIN=1", + "-Iextensions/stackdriver", +] diff --git a/extensions/stackdriver/opencensus/opencensus.bzl b/extensions/stackdriver/opencensus/opencensus.bzl index ca659113958..c70dd960cf3 100644 --- a/extensions/stackdriver/opencensus/opencensus.bzl +++ b/extensions/stackdriver/opencensus/opencensus.bzl @@ -1,4 +1,4 @@ -# Copyright 2017 Istio Authors. All Rights Reserved. +# Copyright 2019 Istio Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/extensions/stackdriver/opencensus/stats/BUILD b/extensions/stackdriver/opencensus/stats/BUILD index f52223a5d4d..a81ebf493e6 100644 --- a/extensions/stackdriver/opencensus/stats/BUILD +++ b/extensions/stackdriver/opencensus/stats/BUILD @@ -19,6 +19,11 @@ load( "envoy_cc_library", ) +load( + "//extensions/stackdriver/opencensus:copts.bzl", + "DEFAULT_COPTS", +) + envoy_cc_library( name = "stats", hdrs = [ @@ -27,10 +32,7 @@ envoy_cc_library( "stats.h", "stats_exporter.h", ], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], deps = [ @@ -82,10 +84,7 @@ envoy_cc_library( "view_data.h", "view_descriptor.h", ], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", deps = [ "//extensions/stackdriver/opencensus/common/internal:string_vector_hash", @@ -98,10 +97,7 @@ envoy_cc_library( name = "recording", srcs = ["internal/recording.cc"], hdrs = ["recording.h"], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", deps = [ ":core", diff --git a/extensions/stackdriver/opencensus/tags/BUILD b/extensions/stackdriver/opencensus/tags/BUILD index e886173be2c..bc7f0b26b37 100644 --- a/extensions/stackdriver/opencensus/tags/BUILD +++ b/extensions/stackdriver/opencensus/tags/BUILD @@ -19,6 +19,11 @@ load( "envoy_cc_library", ) +load( + "//extensions/stackdriver/opencensus:copts.bzl", + "DEFAULT_COPTS", +) + envoy_cc_library( name = "tags", srcs = [ @@ -29,10 +34,7 @@ envoy_cc_library( "tag_key.h", "tag_map.h", ], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], deps = [ @@ -44,10 +46,7 @@ envoy_cc_library( name = "context_util", srcs = ["internal/context_util.cc"], hdrs = ["context_util.h"], - copts = [ - "-DNULL_PLUGIN=1", - "-Iextensions/stackdriver", - ], + copts = DEFAULT_COPTS, repository = "@envoy", visibility = ["//extensions/stackdriver:__subpackages__"], deps = [