diff --git a/opencensus/tags/BUILD b/opencensus/tags/BUILD index 16cc1c56..50f58b9a 100644 --- a/opencensus/tags/BUILD +++ b/opencensus/tags/BUILD @@ -41,6 +41,18 @@ cc_library( ], ) +cc_library( + name = "scoped_tags", + srcs = ["internal/scoped_tags.cc"], + hdrs = ["scoped_tags.h"], + copts = DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":tags", + "//opencensus/context", + ], +) + cc_library( name = "with_tag_map", srcs = ["internal/with_tag_map.cc"], @@ -76,6 +88,18 @@ cc_test( ], ) +cc_test( + name = "scoped_tags_test", + srcs = ["internal/scoped_tags_test.cc"], + copts = TEST_COPTS, + deps = [ + ":scoped_tags", + ":tags", + "//opencensus/context", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "with_tag_map_test", srcs = ["internal/with_tag_map_test.cc"], diff --git a/opencensus/tags/internal/scoped_tags.cc b/opencensus/tags/internal/scoped_tags.cc new file mode 100644 index 00000000..46598898 --- /dev/null +++ b/opencensus/tags/internal/scoped_tags.cc @@ -0,0 +1,40 @@ +// 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/scoped_tags.h" + +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/tags/tag_key.h" + +// Guard macro from scoped_tags.h. +#undef ScopedTags + +namespace opencensus { +namespace tags { + +ScopedTags::ScopedTags( + std::initializer_list> tags) + : swapped_tag_map_({}) { + // TODO: Implement this. +} + +ScopedTags::~ScopedTags() { + // TODO: Implement this. +} + +} // namespace tags +} // namespace opencensus diff --git a/opencensus/tags/internal/scoped_tags_test.cc b/opencensus/tags/internal/scoped_tags_test.cc new file mode 100644 index 00000000..dd5c30f5 --- /dev/null +++ b/opencensus/tags/internal/scoped_tags_test.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/scoped_tags.h" + +#include + +#include "gtest/gtest.h" +//#include "opencensus/context/context.h" +#include "opencensus/tags/tag_key.h" + +// Not in namespace ::opencensus::context in order to better reflect what user +// code should look like. + +namespace { + +void ExpectNoTags() { + // Implement this. +} + +TEST(ScopedTagsTest, NestedScopes) { + static const auto k1 = opencensus::tags::TagKey::Register("key1"); + static const auto k2 = opencensus::tags::TagKey::Register("key2"); + static const auto k3 = opencensus::tags::TagKey::Register("key3"); + + ExpectNoTags(); + { + opencensus::tags::ScopedTags tags1({{k1, "v1"}}); + // Expect something. + { + opencensus::tags::ScopedTags tags2({{k2, "v2"}, {k3, "v3"}}); + // Expect something. + } + } + ExpectNoTags(); +} + +TEST(ScopedTagsTest, ReplaceValue) { + static const auto k1 = opencensus::tags::TagKey::Register("key1"); + static const auto k2 = opencensus::tags::TagKey::Register("key2"); + static const auto k3 = opencensus::tags::TagKey::Register("key3"); + + // Order shouldn't matter. + opencensus::tags::ScopedTags tags1({{k2, "v2"}, {k1, "v1"}}); + { + opencensus::tags::ScopedTags tags2({{k3, "v3"}, {k2, "xx"}}); + // Expect something. + } +} + +// Disable non-compilation test. +#if 0 +TEST(ScopedTagsTest, NCForgotName) { + static const auto k1 = opencensus::tags::TagKey::Register("key1"); + opencensus::tags::ScopedTags({{k1, "v1"}}); +} +#endif + +} // namespace diff --git a/opencensus/tags/scoped_tags.h b/opencensus/tags/scoped_tags.h new file mode 100644 index 00000000..28569c61 --- /dev/null +++ b/opencensus/tags/scoped_tags.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_TAGS_SCOPED_TAGS_H_ +#define OPENCENSUS_TAGS_SCOPED_TAGS_H_ + +#include +#include + +#include "absl/strings/string_view.h" +#include "opencensus/tags/tag_key.h" +#include "opencensus/tags/tag_map.h" + +namespace opencensus { +namespace tags { + +// ScopedTags is an RAII object, only ever stack-allocate it. While it's in +// scope, the current Context will execute with the specified tags added. If a +// tag key was already in use, its value will be replaced. +class ScopedTags { + public: + explicit ScopedTags( + std::initializer_list> tags); + ~ScopedTags(); + + private: + ScopedTags() = delete; + ScopedTags(const ScopedTags&) = delete; + ScopedTags(ScopedTags&&) = delete; + ScopedTags& operator=(const ScopedTags&) = delete; + ScopedTags& operator=(ScopedTags&&) = delete; + + TagMap swapped_tag_map_; +}; + +// Catch a bug where no name is given and the object is immediately discarded. +#define ScopedTags(x) \ + do { \ + static_assert( \ + false, \ + "ScopedTags needs to be an object on the stack and have a name"); \ + } while (0) + +} // namespace tags +} // namespace opencensus + +#endif // OPENCENSUS_TAGS_SCOPED_TAGS_H_