diff --git a/BUILD b/BUILD index 7cc070e4ba0..e7dfa5ed81e 100644 --- a/BUILD +++ b/BUILD @@ -2300,7 +2300,9 @@ grpc_cc_library( "absl-base", "absl-time", "opencensus-trace", + "opencensus-trace-context_util", "opencensus-stats", + "opencensus-context", ], language = "c++", deps = [ diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl index 30471d7d44f..6ddaa37947c 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -81,11 +81,21 @@ def grpc_deps(): actual = "@com_github_grpc_grpc//:grpc++_codegen_proto", ) + native.bind( + name = "opencensus-context", + actual = "@io_opencensus_cpp//opencensus/context:context", + ) + native.bind( name = "opencensus-trace", actual = "@io_opencensus_cpp//opencensus/trace:trace", ) + native.bind( + name = "opencensus-trace-context_util", + actual = "@io_opencensus_cpp//opencensus/trace:context_util", + ) + native.bind( name = "opencensus-stats", actual = "@io_opencensus_cpp//opencensus/stats:stats", @@ -96,6 +106,16 @@ def grpc_deps(): actual = "@io_opencensus_cpp//opencensus/stats:test_utils", ) + native.bind( + name = "opencensus-with-tag-map", + actual = "@io_opencensus_cpp//opencensus/tags:with_tag_map", + ) + + native.bind( + name = "opencensus-tags", + actual = "@io_opencensus_cpp//opencensus/tags:tags", + ) + if "boringssl" not in native.existing_rules(): http_archive( name = "boringssl", diff --git a/src/cpp/ext/filters/census/client_filter.cc b/src/cpp/ext/filters/census/client_filter.cc index f2053a6183a..289ef2b4c7e 100644 --- a/src/cpp/ext/filters/census/client_filter.cc +++ b/src/cpp/ext/filters/census/client_filter.cc @@ -18,11 +18,17 @@ #include +#include +#include +#include + #include "src/cpp/ext/filters/census/client_filter.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "opencensus/stats/stats.h" +#include "opencensus/tags/tag_key.h" +#include "opencensus/tags/tag_map.h" #include "src/core/lib/surface/call.h" #include "src/cpp/ext/filters/census/grpc_plugin.h" #include "src/cpp/ext/filters/census/measures.h" @@ -152,6 +158,13 @@ void CensusClientCallData::Destroy(grpc_call_element* elem, const uint64_t request_size = GetOutgoingDataSize(final_info); const uint64_t response_size = GetIncomingDataSize(final_info); double latency_ms = absl::ToDoubleMilliseconds(absl::Now() - start_time_); + std::vector> tags = + context_.tags().tags(); + std::string method = absl::StrCat(method_); + tags.emplace_back(ClientMethodTagKey(), method); + std::string final_status = + absl::StrCat(StatusCodeToString(final_info->final_status)); + tags.emplace_back(ClientStatusTagKey(), final_status); ::opencensus::stats::Record( {{RpcClientSentBytesPerRpc(), static_cast(request_size)}, {RpcClientReceivedBytesPerRpc(), static_cast(response_size)}, @@ -160,9 +173,13 @@ void CensusClientCallData::Destroy(grpc_call_element* elem, ToDoubleMilliseconds(absl::Nanoseconds(elapsed_time_))}, {RpcClientSentMessagesPerRpc(), sent_message_count_}, {RpcClientReceivedMessagesPerRpc(), recv_message_count_}}, - {{ClientMethodTagKey(), method_}, - {ClientStatusTagKey(), StatusCodeToString(final_info->final_status)}}); + tags); grpc_slice_unref_internal(path_); + if (final_info->final_status != GRPC_STATUS_OK) { + // TODO: Map grpc_status_code to trace::StatusCode. + context_.Span().SetStatus(opencensus::trace::StatusCode::UNKNOWN, + StatusCodeToString(final_info->final_status)); + } context_.EndSpan(); } diff --git a/src/cpp/ext/filters/census/context.cc b/src/cpp/ext/filters/census/context.cc index 160590353a7..b5fd1672242 100644 --- a/src/cpp/ext/filters/census/context.cc +++ b/src/cpp/ext/filters/census/context.cc @@ -18,10 +18,13 @@ #include +#include "opencensus/tags/context_util.h" +#include "opencensus/trace/context_util.h" #include "src/cpp/ext/filters/census/context.h" namespace grpc { +using ::opencensus::tags::TagMap; using ::opencensus::trace::Span; using ::opencensus::trace::SpanContext; @@ -40,7 +43,7 @@ void GenerateServerContext(absl::string_view tracing, absl::string_view stats, return; } } - new (context) CensusContext(method); + new (context) CensusContext(method, TagMap{}); } void GenerateClientContext(absl::string_view method, CensusContext* ctxt, @@ -52,11 +55,19 @@ void GenerateClientContext(absl::string_view method, CensusContext* ctxt, SpanContext span_ctxt = parent_ctxt->Context(); Span span = parent_ctxt->Span(); if (span_ctxt.IsValid()) { - new (ctxt) CensusContext(method, &span); + new (ctxt) CensusContext(method, &span, TagMap{}); return; } } - new (ctxt) CensusContext(method); + const Span& span = opencensus::trace::GetCurrentSpan(); + const TagMap& tags = opencensus::tags::GetCurrentTagMap(); + if (span.context().IsValid()) { + // Create span with parent. + new (ctxt) CensusContext(method, &span, tags); + return; + } + // Create span without parent. + new (ctxt) CensusContext(method, tags); } size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context, diff --git a/src/cpp/ext/filters/census/context.h b/src/cpp/ext/filters/census/context.h index 1643fdd11be..c9d4ad61b01 100644 --- a/src/cpp/ext/filters/census/context.h +++ b/src/cpp/ext/filters/census/context.h @@ -25,6 +25,9 @@ #include "absl/memory/memory.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" +#include "opencensus/context/context.h" +#include "opencensus/tags/tag_map.h" +#include "opencensus/trace/context_util.h" #include "opencensus/trace/span.h" #include "opencensus/trace/span_context.h" #include "opencensus/trace/trace_params.h" @@ -41,25 +44,32 @@ namespace grpc { // Thread compatible. class CensusContext { public: - CensusContext() : span_(::opencensus::trace::Span::BlankSpan()) {} + CensusContext() : span_(::opencensus::trace::Span::BlankSpan()), tags_({}) {} - explicit CensusContext(absl::string_view name) - : span_(::opencensus::trace::Span::StartSpan(name)) {} + explicit CensusContext(absl::string_view name, + const ::opencensus::tags::TagMap& tags) + : span_(::opencensus::trace::Span::StartSpan(name)), tags_(tags) {} - CensusContext(absl::string_view name, const ::opencensus::trace::Span* parent) - : span_(::opencensus::trace::Span::StartSpan(name, parent)) {} + CensusContext(absl::string_view name, const ::opencensus::trace::Span* parent, + const ::opencensus::tags::TagMap& tags) + : span_(::opencensus::trace::Span::StartSpan(name, parent)), + tags_(tags) {} CensusContext(absl::string_view name, const ::opencensus::trace::SpanContext& parent_ctxt) : span_(::opencensus::trace::Span::StartSpanWithRemoteParent( - name, parent_ctxt)) {} + name, parent_ctxt)), + tags_({}) {} - ::opencensus::trace::SpanContext Context() const { return span_.context(); } - ::opencensus::trace::Span Span() const { return span_; } - void EndSpan() { span_.End(); } + const ::opencensus::trace::Span& Span() const { return span_; } + const ::opencensus::tags::TagMap& tags() const { return tags_; } + + ::opencensus::trace::SpanContext Context() const { return Span().context(); } + void EndSpan() { Span().End(); } private: ::opencensus::trace::Span span_; + ::opencensus::tags::TagMap tags_; }; // Serializes the outgoing trace context. Field IDs are 1 byte followed by diff --git a/test/cpp/ext/filters/census/BUILD b/test/cpp/ext/filters/census/BUILD index 01e4e91d9c7..0351330de00 100644 --- a/test/cpp/ext/filters/census/BUILD +++ b/test/cpp/ext/filters/census/BUILD @@ -27,6 +27,8 @@ grpc_cc_test( external_deps = [ "gtest", "opencensus-stats-test", + "opencensus-tags", + "opencensus-with-tag-map", ], language = "C++", tags = ["no_windows"], # TODO(jtattermusch): fix test on windows diff --git a/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc b/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc index 0638c3343e6..d007971ed58 100644 --- a/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc +++ b/test/cpp/ext/filters/census/stats_plugin_end2end_test.cc @@ -27,7 +27,10 @@ #include "include/grpc++/grpc++.h" #include "include/grpcpp/opencensus.h" #include "opencensus/stats/stats.h" +#include "opencensus/stats/tag_key.h" #include "opencensus/stats/testing/test_utils.h" +#include "opencensus/tags/tag_map.h" +#include "opencensus/tags/with_tag_map.h" #include "src/cpp/ext/filters/census/grpc_plugin.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "test/core/util/test_config.h" @@ -41,6 +44,12 @@ using ::opencensus::stats::Distribution; using ::opencensus::stats::View; using ::opencensus::stats::ViewDescriptor; using ::opencensus::stats::testing::TestUtils; +using ::opencensus::tags::TagKey; +using ::opencensus::tags::TagMap; +using ::opencensus::tags::WithTagMap; + +static const auto TEST_TAG_KEY = TagKey::Register("my_key"); +static const auto TEST_TAG_VALUE = "my_value"; class EchoServer final : public EchoTestService::Service { ::grpc::Status Echo(::grpc::ServerContext* context, @@ -104,7 +113,8 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) { .set_measure(kRpcClientRoundtripLatencyMeasureName) .set_name("client_method") .set_aggregation(Aggregation::Count()) - .add_column(ClientMethodTagKey()); + .add_column(ClientMethodTagKey()) + .add_column(TEST_TAG_KEY); View client_method_view(client_method_descriptor); const auto server_method_descriptor = ViewDescriptor() @@ -112,6 +122,7 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) { .set_name("server_method") .set_aggregation(Aggregation::Count()) .add_column(ServerMethodTagKey()); + //.add_column(TEST_TAG_KEY); View server_method_view(server_method_descriptor); const auto client_status_descriptor = @@ -119,7 +130,8 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) { .set_measure(kRpcClientRoundtripLatencyMeasureName) .set_name("client_status") .set_aggregation(Aggregation::Count()) - .add_column(ClientStatusTagKey()); + .add_column(ClientStatusTagKey()) + .add_column(TEST_TAG_KEY); View client_status_view(client_status_descriptor); const auto server_status_descriptor = ViewDescriptor() @@ -136,19 +148,56 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) { request.mutable_param()->mutable_expected_error()->set_code(i); EchoResponse response; ::grpc::ClientContext context; - ::grpc::Status status = stub_->Echo(&context, request, &response); + { + WithTagMap tags({{TEST_TAG_KEY, TEST_TAG_VALUE}}); + ::grpc::Status status = stub_->Echo(&context, request, &response); + } } absl::SleepFor(absl::Milliseconds(500)); TestUtils::Flush(); - EXPECT_THAT(client_method_view.GetData().int_data(), - ::testing::UnorderedElementsAre(::testing::Pair( - ::testing::ElementsAre(client_method_name_), 17))); + // Client side views can be tagged with custom tags. + EXPECT_THAT( + client_method_view.GetData().int_data(), + ::testing::UnorderedElementsAre(::testing::Pair( + ::testing::ElementsAre(client_method_name_, TEST_TAG_VALUE), 17))); + // TODO: Implement server view tagging with custom tags. EXPECT_THAT(server_method_view.GetData().int_data(), ::testing::UnorderedElementsAre(::testing::Pair( ::testing::ElementsAre(server_method_name_), 17))); - auto codes = { + // Client side views can be tagged with custom tags. + auto client_tags = { + ::testing::Pair(::testing::ElementsAre("OK", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("CANCELLED", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("UNKNOWN", TEST_TAG_VALUE), 1), + ::testing::Pair( + ::testing::ElementsAre("INVALID_ARGUMENT", TEST_TAG_VALUE), 1), + ::testing::Pair( + ::testing::ElementsAre("DEADLINE_EXCEEDED", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("NOT_FOUND", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("ALREADY_EXISTS", TEST_TAG_VALUE), + 1), + ::testing::Pair( + ::testing::ElementsAre("PERMISSION_DENIED", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("UNAUTHENTICATED", TEST_TAG_VALUE), + 1), + ::testing::Pair( + ::testing::ElementsAre("RESOURCE_EXHAUSTED", TEST_TAG_VALUE), 1), + ::testing::Pair( + ::testing::ElementsAre("FAILED_PRECONDITION", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("ABORTED", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("OUT_OF_RANGE", TEST_TAG_VALUE), + 1), + ::testing::Pair(::testing::ElementsAre("UNIMPLEMENTED", TEST_TAG_VALUE), + 1), + ::testing::Pair(::testing::ElementsAre("INTERNAL", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("UNAVAILABLE", TEST_TAG_VALUE), 1), + ::testing::Pair(::testing::ElementsAre("DATA_LOSS", TEST_TAG_VALUE), 1), + }; + + // TODO: Implement server view tagging with custom tags. + auto server_tags = { ::testing::Pair(::testing::ElementsAre("OK"), 1), ::testing::Pair(::testing::ElementsAre("CANCELLED"), 1), ::testing::Pair(::testing::ElementsAre("UNKNOWN"), 1), @@ -169,9 +218,9 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) { }; EXPECT_THAT(client_status_view.GetData().int_data(), - ::testing::UnorderedElementsAreArray(codes)); + ::testing::UnorderedElementsAreArray(client_tags)); EXPECT_THAT(server_status_view.GetData().int_data(), - ::testing::UnorderedElementsAreArray(codes)); + ::testing::UnorderedElementsAreArray(server_tags)); } TEST_F(StatsPluginEnd2EndTest, RequestReceivedBytesPerRpc) {