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