|
|
|
//
|
|
|
|
//
|
|
|
|
// Copyright 2023 gRPC 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 "src/cpp/ext/otel/otel_plugin.h"
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
#include <chrono>
|
|
|
|
#include <ratio>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
#include "absl/functional/any_invocable.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "opentelemetry/common/timestamp.h"
|
|
|
|
#include "opentelemetry/metrics/provider.h"
|
|
|
|
#include "opentelemetry/nostd/variant.h"
|
|
|
|
#include "opentelemetry/sdk/common/attribute_utils.h"
|
|
|
|
#include "opentelemetry/sdk/metrics/data/point_data.h"
|
|
|
|
#include "opentelemetry/sdk/metrics/meter_provider.h"
|
|
|
|
#include "opentelemetry/sdk/metrics/metric_reader.h"
|
|
|
|
|
|
|
|
#include <grpcpp/ext/otel_plugin.h>
|
|
|
|
#include <grpcpp/grpcpp.h>
|
|
|
|
|
|
|
|
#include "src/core/lib/channel/call_tracer.h"
|
|
|
|
#include "src/core/lib/config/core_configuration.h"
|
|
|
|
#include "test/core/util/test_config.h"
|
|
|
|
#include "test/cpp/end2end/test_service_impl.h"
|
|
|
|
#include "test/cpp/ext/otel/otel_test_library.h"
|
|
|
|
|
|
|
|
namespace grpc {
|
|
|
|
namespace testing {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
#define GRPC_ARG_SERVER_SELECTOR_KEY "grpc.testing.server_selector_key"
|
|
|
|
#define GRPC_ARG_SERVER_SELECTOR_VALUE "grpc.testing.server_selector_value"
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void PopulateLabelMap(
|
|
|
|
T label_keys, T label_values,
|
|
|
|
std::unordered_map<std::string,
|
|
|
|
opentelemetry::sdk::common::OwnedAttributeValue>*
|
|
|
|
label_maps) {
|
|
|
|
for (size_t i = 0; i < label_keys.size(); ++i) {
|
|
|
|
(*label_maps)[std::string(label_keys[i])] = std::string(label_values[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MATCHER_P4(AttributesEq, label_keys, label_values, optional_label_keys,
|
|
|
|
optional_label_values, "") {
|
|
|
|
std::unordered_map<std::string,
|
|
|
|
opentelemetry::sdk::common::OwnedAttributeValue>
|
|
|
|
label_map;
|
|
|
|
PopulateLabelMap(label_keys, label_values, &label_map);
|
|
|
|
PopulateLabelMap(optional_label_keys, optional_label_values, &label_map);
|
|
|
|
return ::testing::ExplainMatchResult(
|
|
|
|
::testing::UnorderedElementsAreArray(label_map),
|
|
|
|
arg.attributes.GetAttributes(), result_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct Extract;
|
|
|
|
|
|
|
|
template <template <typename> class T, typename U>
|
|
|
|
struct Extract<const T<U>> {
|
|
|
|
using Type = U;
|
|
|
|
};
|
|
|
|
|
|
|
|
MATCHER_P(CounterResultEq, value_matcher, "") {
|
|
|
|
return ::testing::ExplainMatchResult(
|
|
|
|
::testing::VariantWith<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
::testing::Field(&opentelemetry::sdk::metrics::SumPointData::value_,
|
|
|
|
::testing::VariantWith<
|
|
|
|
typename Extract<decltype(value_matcher)>::Type>(
|
|
|
|
value_matcher))),
|
|
|
|
arg.point_data, result_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
MATCHER_P4(HistogramResultEq, sum_matcher, min_matcher, max_matcher, count,
|
|
|
|
"") {
|
|
|
|
return ::testing::ExplainMatchResult(
|
|
|
|
::testing::VariantWith<
|
|
|
|
opentelemetry::sdk::metrics::HistogramPointData>(::testing::AllOf(
|
|
|
|
::testing::Field(
|
|
|
|
&opentelemetry::sdk::metrics::HistogramPointData::sum_,
|
|
|
|
::testing::VariantWith<
|
|
|
|
typename Extract<decltype(sum_matcher)>::Type>(sum_matcher)),
|
|
|
|
::testing::Field(
|
|
|
|
&opentelemetry::sdk::metrics::HistogramPointData::min_,
|
|
|
|
::testing::VariantWith<
|
|
|
|
typename Extract<decltype(min_matcher)>::Type>(min_matcher)),
|
|
|
|
::testing::Field(
|
|
|
|
&opentelemetry::sdk::metrics::HistogramPointData::max_,
|
|
|
|
::testing::VariantWith<
|
|
|
|
typename Extract<decltype(max_matcher)>::Type>(max_matcher)),
|
|
|
|
::testing::Field(
|
|
|
|
&opentelemetry::sdk::metrics::HistogramPointData::count_,
|
|
|
|
::testing::Eq(count)))),
|
|
|
|
arg.point_data, result_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
MATCHER_P(GaugeResultIs, value_matcher, "") {
|
|
|
|
return ::testing::ExplainMatchResult(
|
|
|
|
::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
|
|
|
|
::testing::AllOf(
|
|
|
|
::testing::Field(
|
|
|
|
&opentelemetry::sdk::metrics::LastValuePointData::value_,
|
|
|
|
::testing::VariantWith<
|
|
|
|
typename Extract<decltype(value_matcher)>::Type>(
|
|
|
|
value_matcher)),
|
|
|
|
::testing::Field(&opentelemetry::sdk::metrics::
|
|
|
|
LastValuePointData::is_lastvalue_valid_,
|
|
|
|
::testing::IsTrue()))),
|
|
|
|
arg.point_data, result_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This check might subject to system clock adjustment.
|
|
|
|
MATCHER_P(GaugeResultLaterThan, prev_timestamp, "") {
|
|
|
|
return ::testing::ExplainMatchResult(
|
|
|
|
::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
|
|
|
|
::testing::Field(
|
|
|
|
&opentelemetry::sdk::metrics::LastValuePointData::sample_ts_,
|
|
|
|
::testing::Property(
|
|
|
|
&opentelemetry::common::SystemTimestamp::time_since_epoch,
|
|
|
|
::testing::Gt(prev_timestamp.time_since_epoch())))),
|
|
|
|
arg.point_data, result_listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
MATCHER_P7(GaugeDataIsIncrementalForSpecificMetricAndLabelSet, metric_name,
|
|
|
|
label_key, label_value, optional_label_key, optional_label_value,
|
|
|
|
default_value, greater_than, "") {
|
|
|
|
std::unordered_map<std::string,
|
|
|
|
opentelemetry::sdk::common::OwnedAttributeValue>
|
|
|
|
label_map;
|
|
|
|
PopulateLabelMap(label_key, label_value, &label_map);
|
|
|
|
PopulateLabelMap(optional_label_key, optional_label_value, &label_map);
|
|
|
|
opentelemetry::common::SystemTimestamp prev_timestamp;
|
|
|
|
auto prev_value = default_value;
|
|
|
|
size_t prev_index = 0;
|
|
|
|
auto& data = arg.at(metric_name);
|
|
|
|
bool result = true;
|
|
|
|
for (size_t i = 1; i < data.size(); ++i) {
|
|
|
|
if (::testing::Matches(::testing::UnorderedElementsAreArray(
|
|
|
|
data[i - 1].attributes.GetAttributes()))(label_map)) {
|
|
|
|
// Update the previous value for the same associated label values.
|
|
|
|
prev_value = opentelemetry::nostd::get<decltype(prev_value)>(
|
|
|
|
opentelemetry::nostd::get<
|
|
|
|
opentelemetry::sdk::metrics::LastValuePointData>(
|
|
|
|
data[i - 1].point_data)
|
|
|
|
.value_);
|
|
|
|
prev_index = i - 1;
|
|
|
|
prev_timestamp = opentelemetry::nostd::get<
|
|
|
|
opentelemetry::sdk::metrics::LastValuePointData>(
|
|
|
|
data[i - 1].point_data)
|
|
|
|
.sample_ts_;
|
|
|
|
}
|
|
|
|
if (!::testing::Matches(::testing::UnorderedElementsAreArray(
|
|
|
|
data[i].attributes.GetAttributes()))(label_map)) {
|
|
|
|
// Skip values that do not have the same associated label values.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*result_listener << " Comparing data[" << i << "] with data[" << prev_index
|
|
|
|
<< "] ";
|
|
|
|
if (greater_than) {
|
|
|
|
result &= ::testing::ExplainMatchResult(
|
|
|
|
::testing::AllOf(
|
|
|
|
AttributesEq(label_key, label_value, optional_label_key,
|
|
|
|
optional_label_value),
|
|
|
|
GaugeResultIs(::testing::Gt(prev_value)),
|
|
|
|
GaugeResultLaterThan(prev_timestamp)),
|
|
|
|
data[i], result_listener);
|
|
|
|
} else {
|
|
|
|
result &= ::testing::ExplainMatchResult(
|
|
|
|
::testing::AllOf(
|
|
|
|
AttributesEq(label_key, label_value, optional_label_key,
|
|
|
|
optional_label_value),
|
|
|
|
GaugeResultIs(::testing::Ge(prev_value)),
|
|
|
|
GaugeResultLaterThan(prev_timestamp)),
|
|
|
|
data[i], result_listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OpenTelemetryPluginBuildTest, ApiDependency) {
|
|
|
|
opentelemetry::metrics::Provider::GetMeterProvider();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OpenTelemetryPluginBuildTest, SdkDependency) {
|
|
|
|
opentelemetry::sdk::metrics::MeterProvider();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OpenTelemetryPluginBuildTest, Basic) {
|
|
|
|
grpc::OpenTelemetryPluginBuilder builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptStarted) {
|
|
|
|
Init(std::move(
|
|
|
|
Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptDuration) {
|
|
|
|
Init(std::move(
|
|
|
|
Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.duration";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 3);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
ClientAttemptSentTotalCompressedMessageSize) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptSentTotalCompressedMessageSizeInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName =
|
|
|
|
"grpc.client.attempt.sent_total_compressed_message_size";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 3);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
ClientAttemptRcvdTotalCompressedMessageSize) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName =
|
|
|
|
"grpc.client.attempt.rcvd_total_compressed_message_size";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 3);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallStarted) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.server.call.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto server_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(server_started_value, nullptr);
|
|
|
|
ASSERT_EQ(*server_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 1);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallDuration) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.server.call.duration";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
ServerCallSentTotalCompressedMessageSize) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallSentTotalCompressedMessageSizeInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName =
|
|
|
|
"grpc.server.call.sent_total_compressed_message_size";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
EXPECT_EQ(point_data->count_, 1);
|
|
|
|
ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
ServerCallRcvdTotalCompressedMessageSize) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallRcvdTotalCompressedMessageSizeInstrumentName})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName =
|
|
|
|
"grpc.server.call.rcvd_total_compressed_message_size";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure that no meter provider results in normal operations.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, NoMeterProviderRegistered) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_use_meter_provider(false)));
|
|
|
|
SendRPC();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a channel scope filter returning true records metrics on the
|
|
|
|
// channel.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsTrue) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_channel_scope_filter(
|
|
|
|
[](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
|
|
|
|
return true;
|
|
|
|
})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a channel scope filter returning false does not record metrics on
|
|
|
|
// the channel.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsFalse) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_channel_scope_filter(
|
|
|
|
[](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
|
|
|
|
return false;
|
|
|
|
})));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
/*data*/) { return false; });
|
|
|
|
ASSERT_TRUE(data.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a server selector returning true records metrics on the server.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsTrue) {
|
|
|
|
Init(std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.set_server_selector(
|
|
|
|
[](const grpc_core::ChannelArgs& /*channel_args*/) {
|
|
|
|
return true;
|
|
|
|
})));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.server.call.duration";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(server_attributes.size(), 2);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.method")),
|
|
|
|
kMethodName);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.status")), "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a server selector returning false does not record metrics on the
|
|
|
|
// server.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsFalse) {
|
|
|
|
Init(std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.set_server_selector(
|
|
|
|
[](const grpc_core::ChannelArgs& /*channel_args*/) {
|
|
|
|
return false;
|
|
|
|
})));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
/*data*/) { return false; });
|
|
|
|
ASSERT_TRUE(data.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a target attribute filter returning true records metrics with the
|
|
|
|
// target as is on the channel.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsTrue) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_target_attribute_filter(
|
|
|
|
[](absl::string_view /*target*/) { return true; })));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a target attribute filter returning false records metrics with the
|
|
|
|
// target as "other".
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsFalse) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_target_attribute_filter(
|
|
|
|
[](absl::string_view /*target*/) { return false; })));
|
|
|
|
SendRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
/*data*/) { return false; });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, "other");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that generic method names are scrubbed properly on the client side.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, GenericClientRpc) {
|
|
|
|
Init(std::move(
|
|
|
|
Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})));
|
|
|
|
SendGenericRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
/*data*/) { return false; });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, "other");
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that generic method names are scrubbed properly on the client side if
|
|
|
|
// the method attribute filter is set and it returns false.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
GenericClientRpcWithMethodAttributeFilterReturningFalse) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_generic_method_attribute_filter(
|
|
|
|
[](absl::string_view /*generic_method*/) { return false; })));
|
|
|
|
SendGenericRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
/*data*/) { return false; });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, "other");
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that generic method names is not scrubbed on the client side if
|
|
|
|
// the method attribute filter is set and it returns true.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
GenericClientRpcWithMethodAttributeFilterReturningTrue) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName})
|
|
|
|
.set_generic_method_attribute_filter(
|
|
|
|
[](absl::string_view /*generic_method*/) { return true; })));
|
|
|
|
SendGenericRPC();
|
|
|
|
const char* kMetricName = "grpc.client.attempt.started";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
/*data*/) { return false; });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
|
|
|
|
ASSERT_NE(client_started_value, nullptr);
|
|
|
|
EXPECT_EQ(*client_started_value, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kGenericMethodName);
|
|
|
|
const auto* target_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.target"));
|
|
|
|
ASSERT_NE(target_value, nullptr);
|
|
|
|
EXPECT_EQ(*target_value, canonical_server_address_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that generic method names are scrubbed properly on the server side.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, GenericServerRpc) {
|
|
|
|
Init(std::move(Options().set_metric_names(
|
|
|
|
{grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
|
|
|
|
SendGenericRPC();
|
|
|
|
const char* kMetricName = "grpc.server.call.duration";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, "other");
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "UNIMPLEMENTED");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that generic method names are scrubbed properly on the server side if
|
|
|
|
// the method attribute filter is set and it returns false.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
GenericServerRpcWithMethodAttributeFilterReturningFalse) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.set_generic_method_attribute_filter(
|
|
|
|
[](absl::string_view /*generic_method*/) { return false; })));
|
|
|
|
SendGenericRPC();
|
|
|
|
const char* kMetricName = "grpc.server.call.duration";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, "other");
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "UNIMPLEMENTED");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that generic method names are not scrubbed on the server side if
|
|
|
|
// the method attribute filter is set and it returns true.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
GenericServerRpcWithMethodAttributeFilterReturningTrue) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.set_generic_method_attribute_filter(
|
|
|
|
[](absl::string_view /*generic_method*/) { return true; })));
|
|
|
|
SendGenericRPC();
|
|
|
|
const char* kMetricName = "grpc.server.call.duration";
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
ASSERT_EQ(data[kMetricName].size(), 1);
|
|
|
|
auto point_data =
|
|
|
|
absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
|
|
|
|
&data[kMetricName][0].point_data);
|
|
|
|
ASSERT_NE(point_data, nullptr);
|
|
|
|
ASSERT_EQ(point_data->count_, 1);
|
|
|
|
const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 2);
|
|
|
|
const auto* method_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.method"));
|
|
|
|
ASSERT_NE(method_value, nullptr);
|
|
|
|
EXPECT_EQ(*method_value, kGenericMethodName);
|
|
|
|
const auto* status_value =
|
|
|
|
absl::get_if<std::string>(&attributes.at("grpc.status"));
|
|
|
|
ASSERT_NE(status_value, nullptr);
|
|
|
|
EXPECT_EQ(*status_value, "UNIMPLEMENTED");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest, OptionalPerCallLocalityLabel) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallStartedInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.add_optional_label("grpc.lb.locality")
|
|
|
|
.set_labels_to_inject(
|
|
|
|
{{grpc_core::ClientCallTracer::CallAttemptTracer::
|
|
|
|
OptionalLabelKey::kLocality,
|
|
|
|
grpc_core::RefCountedStringValue("locality")}})));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains("grpc.client.attempt.started") ||
|
|
|
|
!data.contains("grpc.client.attempt.duration") ||
|
|
|
|
!data.contains("grpc.server.call.started") ||
|
|
|
|
!data.contains("grpc.server.call.duration");
|
|
|
|
});
|
|
|
|
// Verify client side metric (grpc.client.attempt.started) does not sees this
|
|
|
|
// label
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
|
|
|
|
const auto& client_attributes =
|
|
|
|
data["grpc.client.attempt.started"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(
|
|
|
|
client_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
|
|
|
|
// Verify client side metric (grpc.client.attempt.duration) sees this label.
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_duration_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(
|
|
|
|
absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
|
|
|
|
"locality");
|
|
|
|
// Verify server metric (grpc.server.call.started) does not see this label
|
|
|
|
ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data["grpc.server.call.started"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(
|
|
|
|
server_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
|
|
|
|
// Verify server metric (grpc.server.call.duration) does not see this label
|
|
|
|
ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
|
|
|
|
const auto& server_duration_attributes =
|
|
|
|
data["grpc.server.call.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(
|
|
|
|
server_duration_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that when locality label is enabled on the plugin but not provided by
|
|
|
|
// gRPC, an empty value is recorded.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
OptionalPerCallLocalityLabelWhenNotAvailable) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName})
|
|
|
|
.add_optional_label("grpc.lb.locality")));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains("grpc.client.attempt.duration"); });
|
|
|
|
// Verify client side metric (grpc.client.attempt.duration) sees the empty
|
|
|
|
// label value.
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_duration_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(
|
|
|
|
absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
|
|
|
|
"");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that when locality label is injected but not enabled by the plugin, the
|
|
|
|
// label is not recorded.
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled) {
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName})
|
|
|
|
.set_labels_to_inject(
|
|
|
|
{{grpc_core::ClientCallTracer::CallAttemptTracer::
|
|
|
|
OptionalLabelKey::kLocality,
|
|
|
|
grpc_core::RefCountedStringValue("locality")}})));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains("grpc.client.attempt.duration"); });
|
|
|
|
// Verify client side metric (grpc.client.attempt.duration) does not see the
|
|
|
|
// locality label.
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_duration_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(
|
|
|
|
client_duration_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginEnd2EndTest,
|
|
|
|
UnknownLabelDoesNotShowOnPerCallMetrics) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptStartedInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallStartedInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.add_optional_label("unknown")));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains("grpc.client.attempt.started") ||
|
|
|
|
!data.contains("grpc.client.attempt.duration") ||
|
|
|
|
!data.contains("grpc.server.call.started") ||
|
|
|
|
!data.contains("grpc.server.call.duration");
|
|
|
|
});
|
|
|
|
// Verify client side metric (grpc.client.attempt.started) does not sees this
|
|
|
|
// label
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
|
|
|
|
const auto& client_attributes =
|
|
|
|
data["grpc.client.attempt.started"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(client_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("unknown"))));
|
|
|
|
// Verify client side metric (grpc.client.attempt.duration) does not see this
|
|
|
|
// label
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_duration_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(client_duration_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("unknown"))));
|
|
|
|
// Verify server metric (grpc.server.call.started) does not see this label
|
|
|
|
ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data["grpc.server.call.started"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(
|
|
|
|
server_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
|
|
|
|
// Verify server metric (grpc.server.call.duration) does not see this label
|
|
|
|
ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
|
|
|
|
const auto& server_duration_attributes =
|
|
|
|
data["grpc.server.call.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_THAT(server_duration_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("unknown"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
using OpenTelemetryPluginOptionEnd2EndTest = OpenTelemetryPluginEnd2EndTest;
|
|
|
|
|
|
|
|
class SimpleLabelIterable : public grpc::internal::LabelsIterable {
|
|
|
|
public:
|
|
|
|
explicit SimpleLabelIterable(
|
|
|
|
std::pair<absl::string_view, absl::string_view> label)
|
|
|
|
: label_(label) {}
|
|
|
|
|
|
|
|
absl::optional<std::pair<absl::string_view, absl::string_view>> Next()
|
|
|
|
override {
|
|
|
|
if (iterated_) {
|
|
|
|
return absl::nullopt;
|
|
|
|
}
|
|
|
|
iterated_ = true;
|
|
|
|
return label_;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t Size() const override { return 1; }
|
|
|
|
|
|
|
|
void ResetIteratorPosition() override { iterated_ = false; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool iterated_ = false;
|
|
|
|
std::pair<absl::string_view, absl::string_view> label_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CustomLabelInjector : public grpc::internal::LabelsInjector {
|
|
|
|
public:
|
|
|
|
explicit CustomLabelInjector(std::pair<std::string, std::string> label)
|
|
|
|
: label_(std::move(label)) {}
|
|
|
|
~CustomLabelInjector() override {}
|
|
|
|
|
|
|
|
std::unique_ptr<grpc::internal::LabelsIterable> GetLabels(
|
|
|
|
grpc_metadata_batch* /*incoming_initial_metadata*/) const override {
|
|
|
|
return std::make_unique<SimpleLabelIterable>(label_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddLabels(
|
|
|
|
grpc_metadata_batch* /*outgoing_initial_metadata*/,
|
|
|
|
grpc::internal::LabelsIterable* /*labels_from_incoming_metadata*/)
|
|
|
|
const override {}
|
|
|
|
|
|
|
|
bool AddOptionalLabels(bool /*is_client*/,
|
|
|
|
absl::Span<const grpc_core::RefCountedStringValue>
|
|
|
|
/*optional_labels*/,
|
|
|
|
opentelemetry::nostd::function_ref<
|
|
|
|
bool(opentelemetry::nostd::string_view,
|
|
|
|
opentelemetry::common::AttributeValue)>
|
|
|
|
/*callback*/) const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t GetOptionalLabelsSize(
|
|
|
|
bool /*is_client*/, absl::Span<const grpc_core::RefCountedStringValue>
|
|
|
|
/*optional_labels_span*/) const override {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::pair<std::string, std::string> label_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CustomPluginOption
|
|
|
|
: public grpc::internal::InternalOpenTelemetryPluginOption {
|
|
|
|
public:
|
|
|
|
CustomPluginOption(bool enabled_on_client, bool enabled_on_server,
|
|
|
|
std::pair<std::string, std::string> label)
|
|
|
|
: enabled_on_client_(enabled_on_client),
|
|
|
|
enabled_on_server_(enabled_on_server),
|
|
|
|
label_injector_(
|
|
|
|
std::make_unique<CustomLabelInjector>(std::move(label))) {}
|
|
|
|
|
|
|
|
~CustomPluginOption() override {}
|
|
|
|
|
|
|
|
bool IsActiveOnClientChannel(absl::string_view /*target*/) const override {
|
|
|
|
return enabled_on_client_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsActiveOnServer(const grpc_core::ChannelArgs& /*args*/) const override {
|
|
|
|
return enabled_on_server_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const grpc::internal::LabelsInjector* labels_injector() const override {
|
|
|
|
return label_injector_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool enabled_on_client_;
|
|
|
|
bool enabled_on_server_;
|
|
|
|
std::unique_ptr<CustomLabelInjector> label_injector_;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginOptionEnd2EndTest, Basic) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ true, /*enabled_on_server*/ true,
|
|
|
|
std::make_pair("key", "value")))));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains("grpc.client.attempt.duration") ||
|
|
|
|
!data.contains("grpc.server.call.duration");
|
|
|
|
});
|
|
|
|
// Verify client side metric
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(client_attributes.size(), 4);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
|
|
|
|
// Verify server side metric
|
|
|
|
ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data["grpc.server.call.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(server_attributes.size(), 3);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ClientOnlyPluginOption) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ true, /*enabled_on_server*/ false,
|
|
|
|
std::make_pair("key", "value")))));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains("grpc.client.attempt.duration") ||
|
|
|
|
!data.contains("grpc.server.call.duration");
|
|
|
|
});
|
|
|
|
// Verify client side metric
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(client_attributes.size(), 4);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
|
|
|
|
// Verify server side metric
|
|
|
|
ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data["grpc.server.call.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(server_attributes.size(), 2);
|
|
|
|
EXPECT_THAT(server_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("key"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ServerOnlyPluginOption) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ false, /*enabled_on_server*/ true,
|
|
|
|
std::make_pair("key", "value")))));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains("grpc.client.attempt.duration") ||
|
|
|
|
!data.contains("grpc.server.call.duration");
|
|
|
|
});
|
|
|
|
// Verify client side metric
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(attributes.size(), 3);
|
|
|
|
EXPECT_THAT(attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("key"))));
|
|
|
|
// Verify server side metric
|
|
|
|
ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data["grpc.server.call.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(server_attributes.size(), 3);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,
|
|
|
|
MultipleEnabledAndDisabledPluginOptions) {
|
|
|
|
Init(
|
|
|
|
std::move(Options()
|
|
|
|
.set_metric_names({grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kClientAttemptDurationInstrumentName,
|
|
|
|
grpc::OpenTelemetryPluginBuilder::
|
|
|
|
kServerCallDurationInstrumentName})
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ true, /*enabled_on_server*/ true,
|
|
|
|
std::make_pair("key1", "value1")))
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ true, /*enabled_on_server*/ false,
|
|
|
|
std::make_pair("key2", "value2")))
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ true, /*enabled_on_server*/ false,
|
|
|
|
std::make_pair("key3", "value3")))
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ false, /*enabled_on_server*/ true,
|
|
|
|
std::make_pair("key4", "value4")))
|
|
|
|
.add_plugin_option(std::make_unique<CustomPluginOption>(
|
|
|
|
/*enabled_on_client*/ false, /*enabled_on_server*/ true,
|
|
|
|
std::make_pair("key5", "value5")))));
|
|
|
|
SendRPC();
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains("grpc.client.attempt.duration") ||
|
|
|
|
!data.contains("grpc.server.call.duration");
|
|
|
|
});
|
|
|
|
// Verify client side metric
|
|
|
|
ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
|
|
|
|
const auto& client_attributes =
|
|
|
|
data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(client_attributes.size(), 6);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(client_attributes.at("key1")), "value1");
|
|
|
|
EXPECT_EQ(absl::get<std::string>(client_attributes.at("key2")), "value2");
|
|
|
|
EXPECT_EQ(absl::get<std::string>(client_attributes.at("key3")), "value3");
|
|
|
|
EXPECT_THAT(client_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("key4"))));
|
|
|
|
EXPECT_THAT(client_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("key5"))));
|
|
|
|
// Verify server side metric
|
|
|
|
ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
|
|
|
|
const auto& server_attributes =
|
|
|
|
data["grpc.server.call.duration"][0].attributes.GetAttributes();
|
|
|
|
EXPECT_EQ(server_attributes.size(), 5);
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("key1")), "value1");
|
|
|
|
EXPECT_THAT(server_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("key2"))));
|
|
|
|
EXPECT_THAT(server_attributes,
|
|
|
|
::testing::Not(::testing::Contains(::testing::Key("key3"))));
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("key4")), "value4");
|
|
|
|
EXPECT_EQ(absl::get<std::string>(server_attributes.at("key5")), "value5");
|
|
|
|
}
|
|
|
|
|
|
|
|
using OpenTelemetryPluginNPCMetricsTest = OpenTelemetryPluginEnd2EndTest;
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Counter) {
|
|
|
|
constexpr absl::string_view kMetricName = "uint64_counter";
|
|
|
|
constexpr int kCounterValues[] = {1, 2, 3};
|
|
|
|
constexpr int64_t kCounterResult = 6;
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
|
|
|
|
"label_value_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2"};
|
|
|
|
auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Counter(
|
|
|
|
kMetricName, "A simple uint64 counter.", "unit", kLabelKeys,
|
|
|
|
kOptionalLabelKeys, /*enable_by_default=*/true);
|
|
|
|
Init(std::move(Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_channel_scope_filter(
|
|
|
|
[](const OpenTelemetryPluginBuilder::ChannelScope&
|
|
|
|
channel_scope) {
|
|
|
|
return absl::StartsWith(channel_scope.target(),
|
|
|
|
"dns:///");
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
|
|
|
grpc_core::experimental::StatsPluginChannelScope(
|
|
|
|
"dns:///localhost:8080", ""));
|
|
|
|
for (auto v : kCounterValues) {
|
|
|
|
stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
CounterResultEq(::testing::Eq(kCounterResult)))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleCounter) {
|
|
|
|
constexpr absl::string_view kMetricName = "double_counter";
|
|
|
|
constexpr double kCounterValues[] = {1.23, 2.34, 3.45};
|
|
|
|
constexpr double kCounterResult = 7.02;
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
|
|
|
|
"label_value_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2"};
|
|
|
|
auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleCounter(
|
|
|
|
kMetricName, "A simple double counter.", "unit", kLabelKeys,
|
|
|
|
kOptionalLabelKeys, /*enable_by_default=*/false);
|
|
|
|
Init(std::move(Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_channel_scope_filter(
|
|
|
|
[](const OpenTelemetryPluginBuilder::ChannelScope&
|
|
|
|
channel_scope) {
|
|
|
|
return absl::StartsWith(channel_scope.target(),
|
|
|
|
"dns:///");
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
|
|
|
grpc_core::experimental::StatsPluginChannelScope(
|
|
|
|
"dns:///localhost:8080", ""));
|
|
|
|
for (auto v : kCounterValues) {
|
|
|
|
stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
CounterResultEq(::testing::DoubleEq(kCounterResult)))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Histogram) {
|
|
|
|
constexpr absl::string_view kMetricName = "uint64_histogram";
|
|
|
|
constexpr int kHistogramValues[] = {1, 1, 2, 3, 4, 4, 5, 6};
|
|
|
|
constexpr int64_t kSum = 26;
|
|
|
|
constexpr int64_t kMin = 1;
|
|
|
|
constexpr int64_t kMax = 6;
|
|
|
|
constexpr int64_t kCount = 8;
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
|
|
|
|
"label_value_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2"};
|
|
|
|
auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Histogram(
|
|
|
|
kMetricName, "A simple uint64 histogram.", "unit", kLabelKeys,
|
|
|
|
kOptionalLabelKeys, /*enable_by_default=*/true);
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_server_selector([](const grpc_core::ChannelArgs& args) {
|
|
|
|
return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
|
|
|
|
GRPC_ARG_SERVER_SELECTOR_VALUE;
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
grpc_core::ChannelArgs args;
|
|
|
|
args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
|
|
|
|
for (auto v : kHistogramValues) {
|
|
|
|
stats_plugins.RecordHistogram(handle, v, kLabelValues,
|
|
|
|
kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
EXPECT_THAT(
|
|
|
|
data, ::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
HistogramResultEq(::testing::Eq(kSum), ::testing::Eq(kMin),
|
|
|
|
::testing::Eq(kMax), kCount))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleHistogram) {
|
|
|
|
constexpr absl::string_view kMetricName = "double_histogram";
|
|
|
|
constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
|
|
|
|
4.4, 4.5, 5.5, 6.6};
|
|
|
|
constexpr double kSum = 28.8;
|
|
|
|
constexpr double kMin = 1.1;
|
|
|
|
constexpr double kMax = 6.6;
|
|
|
|
constexpr double kCount = 8;
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
|
|
|
|
"label_value_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2"};
|
|
|
|
auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
|
|
|
kMetricName, "A simple double histogram.", "unit", kLabelKeys,
|
|
|
|
kOptionalLabelKeys, /*enable_by_default=*/true);
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_server_selector([](const grpc_core::ChannelArgs& args) {
|
|
|
|
return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
|
|
|
|
GRPC_ARG_SERVER_SELECTOR_VALUE;
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
grpc_core::ChannelArgs args;
|
|
|
|
args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
|
|
|
|
for (auto v : kHistogramValues) {
|
|
|
|
stats_plugins.RecordHistogram(handle, v, kLabelValues,
|
|
|
|
kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
HistogramResultEq(::testing::DoubleEq(kSum),
|
|
|
|
::testing::DoubleEq(kMin),
|
|
|
|
::testing::DoubleEq(kMax), kCount))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginNPCMetricsTest,
|
|
|
|
RegisterMultipleOpenTelemetryPlugins) {
|
|
|
|
constexpr absl::string_view kMetricName = "yet_another_double_histogram";
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
|
|
|
|
"label_value_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2"};
|
|
|
|
auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
|
|
|
kMetricName, "A simple double histogram.", "unit", kLabelKeys,
|
|
|
|
kOptionalLabelKeys, /*enable_by_default=*/true);
|
|
|
|
// Build and register a separate OpenTelemetryPlugin and verify its histogram
|
|
|
|
// recording.
|
|
|
|
grpc::internal::OpenTelemetryPluginBuilderImpl ot_builder;
|
|
|
|
auto reader = BuildAndRegisterOpenTelemetryPlugin(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_server_selector([](const grpc_core::ChannelArgs& args) {
|
|
|
|
return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
|
|
|
|
GRPC_ARG_SERVER_SELECTOR_VALUE;
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
EXPECT_EQ(ot_builder.BuildAndRegisterGlobal(), absl::OkStatus());
|
|
|
|
grpc_core::ChannelArgs args;
|
|
|
|
args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
|
|
|
|
{
|
|
|
|
constexpr double kHistogramValues[] = {1.23, 2.34, 3.45, 4.56};
|
|
|
|
constexpr double kSum = 11.58;
|
|
|
|
constexpr double kMin = 1.23;
|
|
|
|
constexpr double kMax = 4.56;
|
|
|
|
constexpr int kCount = 4;
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
|
|
|
|
for (auto v : kHistogramValues) {
|
|
|
|
stats_plugins.RecordHistogram(handle, v, kLabelValues,
|
|
|
|
kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); },
|
|
|
|
reader.get());
|
|
|
|
EXPECT_THAT(
|
|
|
|
data, ::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
HistogramResultEq(::testing::DoubleEq(kSum),
|
|
|
|
::testing::DoubleEq(kMin),
|
|
|
|
::testing::DoubleEq(kMax), kCount))))));
|
|
|
|
}
|
|
|
|
// Now build and register another OpenTelemetryPlugin using the test fixture
|
|
|
|
// and record histogram.
|
|
|
|
constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
|
|
|
|
4.4, 4.5, 5.5, 6.6};
|
|
|
|
constexpr double kSum = 28.8;
|
|
|
|
constexpr double kMin = 1.1;
|
|
|
|
constexpr double kMax = 6.6;
|
|
|
|
constexpr int kCount = 8;
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_server_selector([](const grpc_core::ChannelArgs& args) {
|
|
|
|
return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
|
|
|
|
GRPC_ARG_SERVER_SELECTOR_VALUE;
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
|
|
|
|
for (auto v : kHistogramValues) {
|
|
|
|
stats_plugins.RecordHistogram(handle, v, kLabelValues,
|
|
|
|
kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
HistogramResultEq(::testing::DoubleEq(kSum),
|
|
|
|
::testing::DoubleEq(kMin),
|
|
|
|
::testing::DoubleEq(kMax), kCount))))));
|
|
|
|
// Verify that the first plugin gets the data as well.
|
|
|
|
data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); },
|
|
|
|
reader.get());
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValues),
|
|
|
|
HistogramResultEq(::testing::DoubleEq(kSum),
|
|
|
|
::testing::DoubleEq(kMin),
|
|
|
|
::testing::DoubleEq(kMax), kCount))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(OpenTelemetryPluginNPCMetricsTest,
|
|
|
|
DisabledOptionalLabelKeysShouldNotBeRecorded) {
|
|
|
|
constexpr absl::string_view kMetricName =
|
|
|
|
"yet_another_yet_another_double_histogram";
|
|
|
|
constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
|
|
|
|
4.4, 4.5, 5.5, 6.6};
|
|
|
|
constexpr double kSum = 28.8;
|
|
|
|
constexpr double kMin = 1.1;
|
|
|
|
constexpr double kMax = 6.6;
|
|
|
|
constexpr double kCount = 8;
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 4> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2", "optional_label_key_3",
|
|
|
|
"optional_label_key_4"};
|
|
|
|
constexpr std::array<absl::string_view, 3> kActualOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2", "optional_label_key_4"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
|
|
|
|
"label_value_2"};
|
|
|
|
constexpr std::array<absl::string_view, 4> kOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2",
|
|
|
|
"optional_label_value_3", "optional_label_value_4"};
|
|
|
|
constexpr std::array<absl::string_view, 3> kActualOptionalLabelValues = {
|
|
|
|
"optional_label_value_1", "optional_label_value_2",
|
|
|
|
"optional_label_value_4"};
|
|
|
|
auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
|
|
|
kMetricName, "A simple double histogram.", "unit", kLabelKeys,
|
|
|
|
kOptionalLabelKeys, /*enable_by_default=*/true);
|
|
|
|
Init(std::move(
|
|
|
|
Options()
|
|
|
|
.set_metric_names({kMetricName})
|
|
|
|
.set_server_selector([](const grpc_core::ChannelArgs& args) {
|
|
|
|
return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
|
|
|
|
GRPC_ARG_SERVER_SELECTOR_VALUE;
|
|
|
|
})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[3])));
|
|
|
|
grpc_core::ChannelArgs args;
|
|
|
|
args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
|
|
|
|
for (auto v : kHistogramValues) {
|
|
|
|
stats_plugins.RecordHistogram(handle, v, kLabelValues,
|
|
|
|
kOptionalLabelValues);
|
|
|
|
}
|
|
|
|
auto data = ReadCurrentMetricsData(
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) { return !data.contains(kMetricName); });
|
|
|
|
EXPECT_THAT(
|
|
|
|
data,
|
|
|
|
::testing::ElementsAre(::testing::Pair(
|
|
|
|
kMetricName,
|
|
|
|
::testing::ElementsAre(::testing::AllOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValues, kActualOptionalLabelKeys,
|
|
|
|
kActualOptionalLabelValues),
|
|
|
|
HistogramResultEq(::testing::DoubleEq(kSum),
|
|
|
|
::testing::DoubleEq(kMin),
|
|
|
|
::testing::DoubleEq(kMax), kCount))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
using OpenTelemetryPluginCallbackMetricsTest = OpenTelemetryPluginEnd2EndTest;
|
|
|
|
|
|
|
|
// The callback minimal interval is longer than the OT reporting interval, so we
|
|
|
|
// expect to collect duplicated (cached) values.
|
|
|
|
TEST_F(OpenTelemetryPluginCallbackMetricsTest,
|
|
|
|
ReportDurationLongerThanCollectDuration) {
|
|
|
|
constexpr absl::string_view kInt64CallbackGaugeMetric =
|
|
|
|
"int64_callback_gauge";
|
|
|
|
constexpr absl::string_view kDoubleCallbackGaugeMetric =
|
|
|
|
"double_callback_gauge";
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
|
|
|
|
"label_value_set_1", "label_value_set_1"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
|
|
|
|
"optional_label_value_set_1", "optional_label_value_set_1"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
|
|
|
|
"label_value_set_2", "label_value_set_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
|
|
|
|
"optional_label_value_set_2", "optional_label_value_set_2"};
|
|
|
|
auto integer_gauge_handle =
|
|
|
|
grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
|
|
|
|
kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
|
|
|
|
kLabelKeys, kOptionalLabelKeys,
|
|
|
|
/*enable_by_default=*/true);
|
|
|
|
auto double_gauge_handle =
|
|
|
|
grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
|
|
|
|
kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
|
|
|
|
kLabelKeys, kOptionalLabelKeys,
|
|
|
|
/*enable_by_default=*/true);
|
|
|
|
Init(std::move(Options()
|
|
|
|
.set_metric_names({kInt64CallbackGaugeMetric,
|
|
|
|
kDoubleCallbackGaugeMetric})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
|
|
|
grpc_core::experimental::StatsPluginChannelScope(
|
|
|
|
"dns:///localhost:8080", ""));
|
|
|
|
// Multiple callbacks for the same metrics, each reporting different label
|
|
|
|
// values.
|
|
|
|
int report_count_1 = 0;
|
|
|
|
int64_t int_value_1 = 1;
|
|
|
|
double double_value_1 = 0.5;
|
|
|
|
auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
|
|
|
|
[&](grpc_core::CallbackMetricReporter& reporter) {
|
|
|
|
++report_count_1;
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_1, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_1, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
},
|
|
|
|
{integer_gauge_handle, double_gauge_handle},
|
|
|
|
grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor());
|
|
|
|
int report_count_2 = 0;
|
|
|
|
int64_t int_value_2 = 1;
|
|
|
|
double double_value_2 = 0.5;
|
|
|
|
auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
|
|
|
|
[&](grpc_core::CallbackMetricReporter& reporter) {
|
|
|
|
++report_count_2;
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_2, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_2, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
},
|
|
|
|
{integer_gauge_handle, double_gauge_handle},
|
|
|
|
grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor());
|
|
|
|
constexpr int kIterations = 100;
|
|
|
|
MetricsCollectorThread collector{
|
|
|
|
this, grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor(),
|
|
|
|
kIterations,
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains(kInt64CallbackGaugeMetric) ||
|
|
|
|
!data.contains(kDoubleCallbackGaugeMetric);
|
|
|
|
}};
|
|
|
|
absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
|
|
|
|
data = collector.Stop();
|
|
|
|
// Verify that data is incremental with duplications (cached values).
|
|
|
|
EXPECT_LT(report_count_1, kIterations);
|
|
|
|
EXPECT_LT(report_count_2, kIterations);
|
|
|
|
EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
|
|
|
|
data[kDoubleCallbackGaugeMetric].size());
|
|
|
|
// Verify labels.
|
|
|
|
ASSERT_THAT(
|
|
|
|
data,
|
|
|
|
::testing::UnorderedElementsAre(
|
|
|
|
::testing::Pair(
|
|
|
|
kInt64CallbackGaugeMetric,
|
|
|
|
::testing::Each(::testing::AnyOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet1),
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet2)))),
|
|
|
|
::testing::Pair(
|
|
|
|
kDoubleCallbackGaugeMetric,
|
|
|
|
::testing::Each(::testing::AnyOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet1),
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet2))))));
|
|
|
|
EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet1,
|
|
|
|
int64_t(0), false));
|
|
|
|
EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet2,
|
|
|
|
int64_t(0), false));
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, false));
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, false));
|
|
|
|
}
|
|
|
|
|
|
|
|
// The callback minimal interval is shorter than the OT reporting interval, so
|
|
|
|
// for each collect we should go update the cache and report the latest values.
|
|
|
|
TEST_F(OpenTelemetryPluginCallbackMetricsTest,
|
|
|
|
ReportDurationShorterThanCollectDuration) {
|
|
|
|
constexpr absl::string_view kInt64CallbackGaugeMetric =
|
|
|
|
"yet_another_int64_callback_gauge";
|
|
|
|
constexpr absl::string_view kDoubleCallbackGaugeMetric =
|
|
|
|
"yet_another_double_callback_gauge";
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
|
|
|
|
"label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
|
|
|
|
"optional_label_key_1", "optional_label_key_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
|
|
|
|
"label_value_set_1", "label_value_set_1"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
|
|
|
|
"optional_label_value_set_1", "optional_label_value_set_1"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
|
|
|
|
"label_value_set_2", "label_value_set_2"};
|
|
|
|
constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
|
|
|
|
"optional_label_value_set_2", "optional_label_value_set_2"};
|
|
|
|
auto integer_gauge_handle =
|
|
|
|
grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
|
|
|
|
kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
|
|
|
|
kLabelKeys, kOptionalLabelKeys,
|
|
|
|
/*enable_by_default=*/true);
|
|
|
|
auto double_gauge_handle =
|
|
|
|
grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
|
|
|
|
kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
|
|
|
|
kLabelKeys, kOptionalLabelKeys,
|
|
|
|
/*enable_by_default=*/true);
|
|
|
|
Init(std::move(Options()
|
|
|
|
.set_metric_names({kInt64CallbackGaugeMetric,
|
|
|
|
kDoubleCallbackGaugeMetric})
|
|
|
|
.add_optional_label(kOptionalLabelKeys[0])
|
|
|
|
.add_optional_label(kOptionalLabelKeys[1])));
|
|
|
|
auto stats_plugins =
|
|
|
|
grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
|
|
|
grpc_core::experimental::StatsPluginChannelScope(
|
|
|
|
"dns:///localhost:8080", ""));
|
|
|
|
// Multiple callbacks for the same metrics, each reporting different label
|
|
|
|
// values.
|
|
|
|
int report_count_1 = 0;
|
|
|
|
int64_t int_value_1 = 1;
|
|
|
|
double double_value_1 = 0.5;
|
|
|
|
auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
|
|
|
|
[&](grpc_core::CallbackMetricReporter& reporter) {
|
|
|
|
++report_count_1;
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_1, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_1, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
},
|
|
|
|
{integer_gauge_handle, double_gauge_handle},
|
|
|
|
grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor());
|
|
|
|
int report_count_2 = 0;
|
|
|
|
int64_t int_value_2 = 1;
|
|
|
|
double double_value_2 = 0.5;
|
|
|
|
auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
|
|
|
|
[&](grpc_core::CallbackMetricReporter& reporter) {
|
|
|
|
++report_count_2;
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_2, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_2, kLabelValuesSet1,
|
|
|
|
kOptionalLabelValuesSet1);
|
|
|
|
reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
|
|
|
|
kOptionalLabelValuesSet2);
|
|
|
|
},
|
|
|
|
{integer_gauge_handle, double_gauge_handle},
|
|
|
|
grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor());
|
|
|
|
constexpr int kIterations = 100;
|
|
|
|
MetricsCollectorThread collector{
|
|
|
|
this,
|
|
|
|
grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
|
|
|
|
kIterations,
|
|
|
|
[&](const absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
|
|
|
|
data) {
|
|
|
|
return !data.contains(kInt64CallbackGaugeMetric) ||
|
|
|
|
!data.contains(kDoubleCallbackGaugeMetric);
|
|
|
|
}};
|
|
|
|
absl::flat_hash_map<
|
|
|
|
std::string,
|
|
|
|
std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
|
|
|
|
data = collector.Stop();
|
|
|
|
// Verify that data is incremental without duplications (cached values).
|
|
|
|
EXPECT_EQ(report_count_1, kIterations);
|
|
|
|
EXPECT_EQ(report_count_2, kIterations);
|
|
|
|
EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
|
|
|
|
data[kDoubleCallbackGaugeMetric].size());
|
|
|
|
// Verify labels.
|
|
|
|
ASSERT_THAT(
|
|
|
|
data,
|
|
|
|
::testing::UnorderedElementsAre(
|
|
|
|
::testing::Pair(
|
|
|
|
kInt64CallbackGaugeMetric,
|
|
|
|
::testing::Each(::testing::AnyOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet1),
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet2)))),
|
|
|
|
::testing::Pair(
|
|
|
|
kDoubleCallbackGaugeMetric,
|
|
|
|
::testing::Each(::testing::AnyOf(
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet1),
|
|
|
|
AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
|
|
|
|
kOptionalLabelValuesSet2))))));
|
|
|
|
EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet1,
|
|
|
|
int64_t(0), true));
|
|
|
|
EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet2,
|
|
|
|
int64_t(0), true));
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, true));
|
|
|
|
EXPECT_THAT(data,
|
|
|
|
GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
|
|
|
|
kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
|
|
|
|
kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, true));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OpenTelemetryPluginMetricsEnablingDisablingTest, TestEnableDisableAPIs) {
|
|
|
|
grpc::internal::OpenTelemetryPluginBuilderImpl builder;
|
|
|
|
// First disable all metrics
|
|
|
|
builder.DisableAllMetrics();
|
|
|
|
EXPECT_TRUE(builder.TestOnlyEnabledMetrics().empty());
|
|
|
|
// Add in a few metrics
|
|
|
|
builder.EnableMetrics(
|
|
|
|
{"grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"});
|
|
|
|
EXPECT_THAT(
|
|
|
|
builder.TestOnlyEnabledMetrics(),
|
|
|
|
::testing::UnorderedElementsAre(
|
|
|
|
"grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"));
|
|
|
|
// Now remove a few metrics
|
|
|
|
builder.DisableMetrics({"grpc.test.metric_1", "grpc.test.metric_2"});
|
|
|
|
EXPECT_THAT(builder.TestOnlyEnabledMetrics(),
|
|
|
|
::testing::UnorderedElementsAre("grpc.test.metric_3"));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace testing
|
|
|
|
} // namespace grpc
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
grpc::testing::TestEnvironment env(&argc, argv);
|
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
return RUN_ALL_TESTS();
|
|
|
|
}
|