• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/cpp/ext/otel/otel_plugin.h"
20 
21 #include <grpcpp/ext/otel_plugin.h>
22 #include <grpcpp/grpcpp.h>
23 
24 #include <atomic>
25 #include <chrono>
26 #include <ratio>
27 #include <type_traits>
28 
29 #include "absl/functional/any_invocable.h"
30 #include "gmock/gmock.h"
31 #include "gtest/gtest.h"
32 #include "opentelemetry/common/timestamp.h"
33 #include "opentelemetry/metrics/provider.h"
34 #include "opentelemetry/nostd/variant.h"
35 #include "opentelemetry/sdk/common/attribute_utils.h"
36 #include "opentelemetry/sdk/metrics/data/metric_data.h"
37 #include "opentelemetry/sdk/metrics/data/point_data.h"
38 #include "opentelemetry/sdk/metrics/meter_provider.h"
39 #include "opentelemetry/sdk/metrics/metric_reader.h"
40 #include "src/core/config/core_configuration.h"
41 #include "src/core/lib/event_engine/channel_args_endpoint_config.h"
42 #include "src/core/telemetry/call_tracer.h"
43 #include "test/core/test_util/fake_stats_plugin.h"
44 #include "test/core/test_util/test_config.h"
45 #include "test/cpp/end2end/test_service_impl.h"
46 #include "test/cpp/ext/otel/otel_test_library.h"
47 
48 namespace grpc {
49 namespace testing {
50 namespace {
51 
52 #define GRPC_ARG_SERVER_SELECTOR_KEY "grpc.testing.server_selector_key"
53 #define GRPC_ARG_SERVER_SELECTOR_VALUE "grpc.testing.server_selector_value"
54 
55 template <typename T>
PopulateLabelMap(T label_keys,T label_values,std::unordered_map<std::string,opentelemetry::sdk::common::OwnedAttributeValue> * label_maps)56 void PopulateLabelMap(
57     T label_keys, T label_values,
58     std::unordered_map<std::string,
59                        opentelemetry::sdk::common::OwnedAttributeValue>*
60         label_maps) {
61   for (size_t i = 0; i < label_keys.size(); ++i) {
62     (*label_maps)[std::string(label_keys[i])] = std::string(label_values[i]);
63   }
64 }
65 
66 MATCHER_P4(AttributesEq, label_keys, label_values, optional_label_keys,
67            optional_label_values, "") {
68   std::unordered_map<std::string,
69                      opentelemetry::sdk::common::OwnedAttributeValue>
70       label_map;
71   PopulateLabelMap(label_keys, label_values, &label_map);
72   PopulateLabelMap(optional_label_keys, optional_label_values, &label_map);
73   return ::testing::ExplainMatchResult(
74       ::testing::UnorderedElementsAreArray(label_map),
75       arg.attributes.GetAttributes(), result_listener);
76 }
77 
78 template <typename T>
79 struct Extract;
80 
81 template <template <typename> class T, typename U>
82 struct Extract<const T<U>> {
83   using Type = U;
84 };
85 
86 MATCHER_P(CounterResultEq, value_matcher, "") {
87   return ::testing::ExplainMatchResult(
88       ::testing::VariantWith<opentelemetry::sdk::metrics::SumPointData>(
89           ::testing::Field(&opentelemetry::sdk::metrics::SumPointData::value_,
90                            ::testing::VariantWith<
91                                typename Extract<decltype(value_matcher)>::Type>(
92                                value_matcher))),
93       arg.point_data, result_listener);
94 }
95 
96 MATCHER_P4(HistogramResultEq, sum_matcher, min_matcher, max_matcher, count,
97            "") {
98   return ::testing::ExplainMatchResult(
99       ::testing::VariantWith<
100           opentelemetry::sdk::metrics::HistogramPointData>(::testing::AllOf(
101           ::testing::Field(
102               &opentelemetry::sdk::metrics::HistogramPointData::sum_,
103               ::testing::VariantWith<
104                   typename Extract<decltype(sum_matcher)>::Type>(sum_matcher)),
105           ::testing::Field(
106               &opentelemetry::sdk::metrics::HistogramPointData::min_,
107               ::testing::VariantWith<
108                   typename Extract<decltype(min_matcher)>::Type>(min_matcher)),
109           ::testing::Field(
110               &opentelemetry::sdk::metrics::HistogramPointData::max_,
111               ::testing::VariantWith<
112                   typename Extract<decltype(max_matcher)>::Type>(max_matcher)),
113           ::testing::Field(
114               &opentelemetry::sdk::metrics::HistogramPointData::count_,
115               ::testing::Eq(count)))),
116       arg.point_data, result_listener);
117 }
118 
119 MATCHER_P(GaugeResultIs, value_matcher, "") {
120   return ::testing::ExplainMatchResult(
121       ::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
122           ::testing::AllOf(
123               ::testing::Field(
124                   &opentelemetry::sdk::metrics::LastValuePointData::value_,
125                   ::testing::VariantWith<
126                       typename Extract<decltype(value_matcher)>::Type>(
127                       value_matcher)),
128               ::testing::Field(&opentelemetry::sdk::metrics::
129                                    LastValuePointData::is_lastvalue_valid_,
130                                ::testing::IsTrue()))),
131       arg.point_data, result_listener);
132 }
133 
134 // This check might subject to system clock adjustment.
135 MATCHER_P(GaugeResultLaterThan, prev_timestamp, "") {
136   return ::testing::ExplainMatchResult(
137       ::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
138           ::testing::Field(
139               &opentelemetry::sdk::metrics::LastValuePointData::sample_ts_,
140               ::testing::Property(
141                   &opentelemetry::common::SystemTimestamp::time_since_epoch,
142                   ::testing::Gt(prev_timestamp.time_since_epoch())))),
143       arg.point_data, result_listener);
144 }
145 
146 MATCHER_P7(GaugeDataIsIncrementalForSpecificMetricAndLabelSet, metric_name,
147            label_key, label_value, optional_label_key, optional_label_value,
148            default_value, greater_than, "") {
149   std::unordered_map<std::string,
150                      opentelemetry::sdk::common::OwnedAttributeValue>
151       label_map;
152   PopulateLabelMap(label_key, label_value, &label_map);
153   PopulateLabelMap(optional_label_key, optional_label_value, &label_map);
154   opentelemetry::common::SystemTimestamp prev_timestamp;
155   auto prev_value = default_value;
156   size_t prev_index = 0;
157   auto& data = arg.at(metric_name);
158   bool result = true;
159   for (size_t i = 1; i < data.size(); ++i) {
160     if (::testing::Matches(::testing::UnorderedElementsAreArray(
161             data[i - 1].attributes.GetAttributes()))(label_map)) {
162       // Update the previous value for the same associated label values.
163       prev_value = opentelemetry::nostd::get<decltype(prev_value)>(
164           opentelemetry::nostd::get<
165               opentelemetry::sdk::metrics::LastValuePointData>(
166               data[i - 1].point_data)
167               .value_);
168       prev_index = i - 1;
169       prev_timestamp = opentelemetry::nostd::get<
170                            opentelemetry::sdk::metrics::LastValuePointData>(
171                            data[i - 1].point_data)
172                            .sample_ts_;
173     }
174     if (!::testing::Matches(::testing::UnorderedElementsAreArray(
175             data[i].attributes.GetAttributes()))(label_map)) {
176       // Skip values that do not have the same associated label values.
177       continue;
178     }
179     *result_listener << " Comparing data[" << i << "] with data[" << prev_index
180                      << "] ";
181     if (greater_than) {
182       result &= ::testing::ExplainMatchResult(
183           ::testing::AllOf(
184               AttributesEq(label_key, label_value, optional_label_key,
185                            optional_label_value),
186               GaugeResultIs(::testing::Gt(prev_value)),
187               GaugeResultLaterThan(prev_timestamp)),
188           data[i], result_listener);
189     } else {
190       result &= ::testing::ExplainMatchResult(
191           ::testing::AllOf(
192               AttributesEq(label_key, label_value, optional_label_key,
193                            optional_label_value),
194               GaugeResultIs(::testing::Ge(prev_value)),
195               GaugeResultLaterThan(prev_timestamp)),
196           data[i], result_listener);
197     }
198   }
199   return result;
200 }
201 
TEST(OpenTelemetryPluginBuildTest,ApiDependency)202 TEST(OpenTelemetryPluginBuildTest, ApiDependency) {
203   opentelemetry::metrics::Provider::GetMeterProvider();
204 }
205 
TEST(OpenTelemetryPluginBuildTest,SdkDependency)206 TEST(OpenTelemetryPluginBuildTest, SdkDependency) {
207   opentelemetry::sdk::metrics::MeterProvider();
208 }
209 
TEST(OpenTelemetryPluginBuildTest,Basic)210 TEST(OpenTelemetryPluginBuildTest, Basic) {
211   grpc::OpenTelemetryPluginBuilder builder;
212 }
213 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptStarted)214 TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptStarted) {
215   Init(std::move(
216       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
217                                       kClientAttemptStartedInstrumentName})));
218   SendRPC();
219   const char* kMetricName = "grpc.client.attempt.started";
220   auto data = ReadCurrentMetricsData(
221       [&](const absl::flat_hash_map<
222           std::string,
223           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
224               data) { return !data.contains(kMetricName); });
225   ASSERT_EQ(data[kMetricName].size(), 1);
226   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
227       &data[kMetricName][0].point_data);
228   ASSERT_NE(point_data, nullptr);
229   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
230   ASSERT_NE(client_started_value, nullptr);
231   EXPECT_EQ(*client_started_value, 1);
232   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
233   EXPECT_EQ(attributes.size(), 2);
234   const auto* method_value =
235       absl::get_if<std::string>(&attributes.at("grpc.method"));
236   ASSERT_NE(method_value, nullptr);
237   EXPECT_EQ(*method_value, kMethodName);
238   const auto* target_value =
239       absl::get_if<std::string>(&attributes.at("grpc.target"));
240   ASSERT_NE(target_value, nullptr);
241   EXPECT_EQ(*target_value, canonical_server_address_);
242 }
243 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptDuration)244 TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptDuration) {
245   Init(std::move(
246       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
247                                       kClientAttemptDurationInstrumentName})));
248   SendRPC();
249   const char* kMetricName = "grpc.client.attempt.duration";
250   auto data = ReadCurrentMetricsData(
251       [&](const absl::flat_hash_map<
252           std::string,
253           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
254               data) { return !data.contains(kMetricName); });
255   ASSERT_EQ(data[kMetricName].size(), 1);
256   auto point_data =
257       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
258           &data[kMetricName][0].point_data);
259   ASSERT_NE(point_data, nullptr);
260   ASSERT_EQ(point_data->count_, 1);
261   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
262   EXPECT_EQ(attributes.size(), 3);
263   const auto* method_value =
264       absl::get_if<std::string>(&attributes.at("grpc.method"));
265   ASSERT_NE(method_value, nullptr);
266   EXPECT_EQ(*method_value, kMethodName);
267   const auto* target_value =
268       absl::get_if<std::string>(&attributes.at("grpc.target"));
269   ASSERT_NE(target_value, nullptr);
270   EXPECT_EQ(*target_value, canonical_server_address_);
271   const auto* status_value =
272       absl::get_if<std::string>(&attributes.at("grpc.status"));
273   ASSERT_NE(status_value, nullptr);
274   EXPECT_EQ(*status_value, "OK");
275 }
276 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptSentTotalCompressedMessageSize)277 TEST_F(OpenTelemetryPluginEnd2EndTest,
278        ClientAttemptSentTotalCompressedMessageSize) {
279   Init(std::move(Options().set_metric_names(
280       {grpc::OpenTelemetryPluginBuilder::
281            kClientAttemptSentTotalCompressedMessageSizeInstrumentName})));
282   SendRPC();
283   const char* kMetricName =
284       "grpc.client.attempt.sent_total_compressed_message_size";
285   auto data = ReadCurrentMetricsData(
286       [&](const absl::flat_hash_map<
287           std::string,
288           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
289               data) { return !data.contains(kMetricName); });
290   ASSERT_EQ(data[kMetricName].size(), 1);
291   auto point_data =
292       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
293           &data[kMetricName][0].point_data);
294   ASSERT_NE(point_data, nullptr);
295   ASSERT_EQ(point_data->count_, 1);
296   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
297   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
298   EXPECT_EQ(attributes.size(), 3);
299   const auto* method_value =
300       absl::get_if<std::string>(&attributes.at("grpc.method"));
301   ASSERT_NE(method_value, nullptr);
302   EXPECT_EQ(*method_value, kMethodName);
303   const auto* target_value =
304       absl::get_if<std::string>(&attributes.at("grpc.target"));
305   ASSERT_NE(target_value, nullptr);
306   EXPECT_EQ(*target_value, canonical_server_address_);
307   const auto* status_value =
308       absl::get_if<std::string>(&attributes.at("grpc.status"));
309   ASSERT_NE(status_value, nullptr);
310   EXPECT_EQ(*status_value, "OK");
311 }
312 
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptRcvdTotalCompressedMessageSize)313 TEST_F(OpenTelemetryPluginEnd2EndTest,
314        ClientAttemptRcvdTotalCompressedMessageSize) {
315   Init(std::move(Options().set_metric_names(
316       {grpc::OpenTelemetryPluginBuilder::
317            kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName})));
318   SendRPC();
319   const char* kMetricName =
320       "grpc.client.attempt.rcvd_total_compressed_message_size";
321   auto data = ReadCurrentMetricsData(
322       [&](const absl::flat_hash_map<
323           std::string,
324           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
325               data) { return !data.contains(kMetricName); });
326   ASSERT_EQ(data[kMetricName].size(), 1);
327   auto point_data =
328       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
329           &data[kMetricName][0].point_data);
330   ASSERT_NE(point_data, nullptr);
331   ASSERT_EQ(point_data->count_, 1);
332   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
333   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
334   EXPECT_EQ(attributes.size(), 3);
335   const auto* method_value =
336       absl::get_if<std::string>(&attributes.at("grpc.method"));
337   ASSERT_NE(method_value, nullptr);
338   EXPECT_EQ(*method_value, kMethodName);
339   const auto* target_value =
340       absl::get_if<std::string>(&attributes.at("grpc.target"));
341   ASSERT_NE(target_value, nullptr);
342   EXPECT_EQ(*target_value, canonical_server_address_);
343   const auto* status_value =
344       absl::get_if<std::string>(&attributes.at("grpc.status"));
345   ASSERT_NE(status_value, nullptr);
346   EXPECT_EQ(*status_value, "OK");
347 }
348 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallStarted)349 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallStarted) {
350   Init(std::move(Options().set_metric_names(
351       {grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName})));
352   SendRPC();
353   const char* kMetricName = "grpc.server.call.started";
354   auto data = ReadCurrentMetricsData(
355       [&](const absl::flat_hash_map<
356           std::string,
357           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
358               data) { return !data.contains(kMetricName); });
359   ASSERT_EQ(data[kMetricName].size(), 1);
360   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
361       &data[kMetricName][0].point_data);
362   ASSERT_NE(point_data, nullptr);
363   auto server_started_value = absl::get_if<int64_t>(&point_data->value_);
364   ASSERT_NE(server_started_value, nullptr);
365   ASSERT_EQ(*server_started_value, 1);
366   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
367   EXPECT_EQ(attributes.size(), 1);
368   const auto* method_value =
369       absl::get_if<std::string>(&attributes.at("grpc.method"));
370   ASSERT_NE(method_value, nullptr);
371   EXPECT_EQ(*method_value, kMethodName);
372 }
373 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallDuration)374 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallDuration) {
375   Init(std::move(Options().set_metric_names(
376       {grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
377   SendRPC();
378   const char* kMetricName = "grpc.server.call.duration";
379   auto data = ReadCurrentMetricsData(
380       [&](const absl::flat_hash_map<
381           std::string,
382           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
383               data) { return !data.contains(kMetricName); });
384   ASSERT_EQ(data[kMetricName].size(), 1);
385   auto point_data =
386       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
387           &data[kMetricName][0].point_data);
388   ASSERT_NE(point_data, nullptr);
389   ASSERT_EQ(point_data->count_, 1);
390   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
391   EXPECT_EQ(attributes.size(), 2);
392   const auto* method_value =
393       absl::get_if<std::string>(&attributes.at("grpc.method"));
394   ASSERT_NE(method_value, nullptr);
395   EXPECT_EQ(*method_value, kMethodName);
396   const auto* status_value =
397       absl::get_if<std::string>(&attributes.at("grpc.status"));
398   ASSERT_NE(status_value, nullptr);
399   EXPECT_EQ(*status_value, "OK");
400 }
401 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallSentTotalCompressedMessageSize)402 TEST_F(OpenTelemetryPluginEnd2EndTest,
403        ServerCallSentTotalCompressedMessageSize) {
404   Init(std::move(Options().set_metric_names(
405       {grpc::OpenTelemetryPluginBuilder::
406            kServerCallSentTotalCompressedMessageSizeInstrumentName})));
407   SendRPC();
408   const char* kMetricName =
409       "grpc.server.call.sent_total_compressed_message_size";
410   auto data = ReadCurrentMetricsData(
411       [&](const absl::flat_hash_map<
412           std::string,
413           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
414               data) { return !data.contains(kMetricName); });
415   ASSERT_EQ(data[kMetricName].size(), 1);
416   auto point_data =
417       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
418           &data[kMetricName][0].point_data);
419   ASSERT_NE(point_data, nullptr);
420   EXPECT_EQ(point_data->count_, 1);
421   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
422   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
423   EXPECT_EQ(attributes.size(), 2);
424   const auto* method_value =
425       absl::get_if<std::string>(&attributes.at("grpc.method"));
426   ASSERT_NE(method_value, nullptr);
427   EXPECT_EQ(*method_value, kMethodName);
428   const auto* status_value =
429       absl::get_if<std::string>(&attributes.at("grpc.status"));
430   ASSERT_NE(status_value, nullptr);
431   EXPECT_EQ(*status_value, "OK");
432 }
433 
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallRcvdTotalCompressedMessageSize)434 TEST_F(OpenTelemetryPluginEnd2EndTest,
435        ServerCallRcvdTotalCompressedMessageSize) {
436   Init(std::move(Options().set_metric_names(
437       {grpc::OpenTelemetryPluginBuilder::
438            kServerCallRcvdTotalCompressedMessageSizeInstrumentName})));
439   SendRPC();
440   const char* kMetricName =
441       "grpc.server.call.rcvd_total_compressed_message_size";
442   auto data = ReadCurrentMetricsData(
443       [&](const absl::flat_hash_map<
444           std::string,
445           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
446               data) { return !data.contains(kMetricName); });
447   ASSERT_EQ(data[kMetricName].size(), 1);
448   auto point_data =
449       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
450           &data[kMetricName][0].point_data);
451   ASSERT_NE(point_data, nullptr);
452   ASSERT_EQ(point_data->count_, 1);
453   ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
454   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
455   EXPECT_EQ(attributes.size(), 2);
456   const auto* method_value =
457       absl::get_if<std::string>(&attributes.at("grpc.method"));
458   ASSERT_NE(method_value, nullptr);
459   EXPECT_EQ(*method_value, kMethodName);
460   const auto* status_value =
461       absl::get_if<std::string>(&attributes.at("grpc.status"));
462   ASSERT_NE(status_value, nullptr);
463   EXPECT_EQ(*status_value, "OK");
464 }
465 
466 // Make sure that no meter provider results in normal operations.
TEST_F(OpenTelemetryPluginEnd2EndTest,NoMeterProviderRegistered)467 TEST_F(OpenTelemetryPluginEnd2EndTest, NoMeterProviderRegistered) {
468   Init(
469       std::move(Options()
470                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
471                                            kClientAttemptStartedInstrumentName})
472                     .set_use_meter_provider(false)));
473   SendRPC();
474 }
475 
476 // Test that the otel plugin sees the expected channel target and default
477 // authority.
TEST_F(OpenTelemetryPluginEnd2EndTest,VerifyChannelScopeTargetAndAuthority)478 TEST_F(OpenTelemetryPluginEnd2EndTest, VerifyChannelScopeTargetAndAuthority) {
479   Init(std::move(
480       Options()
481           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
482                                  kClientAttemptStartedInstrumentName})
483           .set_channel_scope_filter(
484               [&](const OpenTelemetryPluginBuilder::ChannelScope& scope) {
485                 return scope.target() == canonical_server_address_ &&
486                        scope.default_authority() == server_address_;
487               })));
488   SendRPC();
489   const char* kMetricName = "grpc.client.attempt.started";
490   auto data = ReadCurrentMetricsData(
491       [&](const absl::flat_hash_map<
492           std::string,
493           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
494               data) { return !data.contains(kMetricName); });
495   ASSERT_EQ(data[kMetricName].size(), 1);
496 }
497 
498 // Test that a channel scope filter returning true records metrics on the
499 // channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,ChannelScopeFilterReturnsTrue)500 TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsTrue) {
501   Init(std::move(
502       Options()
503           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
504                                  kClientAttemptStartedInstrumentName})
505           .set_channel_scope_filter(
506               [](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
507                 return true;
508               })));
509   SendRPC();
510   const char* kMetricName = "grpc.client.attempt.started";
511   auto data = ReadCurrentMetricsData(
512       [&](const absl::flat_hash_map<
513           std::string,
514           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
515               data) { return !data.contains(kMetricName); });
516   ASSERT_EQ(data[kMetricName].size(), 1);
517   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
518       &data[kMetricName][0].point_data);
519   ASSERT_NE(point_data, nullptr);
520   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
521   ASSERT_NE(client_started_value, nullptr);
522   EXPECT_EQ(*client_started_value, 1);
523   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
524   EXPECT_EQ(attributes.size(), 2);
525   const auto* method_value =
526       absl::get_if<std::string>(&attributes.at("grpc.method"));
527   ASSERT_NE(method_value, nullptr);
528   EXPECT_EQ(*method_value, kMethodName);
529   const auto* target_value =
530       absl::get_if<std::string>(&attributes.at("grpc.target"));
531   ASSERT_NE(target_value, nullptr);
532   EXPECT_EQ(*target_value, canonical_server_address_);
533 }
534 
535 // Test that a channel scope filter returning false does not record metrics on
536 // the channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,ChannelScopeFilterReturnsFalse)537 TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsFalse) {
538   Init(std::move(
539       Options()
540           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
541                                  kClientAttemptStartedInstrumentName})
542           .set_channel_scope_filter(
543               [](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
544                 return false;
545               })));
546   SendRPC();
547   auto data = ReadCurrentMetricsData(
548       [&](const absl::flat_hash_map<
549           std::string,
550           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
551           /*data*/) { return false; });
552   ASSERT_TRUE(data.empty());
553 }
554 
555 // Test that a server selector returning true records metrics on the server.
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerSelectorReturnsTrue)556 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsTrue) {
557   Init(std::move(Options()
558                      .set_metric_names({grpc::OpenTelemetryPluginBuilder::
559                                             kServerCallDurationInstrumentName})
560                      .set_server_selector(
561                          [](const grpc_core::ChannelArgs& /*channel_args*/) {
562                            return true;
563                          })));
564   SendRPC();
565   const char* kMetricName = "grpc.server.call.duration";
566   auto data = ReadCurrentMetricsData(
567       [&](const absl::flat_hash_map<
568           std::string,
569           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
570               data) { return !data.contains(kMetricName); });
571   ASSERT_EQ(data[kMetricName].size(), 1);
572   const auto& server_attributes =
573       data[kMetricName][0].attributes.GetAttributes();
574   EXPECT_EQ(server_attributes.size(), 2);
575   EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.method")),
576             kMethodName);
577   EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.status")), "OK");
578 }
579 
580 // Test that a server selector returning false does not record metrics on the
581 // server.
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerSelectorReturnsFalse)582 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsFalse) {
583   Init(std::move(Options()
584                      .set_metric_names({grpc::OpenTelemetryPluginBuilder::
585                                             kServerCallDurationInstrumentName})
586                      .set_server_selector(
587                          [](const grpc_core::ChannelArgs& /*channel_args*/) {
588                            return false;
589                          })));
590   SendRPC();
591   auto data = ReadCurrentMetricsData(
592       [&](const absl::flat_hash_map<
593           std::string,
594           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
595           /*data*/) { return false; });
596   ASSERT_TRUE(data.empty());
597 }
598 
599 // Test that a target attribute filter returning true records metrics with the
600 // target as is on the channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,TargetAttributeFilterReturnsTrue)601 TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsTrue) {
602   Init(
603       std::move(Options()
604                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
605                                            kClientAttemptStartedInstrumentName})
606                     .set_target_attribute_filter(
607                         [](absl::string_view /*target*/) { return true; })));
608   SendRPC();
609   const char* kMetricName = "grpc.client.attempt.started";
610   auto data = ReadCurrentMetricsData(
611       [&](const absl::flat_hash_map<
612           std::string,
613           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
614               data) { return !data.contains(kMetricName); });
615   ASSERT_EQ(data[kMetricName].size(), 1);
616   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
617       &data[kMetricName][0].point_data);
618   ASSERT_NE(point_data, nullptr);
619   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
620   ASSERT_NE(client_started_value, nullptr);
621   EXPECT_EQ(*client_started_value, 1);
622   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
623   EXPECT_EQ(attributes.size(), 2);
624   const auto* method_value =
625       absl::get_if<std::string>(&attributes.at("grpc.method"));
626   ASSERT_NE(method_value, nullptr);
627   EXPECT_EQ(*method_value, kMethodName);
628   const auto* target_value =
629       absl::get_if<std::string>(&attributes.at("grpc.target"));
630   ASSERT_NE(target_value, nullptr);
631   EXPECT_EQ(*target_value, canonical_server_address_);
632 }
633 
634 // Test that a target attribute filter returning false records metrics with the
635 // target as "other".
TEST_F(OpenTelemetryPluginEnd2EndTest,TargetAttributeFilterReturnsFalse)636 TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsFalse) {
637   Init(
638       std::move(Options()
639                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
640                                            kClientAttemptStartedInstrumentName})
641                     .set_target_attribute_filter(
642                         [](absl::string_view /*target*/) { return false; })));
643   SendRPC();
644   const char* kMetricName = "grpc.client.attempt.started";
645   auto data = ReadCurrentMetricsData(
646       [&](const absl::flat_hash_map<
647           std::string,
648           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
649           /*data*/) { return false; });
650   ASSERT_EQ(data[kMetricName].size(), 1);
651   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
652       &data[kMetricName][0].point_data);
653   ASSERT_NE(point_data, nullptr);
654   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
655   ASSERT_NE(client_started_value, nullptr);
656   EXPECT_EQ(*client_started_value, 1);
657   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
658   EXPECT_EQ(attributes.size(), 2);
659   const auto* method_value =
660       absl::get_if<std::string>(&attributes.at("grpc.method"));
661   ASSERT_NE(method_value, nullptr);
662   EXPECT_EQ(*method_value, kMethodName);
663   const auto* target_value =
664       absl::get_if<std::string>(&attributes.at("grpc.target"));
665   ASSERT_NE(target_value, nullptr);
666   EXPECT_EQ(*target_value, "other");
667 }
668 
669 // Test that generic method names are scrubbed properly on the client side.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpc)670 TEST_F(OpenTelemetryPluginEnd2EndTest, GenericClientRpc) {
671   Init(std::move(
672       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
673                                       kClientAttemptStartedInstrumentName})));
674   SendGenericRPC();
675   const char* kMetricName = "grpc.client.attempt.started";
676   auto data = ReadCurrentMetricsData(
677       [&](const absl::flat_hash_map<
678           std::string,
679           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
680           /*data*/) { return false; });
681   ASSERT_EQ(data[kMetricName].size(), 1);
682   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
683       &data[kMetricName][0].point_data);
684   ASSERT_NE(point_data, nullptr);
685   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
686   ASSERT_NE(client_started_value, nullptr);
687   EXPECT_EQ(*client_started_value, 1);
688   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
689   EXPECT_EQ(attributes.size(), 2);
690   const auto* method_value =
691       absl::get_if<std::string>(&attributes.at("grpc.method"));
692   ASSERT_NE(method_value, nullptr);
693   EXPECT_EQ(*method_value, "other");
694   const auto* target_value =
695       absl::get_if<std::string>(&attributes.at("grpc.target"));
696   ASSERT_NE(target_value, nullptr);
697   EXPECT_EQ(*target_value, canonical_server_address_);
698 }
699 
700 // Test that generic method names are scrubbed properly on the client side if
701 // the method attribute filter is set and it returns false.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpcWithMethodAttributeFilterReturningFalse)702 TEST_F(OpenTelemetryPluginEnd2EndTest,
703        GenericClientRpcWithMethodAttributeFilterReturningFalse) {
704   Init(std::move(
705       Options()
706           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
707                                  kClientAttemptStartedInstrumentName})
708           .set_generic_method_attribute_filter(
709               [](absl::string_view /*generic_method*/) { return false; })));
710   SendGenericRPC();
711   const char* kMetricName = "grpc.client.attempt.started";
712   auto data = ReadCurrentMetricsData(
713       [&](const absl::flat_hash_map<
714           std::string,
715           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
716           /*data*/) { return false; });
717   ASSERT_EQ(data[kMetricName].size(), 1);
718   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
719       &data[kMetricName][0].point_data);
720   ASSERT_NE(point_data, nullptr);
721   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
722   ASSERT_NE(client_started_value, nullptr);
723   EXPECT_EQ(*client_started_value, 1);
724   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
725   EXPECT_EQ(attributes.size(), 2);
726   const auto* method_value =
727       absl::get_if<std::string>(&attributes.at("grpc.method"));
728   ASSERT_NE(method_value, nullptr);
729   EXPECT_EQ(*method_value, "other");
730   const auto* target_value =
731       absl::get_if<std::string>(&attributes.at("grpc.target"));
732   ASSERT_NE(target_value, nullptr);
733   EXPECT_EQ(*target_value, canonical_server_address_);
734 }
735 
736 // Test that generic method names is not scrubbed on the client side if
737 // the method attribute filter is set and it returns true.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpcWithMethodAttributeFilterReturningTrue)738 TEST_F(OpenTelemetryPluginEnd2EndTest,
739        GenericClientRpcWithMethodAttributeFilterReturningTrue) {
740   Init(std::move(
741       Options()
742           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
743                                  kClientAttemptStartedInstrumentName})
744           .set_generic_method_attribute_filter(
745               [](absl::string_view /*generic_method*/) { return true; })));
746   SendGenericRPC();
747   const char* kMetricName = "grpc.client.attempt.started";
748   auto data = ReadCurrentMetricsData(
749       [&](const absl::flat_hash_map<
750           std::string,
751           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
752           /*data*/) { return false; });
753   ASSERT_EQ(data[kMetricName].size(), 1);
754   auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
755       &data[kMetricName][0].point_data);
756   ASSERT_NE(point_data, nullptr);
757   auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
758   ASSERT_NE(client_started_value, nullptr);
759   EXPECT_EQ(*client_started_value, 1);
760   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
761   EXPECT_EQ(attributes.size(), 2);
762   const auto* method_value =
763       absl::get_if<std::string>(&attributes.at("grpc.method"));
764   ASSERT_NE(method_value, nullptr);
765   EXPECT_EQ(*method_value, kGenericMethodName);
766   const auto* target_value =
767       absl::get_if<std::string>(&attributes.at("grpc.target"));
768   ASSERT_NE(target_value, nullptr);
769   EXPECT_EQ(*target_value, canonical_server_address_);
770 }
771 
772 // Test that generic method names are scrubbed properly on the server side.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpc)773 TEST_F(OpenTelemetryPluginEnd2EndTest, GenericServerRpc) {
774   Init(std::move(Options().set_metric_names(
775       {grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
776   SendGenericRPC();
777   const char* kMetricName = "grpc.server.call.duration";
778   auto data = ReadCurrentMetricsData(
779       [&](const absl::flat_hash_map<
780           std::string,
781           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
782               data) { return !data.contains(kMetricName); });
783   ASSERT_EQ(data[kMetricName].size(), 1);
784   auto point_data =
785       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
786           &data[kMetricName][0].point_data);
787   ASSERT_NE(point_data, nullptr);
788   ASSERT_EQ(point_data->count_, 1);
789   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
790   EXPECT_EQ(attributes.size(), 2);
791   const auto* method_value =
792       absl::get_if<std::string>(&attributes.at("grpc.method"));
793   ASSERT_NE(method_value, nullptr);
794   EXPECT_EQ(*method_value, "other");
795   const auto* status_value =
796       absl::get_if<std::string>(&attributes.at("grpc.status"));
797   ASSERT_NE(status_value, nullptr);
798   EXPECT_EQ(*status_value, "UNIMPLEMENTED");
799 }
800 
801 // Test that generic method names are scrubbed properly on the server side if
802 // the method attribute filter is set and it returns false.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpcWithMethodAttributeFilterReturningFalse)803 TEST_F(OpenTelemetryPluginEnd2EndTest,
804        GenericServerRpcWithMethodAttributeFilterReturningFalse) {
805   Init(std::move(
806       Options()
807           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
808                                  kServerCallDurationInstrumentName})
809           .set_generic_method_attribute_filter(
810               [](absl::string_view /*generic_method*/) { return false; })));
811   SendGenericRPC();
812   const char* kMetricName = "grpc.server.call.duration";
813   auto data = ReadCurrentMetricsData(
814       [&](const absl::flat_hash_map<
815           std::string,
816           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
817               data) { return !data.contains(kMetricName); });
818   ASSERT_EQ(data[kMetricName].size(), 1);
819   auto point_data =
820       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
821           &data[kMetricName][0].point_data);
822   ASSERT_NE(point_data, nullptr);
823   ASSERT_EQ(point_data->count_, 1);
824   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
825   EXPECT_EQ(attributes.size(), 2);
826   const auto* method_value =
827       absl::get_if<std::string>(&attributes.at("grpc.method"));
828   ASSERT_NE(method_value, nullptr);
829   EXPECT_EQ(*method_value, "other");
830   const auto* status_value =
831       absl::get_if<std::string>(&attributes.at("grpc.status"));
832   ASSERT_NE(status_value, nullptr);
833   EXPECT_EQ(*status_value, "UNIMPLEMENTED");
834 }
835 
836 // Test that generic method names are not scrubbed on the server side if
837 // the method attribute filter is set and it returns true.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpcWithMethodAttributeFilterReturningTrue)838 TEST_F(OpenTelemetryPluginEnd2EndTest,
839        GenericServerRpcWithMethodAttributeFilterReturningTrue) {
840   Init(std::move(
841       Options()
842           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
843                                  kServerCallDurationInstrumentName})
844           .set_generic_method_attribute_filter(
845               [](absl::string_view /*generic_method*/) { return true; })));
846   SendGenericRPC();
847   const char* kMetricName = "grpc.server.call.duration";
848   auto data = ReadCurrentMetricsData(
849       [&](const absl::flat_hash_map<
850           std::string,
851           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
852               data) { return !data.contains(kMetricName); });
853   ASSERT_EQ(data[kMetricName].size(), 1);
854   auto point_data =
855       absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
856           &data[kMetricName][0].point_data);
857   ASSERT_NE(point_data, nullptr);
858   ASSERT_EQ(point_data->count_, 1);
859   const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
860   EXPECT_EQ(attributes.size(), 2);
861   const auto* method_value =
862       absl::get_if<std::string>(&attributes.at("grpc.method"));
863   ASSERT_NE(method_value, nullptr);
864   EXPECT_EQ(*method_value, kGenericMethodName);
865   const auto* status_value =
866       absl::get_if<std::string>(&attributes.at("grpc.status"));
867   ASSERT_NE(status_value, nullptr);
868   EXPECT_EQ(*status_value, "UNIMPLEMENTED");
869 }
870 
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabel)871 TEST_F(OpenTelemetryPluginEnd2EndTest, OptionalPerCallLocalityLabel) {
872   Init(
873       std::move(Options()
874                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
875                                            kClientAttemptStartedInstrumentName,
876                                        grpc::OpenTelemetryPluginBuilder::
877                                            kClientAttemptDurationInstrumentName,
878                                        grpc::OpenTelemetryPluginBuilder::
879                                            kServerCallStartedInstrumentName,
880                                        grpc::OpenTelemetryPluginBuilder::
881                                            kServerCallDurationInstrumentName})
882                     .add_optional_label("grpc.lb.locality")
883                     .set_labels_to_inject(
884                         {{grpc_core::ClientCallTracer::CallAttemptTracer::
885                               OptionalLabelKey::kLocality,
886                           grpc_core::RefCountedStringValue("locality")}})));
887   SendRPC();
888   auto data = ReadCurrentMetricsData(
889       [&](const absl::flat_hash_map<
890           std::string,
891           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
892               data) {
893         return !data.contains("grpc.client.attempt.started") ||
894                !data.contains("grpc.client.attempt.duration") ||
895                !data.contains("grpc.server.call.started") ||
896                !data.contains("grpc.server.call.duration");
897       });
898   // Verify client side metric (grpc.client.attempt.started) does not sees this
899   // label
900   ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
901   const auto& client_attributes =
902       data["grpc.client.attempt.started"][0].attributes.GetAttributes();
903   EXPECT_THAT(
904       client_attributes,
905       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
906   // Verify client side metric (grpc.client.attempt.duration) sees this label.
907   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
908   const auto& client_duration_attributes =
909       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
910   EXPECT_EQ(
911       absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
912       "locality");
913   // Verify server metric (grpc.server.call.started) does not see this label
914   ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
915   const auto& server_attributes =
916       data["grpc.server.call.started"][0].attributes.GetAttributes();
917   EXPECT_THAT(
918       server_attributes,
919       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
920   // Verify server metric (grpc.server.call.duration) does not see this label
921   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
922   const auto& server_duration_attributes =
923       data["grpc.server.call.duration"][0].attributes.GetAttributes();
924   EXPECT_THAT(
925       server_duration_attributes,
926       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
927 }
928 
929 // Tests that when locality label is enabled on the plugin but not provided by
930 // gRPC, an empty value is recorded.
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabelWhenNotAvailable)931 TEST_F(OpenTelemetryPluginEnd2EndTest,
932        OptionalPerCallLocalityLabelWhenNotAvailable) {
933   Init(std::move(
934       Options()
935           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
936                                  kClientAttemptDurationInstrumentName})
937           .add_optional_label("grpc.lb.locality")));
938   SendRPC();
939   auto data = ReadCurrentMetricsData(
940       [&](const absl::flat_hash_map<
941           std::string,
942           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
943               data) { return !data.contains("grpc.client.attempt.duration"); });
944   // Verify client side metric (grpc.client.attempt.duration) sees the empty
945   // label value.
946   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
947   const auto& client_duration_attributes =
948       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
949   EXPECT_EQ(
950       absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
951       "");
952 }
953 
954 // Tests that when locality label is injected but not enabled by the plugin, the
955 // label is not recorded.
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled)956 TEST_F(OpenTelemetryPluginEnd2EndTest,
957        OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled) {
958   Init(std::move(
959       Options()
960           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
961                                  kClientAttemptDurationInstrumentName})
962           .set_labels_to_inject(
963               {{grpc_core::ClientCallTracer::CallAttemptTracer::
964                     OptionalLabelKey::kLocality,
965                 grpc_core::RefCountedStringValue("locality")}})));
966   SendRPC();
967   auto data = ReadCurrentMetricsData(
968       [&](const absl::flat_hash_map<
969           std::string,
970           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
971               data) { return !data.contains("grpc.client.attempt.duration"); });
972   // Verify client side metric (grpc.client.attempt.duration) does not see the
973   // locality label.
974   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
975   const auto& client_duration_attributes =
976       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
977   EXPECT_THAT(
978       client_duration_attributes,
979       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
980 }
981 
TEST_F(OpenTelemetryPluginEnd2EndTest,UnknownLabelDoesNotShowOnPerCallMetrics)982 TEST_F(OpenTelemetryPluginEnd2EndTest,
983        UnknownLabelDoesNotShowOnPerCallMetrics) {
984   Init(
985       std::move(Options()
986                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
987                                            kClientAttemptStartedInstrumentName,
988                                        grpc::OpenTelemetryPluginBuilder::
989                                            kClientAttemptDurationInstrumentName,
990                                        grpc::OpenTelemetryPluginBuilder::
991                                            kServerCallStartedInstrumentName,
992                                        grpc::OpenTelemetryPluginBuilder::
993                                            kServerCallDurationInstrumentName})
994                     .add_optional_label("unknown")));
995   SendRPC();
996   auto data = ReadCurrentMetricsData(
997       [&](const absl::flat_hash_map<
998           std::string,
999           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1000               data) {
1001         return !data.contains("grpc.client.attempt.started") ||
1002                !data.contains("grpc.client.attempt.duration") ||
1003                !data.contains("grpc.server.call.started") ||
1004                !data.contains("grpc.server.call.duration");
1005       });
1006   // Verify client side metric (grpc.client.attempt.started) does not sees this
1007   // label
1008   ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
1009   const auto& client_attributes =
1010       data["grpc.client.attempt.started"][0].attributes.GetAttributes();
1011   EXPECT_THAT(client_attributes,
1012               ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1013   // Verify client side metric (grpc.client.attempt.duration) does not see this
1014   // label
1015   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1016   const auto& client_duration_attributes =
1017       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1018   EXPECT_THAT(client_duration_attributes,
1019               ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1020   // Verify server metric (grpc.server.call.started) does not see this label
1021   ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
1022   const auto& server_attributes =
1023       data["grpc.server.call.started"][0].attributes.GetAttributes();
1024   EXPECT_THAT(
1025       server_attributes,
1026       ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
1027   // Verify server metric (grpc.server.call.duration) does not see this label
1028   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1029   const auto& server_duration_attributes =
1030       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1031   EXPECT_THAT(server_duration_attributes,
1032               ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1033 }
1034 
1035 using OpenTelemetryPluginOptionEnd2EndTest = OpenTelemetryPluginEnd2EndTest;
1036 
1037 class SimpleLabelIterable : public grpc::internal::LabelsIterable {
1038  public:
SimpleLabelIterable(std::pair<absl::string_view,absl::string_view> label)1039   explicit SimpleLabelIterable(
1040       std::pair<absl::string_view, absl::string_view> label)
1041       : label_(label) {}
1042 
Next()1043   absl::optional<std::pair<absl::string_view, absl::string_view>> Next()
1044       override {
1045     if (iterated_) {
1046       return absl::nullopt;
1047     }
1048     iterated_ = true;
1049     return label_;
1050   }
1051 
Size() const1052   size_t Size() const override { return 1; }
1053 
ResetIteratorPosition()1054   void ResetIteratorPosition() override { iterated_ = false; }
1055 
1056  private:
1057   bool iterated_ = false;
1058   std::pair<absl::string_view, absl::string_view> label_;
1059 };
1060 
1061 class CustomLabelInjector : public grpc::internal::LabelsInjector {
1062  public:
CustomLabelInjector(std::pair<std::string,std::string> label)1063   explicit CustomLabelInjector(std::pair<std::string, std::string> label)
1064       : label_(std::move(label)) {}
~CustomLabelInjector()1065   ~CustomLabelInjector() override {}
1066 
GetLabels(grpc_metadata_batch *) const1067   std::unique_ptr<grpc::internal::LabelsIterable> GetLabels(
1068       grpc_metadata_batch* /*incoming_initial_metadata*/) const override {
1069     return std::make_unique<SimpleLabelIterable>(label_);
1070   }
1071 
AddLabels(grpc_metadata_batch *,grpc::internal::LabelsIterable *) const1072   void AddLabels(
1073       grpc_metadata_batch* /*outgoing_initial_metadata*/,
1074       grpc::internal::LabelsIterable* /*labels_from_incoming_metadata*/)
1075       const override {}
1076 
AddOptionalLabels(bool,absl::Span<const grpc_core::RefCountedStringValue>,opentelemetry::nostd::function_ref<bool (opentelemetry::nostd::string_view,opentelemetry::common::AttributeValue)>) const1077   bool AddOptionalLabels(bool /*is_client*/,
1078                          absl::Span<const grpc_core::RefCountedStringValue>
1079                          /*optional_labels*/,
1080                          opentelemetry::nostd::function_ref<
1081                              bool(opentelemetry::nostd::string_view,
1082                                   opentelemetry::common::AttributeValue)>
1083                          /*callback*/) const override {
1084     return true;
1085   }
1086 
GetOptionalLabelsSize(bool,absl::Span<const grpc_core::RefCountedStringValue>) const1087   size_t GetOptionalLabelsSize(
1088       bool /*is_client*/, absl::Span<const grpc_core::RefCountedStringValue>
1089       /*optional_labels_span*/) const override {
1090     return 0;
1091   }
1092 
1093  private:
1094   std::pair<std::string, std::string> label_;
1095 };
1096 
1097 class CustomPluginOption
1098     : public grpc::internal::InternalOpenTelemetryPluginOption {
1099  public:
CustomPluginOption(bool enabled_on_client,bool enabled_on_server,std::pair<std::string,std::string> label)1100   CustomPluginOption(bool enabled_on_client, bool enabled_on_server,
1101                      std::pair<std::string, std::string> label)
1102       : enabled_on_client_(enabled_on_client),
1103         enabled_on_server_(enabled_on_server),
1104         label_injector_(
1105             std::make_unique<CustomLabelInjector>(std::move(label))) {}
1106 
~CustomPluginOption()1107   ~CustomPluginOption() override {}
1108 
IsActiveOnClientChannel(absl::string_view) const1109   bool IsActiveOnClientChannel(absl::string_view /*target*/) const override {
1110     return enabled_on_client_;
1111   }
1112 
IsActiveOnServer(const grpc_core::ChannelArgs &) const1113   bool IsActiveOnServer(const grpc_core::ChannelArgs& /*args*/) const override {
1114     return enabled_on_server_;
1115   }
1116 
labels_injector() const1117   const grpc::internal::LabelsInjector* labels_injector() const override {
1118     return label_injector_.get();
1119   }
1120 
1121  private:
1122   bool enabled_on_client_;
1123   bool enabled_on_server_;
1124   std::unique_ptr<CustomLabelInjector> label_injector_;
1125 };
1126 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,Basic)1127 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, Basic) {
1128   Init(
1129       std::move(Options()
1130                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1131                                            kClientAttemptDurationInstrumentName,
1132                                        grpc::OpenTelemetryPluginBuilder::
1133                                            kServerCallDurationInstrumentName})
1134                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1135                         /*enabled_on_client*/ true, /*enabled_on_server*/ true,
1136                         std::make_pair("key", "value")))));
1137   SendRPC();
1138   auto data = ReadCurrentMetricsData(
1139       [&](const absl::flat_hash_map<
1140           std::string,
1141           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1142               data) {
1143         return !data.contains("grpc.client.attempt.duration") ||
1144                !data.contains("grpc.server.call.duration");
1145       });
1146   // Verify client side metric
1147   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1148   const auto& client_attributes =
1149       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1150   EXPECT_EQ(client_attributes.size(), 4);
1151   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
1152   // Verify server side metric
1153   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1154   const auto& server_attributes =
1155       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1156   EXPECT_EQ(server_attributes.size(), 3);
1157   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
1158 }
1159 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,ClientOnlyPluginOption)1160 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ClientOnlyPluginOption) {
1161   Init(
1162       std::move(Options()
1163                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1164                                            kClientAttemptDurationInstrumentName,
1165                                        grpc::OpenTelemetryPluginBuilder::
1166                                            kServerCallDurationInstrumentName})
1167                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1168                         /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1169                         std::make_pair("key", "value")))));
1170   SendRPC();
1171   auto data = ReadCurrentMetricsData(
1172       [&](const absl::flat_hash_map<
1173           std::string,
1174           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1175               data) {
1176         return !data.contains("grpc.client.attempt.duration") ||
1177                !data.contains("grpc.server.call.duration");
1178       });
1179   // Verify client side metric
1180   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1181   const auto& client_attributes =
1182       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1183   EXPECT_EQ(client_attributes.size(), 4);
1184   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
1185   // Verify server side metric
1186   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1187   const auto& server_attributes =
1188       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1189   EXPECT_EQ(server_attributes.size(), 2);
1190   EXPECT_THAT(server_attributes,
1191               ::testing::Not(::testing::Contains(::testing::Key("key"))));
1192 }
1193 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,ServerOnlyPluginOption)1194 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ServerOnlyPluginOption) {
1195   Init(
1196       std::move(Options()
1197                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1198                                            kClientAttemptDurationInstrumentName,
1199                                        grpc::OpenTelemetryPluginBuilder::
1200                                            kServerCallDurationInstrumentName})
1201                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1202                         /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1203                         std::make_pair("key", "value")))));
1204   SendRPC();
1205   auto data = ReadCurrentMetricsData(
1206       [&](const absl::flat_hash_map<
1207           std::string,
1208           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1209               data) {
1210         return !data.contains("grpc.client.attempt.duration") ||
1211                !data.contains("grpc.server.call.duration");
1212       });
1213   // Verify client side metric
1214   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1215   const auto& attributes =
1216       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1217   EXPECT_EQ(attributes.size(), 3);
1218   EXPECT_THAT(attributes,
1219               ::testing::Not(::testing::Contains(::testing::Key("key"))));
1220   // Verify server side metric
1221   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1222   const auto& server_attributes =
1223       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1224   EXPECT_EQ(server_attributes.size(), 3);
1225   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
1226 }
1227 
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,MultipleEnabledAndDisabledPluginOptions)1228 TEST_F(OpenTelemetryPluginOptionEnd2EndTest,
1229        MultipleEnabledAndDisabledPluginOptions) {
1230   Init(
1231       std::move(Options()
1232                     .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1233                                            kClientAttemptDurationInstrumentName,
1234                                        grpc::OpenTelemetryPluginBuilder::
1235                                            kServerCallDurationInstrumentName})
1236                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1237                         /*enabled_on_client*/ true, /*enabled_on_server*/ true,
1238                         std::make_pair("key1", "value1")))
1239                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1240                         /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1241                         std::make_pair("key2", "value2")))
1242                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1243                         /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1244                         std::make_pair("key3", "value3")))
1245                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1246                         /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1247                         std::make_pair("key4", "value4")))
1248                     .add_plugin_option(std::make_unique<CustomPluginOption>(
1249                         /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1250                         std::make_pair("key5", "value5")))));
1251   SendRPC();
1252   auto data = ReadCurrentMetricsData(
1253       [&](const absl::flat_hash_map<
1254           std::string,
1255           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1256               data) {
1257         return !data.contains("grpc.client.attempt.duration") ||
1258                !data.contains("grpc.server.call.duration");
1259       });
1260   // Verify client side metric
1261   ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1262   const auto& client_attributes =
1263       data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1264   EXPECT_EQ(client_attributes.size(), 6);
1265   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key1")), "value1");
1266   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key2")), "value2");
1267   EXPECT_EQ(absl::get<std::string>(client_attributes.at("key3")), "value3");
1268   EXPECT_THAT(client_attributes,
1269               ::testing::Not(::testing::Contains(::testing::Key("key4"))));
1270   EXPECT_THAT(client_attributes,
1271               ::testing::Not(::testing::Contains(::testing::Key("key5"))));
1272   // Verify server side metric
1273   ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1274   const auto& server_attributes =
1275       data["grpc.server.call.duration"][0].attributes.GetAttributes();
1276   EXPECT_EQ(server_attributes.size(), 5);
1277   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key1")), "value1");
1278   EXPECT_THAT(server_attributes,
1279               ::testing::Not(::testing::Contains(::testing::Key("key2"))));
1280   EXPECT_THAT(server_attributes,
1281               ::testing::Not(::testing::Contains(::testing::Key("key3"))));
1282   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key4")), "value4");
1283   EXPECT_EQ(absl::get<std::string>(server_attributes.at("key5")), "value5");
1284 }
1285 
1286 class OpenTelemetryPluginNPCMetricsTest
1287     : public OpenTelemetryPluginEnd2EndTest {
1288  protected:
OpenTelemetryPluginNPCMetricsTest()1289   OpenTelemetryPluginNPCMetricsTest()
1290       : endpoint_config_(grpc_core::ChannelArgs()) {}
1291 
TearDown()1292   void TearDown() override {
1293     // We are tearing down OpenTelemetryPluginEnd2EndTest first to ensure that
1294     // gRPC has shutdown before we reset the instruments registry.
1295     OpenTelemetryPluginEnd2EndTest::TearDown();
1296     grpc_core::GlobalInstrumentsRegistryTestPeer::
1297         ResetGlobalInstrumentsRegistry();
1298   }
1299 
1300   grpc_event_engine::experimental::ChannelArgsEndpointConfig endpoint_config_;
1301 };
1302 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordUInt64Counter)1303 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Counter) {
1304   constexpr absl::string_view kMetricName = "uint64_counter";
1305   constexpr uint64_t kCounterValues[] = {1, 2, 3};
1306   constexpr int64_t kCounterResult = 6;
1307   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1308                                                            "label_key_2"};
1309   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1310       "optional_label_key_1", "optional_label_key_2"};
1311   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1312                                                              "label_value_2"};
1313   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1314       "optional_label_value_1", "optional_label_value_2"};
1315   auto handle =
1316       grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Counter(
1317           kMetricName, "A simple uint64 counter.", "unit",
1318           /*enable_by_default=*/true)
1319           .Labels(kLabelKeys[0], kLabelKeys[1])
1320           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1321           .Build();
1322   Init(std::move(Options()
1323                      .set_metric_names({kMetricName})
1324                      .set_channel_scope_filter(
1325                          [](const OpenTelemetryPluginBuilder::ChannelScope&
1326                                 channel_scope) {
1327                            return absl::StartsWith(channel_scope.target(),
1328                                                    "dns:///");
1329                          })
1330                      .add_optional_label(kOptionalLabelKeys[0])
1331                      .add_optional_label(kOptionalLabelKeys[1])));
1332   auto stats_plugins =
1333       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1334           grpc_core::experimental::StatsPluginChannelScope(
1335               "dns:///localhost:8080", "", endpoint_config_));
1336   for (auto v : kCounterValues) {
1337     stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
1338   }
1339   auto data = ReadCurrentMetricsData(
1340       [&](const absl::flat_hash_map<
1341           std::string,
1342           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1343               data) { return !data.contains(kMetricName); });
1344   EXPECT_THAT(data,
1345               ::testing::ElementsAre(::testing::Pair(
1346                   kMetricName,
1347                   ::testing::ElementsAre(::testing::AllOf(
1348                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1349                                    kOptionalLabelValues),
1350                       CounterResultEq(::testing::Eq(kCounterResult)))))));
1351 }
1352 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordDoubleCounter)1353 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleCounter) {
1354   constexpr absl::string_view kMetricName = "double_counter";
1355   constexpr double kCounterValues[] = {1.23, 2.34, 3.45};
1356   constexpr double kCounterResult = 7.02;
1357   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1358                                                            "label_key_2"};
1359   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1360       "optional_label_key_1", "optional_label_key_2"};
1361   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1362                                                              "label_value_2"};
1363   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1364       "optional_label_value_1", "optional_label_value_2"};
1365   auto handle =
1366       grpc_core::GlobalInstrumentsRegistry::RegisterDoubleCounter(
1367           kMetricName, "A simple double counter.", "unit",
1368           /*enable_by_default=*/false)
1369           .Labels(kLabelKeys[0], kLabelKeys[1])
1370           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1371           .Build();
1372   Init(std::move(Options()
1373                      .set_metric_names({kMetricName})
1374                      .set_channel_scope_filter(
1375                          [](const OpenTelemetryPluginBuilder::ChannelScope&
1376                                 channel_scope) {
1377                            return absl::StartsWith(channel_scope.target(),
1378                                                    "dns:///");
1379                          })
1380                      .add_optional_label(kOptionalLabelKeys[0])
1381                      .add_optional_label(kOptionalLabelKeys[1])));
1382   auto stats_plugins =
1383       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1384           grpc_core::experimental::StatsPluginChannelScope(
1385               "dns:///localhost:8080", "", endpoint_config_));
1386   for (auto v : kCounterValues) {
1387     stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
1388   }
1389   auto data = ReadCurrentMetricsData(
1390       [&](const absl::flat_hash_map<
1391           std::string,
1392           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1393               data) { return !data.contains(kMetricName); });
1394   EXPECT_THAT(data,
1395               ::testing::ElementsAre(::testing::Pair(
1396                   kMetricName,
1397                   ::testing::ElementsAre(::testing::AllOf(
1398                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1399                                    kOptionalLabelValues),
1400                       CounterResultEq(::testing::DoubleEq(kCounterResult)))))));
1401 }
1402 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordUInt64Histogram)1403 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Histogram) {
1404   constexpr absl::string_view kMetricName = "uint64_histogram";
1405   constexpr uint64_t kHistogramValues[] = {1, 1, 2, 3, 4, 4, 5, 6};
1406   constexpr int64_t kSum = 26;
1407   constexpr int64_t kMin = 1;
1408   constexpr int64_t kMax = 6;
1409   constexpr int64_t kCount = 8;
1410   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1411                                                            "label_key_2"};
1412   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1413       "optional_label_key_1", "optional_label_key_2"};
1414   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1415                                                              "label_value_2"};
1416   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1417       "optional_label_value_1", "optional_label_value_2"};
1418   auto handle =
1419       grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Histogram(
1420           kMetricName, "A simple uint64 histogram.", "unit",
1421           /*enable_by_default=*/true)
1422           .Labels(kLabelKeys[0], kLabelKeys[1])
1423           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1424           .Build();
1425   Init(std::move(
1426       Options()
1427           .set_metric_names({kMetricName})
1428           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1429             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1430                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1431           })
1432           .add_optional_label(kOptionalLabelKeys[0])
1433           .add_optional_label(kOptionalLabelKeys[1])));
1434   grpc_core::ChannelArgs args;
1435   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1436   auto stats_plugins =
1437       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1438   for (auto v : kHistogramValues) {
1439     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1440                                   kOptionalLabelValues);
1441   }
1442   auto data = ReadCurrentMetricsData(
1443       [&](const absl::flat_hash_map<
1444           std::string,
1445           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1446               data) { return !data.contains(kMetricName); });
1447   EXPECT_THAT(
1448       data, ::testing::ElementsAre(::testing::Pair(
1449                 kMetricName,
1450                 ::testing::ElementsAre(::testing::AllOf(
1451                     AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1452                                  kOptionalLabelValues),
1453                     HistogramResultEq(::testing::Eq(kSum), ::testing::Eq(kMin),
1454                                       ::testing::Eq(kMax), kCount))))));
1455 }
1456 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordDoubleHistogram)1457 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleHistogram) {
1458   constexpr absl::string_view kMetricName = "double_histogram";
1459   constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1460                                          4.4, 4.5, 5.5, 6.6};
1461   constexpr double kSum = 28.8;
1462   constexpr double kMin = 1.1;
1463   constexpr double kMax = 6.6;
1464   constexpr double kCount = 8;
1465   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1466                                                            "label_key_2"};
1467   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1468       "optional_label_key_1", "optional_label_key_2"};
1469   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1470                                                              "label_value_2"};
1471   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1472       "optional_label_value_1", "optional_label_value_2"};
1473   auto handle =
1474       grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1475           kMetricName, "A simple double histogram.", "unit",
1476           /*enable_by_default=*/true)
1477           .Labels(kLabelKeys[0], kLabelKeys[1])
1478           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1479           .Build();
1480   Init(std::move(
1481       Options()
1482           .set_metric_names({kMetricName})
1483           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1484             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1485                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1486           })
1487           .add_optional_label(kOptionalLabelKeys[0])
1488           .add_optional_label(kOptionalLabelKeys[1])));
1489   grpc_core::ChannelArgs args;
1490   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1491   auto stats_plugins =
1492       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1493   for (auto v : kHistogramValues) {
1494     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1495                                   kOptionalLabelValues);
1496   }
1497   auto data = ReadCurrentMetricsData(
1498       [&](const absl::flat_hash_map<
1499           std::string,
1500           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1501               data) { return !data.contains(kMetricName); });
1502   EXPECT_THAT(data,
1503               ::testing::ElementsAre(::testing::Pair(
1504                   kMetricName,
1505                   ::testing::ElementsAre(::testing::AllOf(
1506                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1507                                    kOptionalLabelValues),
1508                       HistogramResultEq(::testing::DoubleEq(kSum),
1509                                         ::testing::DoubleEq(kMin),
1510                                         ::testing::DoubleEq(kMax), kCount))))));
1511 }
1512 
TEST_F(OpenTelemetryPluginNPCMetricsTest,RegisterMultipleOpenTelemetryPlugins)1513 TEST_F(OpenTelemetryPluginNPCMetricsTest,
1514        RegisterMultipleOpenTelemetryPlugins) {
1515   constexpr absl::string_view kMetricName = "yet_another_double_histogram";
1516   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1517                                                            "label_key_2"};
1518   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1519       "optional_label_key_1", "optional_label_key_2"};
1520   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1521                                                              "label_value_2"};
1522   constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1523       "optional_label_value_1", "optional_label_value_2"};
1524   auto handle =
1525       grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1526           kMetricName, "A simple double histogram.", "unit",
1527           /*enable_by_default=*/true)
1528           .Labels(kLabelKeys[0], kLabelKeys[1])
1529           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1530           .Build();
1531   // Build and register a separate OpenTelemetryPlugin and verify its histogram
1532   // recording.
1533   auto reader = BuildAndRegisterOpenTelemetryPlugin(std::move(
1534       Options()
1535           .set_metric_names({kMetricName})
1536           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1537             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1538                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1539           })
1540           .add_optional_label(kOptionalLabelKeys[0])
1541           .add_optional_label(kOptionalLabelKeys[1])));
1542   grpc_core::ChannelArgs args;
1543   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1544   {
1545     constexpr double kHistogramValues[] = {1.23, 2.34, 3.45, 4.56};
1546     constexpr double kSum = 11.58;
1547     constexpr double kMin = 1.23;
1548     constexpr double kMax = 4.56;
1549     constexpr int kCount = 4;
1550     auto stats_plugins =
1551         grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1552     for (auto v : kHistogramValues) {
1553       stats_plugins.RecordHistogram(handle, v, kLabelValues,
1554                                     kOptionalLabelValues);
1555     }
1556     auto data = ReadCurrentMetricsData(
1557         [&](const absl::flat_hash_map<
1558             std::string,
1559             std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1560                 data) { return !data.contains(kMetricName); },
1561         reader.get());
1562     EXPECT_THAT(
1563         data, ::testing::ElementsAre(::testing::Pair(
1564                   kMetricName,
1565                   ::testing::ElementsAre(::testing::AllOf(
1566                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1567                                    kOptionalLabelValues),
1568                       HistogramResultEq(::testing::DoubleEq(kSum),
1569                                         ::testing::DoubleEq(kMin),
1570                                         ::testing::DoubleEq(kMax), kCount))))));
1571   }
1572   // Now build and register another OpenTelemetryPlugin using the test fixture
1573   // and record histogram.
1574   constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1575                                          4.4, 4.5, 5.5, 6.6};
1576   constexpr double kSum = 28.8;
1577   constexpr double kMin = 1.1;
1578   constexpr double kMax = 6.6;
1579   constexpr int kCount = 8;
1580   Init(std::move(
1581       Options()
1582           .set_metric_names({kMetricName})
1583           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1584             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1585                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1586           })
1587           .add_optional_label(kOptionalLabelKeys[0])
1588           .add_optional_label(kOptionalLabelKeys[1])));
1589   auto stats_plugins =
1590       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1591   for (auto v : kHistogramValues) {
1592     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1593                                   kOptionalLabelValues);
1594   }
1595   auto data = ReadCurrentMetricsData(
1596       [&](const absl::flat_hash_map<
1597           std::string,
1598           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1599               data) { return !data.contains(kMetricName); });
1600   EXPECT_THAT(data,
1601               ::testing::ElementsAre(::testing::Pair(
1602                   kMetricName,
1603                   ::testing::ElementsAre(::testing::AllOf(
1604                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1605                                    kOptionalLabelValues),
1606                       HistogramResultEq(::testing::DoubleEq(kSum),
1607                                         ::testing::DoubleEq(kMin),
1608                                         ::testing::DoubleEq(kMax), kCount))))));
1609   // Verify that the first plugin gets the data as well.
1610   data = ReadCurrentMetricsData(
1611       [&](const absl::flat_hash_map<
1612           std::string,
1613           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1614               data) { return !data.contains(kMetricName); },
1615       reader.get());
1616   EXPECT_THAT(data,
1617               ::testing::ElementsAre(::testing::Pair(
1618                   kMetricName,
1619                   ::testing::ElementsAre(::testing::AllOf(
1620                       AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1621                                    kOptionalLabelValues),
1622                       HistogramResultEq(::testing::DoubleEq(kSum),
1623                                         ::testing::DoubleEq(kMin),
1624                                         ::testing::DoubleEq(kMax), kCount))))));
1625 }
1626 
TEST_F(OpenTelemetryPluginNPCMetricsTest,DisabledOptionalLabelKeysShouldNotBeRecorded)1627 TEST_F(OpenTelemetryPluginNPCMetricsTest,
1628        DisabledOptionalLabelKeysShouldNotBeRecorded) {
1629   constexpr absl::string_view kMetricName =
1630       "yet_another_yet_another_double_histogram";
1631   constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1632                                          4.4, 4.5, 5.5, 6.6};
1633   constexpr double kSum = 28.8;
1634   constexpr double kMin = 1.1;
1635   constexpr double kMax = 6.6;
1636   constexpr double kCount = 8;
1637   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1638                                                            "label_key_2"};
1639   constexpr std::array<absl::string_view, 4> kOptionalLabelKeys = {
1640       "optional_label_key_1", "optional_label_key_2", "optional_label_key_3",
1641       "optional_label_key_4"};
1642   constexpr std::array<absl::string_view, 3> kActualOptionalLabelKeys = {
1643       "optional_label_key_1", "optional_label_key_2", "optional_label_key_4"};
1644   constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1645                                                              "label_value_2"};
1646   constexpr std::array<absl::string_view, 4> kOptionalLabelValues = {
1647       "optional_label_value_1", "optional_label_value_2",
1648       "optional_label_value_3", "optional_label_value_4"};
1649   constexpr std::array<absl::string_view, 3> kActualOptionalLabelValues = {
1650       "optional_label_value_1", "optional_label_value_2",
1651       "optional_label_value_4"};
1652   auto handle =
1653       grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1654           kMetricName, "A simple double histogram.", "unit",
1655           /*enable_by_default=*/true)
1656           .Labels(kLabelKeys[0], kLabelKeys[1])
1657           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1],
1658                           kOptionalLabelKeys[2], kOptionalLabelKeys[3])
1659           .Build();
1660   Init(std::move(
1661       Options()
1662           .set_metric_names({kMetricName})
1663           .set_server_selector([](const grpc_core::ChannelArgs& args) {
1664             return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1665                    GRPC_ARG_SERVER_SELECTOR_VALUE;
1666           })
1667           .add_optional_label(kOptionalLabelKeys[0])
1668           .add_optional_label(kOptionalLabelKeys[1])
1669           .add_optional_label(kOptionalLabelKeys[3])));
1670   grpc_core::ChannelArgs args;
1671   args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1672   auto stats_plugins =
1673       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1674   for (auto v : kHistogramValues) {
1675     stats_plugins.RecordHistogram(handle, v, kLabelValues,
1676                                   kOptionalLabelValues);
1677   }
1678   auto data = ReadCurrentMetricsData(
1679       [&](const absl::flat_hash_map<
1680           std::string,
1681           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1682               data) { return !data.contains(kMetricName); });
1683   EXPECT_THAT(
1684       data,
1685       ::testing::ElementsAre(::testing::Pair(
1686           kMetricName,
1687           ::testing::ElementsAre(::testing::AllOf(
1688               AttributesEq(kLabelKeys, kLabelValues, kActualOptionalLabelKeys,
1689                            kActualOptionalLabelValues),
1690               HistogramResultEq(::testing::DoubleEq(kSum),
1691                                 ::testing::DoubleEq(kMin),
1692                                 ::testing::DoubleEq(kMax), kCount))))));
1693 }
1694 
TEST_F(OpenTelemetryPluginNPCMetricsTest,InstrumentsEnabledTest)1695 TEST_F(OpenTelemetryPluginNPCMetricsTest, InstrumentsEnabledTest) {
1696   constexpr absl::string_view kDoubleHistogramMetricName =
1697       "yet_another_yet_another_double_histogram";
1698   constexpr absl::string_view kUnit64CounterMetricName = "uint64_counter";
1699   auto histogram_handle =
1700       grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1701           kDoubleHistogramMetricName, "A simple double histogram.", "unit",
1702           /*enable_by_default=*/false)
1703           .Build();
1704   auto counter_handle =
1705       grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Counter(
1706           kUnit64CounterMetricName, "A simple unit64 counter.", "unit",
1707           /*enable_by_default=*/false)
1708           .Build();
1709   Init(std::move(Options().set_metric_names({kDoubleHistogramMetricName})));
1710   auto stats_plugins =
1711       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(
1712           grpc_core::ChannelArgs());
1713   EXPECT_TRUE(stats_plugins.IsInstrumentEnabled(histogram_handle));
1714   EXPECT_FALSE(stats_plugins.IsInstrumentEnabled(counter_handle));
1715 }
1716 
1717 using OpenTelemetryPluginCallbackMetricsTest =
1718     OpenTelemetryPluginNPCMetricsTest;
1719 
1720 // The callback minimal interval is longer than the OT reporting interval, so we
1721 // expect to collect duplicated (cached) values.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDurationLongerThanCollectDuration)1722 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
1723        ReportDurationLongerThanCollectDuration) {
1724   constexpr absl::string_view kInt64CallbackGaugeMetric =
1725       "int64_callback_gauge";
1726   constexpr absl::string_view kDoubleCallbackGaugeMetric =
1727       "double_callback_gauge";
1728   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1729                                                            "label_key_2"};
1730   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1731       "optional_label_key_1", "optional_label_key_2"};
1732   constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
1733       "label_value_set_1", "label_value_set_1"};
1734   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
1735       "optional_label_value_set_1", "optional_label_value_set_1"};
1736   constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
1737       "label_value_set_2", "label_value_set_2"};
1738   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
1739       "optional_label_value_set_2", "optional_label_value_set_2"};
1740   auto integer_gauge_handle =
1741       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1742           kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1743           /*enable_by_default=*/true)
1744           .Labels(kLabelKeys[0], kLabelKeys[1])
1745           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1746           .Build();
1747   auto double_gauge_handle =
1748       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1749           kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1750           /*enable_by_default=*/true)
1751           .Labels(kLabelKeys[0], kLabelKeys[1])
1752           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1753           .Build();
1754   Init(std::move(Options()
1755                      .set_metric_names({kInt64CallbackGaugeMetric,
1756                                         kDoubleCallbackGaugeMetric})
1757                      .add_optional_label(kOptionalLabelKeys[0])
1758                      .add_optional_label(kOptionalLabelKeys[1])));
1759   auto stats_plugins =
1760       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1761           grpc_core::experimental::StatsPluginChannelScope(
1762               "dns:///localhost:8080", "", endpoint_config_));
1763   // Multiple callbacks for the same metrics, each reporting different
1764   // label values.
1765   int report_count_1 = 0;
1766   int64_t int_value_1 = 1;
1767   double double_value_1 = 0.5;
1768   auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
1769       [&](grpc_core::CallbackMetricReporter& reporter) {
1770         ++report_count_1;
1771         reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet1,
1772                         kOptionalLabelValuesSet1);
1773         reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet1,
1774                         kOptionalLabelValuesSet1);
1775         ;
1776       },
1777       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
1778       integer_gauge_handle, double_gauge_handle);
1779   int report_count_2 = 0;
1780   int64_t int_value_2 = 1;
1781   double double_value_2 = 0.5;
1782   auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
1783       [&](grpc_core::CallbackMetricReporter& reporter) {
1784         ++report_count_2;
1785         reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
1786                         kOptionalLabelValuesSet2);
1787         reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
1788                         kOptionalLabelValuesSet2);
1789       },
1790       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
1791       integer_gauge_handle, double_gauge_handle);
1792   constexpr int kIterations = 100;
1793   MetricsCollectorThread collector{
1794       this, grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor(),
1795       kIterations,
1796       [&](const absl::flat_hash_map<
1797           std::string,
1798           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1799               data) {
1800         return !data.contains(kInt64CallbackGaugeMetric) ||
1801                !data.contains(kDoubleCallbackGaugeMetric);
1802       }};
1803   absl::flat_hash_map<
1804       std::string,
1805       std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
1806       data = collector.Stop();
1807   // Verify that data is incremental with duplications (cached values).
1808   EXPECT_LT(report_count_1, kIterations);
1809   EXPECT_LT(report_count_2, kIterations);
1810   EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
1811             data[kDoubleCallbackGaugeMetric].size());
1812   // Verify labels.
1813   ASSERT_THAT(
1814       data,
1815       ::testing::UnorderedElementsAre(
1816           ::testing::Pair(
1817               kInt64CallbackGaugeMetric,
1818               ::testing::Each(::testing::AnyOf(
1819                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1820                                kOptionalLabelValuesSet1),
1821                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1822                                kOptionalLabelValuesSet2)))),
1823           ::testing::Pair(
1824               kDoubleCallbackGaugeMetric,
1825               ::testing::Each(::testing::AnyOf(
1826                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1827                                kOptionalLabelValuesSet1),
1828                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1829                                kOptionalLabelValuesSet2))))));
1830   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1831                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1832                         kOptionalLabelKeys, kOptionalLabelValuesSet1,
1833                         int64_t(0), false));
1834   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1835                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1836                         kOptionalLabelKeys, kOptionalLabelValuesSet2,
1837                         int64_t(0), false));
1838   EXPECT_THAT(data,
1839               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1840                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1841                   kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, false));
1842   EXPECT_THAT(data,
1843               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1844                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1845                   kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, false));
1846 }
1847 
1848 // The callback minimal interval is shorter than the OT reporting interval, so
1849 // for each collect we should go update the cache and report the latest values.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDurationShorterThanCollectDuration)1850 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
1851        ReportDurationShorterThanCollectDuration) {
1852   constexpr absl::string_view kInt64CallbackGaugeMetric =
1853       "yet_another_int64_callback_gauge";
1854   constexpr absl::string_view kDoubleCallbackGaugeMetric =
1855       "yet_another_double_callback_gauge";
1856   constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1857                                                            "label_key_2"};
1858   constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1859       "optional_label_key_1", "optional_label_key_2"};
1860   constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
1861       "label_value_set_1", "label_value_set_1"};
1862   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
1863       "optional_label_value_set_1", "optional_label_value_set_1"};
1864   constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
1865       "label_value_set_2", "label_value_set_2"};
1866   constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
1867       "optional_label_value_set_2", "optional_label_value_set_2"};
1868   auto integer_gauge_handle =
1869       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1870           kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1871           /*enable_by_default=*/true)
1872           .Labels(kLabelKeys[0], kLabelKeys[1])
1873           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1874           .Build();
1875   auto double_gauge_handle =
1876       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1877           kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1878           /*enable_by_default=*/true)
1879           .Labels(kLabelKeys[0], kLabelKeys[1])
1880           .OptionalLabels(kOptionalLabelKeys[0], kOptionalLabelKeys[1])
1881           .Build();
1882   Init(std::move(Options()
1883                      .set_metric_names({kInt64CallbackGaugeMetric,
1884                                         kDoubleCallbackGaugeMetric})
1885                      .add_optional_label(kOptionalLabelKeys[0])
1886                      .add_optional_label(kOptionalLabelKeys[1])));
1887   auto stats_plugins =
1888       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1889           grpc_core::experimental::StatsPluginChannelScope(
1890               "dns:///localhost:8080", "", endpoint_config_));
1891   // Multiple callbacks for the same metrics, each reporting different
1892   // label values.
1893   int report_count_1 = 0;
1894   int64_t int_value_1 = 1;
1895   double double_value_1 = 0.5;
1896   auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
1897       [&](grpc_core::CallbackMetricReporter& reporter) {
1898         ++report_count_1;
1899         reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet1,
1900                         kOptionalLabelValuesSet1);
1901         reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet1,
1902                         kOptionalLabelValuesSet1);
1903       },
1904       grpc_core::Duration::Milliseconds(50) * grpc_test_slowdown_factor(),
1905       integer_gauge_handle, double_gauge_handle);
1906   int report_count_2 = 0;
1907   int64_t int_value_2 = 1;
1908   double double_value_2 = 0.5;
1909   auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
1910       [&](grpc_core::CallbackMetricReporter& reporter) {
1911         ++report_count_2;
1912         reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
1913                         kOptionalLabelValuesSet2);
1914         reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
1915                         kOptionalLabelValuesSet2);
1916       },
1917       grpc_core::Duration::Milliseconds(50) * grpc_test_slowdown_factor(),
1918       integer_gauge_handle, double_gauge_handle);
1919   constexpr int kIterations = 50;
1920   MetricsCollectorThread collector{
1921       this,
1922       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
1923       kIterations,
1924       [&](const absl::flat_hash_map<
1925           std::string,
1926           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1927               data) {
1928         return !data.contains(kInt64CallbackGaugeMetric) ||
1929                !data.contains(kDoubleCallbackGaugeMetric);
1930       }};
1931   absl::flat_hash_map<
1932       std::string,
1933       std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
1934       data = collector.Stop();
1935   // Verify that data is incremental without duplications (cached
1936   // values).
1937   EXPECT_EQ(report_count_1, kIterations);
1938   EXPECT_EQ(report_count_2, kIterations);
1939   EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
1940             data[kDoubleCallbackGaugeMetric].size());
1941   // Verify labels.
1942   ASSERT_THAT(
1943       data,
1944       ::testing::UnorderedElementsAre(
1945           ::testing::Pair(
1946               kInt64CallbackGaugeMetric,
1947               ::testing::Each(::testing::AnyOf(
1948                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1949                                kOptionalLabelValuesSet1),
1950                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1951                                kOptionalLabelValuesSet2)))),
1952           ::testing::Pair(
1953               kDoubleCallbackGaugeMetric,
1954               ::testing::Each(::testing::AnyOf(
1955                   AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1956                                kOptionalLabelValuesSet1),
1957                   AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1958                                kOptionalLabelValuesSet2))))));
1959   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1960                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1961                         kOptionalLabelKeys, kOptionalLabelValuesSet1,
1962                         int64_t(0), true));
1963   EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1964                         kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1965                         kOptionalLabelKeys, kOptionalLabelValuesSet2,
1966                         int64_t(0), true));
1967   EXPECT_THAT(data,
1968               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1969                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1970                   kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, true));
1971   EXPECT_THAT(data,
1972               GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1973                   kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1974                   kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, true));
1975 }
1976 
1977 // Verifies that callbacks are cleaned up when the OpenTelemetry plugin is
1978 // destroyed.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,VerifyCallbacksAreCleanedUp)1979 TEST_F(OpenTelemetryPluginCallbackMetricsTest, VerifyCallbacksAreCleanedUp) {
1980   constexpr absl::string_view kInt64CallbackGaugeMetric =
1981       "yet_another_int64_callback_gauge";
1982   constexpr absl::string_view kDoubleCallbackGaugeMetric =
1983       "yet_another_double_callback_gauge";
1984   auto integer_gauge_handle =
1985       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1986           kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1987           /*enable_by_default=*/true)
1988           .Build();
1989   auto double_gauge_handle =
1990       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1991           kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1992           /*enable_by_default=*/true)
1993           .Build();
1994   Init(std::move(Options().set_metric_names(
1995       {kInt64CallbackGaugeMetric, kDoubleCallbackGaugeMetric})));
1996   auto stats_plugins =
1997       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1998           grpc_core::experimental::StatsPluginChannelScope(
1999               "dns:///localhost:8080", "", endpoint_config_));
2000   // Multiple callbacks for the same metrics, each reporting different
2001   // label values.
2002   int report_count_1 = 0;
2003   int64_t int_value_1 = 1;
2004   double double_value_1 = 0.5;
2005   auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
2006       [&](grpc_core::CallbackMetricReporter& reporter) {
2007         ++report_count_1;
2008         reporter.Report(integer_gauge_handle, int_value_1++, {}, {});
2009         reporter.Report(double_gauge_handle, double_value_1++, {}, {});
2010       },
2011       grpc_core::Duration::Milliseconds(50) * grpc_test_slowdown_factor(),
2012       integer_gauge_handle, double_gauge_handle);
2013   int report_count_2 = 0;
2014   int64_t int_value_2 = 1;
2015   double double_value_2 = 0.5;
2016   auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
2017       [&](grpc_core::CallbackMetricReporter& reporter) {
2018         ++report_count_2;
2019         reporter.Report(integer_gauge_handle, int_value_2++, {}, {});
2020         reporter.Report(double_gauge_handle, double_value_2++, {}, {});
2021       },
2022       grpc_core::Duration::Milliseconds(50) * grpc_test_slowdown_factor(),
2023       integer_gauge_handle, double_gauge_handle);
2024   constexpr int kIterations = 50;
2025   {
2026     MetricsCollectorThread collector{
2027         this,
2028         grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
2029         kIterations,
2030         [&](const absl::flat_hash_map<
2031             std::string,
2032             std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2033                 data) {
2034           return !data.contains(kInt64CallbackGaugeMetric) ||
2035                  !data.contains(kDoubleCallbackGaugeMetric);
2036         }};
2037   }
2038   // Verify that callbacks are invoked
2039   EXPECT_EQ(report_count_1, kIterations);
2040   EXPECT_EQ(report_count_2, kIterations);
2041   // Remove one of the callbacks
2042   registered_metric_callback_1.reset();
2043   {
2044     MetricsCollectorThread new_collector{
2045         this,
2046         grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
2047         kIterations,
2048         [&](const absl::flat_hash_map<
2049             std::string,
2050             std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2051                 data) { return false; }};
2052   }
2053   EXPECT_EQ(report_count_1, kIterations);      // No change since previous
2054   EXPECT_EQ(report_count_2, 2 * kIterations);  // Gets another kIterations
2055   // Remove the other callback as well
2056   registered_metric_callback_2.reset();
2057   MetricsCollectorThread new_new_collector{
2058       this,
2059       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
2060       kIterations,
2061       [&](const absl::flat_hash_map<
2062           std::string,
2063           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2064               data) { return false; }};
2065   // We shouldn't get any new callbacks
2066   EXPECT_THAT(new_new_collector.Stop(), ::testing::IsEmpty());
2067   EXPECT_EQ(report_count_1, kIterations);
2068   EXPECT_EQ(report_count_2, 2 * kIterations);
2069   // Reset stats plugins as well
2070   grpc_core::GlobalStatsPluginRegistryTestPeer::
2071       ResetGlobalStatsPluginRegistry();
2072   registered_metric_callback_2.reset();
2073   MetricsCollectorThread new_new_new_collector{
2074       this,
2075       grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
2076       kIterations,
2077       [&](const absl::flat_hash_map<
2078           std::string,
2079           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2080               data) { return false; }};
2081   // Still no new callbacks
2082   EXPECT_THAT(new_new_new_collector.Stop(), ::testing::IsEmpty());
2083   EXPECT_EQ(report_count_1, kIterations);
2084   EXPECT_EQ(report_count_2, 2 * kIterations);
2085 }
2086 
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDifferentGaugeThanRegisteredWontCrash)2087 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
2088        ReportDifferentGaugeThanRegisteredWontCrash) {
2089   constexpr absl::string_view kInt64CallbackGaugeMetric =
2090       "yet_another_int64_callback_gauge";
2091   constexpr absl::string_view kDoubleCallbackGaugeMetric =
2092       "yet_another_double_callback_gauge";
2093   auto integer_gauge_handle =
2094       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
2095           kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
2096           /*enable_by_default=*/true)
2097           .Build();
2098   auto double_gauge_handle =
2099       grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
2100           kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
2101           /*enable_by_default=*/true)
2102           .Build();
2103   Init(std::move(Options().set_metric_names(
2104       {kInt64CallbackGaugeMetric, kDoubleCallbackGaugeMetric})));
2105   auto stats_plugins =
2106       grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
2107           grpc_core::experimental::StatsPluginChannelScope(
2108               "dns:///localhost:8080", "", endpoint_config_));
2109   // Registers integer_gauge_handle but reports double_gauge_handle.
2110   int report_count_1 = 0;
2111   double double_value_1 = 0.5;
2112   auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
2113       [&](grpc_core::CallbackMetricReporter& reporter) {
2114         ++report_count_1;
2115         reporter.Report(double_gauge_handle, double_value_1++, {}, {});
2116       },
2117       grpc_core::Duration::Milliseconds(50) * grpc_test_slowdown_factor(),
2118       integer_gauge_handle);
2119   constexpr int kIterations = 50;
2120   {
2121     MetricsCollectorThread collector{
2122         this,
2123         grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
2124         kIterations,
2125         [&](const absl::flat_hash_map<
2126             std::string,
2127             std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2128                 data) { return false; }};
2129   }
2130   // Verify that callbacks are invoked
2131   EXPECT_EQ(report_count_1, kIterations);
2132 }
2133 
TEST(OpenTelemetryPluginMetricsEnablingDisablingTest,TestEnableDisableAPIs)2134 TEST(OpenTelemetryPluginMetricsEnablingDisablingTest, TestEnableDisableAPIs) {
2135   grpc::internal::OpenTelemetryPluginBuilderImpl builder;
2136   // First disable all metrics
2137   builder.DisableAllMetrics();
2138   EXPECT_TRUE(builder.TestOnlyEnabledMetrics().empty());
2139   // Add in a few metrics
2140   builder.EnableMetrics(
2141       {"grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"});
2142   EXPECT_THAT(
2143       builder.TestOnlyEnabledMetrics(),
2144       ::testing::UnorderedElementsAre(
2145           "grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"));
2146   // Now remove a few metrics
2147   builder.DisableMetrics({"grpc.test.metric_1", "grpc.test.metric_2"});
2148   EXPECT_THAT(builder.TestOnlyEnabledMetrics(),
2149               ::testing::UnorderedElementsAre("grpc.test.metric_3"));
2150 }
2151 
TEST_F(OpenTelemetryPluginEnd2EndTest,RegisterMultipleStatsPluginsPerChannel)2152 TEST_F(OpenTelemetryPluginEnd2EndTest, RegisterMultipleStatsPluginsPerChannel) {
2153   std::shared_ptr<grpc::experimental::OpenTelemetryPlugin> plugin1;
2154   std::shared_ptr<opentelemetry::sdk::metrics::MetricReader> reader1;
2155   std::tie(plugin1, reader1) = BuildOpenTelemetryPlugin(std::move(
2156       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
2157                                       kClientAttemptDurationInstrumentName})));
2158   std::shared_ptr<grpc::experimental::OpenTelemetryPlugin> plugin2;
2159   std::shared_ptr<opentelemetry::sdk::metrics::MetricReader> reader2;
2160   std::tie(plugin2, reader2) = BuildOpenTelemetryPlugin(std::move(
2161       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
2162                                       kClientAttemptDurationInstrumentName})));
2163   Init(std::move(
2164       Options()
2165           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
2166                                  kClientAttemptDurationInstrumentName})
2167           .add_per_channel_stats_plugin(std::move(plugin1))
2168           .add_per_channel_stats_plugin(std::move(plugin2))));
2169   const std::vector<absl::string_view> kLabelKeys = {
2170       "grpc.method", "grpc.target", "grpc.status"};
2171   const std::vector<absl::string_view> kLabelValues = {
2172       kMethodName, canonical_server_address_, "OK"};
2173   const std::vector<absl::string_view> kOptionalLabelKeys = {};
2174   const std::vector<absl::string_view> kOptionalLabelValues = {};
2175   SendRPC();
2176   const char* kMetricName = "grpc.client.attempt.duration";
2177   auto data = ReadCurrentMetricsData(
2178       [&](const absl::flat_hash_map<
2179           std::string,
2180           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2181               data) { return !data.contains(kMetricName); });
2182   EXPECT_THAT(
2183       data,
2184       ::testing::ElementsAre(::testing::Pair(
2185           kMetricName,
2186           ::testing::ElementsAre(::testing::AllOf(
2187               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2188                            kOptionalLabelValues),
2189               ::testing::Field(
2190                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2191                   ::testing::VariantWith<
2192                       opentelemetry::sdk::metrics::HistogramPointData>(
2193                       ::testing::Field(&opentelemetry::sdk::metrics::
2194                                            HistogramPointData::count_,
2195                                        ::testing::Eq(1)))))))));
2196   data = ReadCurrentMetricsData(
2197       [&](const absl::flat_hash_map<
2198           std::string,
2199           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2200               data) { return !data.contains(kMetricName); },
2201       reader1.get());
2202   EXPECT_THAT(
2203       data,
2204       ::testing::ElementsAre(::testing::Pair(
2205           kMetricName,
2206           ::testing::ElementsAre(::testing::AllOf(
2207               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2208                            kOptionalLabelValues),
2209               ::testing::Field(
2210                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2211                   ::testing::VariantWith<
2212                       opentelemetry::sdk::metrics::HistogramPointData>(
2213                       ::testing::Field(&opentelemetry::sdk::metrics::
2214                                            HistogramPointData::count_,
2215                                        ::testing::Eq(1)))))))));
2216   data = ReadCurrentMetricsData(
2217       [&](const absl::flat_hash_map<
2218           std::string,
2219           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2220               data) { return !data.contains(kMetricName); },
2221       reader2.get());
2222   EXPECT_THAT(
2223       data,
2224       ::testing::ElementsAre(::testing::Pair(
2225           kMetricName,
2226           ::testing::ElementsAre(::testing::AllOf(
2227               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2228                            kOptionalLabelValues),
2229               ::testing::Field(
2230                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2231                   ::testing::VariantWith<
2232                       opentelemetry::sdk::metrics::HistogramPointData>(
2233                       ::testing::Field(&opentelemetry::sdk::metrics::
2234                                            HistogramPointData::count_,
2235                                        ::testing::Eq(1)))))))));
2236 }
2237 
TEST_F(OpenTelemetryPluginEnd2EndTest,RegisterSameStatsPluginForMultipleChannels)2238 TEST_F(OpenTelemetryPluginEnd2EndTest,
2239        RegisterSameStatsPluginForMultipleChannels) {
2240   // channel1                         channel2
2241   //    |                                |
2242   //    | (global plugin, plugin1)       | (global plugin, plugin1, plugin2)
2243   //    |                                |
2244   std::shared_ptr<grpc::experimental::OpenTelemetryPlugin> plugin1;
2245   std::shared_ptr<opentelemetry::sdk::metrics::MetricReader> reader1;
2246   std::tie(plugin1, reader1) = BuildOpenTelemetryPlugin(std::move(
2247       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
2248                                       kClientAttemptDurationInstrumentName})));
2249   std::shared_ptr<grpc::experimental::OpenTelemetryPlugin> plugin2;
2250   std::shared_ptr<opentelemetry::sdk::metrics::MetricReader> reader2;
2251   std::tie(plugin2, reader2) = BuildOpenTelemetryPlugin(std::move(
2252       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
2253                                       kClientAttemptDurationInstrumentName})));
2254   Init(std::move(
2255       Options()
2256           .set_metric_names({grpc::OpenTelemetryPluginBuilder::
2257                                  kClientAttemptDurationInstrumentName})
2258           .add_per_channel_stats_plugin(plugin1)));
2259   // Adds the same plugin to another channel.
2260   ChannelArguments channel_args;
2261   plugin1->AddToChannelArguments(&channel_args);
2262   plugin2->AddToChannelArguments(&channel_args);
2263   auto channel2 = grpc::CreateCustomChannel(
2264       server_address_, grpc::InsecureChannelCredentials(), channel_args);
2265   std::unique_ptr<EchoTestService::Stub> stub =
2266       EchoTestService::NewStub(std::move(channel2));
2267   // Sends 2 RPCs, one from each channel.
2268   EchoRequest request;
2269   request.set_message("foo");
2270   EchoResponse response;
2271   grpc::ClientContext context;
2272   stub->Echo(&context, request, &response);
2273   SendRPC();
2274   const std::vector<absl::string_view> kLabelKeys = {
2275       "grpc.method", "grpc.target", "grpc.status"};
2276   const std::vector<absl::string_view> kLabelValues = {
2277       kMethodName, canonical_server_address_, "OK"};
2278   const std::vector<absl::string_view> kOptionalLabelKeys = {};
2279   const std::vector<absl::string_view> kOptionalLabelValues = {};
2280   const char* kMetricName = "grpc.client.attempt.duration";
2281   // Verifies that we got 2 histogram points in global plugin.
2282   auto data = ReadCurrentMetricsData(
2283       [&](const absl::flat_hash_map<
2284           std::string,
2285           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2286               data) { return !data.contains(kMetricName); });
2287   EXPECT_THAT(
2288       data,
2289       ::testing::ElementsAre(::testing::Pair(
2290           kMetricName,
2291           ::testing::ElementsAre(::testing::AllOf(
2292               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2293                            kOptionalLabelValues),
2294               ::testing::Field(
2295                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2296                   ::testing::VariantWith<
2297                       opentelemetry::sdk::metrics::HistogramPointData>(
2298                       ::testing::Field(&opentelemetry::sdk::metrics::
2299                                            HistogramPointData::count_,
2300                                        ::testing::Eq(2)))))))));
2301   // Verifies that we got 2 histogram points in plugin1.
2302   data = ReadCurrentMetricsData(
2303       [&](const absl::flat_hash_map<
2304           std::string,
2305           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2306               data) { return !data.contains(kMetricName); },
2307       reader1.get());
2308   EXPECT_THAT(
2309       data,
2310       ::testing::ElementsAre(::testing::Pair(
2311           kMetricName,
2312           ::testing::ElementsAre(::testing::AllOf(
2313               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2314                            kOptionalLabelValues),
2315               ::testing::Field(
2316                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2317                   ::testing::VariantWith<
2318                       opentelemetry::sdk::metrics::HistogramPointData>(
2319                       ::testing::Field(&opentelemetry::sdk::metrics::
2320                                            HistogramPointData::count_,
2321                                        ::testing::Eq(2)))))))));
2322   // Verifies that we got 1 histogram point in plugin2.
2323   data = ReadCurrentMetricsData(
2324       [&](const absl::flat_hash_map<
2325           std::string,
2326           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2327               data) { return !data.contains(kMetricName); },
2328       reader2.get());
2329   EXPECT_THAT(
2330       data,
2331       ::testing::ElementsAre(::testing::Pair(
2332           kMetricName,
2333           ::testing::ElementsAre(::testing::AllOf(
2334               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2335                            kOptionalLabelValues),
2336               ::testing::Field(
2337                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2338                   ::testing::VariantWith<
2339                       opentelemetry::sdk::metrics::HistogramPointData>(
2340                       ::testing::Field(&opentelemetry::sdk::metrics::
2341                                            HistogramPointData::count_,
2342                                        ::testing::Eq(1)))))))));
2343 }
2344 
TEST_F(OpenTelemetryPluginEnd2EndTest,RegisterMultipleStatsPluginsPerServer)2345 TEST_F(OpenTelemetryPluginEnd2EndTest, RegisterMultipleStatsPluginsPerServer) {
2346   std::shared_ptr<grpc::experimental::OpenTelemetryPlugin> plugin;
2347   std::shared_ptr<opentelemetry::sdk::metrics::MetricReader> reader;
2348   std::tie(plugin, reader) = BuildOpenTelemetryPlugin(std::move(
2349       Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
2350                                       kServerCallDurationInstrumentName})));
2351   Init(std::move(Options()
2352                      .set_metric_names({grpc::OpenTelemetryPluginBuilder::
2353                                             kServerCallDurationInstrumentName})
2354                      .add_per_server_stats_plugin(std::move(plugin))));
2355   const std::vector<absl::string_view> kLabelKeys = {"grpc.method",
2356                                                      "grpc.status"};
2357   const std::vector<absl::string_view> kLabelValues = {kMethodName, "OK"};
2358   const std::vector<absl::string_view> kOptionalLabelKeys = {};
2359   const std::vector<absl::string_view> kOptionalLabelValues = {};
2360   SendRPC();
2361   const char* kMetricName = "grpc.server.call.duration";
2362   // Verifies that both plugins have the server-side metrics recorded.
2363   auto data = ReadCurrentMetricsData(
2364       [&](const absl::flat_hash_map<
2365           std::string,
2366           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2367               data) { return !data.contains(kMetricName); });
2368   EXPECT_THAT(
2369       data,
2370       ::testing::ElementsAre(::testing::Pair(
2371           kMetricName,
2372           ::testing::ElementsAre(::testing::AllOf(
2373               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2374                            kOptionalLabelValues),
2375               ::testing::Field(
2376                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2377                   ::testing::VariantWith<
2378                       opentelemetry::sdk::metrics::HistogramPointData>(
2379                       ::testing::Field(&opentelemetry::sdk::metrics::
2380                                            HistogramPointData::count_,
2381                                        ::testing::Eq(1)))))))));
2382   data = ReadCurrentMetricsData(
2383       [&](const absl::flat_hash_map<
2384           std::string,
2385           std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
2386               data) { return !data.contains(kMetricName); },
2387       reader.get());
2388   EXPECT_THAT(
2389       data,
2390       ::testing::ElementsAre(::testing::Pair(
2391           kMetricName,
2392           ::testing::ElementsAre(::testing::AllOf(
2393               AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
2394                            kOptionalLabelValues),
2395               ::testing::Field(
2396                   &opentelemetry::sdk::metrics::PointDataAttributes::point_data,
2397                   ::testing::VariantWith<
2398                       opentelemetry::sdk::metrics::HistogramPointData>(
2399                       ::testing::Field(&opentelemetry::sdk::metrics::
2400                                            HistogramPointData::count_,
2401                                        ::testing::Eq(1)))))))));
2402 }
2403 
2404 }  // namespace
2405 }  // namespace testing
2406 }  // namespace grpc
2407 
main(int argc,char ** argv)2408 int main(int argc, char** argv) {
2409   grpc::testing::TestEnvironment env(&argc, argv);
2410   ::testing::InitGoogleTest(&argc, argv);
2411   return RUN_ALL_TESTS();
2412 }
2413