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 <atomic>
22 #include <chrono>
23 #include <ratio>
24 #include <type_traits>
25
26 #include "absl/functional/any_invocable.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "opentelemetry/common/timestamp.h"
30 #include "opentelemetry/metrics/provider.h"
31 #include "opentelemetry/nostd/variant.h"
32 #include "opentelemetry/sdk/common/attribute_utils.h"
33 #include "opentelemetry/sdk/metrics/data/point_data.h"
34 #include "opentelemetry/sdk/metrics/meter_provider.h"
35 #include "opentelemetry/sdk/metrics/metric_reader.h"
36
37 #include <grpcpp/ext/otel_plugin.h>
38 #include <grpcpp/grpcpp.h>
39
40 #include "src/core/lib/channel/call_tracer.h"
41 #include "src/core/lib/config/core_configuration.h"
42 #include "test/core/util/test_config.h"
43 #include "test/cpp/end2end/test_service_impl.h"
44 #include "test/cpp/ext/otel/otel_test_library.h"
45
46 namespace grpc {
47 namespace testing {
48 namespace {
49
50 #define GRPC_ARG_SERVER_SELECTOR_KEY "grpc.testing.server_selector_key"
51 #define GRPC_ARG_SERVER_SELECTOR_VALUE "grpc.testing.server_selector_value"
52
53 template <typename T>
PopulateLabelMap(T label_keys,T label_values,std::unordered_map<std::string,opentelemetry::sdk::common::OwnedAttributeValue> * label_maps)54 void PopulateLabelMap(
55 T label_keys, T label_values,
56 std::unordered_map<std::string,
57 opentelemetry::sdk::common::OwnedAttributeValue>*
58 label_maps) {
59 for (size_t i = 0; i < label_keys.size(); ++i) {
60 (*label_maps)[std::string(label_keys[i])] = std::string(label_values[i]);
61 }
62 }
63
64 MATCHER_P4(AttributesEq, label_keys, label_values, optional_label_keys,
65 optional_label_values, "") {
66 std::unordered_map<std::string,
67 opentelemetry::sdk::common::OwnedAttributeValue>
68 label_map;
69 PopulateLabelMap(label_keys, label_values, &label_map);
70 PopulateLabelMap(optional_label_keys, optional_label_values, &label_map);
71 return ::testing::ExplainMatchResult(
72 ::testing::UnorderedElementsAreArray(label_map),
73 arg.attributes.GetAttributes(), result_listener);
74 }
75
76 template <typename T>
77 struct Extract;
78
79 template <template <typename> class T, typename U>
80 struct Extract<const T<U>> {
81 using Type = U;
82 };
83
84 MATCHER_P(CounterResultEq, value_matcher, "") {
85 return ::testing::ExplainMatchResult(
86 ::testing::VariantWith<opentelemetry::sdk::metrics::SumPointData>(
87 ::testing::Field(&opentelemetry::sdk::metrics::SumPointData::value_,
88 ::testing::VariantWith<
89 typename Extract<decltype(value_matcher)>::Type>(
90 value_matcher))),
91 arg.point_data, result_listener);
92 }
93
94 MATCHER_P4(HistogramResultEq, sum_matcher, min_matcher, max_matcher, count,
95 "") {
96 return ::testing::ExplainMatchResult(
97 ::testing::VariantWith<
98 opentelemetry::sdk::metrics::HistogramPointData>(::testing::AllOf(
99 ::testing::Field(
100 &opentelemetry::sdk::metrics::HistogramPointData::sum_,
101 ::testing::VariantWith<
102 typename Extract<decltype(sum_matcher)>::Type>(sum_matcher)),
103 ::testing::Field(
104 &opentelemetry::sdk::metrics::HistogramPointData::min_,
105 ::testing::VariantWith<
106 typename Extract<decltype(min_matcher)>::Type>(min_matcher)),
107 ::testing::Field(
108 &opentelemetry::sdk::metrics::HistogramPointData::max_,
109 ::testing::VariantWith<
110 typename Extract<decltype(max_matcher)>::Type>(max_matcher)),
111 ::testing::Field(
112 &opentelemetry::sdk::metrics::HistogramPointData::count_,
113 ::testing::Eq(count)))),
114 arg.point_data, result_listener);
115 }
116
117 MATCHER_P(GaugeResultIs, value_matcher, "") {
118 return ::testing::ExplainMatchResult(
119 ::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
120 ::testing::AllOf(
121 ::testing::Field(
122 &opentelemetry::sdk::metrics::LastValuePointData::value_,
123 ::testing::VariantWith<
124 typename Extract<decltype(value_matcher)>::Type>(
125 value_matcher)),
126 ::testing::Field(&opentelemetry::sdk::metrics::
127 LastValuePointData::is_lastvalue_valid_,
128 ::testing::IsTrue()))),
129 arg.point_data, result_listener);
130 }
131
132 // This check might subject to system clock adjustment.
133 MATCHER_P(GaugeResultLaterThan, prev_timestamp, "") {
134 return ::testing::ExplainMatchResult(
135 ::testing::VariantWith<opentelemetry::sdk::metrics::LastValuePointData>(
136 ::testing::Field(
137 &opentelemetry::sdk::metrics::LastValuePointData::sample_ts_,
138 ::testing::Property(
139 &opentelemetry::common::SystemTimestamp::time_since_epoch,
140 ::testing::Gt(prev_timestamp.time_since_epoch())))),
141 arg.point_data, result_listener);
142 }
143
144 MATCHER_P7(GaugeDataIsIncrementalForSpecificMetricAndLabelSet, metric_name,
145 label_key, label_value, optional_label_key, optional_label_value,
146 default_value, greater_than, "") {
147 std::unordered_map<std::string,
148 opentelemetry::sdk::common::OwnedAttributeValue>
149 label_map;
150 PopulateLabelMap(label_key, label_value, &label_map);
151 PopulateLabelMap(optional_label_key, optional_label_value, &label_map);
152 opentelemetry::common::SystemTimestamp prev_timestamp;
153 auto prev_value = default_value;
154 size_t prev_index = 0;
155 auto& data = arg.at(metric_name);
156 bool result = true;
157 for (size_t i = 1; i < data.size(); ++i) {
158 if (::testing::Matches(::testing::UnorderedElementsAreArray(
159 data[i - 1].attributes.GetAttributes()))(label_map)) {
160 // Update the previous value for the same associated label values.
161 prev_value = opentelemetry::nostd::get<decltype(prev_value)>(
162 opentelemetry::nostd::get<
163 opentelemetry::sdk::metrics::LastValuePointData>(
164 data[i - 1].point_data)
165 .value_);
166 prev_index = i - 1;
167 prev_timestamp = opentelemetry::nostd::get<
168 opentelemetry::sdk::metrics::LastValuePointData>(
169 data[i - 1].point_data)
170 .sample_ts_;
171 }
172 if (!::testing::Matches(::testing::UnorderedElementsAreArray(
173 data[i].attributes.GetAttributes()))(label_map)) {
174 // Skip values that do not have the same associated label values.
175 continue;
176 }
177 *result_listener << " Comparing data[" << i << "] with data[" << prev_index
178 << "] ";
179 if (greater_than) {
180 result &= ::testing::ExplainMatchResult(
181 ::testing::AllOf(
182 AttributesEq(label_key, label_value, optional_label_key,
183 optional_label_value),
184 GaugeResultIs(::testing::Gt(prev_value)),
185 GaugeResultLaterThan(prev_timestamp)),
186 data[i], result_listener);
187 } else {
188 result &= ::testing::ExplainMatchResult(
189 ::testing::AllOf(
190 AttributesEq(label_key, label_value, optional_label_key,
191 optional_label_value),
192 GaugeResultIs(::testing::Ge(prev_value)),
193 GaugeResultLaterThan(prev_timestamp)),
194 data[i], result_listener);
195 }
196 }
197 return result;
198 }
199
TEST(OpenTelemetryPluginBuildTest,ApiDependency)200 TEST(OpenTelemetryPluginBuildTest, ApiDependency) {
201 opentelemetry::metrics::Provider::GetMeterProvider();
202 }
203
TEST(OpenTelemetryPluginBuildTest,SdkDependency)204 TEST(OpenTelemetryPluginBuildTest, SdkDependency) {
205 opentelemetry::sdk::metrics::MeterProvider();
206 }
207
TEST(OpenTelemetryPluginBuildTest,Basic)208 TEST(OpenTelemetryPluginBuildTest, Basic) {
209 grpc::OpenTelemetryPluginBuilder builder;
210 }
211
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptStarted)212 TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptStarted) {
213 Init(std::move(
214 Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
215 kClientAttemptStartedInstrumentName})));
216 SendRPC();
217 const char* kMetricName = "grpc.client.attempt.started";
218 auto data = ReadCurrentMetricsData(
219 [&](const absl::flat_hash_map<
220 std::string,
221 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
222 data) { return !data.contains(kMetricName); });
223 ASSERT_EQ(data[kMetricName].size(), 1);
224 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
225 &data[kMetricName][0].point_data);
226 ASSERT_NE(point_data, nullptr);
227 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
228 ASSERT_NE(client_started_value, nullptr);
229 EXPECT_EQ(*client_started_value, 1);
230 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
231 EXPECT_EQ(attributes.size(), 2);
232 const auto* method_value =
233 absl::get_if<std::string>(&attributes.at("grpc.method"));
234 ASSERT_NE(method_value, nullptr);
235 EXPECT_EQ(*method_value, kMethodName);
236 const auto* target_value =
237 absl::get_if<std::string>(&attributes.at("grpc.target"));
238 ASSERT_NE(target_value, nullptr);
239 EXPECT_EQ(*target_value, canonical_server_address_);
240 }
241
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptDuration)242 TEST_F(OpenTelemetryPluginEnd2EndTest, ClientAttemptDuration) {
243 Init(std::move(
244 Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
245 kClientAttemptDurationInstrumentName})));
246 SendRPC();
247 const char* kMetricName = "grpc.client.attempt.duration";
248 auto data = ReadCurrentMetricsData(
249 [&](const absl::flat_hash_map<
250 std::string,
251 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
252 data) { return !data.contains(kMetricName); });
253 ASSERT_EQ(data[kMetricName].size(), 1);
254 auto point_data =
255 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
256 &data[kMetricName][0].point_data);
257 ASSERT_NE(point_data, nullptr);
258 ASSERT_EQ(point_data->count_, 1);
259 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
260 EXPECT_EQ(attributes.size(), 3);
261 const auto* method_value =
262 absl::get_if<std::string>(&attributes.at("grpc.method"));
263 ASSERT_NE(method_value, nullptr);
264 EXPECT_EQ(*method_value, kMethodName);
265 const auto* target_value =
266 absl::get_if<std::string>(&attributes.at("grpc.target"));
267 ASSERT_NE(target_value, nullptr);
268 EXPECT_EQ(*target_value, canonical_server_address_);
269 const auto* status_value =
270 absl::get_if<std::string>(&attributes.at("grpc.status"));
271 ASSERT_NE(status_value, nullptr);
272 EXPECT_EQ(*status_value, "OK");
273 }
274
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptSentTotalCompressedMessageSize)275 TEST_F(OpenTelemetryPluginEnd2EndTest,
276 ClientAttemptSentTotalCompressedMessageSize) {
277 Init(std::move(Options().set_metric_names(
278 {grpc::OpenTelemetryPluginBuilder::
279 kClientAttemptSentTotalCompressedMessageSizeInstrumentName})));
280 SendRPC();
281 const char* kMetricName =
282 "grpc.client.attempt.sent_total_compressed_message_size";
283 auto data = ReadCurrentMetricsData(
284 [&](const absl::flat_hash_map<
285 std::string,
286 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
287 data) { return !data.contains(kMetricName); });
288 ASSERT_EQ(data[kMetricName].size(), 1);
289 auto point_data =
290 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
291 &data[kMetricName][0].point_data);
292 ASSERT_NE(point_data, nullptr);
293 ASSERT_EQ(point_data->count_, 1);
294 ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
295 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
296 EXPECT_EQ(attributes.size(), 3);
297 const auto* method_value =
298 absl::get_if<std::string>(&attributes.at("grpc.method"));
299 ASSERT_NE(method_value, nullptr);
300 EXPECT_EQ(*method_value, kMethodName);
301 const auto* target_value =
302 absl::get_if<std::string>(&attributes.at("grpc.target"));
303 ASSERT_NE(target_value, nullptr);
304 EXPECT_EQ(*target_value, canonical_server_address_);
305 const auto* status_value =
306 absl::get_if<std::string>(&attributes.at("grpc.status"));
307 ASSERT_NE(status_value, nullptr);
308 EXPECT_EQ(*status_value, "OK");
309 }
310
TEST_F(OpenTelemetryPluginEnd2EndTest,ClientAttemptRcvdTotalCompressedMessageSize)311 TEST_F(OpenTelemetryPluginEnd2EndTest,
312 ClientAttemptRcvdTotalCompressedMessageSize) {
313 Init(std::move(Options().set_metric_names(
314 {grpc::OpenTelemetryPluginBuilder::
315 kClientAttemptRcvdTotalCompressedMessageSizeInstrumentName})));
316 SendRPC();
317 const char* kMetricName =
318 "grpc.client.attempt.rcvd_total_compressed_message_size";
319 auto data = ReadCurrentMetricsData(
320 [&](const absl::flat_hash_map<
321 std::string,
322 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
323 data) { return !data.contains(kMetricName); });
324 ASSERT_EQ(data[kMetricName].size(), 1);
325 auto point_data =
326 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
327 &data[kMetricName][0].point_data);
328 ASSERT_NE(point_data, nullptr);
329 ASSERT_EQ(point_data->count_, 1);
330 ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
331 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
332 EXPECT_EQ(attributes.size(), 3);
333 const auto* method_value =
334 absl::get_if<std::string>(&attributes.at("grpc.method"));
335 ASSERT_NE(method_value, nullptr);
336 EXPECT_EQ(*method_value, kMethodName);
337 const auto* target_value =
338 absl::get_if<std::string>(&attributes.at("grpc.target"));
339 ASSERT_NE(target_value, nullptr);
340 EXPECT_EQ(*target_value, canonical_server_address_);
341 const auto* status_value =
342 absl::get_if<std::string>(&attributes.at("grpc.status"));
343 ASSERT_NE(status_value, nullptr);
344 EXPECT_EQ(*status_value, "OK");
345 }
346
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallStarted)347 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallStarted) {
348 Init(std::move(Options().set_metric_names(
349 {grpc::OpenTelemetryPluginBuilder::kServerCallStartedInstrumentName})));
350 SendRPC();
351 const char* kMetricName = "grpc.server.call.started";
352 auto data = ReadCurrentMetricsData(
353 [&](const absl::flat_hash_map<
354 std::string,
355 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
356 data) { return !data.contains(kMetricName); });
357 ASSERT_EQ(data[kMetricName].size(), 1);
358 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
359 &data[kMetricName][0].point_data);
360 ASSERT_NE(point_data, nullptr);
361 auto server_started_value = absl::get_if<int64_t>(&point_data->value_);
362 ASSERT_NE(server_started_value, nullptr);
363 ASSERT_EQ(*server_started_value, 1);
364 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
365 EXPECT_EQ(attributes.size(), 1);
366 const auto* method_value =
367 absl::get_if<std::string>(&attributes.at("grpc.method"));
368 ASSERT_NE(method_value, nullptr);
369 EXPECT_EQ(*method_value, kMethodName);
370 }
371
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallDuration)372 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerCallDuration) {
373 Init(std::move(Options().set_metric_names(
374 {grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
375 SendRPC();
376 const char* kMetricName = "grpc.server.call.duration";
377 auto data = ReadCurrentMetricsData(
378 [&](const absl::flat_hash_map<
379 std::string,
380 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
381 data) { return !data.contains(kMetricName); });
382 ASSERT_EQ(data[kMetricName].size(), 1);
383 auto point_data =
384 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
385 &data[kMetricName][0].point_data);
386 ASSERT_NE(point_data, nullptr);
387 ASSERT_EQ(point_data->count_, 1);
388 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
389 EXPECT_EQ(attributes.size(), 2);
390 const auto* method_value =
391 absl::get_if<std::string>(&attributes.at("grpc.method"));
392 ASSERT_NE(method_value, nullptr);
393 EXPECT_EQ(*method_value, kMethodName);
394 const auto* status_value =
395 absl::get_if<std::string>(&attributes.at("grpc.status"));
396 ASSERT_NE(status_value, nullptr);
397 EXPECT_EQ(*status_value, "OK");
398 }
399
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallSentTotalCompressedMessageSize)400 TEST_F(OpenTelemetryPluginEnd2EndTest,
401 ServerCallSentTotalCompressedMessageSize) {
402 Init(std::move(Options().set_metric_names(
403 {grpc::OpenTelemetryPluginBuilder::
404 kServerCallSentTotalCompressedMessageSizeInstrumentName})));
405 SendRPC();
406 const char* kMetricName =
407 "grpc.server.call.sent_total_compressed_message_size";
408 auto data = ReadCurrentMetricsData(
409 [&](const absl::flat_hash_map<
410 std::string,
411 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
412 data) { return !data.contains(kMetricName); });
413 ASSERT_EQ(data[kMetricName].size(), 1);
414 auto point_data =
415 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
416 &data[kMetricName][0].point_data);
417 ASSERT_NE(point_data, nullptr);
418 EXPECT_EQ(point_data->count_, 1);
419 ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
420 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
421 EXPECT_EQ(attributes.size(), 2);
422 const auto* method_value =
423 absl::get_if<std::string>(&attributes.at("grpc.method"));
424 ASSERT_NE(method_value, nullptr);
425 EXPECT_EQ(*method_value, kMethodName);
426 const auto* status_value =
427 absl::get_if<std::string>(&attributes.at("grpc.status"));
428 ASSERT_NE(status_value, nullptr);
429 EXPECT_EQ(*status_value, "OK");
430 }
431
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerCallRcvdTotalCompressedMessageSize)432 TEST_F(OpenTelemetryPluginEnd2EndTest,
433 ServerCallRcvdTotalCompressedMessageSize) {
434 Init(std::move(Options().set_metric_names(
435 {grpc::OpenTelemetryPluginBuilder::
436 kServerCallRcvdTotalCompressedMessageSizeInstrumentName})));
437 SendRPC();
438 const char* kMetricName =
439 "grpc.server.call.rcvd_total_compressed_message_size";
440 auto data = ReadCurrentMetricsData(
441 [&](const absl::flat_hash_map<
442 std::string,
443 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
444 data) { return !data.contains(kMetricName); });
445 ASSERT_EQ(data[kMetricName].size(), 1);
446 auto point_data =
447 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
448 &data[kMetricName][0].point_data);
449 ASSERT_NE(point_data, nullptr);
450 ASSERT_EQ(point_data->count_, 1);
451 ASSERT_EQ(absl::get<int64_t>(point_data->max_), 5);
452 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
453 EXPECT_EQ(attributes.size(), 2);
454 const auto* method_value =
455 absl::get_if<std::string>(&attributes.at("grpc.method"));
456 ASSERT_NE(method_value, nullptr);
457 EXPECT_EQ(*method_value, kMethodName);
458 const auto* status_value =
459 absl::get_if<std::string>(&attributes.at("grpc.status"));
460 ASSERT_NE(status_value, nullptr);
461 EXPECT_EQ(*status_value, "OK");
462 }
463
464 // Make sure that no meter provider results in normal operations.
TEST_F(OpenTelemetryPluginEnd2EndTest,NoMeterProviderRegistered)465 TEST_F(OpenTelemetryPluginEnd2EndTest, NoMeterProviderRegistered) {
466 Init(
467 std::move(Options()
468 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
469 kClientAttemptStartedInstrumentName})
470 .set_use_meter_provider(false)));
471 SendRPC();
472 }
473
474 // Test that the otel plugin sees the expected channel target and default
475 // authority.
TEST_F(OpenTelemetryPluginEnd2EndTest,VerifyChannelScopeTargetAndAuthority)476 TEST_F(OpenTelemetryPluginEnd2EndTest, VerifyChannelScopeTargetAndAuthority) {
477 Init(std::move(
478 Options()
479 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
480 kClientAttemptStartedInstrumentName})
481 .set_channel_scope_filter(
482 [&](const OpenTelemetryPluginBuilder::ChannelScope& scope) {
483 return scope.target() == canonical_server_address_ &&
484 scope.default_authority() == server_address_;
485 })));
486 SendRPC();
487 const char* kMetricName = "grpc.client.attempt.started";
488 auto data = ReadCurrentMetricsData(
489 [&](const absl::flat_hash_map<
490 std::string,
491 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
492 data) { return !data.contains(kMetricName); });
493 ASSERT_EQ(data[kMetricName].size(), 1);
494 }
495
496 // Test that a channel scope filter returning true records metrics on the
497 // channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,ChannelScopeFilterReturnsTrue)498 TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsTrue) {
499 Init(std::move(
500 Options()
501 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
502 kClientAttemptStartedInstrumentName})
503 .set_channel_scope_filter(
504 [](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
505 return true;
506 })));
507 SendRPC();
508 const char* kMetricName = "grpc.client.attempt.started";
509 auto data = ReadCurrentMetricsData(
510 [&](const absl::flat_hash_map<
511 std::string,
512 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
513 data) { return !data.contains(kMetricName); });
514 ASSERT_EQ(data[kMetricName].size(), 1);
515 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
516 &data[kMetricName][0].point_data);
517 ASSERT_NE(point_data, nullptr);
518 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
519 ASSERT_NE(client_started_value, nullptr);
520 EXPECT_EQ(*client_started_value, 1);
521 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
522 EXPECT_EQ(attributes.size(), 2);
523 const auto* method_value =
524 absl::get_if<std::string>(&attributes.at("grpc.method"));
525 ASSERT_NE(method_value, nullptr);
526 EXPECT_EQ(*method_value, kMethodName);
527 const auto* target_value =
528 absl::get_if<std::string>(&attributes.at("grpc.target"));
529 ASSERT_NE(target_value, nullptr);
530 EXPECT_EQ(*target_value, canonical_server_address_);
531 }
532
533 // Test that a channel scope filter returning false does not record metrics on
534 // the channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,ChannelScopeFilterReturnsFalse)535 TEST_F(OpenTelemetryPluginEnd2EndTest, ChannelScopeFilterReturnsFalse) {
536 Init(std::move(
537 Options()
538 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
539 kClientAttemptStartedInstrumentName})
540 .set_channel_scope_filter(
541 [](const OpenTelemetryPluginBuilder::ChannelScope& /*scope*/) {
542 return false;
543 })));
544 SendRPC();
545 auto data = ReadCurrentMetricsData(
546 [&](const absl::flat_hash_map<
547 std::string,
548 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
549 /*data*/) { return false; });
550 ASSERT_TRUE(data.empty());
551 }
552
553 // Test that a server selector returning true records metrics on the server.
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerSelectorReturnsTrue)554 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsTrue) {
555 Init(std::move(Options()
556 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
557 kServerCallDurationInstrumentName})
558 .set_server_selector(
559 [](const grpc_core::ChannelArgs& /*channel_args*/) {
560 return true;
561 })));
562 SendRPC();
563 const char* kMetricName = "grpc.server.call.duration";
564 auto data = ReadCurrentMetricsData(
565 [&](const absl::flat_hash_map<
566 std::string,
567 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
568 data) { return !data.contains(kMetricName); });
569 ASSERT_EQ(data[kMetricName].size(), 1);
570 const auto& server_attributes =
571 data[kMetricName][0].attributes.GetAttributes();
572 EXPECT_EQ(server_attributes.size(), 2);
573 EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.method")),
574 kMethodName);
575 EXPECT_EQ(absl::get<std::string>(server_attributes.at("grpc.status")), "OK");
576 }
577
578 // Test that a server selector returning false does not record metrics on the
579 // server.
TEST_F(OpenTelemetryPluginEnd2EndTest,ServerSelectorReturnsFalse)580 TEST_F(OpenTelemetryPluginEnd2EndTest, ServerSelectorReturnsFalse) {
581 Init(std::move(Options()
582 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
583 kServerCallDurationInstrumentName})
584 .set_server_selector(
585 [](const grpc_core::ChannelArgs& /*channel_args*/) {
586 return false;
587 })));
588 SendRPC();
589 auto data = ReadCurrentMetricsData(
590 [&](const absl::flat_hash_map<
591 std::string,
592 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
593 /*data*/) { return false; });
594 ASSERT_TRUE(data.empty());
595 }
596
597 // Test that a target attribute filter returning true records metrics with the
598 // target as is on the channel.
TEST_F(OpenTelemetryPluginEnd2EndTest,TargetAttributeFilterReturnsTrue)599 TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsTrue) {
600 Init(
601 std::move(Options()
602 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
603 kClientAttemptStartedInstrumentName})
604 .set_target_attribute_filter(
605 [](absl::string_view /*target*/) { return true; })));
606 SendRPC();
607 const char* kMetricName = "grpc.client.attempt.started";
608 auto data = ReadCurrentMetricsData(
609 [&](const absl::flat_hash_map<
610 std::string,
611 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
612 data) { return !data.contains(kMetricName); });
613 ASSERT_EQ(data[kMetricName].size(), 1);
614 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
615 &data[kMetricName][0].point_data);
616 ASSERT_NE(point_data, nullptr);
617 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
618 ASSERT_NE(client_started_value, nullptr);
619 EXPECT_EQ(*client_started_value, 1);
620 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
621 EXPECT_EQ(attributes.size(), 2);
622 const auto* method_value =
623 absl::get_if<std::string>(&attributes.at("grpc.method"));
624 ASSERT_NE(method_value, nullptr);
625 EXPECT_EQ(*method_value, kMethodName);
626 const auto* target_value =
627 absl::get_if<std::string>(&attributes.at("grpc.target"));
628 ASSERT_NE(target_value, nullptr);
629 EXPECT_EQ(*target_value, canonical_server_address_);
630 }
631
632 // Test that a target attribute filter returning false records metrics with the
633 // target as "other".
TEST_F(OpenTelemetryPluginEnd2EndTest,TargetAttributeFilterReturnsFalse)634 TEST_F(OpenTelemetryPluginEnd2EndTest, TargetAttributeFilterReturnsFalse) {
635 Init(
636 std::move(Options()
637 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
638 kClientAttemptStartedInstrumentName})
639 .set_target_attribute_filter(
640 [](absl::string_view /*target*/) { return false; })));
641 SendRPC();
642 const char* kMetricName = "grpc.client.attempt.started";
643 auto data = ReadCurrentMetricsData(
644 [&](const absl::flat_hash_map<
645 std::string,
646 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
647 /*data*/) { return false; });
648 ASSERT_EQ(data[kMetricName].size(), 1);
649 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
650 &data[kMetricName][0].point_data);
651 ASSERT_NE(point_data, nullptr);
652 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
653 ASSERT_NE(client_started_value, nullptr);
654 EXPECT_EQ(*client_started_value, 1);
655 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
656 EXPECT_EQ(attributes.size(), 2);
657 const auto* method_value =
658 absl::get_if<std::string>(&attributes.at("grpc.method"));
659 ASSERT_NE(method_value, nullptr);
660 EXPECT_EQ(*method_value, kMethodName);
661 const auto* target_value =
662 absl::get_if<std::string>(&attributes.at("grpc.target"));
663 ASSERT_NE(target_value, nullptr);
664 EXPECT_EQ(*target_value, "other");
665 }
666
667 // Test that generic method names are scrubbed properly on the client side.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpc)668 TEST_F(OpenTelemetryPluginEnd2EndTest, GenericClientRpc) {
669 Init(std::move(
670 Options().set_metric_names({grpc::OpenTelemetryPluginBuilder::
671 kClientAttemptStartedInstrumentName})));
672 SendGenericRPC();
673 const char* kMetricName = "grpc.client.attempt.started";
674 auto data = ReadCurrentMetricsData(
675 [&](const absl::flat_hash_map<
676 std::string,
677 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
678 /*data*/) { return false; });
679 ASSERT_EQ(data[kMetricName].size(), 1);
680 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
681 &data[kMetricName][0].point_data);
682 ASSERT_NE(point_data, nullptr);
683 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
684 ASSERT_NE(client_started_value, nullptr);
685 EXPECT_EQ(*client_started_value, 1);
686 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
687 EXPECT_EQ(attributes.size(), 2);
688 const auto* method_value =
689 absl::get_if<std::string>(&attributes.at("grpc.method"));
690 ASSERT_NE(method_value, nullptr);
691 EXPECT_EQ(*method_value, "other");
692 const auto* target_value =
693 absl::get_if<std::string>(&attributes.at("grpc.target"));
694 ASSERT_NE(target_value, nullptr);
695 EXPECT_EQ(*target_value, canonical_server_address_);
696 }
697
698 // Test that generic method names are scrubbed properly on the client side if
699 // the method attribute filter is set and it returns false.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpcWithMethodAttributeFilterReturningFalse)700 TEST_F(OpenTelemetryPluginEnd2EndTest,
701 GenericClientRpcWithMethodAttributeFilterReturningFalse) {
702 Init(std::move(
703 Options()
704 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
705 kClientAttemptStartedInstrumentName})
706 .set_generic_method_attribute_filter(
707 [](absl::string_view /*generic_method*/) { return false; })));
708 SendGenericRPC();
709 const char* kMetricName = "grpc.client.attempt.started";
710 auto data = ReadCurrentMetricsData(
711 [&](const absl::flat_hash_map<
712 std::string,
713 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
714 /*data*/) { return false; });
715 ASSERT_EQ(data[kMetricName].size(), 1);
716 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
717 &data[kMetricName][0].point_data);
718 ASSERT_NE(point_data, nullptr);
719 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
720 ASSERT_NE(client_started_value, nullptr);
721 EXPECT_EQ(*client_started_value, 1);
722 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
723 EXPECT_EQ(attributes.size(), 2);
724 const auto* method_value =
725 absl::get_if<std::string>(&attributes.at("grpc.method"));
726 ASSERT_NE(method_value, nullptr);
727 EXPECT_EQ(*method_value, "other");
728 const auto* target_value =
729 absl::get_if<std::string>(&attributes.at("grpc.target"));
730 ASSERT_NE(target_value, nullptr);
731 EXPECT_EQ(*target_value, canonical_server_address_);
732 }
733
734 // Test that generic method names is not scrubbed on the client side if
735 // the method attribute filter is set and it returns true.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericClientRpcWithMethodAttributeFilterReturningTrue)736 TEST_F(OpenTelemetryPluginEnd2EndTest,
737 GenericClientRpcWithMethodAttributeFilterReturningTrue) {
738 Init(std::move(
739 Options()
740 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
741 kClientAttemptStartedInstrumentName})
742 .set_generic_method_attribute_filter(
743 [](absl::string_view /*generic_method*/) { return true; })));
744 SendGenericRPC();
745 const char* kMetricName = "grpc.client.attempt.started";
746 auto data = ReadCurrentMetricsData(
747 [&](const absl::flat_hash_map<
748 std::string,
749 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
750 /*data*/) { return false; });
751 ASSERT_EQ(data[kMetricName].size(), 1);
752 auto point_data = absl::get_if<opentelemetry::sdk::metrics::SumPointData>(
753 &data[kMetricName][0].point_data);
754 ASSERT_NE(point_data, nullptr);
755 auto client_started_value = absl::get_if<int64_t>(&point_data->value_);
756 ASSERT_NE(client_started_value, nullptr);
757 EXPECT_EQ(*client_started_value, 1);
758 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
759 EXPECT_EQ(attributes.size(), 2);
760 const auto* method_value =
761 absl::get_if<std::string>(&attributes.at("grpc.method"));
762 ASSERT_NE(method_value, nullptr);
763 EXPECT_EQ(*method_value, kGenericMethodName);
764 const auto* target_value =
765 absl::get_if<std::string>(&attributes.at("grpc.target"));
766 ASSERT_NE(target_value, nullptr);
767 EXPECT_EQ(*target_value, canonical_server_address_);
768 }
769
770 // Test that generic method names are scrubbed properly on the server side.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpc)771 TEST_F(OpenTelemetryPluginEnd2EndTest, GenericServerRpc) {
772 Init(std::move(Options().set_metric_names(
773 {grpc::OpenTelemetryPluginBuilder::kServerCallDurationInstrumentName})));
774 SendGenericRPC();
775 const char* kMetricName = "grpc.server.call.duration";
776 auto data = ReadCurrentMetricsData(
777 [&](const absl::flat_hash_map<
778 std::string,
779 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
780 data) { return !data.contains(kMetricName); });
781 ASSERT_EQ(data[kMetricName].size(), 1);
782 auto point_data =
783 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
784 &data[kMetricName][0].point_data);
785 ASSERT_NE(point_data, nullptr);
786 ASSERT_EQ(point_data->count_, 1);
787 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
788 EXPECT_EQ(attributes.size(), 2);
789 const auto* method_value =
790 absl::get_if<std::string>(&attributes.at("grpc.method"));
791 ASSERT_NE(method_value, nullptr);
792 EXPECT_EQ(*method_value, "other");
793 const auto* status_value =
794 absl::get_if<std::string>(&attributes.at("grpc.status"));
795 ASSERT_NE(status_value, nullptr);
796 EXPECT_EQ(*status_value, "UNIMPLEMENTED");
797 }
798
799 // Test that generic method names are scrubbed properly on the server side if
800 // the method attribute filter is set and it returns false.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpcWithMethodAttributeFilterReturningFalse)801 TEST_F(OpenTelemetryPluginEnd2EndTest,
802 GenericServerRpcWithMethodAttributeFilterReturningFalse) {
803 Init(std::move(
804 Options()
805 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
806 kServerCallDurationInstrumentName})
807 .set_generic_method_attribute_filter(
808 [](absl::string_view /*generic_method*/) { return false; })));
809 SendGenericRPC();
810 const char* kMetricName = "grpc.server.call.duration";
811 auto data = ReadCurrentMetricsData(
812 [&](const absl::flat_hash_map<
813 std::string,
814 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
815 data) { return !data.contains(kMetricName); });
816 ASSERT_EQ(data[kMetricName].size(), 1);
817 auto point_data =
818 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
819 &data[kMetricName][0].point_data);
820 ASSERT_NE(point_data, nullptr);
821 ASSERT_EQ(point_data->count_, 1);
822 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
823 EXPECT_EQ(attributes.size(), 2);
824 const auto* method_value =
825 absl::get_if<std::string>(&attributes.at("grpc.method"));
826 ASSERT_NE(method_value, nullptr);
827 EXPECT_EQ(*method_value, "other");
828 const auto* status_value =
829 absl::get_if<std::string>(&attributes.at("grpc.status"));
830 ASSERT_NE(status_value, nullptr);
831 EXPECT_EQ(*status_value, "UNIMPLEMENTED");
832 }
833
834 // Test that generic method names are not scrubbed on the server side if
835 // the method attribute filter is set and it returns true.
TEST_F(OpenTelemetryPluginEnd2EndTest,GenericServerRpcWithMethodAttributeFilterReturningTrue)836 TEST_F(OpenTelemetryPluginEnd2EndTest,
837 GenericServerRpcWithMethodAttributeFilterReturningTrue) {
838 Init(std::move(
839 Options()
840 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
841 kServerCallDurationInstrumentName})
842 .set_generic_method_attribute_filter(
843 [](absl::string_view /*generic_method*/) { return true; })));
844 SendGenericRPC();
845 const char* kMetricName = "grpc.server.call.duration";
846 auto data = ReadCurrentMetricsData(
847 [&](const absl::flat_hash_map<
848 std::string,
849 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
850 data) { return !data.contains(kMetricName); });
851 ASSERT_EQ(data[kMetricName].size(), 1);
852 auto point_data =
853 absl::get_if<opentelemetry::sdk::metrics::HistogramPointData>(
854 &data[kMetricName][0].point_data);
855 ASSERT_NE(point_data, nullptr);
856 ASSERT_EQ(point_data->count_, 1);
857 const auto& attributes = data[kMetricName][0].attributes.GetAttributes();
858 EXPECT_EQ(attributes.size(), 2);
859 const auto* method_value =
860 absl::get_if<std::string>(&attributes.at("grpc.method"));
861 ASSERT_NE(method_value, nullptr);
862 EXPECT_EQ(*method_value, kGenericMethodName);
863 const auto* status_value =
864 absl::get_if<std::string>(&attributes.at("grpc.status"));
865 ASSERT_NE(status_value, nullptr);
866 EXPECT_EQ(*status_value, "UNIMPLEMENTED");
867 }
868
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabel)869 TEST_F(OpenTelemetryPluginEnd2EndTest, OptionalPerCallLocalityLabel) {
870 Init(
871 std::move(Options()
872 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
873 kClientAttemptStartedInstrumentName,
874 grpc::OpenTelemetryPluginBuilder::
875 kClientAttemptDurationInstrumentName,
876 grpc::OpenTelemetryPluginBuilder::
877 kServerCallStartedInstrumentName,
878 grpc::OpenTelemetryPluginBuilder::
879 kServerCallDurationInstrumentName})
880 .add_optional_label("grpc.lb.locality")
881 .set_labels_to_inject(
882 {{grpc_core::ClientCallTracer::CallAttemptTracer::
883 OptionalLabelKey::kLocality,
884 grpc_core::RefCountedStringValue("locality")}})));
885 SendRPC();
886 auto data = ReadCurrentMetricsData(
887 [&](const absl::flat_hash_map<
888 std::string,
889 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
890 data) {
891 return !data.contains("grpc.client.attempt.started") ||
892 !data.contains("grpc.client.attempt.duration") ||
893 !data.contains("grpc.server.call.started") ||
894 !data.contains("grpc.server.call.duration");
895 });
896 // Verify client side metric (grpc.client.attempt.started) does not sees this
897 // label
898 ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
899 const auto& client_attributes =
900 data["grpc.client.attempt.started"][0].attributes.GetAttributes();
901 EXPECT_THAT(
902 client_attributes,
903 ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
904 // Verify client side metric (grpc.client.attempt.duration) sees this label.
905 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
906 const auto& client_duration_attributes =
907 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
908 EXPECT_EQ(
909 absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
910 "locality");
911 // Verify server metric (grpc.server.call.started) does not see this label
912 ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
913 const auto& server_attributes =
914 data["grpc.server.call.started"][0].attributes.GetAttributes();
915 EXPECT_THAT(
916 server_attributes,
917 ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
918 // Verify server metric (grpc.server.call.duration) does not see this label
919 ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
920 const auto& server_duration_attributes =
921 data["grpc.server.call.duration"][0].attributes.GetAttributes();
922 EXPECT_THAT(
923 server_duration_attributes,
924 ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
925 }
926
927 // Tests that when locality label is enabled on the plugin but not provided by
928 // gRPC, an empty value is recorded.
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabelWhenNotAvailable)929 TEST_F(OpenTelemetryPluginEnd2EndTest,
930 OptionalPerCallLocalityLabelWhenNotAvailable) {
931 Init(std::move(
932 Options()
933 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
934 kClientAttemptDurationInstrumentName})
935 .add_optional_label("grpc.lb.locality")));
936 SendRPC();
937 auto data = ReadCurrentMetricsData(
938 [&](const absl::flat_hash_map<
939 std::string,
940 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
941 data) { return !data.contains("grpc.client.attempt.duration"); });
942 // Verify client side metric (grpc.client.attempt.duration) sees the empty
943 // label value.
944 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
945 const auto& client_duration_attributes =
946 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
947 EXPECT_EQ(
948 absl::get<std::string>(client_duration_attributes.at("grpc.lb.locality")),
949 "");
950 }
951
952 // Tests that when locality label is injected but not enabled by the plugin, the
953 // label is not recorded.
TEST_F(OpenTelemetryPluginEnd2EndTest,OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled)954 TEST_F(OpenTelemetryPluginEnd2EndTest,
955 OptionalPerCallLocalityLabelNotRecordedWhenNotEnabled) {
956 Init(std::move(
957 Options()
958 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
959 kClientAttemptDurationInstrumentName})
960 .set_labels_to_inject(
961 {{grpc_core::ClientCallTracer::CallAttemptTracer::
962 OptionalLabelKey::kLocality,
963 grpc_core::RefCountedStringValue("locality")}})));
964 SendRPC();
965 auto data = ReadCurrentMetricsData(
966 [&](const absl::flat_hash_map<
967 std::string,
968 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
969 data) { return !data.contains("grpc.client.attempt.duration"); });
970 // Verify client side metric (grpc.client.attempt.duration) does not see the
971 // locality label.
972 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
973 const auto& client_duration_attributes =
974 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
975 EXPECT_THAT(
976 client_duration_attributes,
977 ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
978 }
979
TEST_F(OpenTelemetryPluginEnd2EndTest,UnknownLabelDoesNotShowOnPerCallMetrics)980 TEST_F(OpenTelemetryPluginEnd2EndTest,
981 UnknownLabelDoesNotShowOnPerCallMetrics) {
982 Init(
983 std::move(Options()
984 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
985 kClientAttemptStartedInstrumentName,
986 grpc::OpenTelemetryPluginBuilder::
987 kClientAttemptDurationInstrumentName,
988 grpc::OpenTelemetryPluginBuilder::
989 kServerCallStartedInstrumentName,
990 grpc::OpenTelemetryPluginBuilder::
991 kServerCallDurationInstrumentName})
992 .add_optional_label("unknown")));
993 SendRPC();
994 auto data = ReadCurrentMetricsData(
995 [&](const absl::flat_hash_map<
996 std::string,
997 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
998 data) {
999 return !data.contains("grpc.client.attempt.started") ||
1000 !data.contains("grpc.client.attempt.duration") ||
1001 !data.contains("grpc.server.call.started") ||
1002 !data.contains("grpc.server.call.duration");
1003 });
1004 // Verify client side metric (grpc.client.attempt.started) does not sees this
1005 // label
1006 ASSERT_EQ(data["grpc.client.attempt.started"].size(), 1);
1007 const auto& client_attributes =
1008 data["grpc.client.attempt.started"][0].attributes.GetAttributes();
1009 EXPECT_THAT(client_attributes,
1010 ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1011 // Verify client side metric (grpc.client.attempt.duration) does not see this
1012 // label
1013 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1014 const auto& client_duration_attributes =
1015 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1016 EXPECT_THAT(client_duration_attributes,
1017 ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1018 // Verify server metric (grpc.server.call.started) does not see this label
1019 ASSERT_EQ(data["grpc.server.call.started"].size(), 1);
1020 const auto& server_attributes =
1021 data["grpc.server.call.started"][0].attributes.GetAttributes();
1022 EXPECT_THAT(
1023 server_attributes,
1024 ::testing::Not(::testing::Contains(::testing::Key("grpc.lb.locality"))));
1025 // Verify server metric (grpc.server.call.duration) does not see this label
1026 ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1027 const auto& server_duration_attributes =
1028 data["grpc.server.call.duration"][0].attributes.GetAttributes();
1029 EXPECT_THAT(server_duration_attributes,
1030 ::testing::Not(::testing::Contains(::testing::Key("unknown"))));
1031 }
1032
1033 using OpenTelemetryPluginOptionEnd2EndTest = OpenTelemetryPluginEnd2EndTest;
1034
1035 class SimpleLabelIterable : public grpc::internal::LabelsIterable {
1036 public:
SimpleLabelIterable(std::pair<absl::string_view,absl::string_view> label)1037 explicit SimpleLabelIterable(
1038 std::pair<absl::string_view, absl::string_view> label)
1039 : label_(label) {}
1040
Next()1041 absl::optional<std::pair<absl::string_view, absl::string_view>> Next()
1042 override {
1043 if (iterated_) {
1044 return absl::nullopt;
1045 }
1046 iterated_ = true;
1047 return label_;
1048 }
1049
Size() const1050 size_t Size() const override { return 1; }
1051
ResetIteratorPosition()1052 void ResetIteratorPosition() override { iterated_ = false; }
1053
1054 private:
1055 bool iterated_ = false;
1056 std::pair<absl::string_view, absl::string_view> label_;
1057 };
1058
1059 class CustomLabelInjector : public grpc::internal::LabelsInjector {
1060 public:
CustomLabelInjector(std::pair<std::string,std::string> label)1061 explicit CustomLabelInjector(std::pair<std::string, std::string> label)
1062 : label_(std::move(label)) {}
~CustomLabelInjector()1063 ~CustomLabelInjector() override {}
1064
GetLabels(grpc_metadata_batch *) const1065 std::unique_ptr<grpc::internal::LabelsIterable> GetLabels(
1066 grpc_metadata_batch* /*incoming_initial_metadata*/) const override {
1067 return std::make_unique<SimpleLabelIterable>(label_);
1068 }
1069
AddLabels(grpc_metadata_batch *,grpc::internal::LabelsIterable *) const1070 void AddLabels(
1071 grpc_metadata_batch* /*outgoing_initial_metadata*/,
1072 grpc::internal::LabelsIterable* /*labels_from_incoming_metadata*/)
1073 const override {}
1074
AddOptionalLabels(bool,absl::Span<const grpc_core::RefCountedStringValue>,opentelemetry::nostd::function_ref<bool (opentelemetry::nostd::string_view,opentelemetry::common::AttributeValue)>) const1075 bool AddOptionalLabels(bool /*is_client*/,
1076 absl::Span<const grpc_core::RefCountedStringValue>
1077 /*optional_labels*/,
1078 opentelemetry::nostd::function_ref<
1079 bool(opentelemetry::nostd::string_view,
1080 opentelemetry::common::AttributeValue)>
1081 /*callback*/) const override {
1082 return true;
1083 }
1084
GetOptionalLabelsSize(bool,absl::Span<const grpc_core::RefCountedStringValue>) const1085 size_t GetOptionalLabelsSize(
1086 bool /*is_client*/, absl::Span<const grpc_core::RefCountedStringValue>
1087 /*optional_labels_span*/) const override {
1088 return 0;
1089 }
1090
1091 private:
1092 std::pair<std::string, std::string> label_;
1093 };
1094
1095 class CustomPluginOption
1096 : public grpc::internal::InternalOpenTelemetryPluginOption {
1097 public:
CustomPluginOption(bool enabled_on_client,bool enabled_on_server,std::pair<std::string,std::string> label)1098 CustomPluginOption(bool enabled_on_client, bool enabled_on_server,
1099 std::pair<std::string, std::string> label)
1100 : enabled_on_client_(enabled_on_client),
1101 enabled_on_server_(enabled_on_server),
1102 label_injector_(
1103 std::make_unique<CustomLabelInjector>(std::move(label))) {}
1104
~CustomPluginOption()1105 ~CustomPluginOption() override {}
1106
IsActiveOnClientChannel(absl::string_view) const1107 bool IsActiveOnClientChannel(absl::string_view /*target*/) const override {
1108 return enabled_on_client_;
1109 }
1110
IsActiveOnServer(const grpc_core::ChannelArgs &) const1111 bool IsActiveOnServer(const grpc_core::ChannelArgs& /*args*/) const override {
1112 return enabled_on_server_;
1113 }
1114
labels_injector() const1115 const grpc::internal::LabelsInjector* labels_injector() const override {
1116 return label_injector_.get();
1117 }
1118
1119 private:
1120 bool enabled_on_client_;
1121 bool enabled_on_server_;
1122 std::unique_ptr<CustomLabelInjector> label_injector_;
1123 };
1124
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,Basic)1125 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, Basic) {
1126 Init(
1127 std::move(Options()
1128 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1129 kClientAttemptDurationInstrumentName,
1130 grpc::OpenTelemetryPluginBuilder::
1131 kServerCallDurationInstrumentName})
1132 .add_plugin_option(std::make_unique<CustomPluginOption>(
1133 /*enabled_on_client*/ true, /*enabled_on_server*/ true,
1134 std::make_pair("key", "value")))));
1135 SendRPC();
1136 auto data = ReadCurrentMetricsData(
1137 [&](const absl::flat_hash_map<
1138 std::string,
1139 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1140 data) {
1141 return !data.contains("grpc.client.attempt.duration") ||
1142 !data.contains("grpc.server.call.duration");
1143 });
1144 // Verify client side metric
1145 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1146 const auto& client_attributes =
1147 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1148 EXPECT_EQ(client_attributes.size(), 4);
1149 EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
1150 // Verify server side metric
1151 ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1152 const auto& server_attributes =
1153 data["grpc.server.call.duration"][0].attributes.GetAttributes();
1154 EXPECT_EQ(server_attributes.size(), 3);
1155 EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
1156 }
1157
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,ClientOnlyPluginOption)1158 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ClientOnlyPluginOption) {
1159 Init(
1160 std::move(Options()
1161 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1162 kClientAttemptDurationInstrumentName,
1163 grpc::OpenTelemetryPluginBuilder::
1164 kServerCallDurationInstrumentName})
1165 .add_plugin_option(std::make_unique<CustomPluginOption>(
1166 /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1167 std::make_pair("key", "value")))));
1168 SendRPC();
1169 auto data = ReadCurrentMetricsData(
1170 [&](const absl::flat_hash_map<
1171 std::string,
1172 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1173 data) {
1174 return !data.contains("grpc.client.attempt.duration") ||
1175 !data.contains("grpc.server.call.duration");
1176 });
1177 // Verify client side metric
1178 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1179 const auto& client_attributes =
1180 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1181 EXPECT_EQ(client_attributes.size(), 4);
1182 EXPECT_EQ(absl::get<std::string>(client_attributes.at("key")), "value");
1183 // Verify server side metric
1184 ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1185 const auto& server_attributes =
1186 data["grpc.server.call.duration"][0].attributes.GetAttributes();
1187 EXPECT_EQ(server_attributes.size(), 2);
1188 EXPECT_THAT(server_attributes,
1189 ::testing::Not(::testing::Contains(::testing::Key("key"))));
1190 }
1191
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,ServerOnlyPluginOption)1192 TEST_F(OpenTelemetryPluginOptionEnd2EndTest, ServerOnlyPluginOption) {
1193 Init(
1194 std::move(Options()
1195 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1196 kClientAttemptDurationInstrumentName,
1197 grpc::OpenTelemetryPluginBuilder::
1198 kServerCallDurationInstrumentName})
1199 .add_plugin_option(std::make_unique<CustomPluginOption>(
1200 /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1201 std::make_pair("key", "value")))));
1202 SendRPC();
1203 auto data = ReadCurrentMetricsData(
1204 [&](const absl::flat_hash_map<
1205 std::string,
1206 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1207 data) {
1208 return !data.contains("grpc.client.attempt.duration") ||
1209 !data.contains("grpc.server.call.duration");
1210 });
1211 // Verify client side metric
1212 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1213 const auto& attributes =
1214 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1215 EXPECT_EQ(attributes.size(), 3);
1216 EXPECT_THAT(attributes,
1217 ::testing::Not(::testing::Contains(::testing::Key("key"))));
1218 // Verify server side metric
1219 ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1220 const auto& server_attributes =
1221 data["grpc.server.call.duration"][0].attributes.GetAttributes();
1222 EXPECT_EQ(server_attributes.size(), 3);
1223 EXPECT_EQ(absl::get<std::string>(server_attributes.at("key")), "value");
1224 }
1225
TEST_F(OpenTelemetryPluginOptionEnd2EndTest,MultipleEnabledAndDisabledPluginOptions)1226 TEST_F(OpenTelemetryPluginOptionEnd2EndTest,
1227 MultipleEnabledAndDisabledPluginOptions) {
1228 Init(
1229 std::move(Options()
1230 .set_metric_names({grpc::OpenTelemetryPluginBuilder::
1231 kClientAttemptDurationInstrumentName,
1232 grpc::OpenTelemetryPluginBuilder::
1233 kServerCallDurationInstrumentName})
1234 .add_plugin_option(std::make_unique<CustomPluginOption>(
1235 /*enabled_on_client*/ true, /*enabled_on_server*/ true,
1236 std::make_pair("key1", "value1")))
1237 .add_plugin_option(std::make_unique<CustomPluginOption>(
1238 /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1239 std::make_pair("key2", "value2")))
1240 .add_plugin_option(std::make_unique<CustomPluginOption>(
1241 /*enabled_on_client*/ true, /*enabled_on_server*/ false,
1242 std::make_pair("key3", "value3")))
1243 .add_plugin_option(std::make_unique<CustomPluginOption>(
1244 /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1245 std::make_pair("key4", "value4")))
1246 .add_plugin_option(std::make_unique<CustomPluginOption>(
1247 /*enabled_on_client*/ false, /*enabled_on_server*/ true,
1248 std::make_pair("key5", "value5")))));
1249 SendRPC();
1250 auto data = ReadCurrentMetricsData(
1251 [&](const absl::flat_hash_map<
1252 std::string,
1253 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1254 data) {
1255 return !data.contains("grpc.client.attempt.duration") ||
1256 !data.contains("grpc.server.call.duration");
1257 });
1258 // Verify client side metric
1259 ASSERT_EQ(data["grpc.client.attempt.duration"].size(), 1);
1260 const auto& client_attributes =
1261 data["grpc.client.attempt.duration"][0].attributes.GetAttributes();
1262 EXPECT_EQ(client_attributes.size(), 6);
1263 EXPECT_EQ(absl::get<std::string>(client_attributes.at("key1")), "value1");
1264 EXPECT_EQ(absl::get<std::string>(client_attributes.at("key2")), "value2");
1265 EXPECT_EQ(absl::get<std::string>(client_attributes.at("key3")), "value3");
1266 EXPECT_THAT(client_attributes,
1267 ::testing::Not(::testing::Contains(::testing::Key("key4"))));
1268 EXPECT_THAT(client_attributes,
1269 ::testing::Not(::testing::Contains(::testing::Key("key5"))));
1270 // Verify server side metric
1271 ASSERT_EQ(data["grpc.server.call.duration"].size(), 1);
1272 const auto& server_attributes =
1273 data["grpc.server.call.duration"][0].attributes.GetAttributes();
1274 EXPECT_EQ(server_attributes.size(), 5);
1275 EXPECT_EQ(absl::get<std::string>(server_attributes.at("key1")), "value1");
1276 EXPECT_THAT(server_attributes,
1277 ::testing::Not(::testing::Contains(::testing::Key("key2"))));
1278 EXPECT_THAT(server_attributes,
1279 ::testing::Not(::testing::Contains(::testing::Key("key3"))));
1280 EXPECT_EQ(absl::get<std::string>(server_attributes.at("key4")), "value4");
1281 EXPECT_EQ(absl::get<std::string>(server_attributes.at("key5")), "value5");
1282 }
1283
1284 using OpenTelemetryPluginNPCMetricsTest = OpenTelemetryPluginEnd2EndTest;
1285
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordUInt64Counter)1286 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Counter) {
1287 constexpr absl::string_view kMetricName = "uint64_counter";
1288 constexpr int kCounterValues[] = {1, 2, 3};
1289 constexpr int64_t kCounterResult = 6;
1290 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1291 "label_key_2"};
1292 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1293 "optional_label_key_1", "optional_label_key_2"};
1294 constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1295 "label_value_2"};
1296 constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1297 "optional_label_value_1", "optional_label_value_2"};
1298 auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Counter(
1299 kMetricName, "A simple uint64 counter.", "unit", kLabelKeys,
1300 kOptionalLabelKeys, /*enable_by_default=*/true);
1301 Init(std::move(Options()
1302 .set_metric_names({kMetricName})
1303 .set_channel_scope_filter(
1304 [](const OpenTelemetryPluginBuilder::ChannelScope&
1305 channel_scope) {
1306 return absl::StartsWith(channel_scope.target(),
1307 "dns:///");
1308 })
1309 .add_optional_label(kOptionalLabelKeys[0])
1310 .add_optional_label(kOptionalLabelKeys[1])));
1311 auto stats_plugins =
1312 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1313 grpc_core::experimental::StatsPluginChannelScope(
1314 "dns:///localhost:8080", ""));
1315 for (auto v : kCounterValues) {
1316 stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
1317 }
1318 auto data = ReadCurrentMetricsData(
1319 [&](const absl::flat_hash_map<
1320 std::string,
1321 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1322 data) { return !data.contains(kMetricName); });
1323 EXPECT_THAT(data,
1324 ::testing::ElementsAre(::testing::Pair(
1325 kMetricName,
1326 ::testing::ElementsAre(::testing::AllOf(
1327 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1328 kOptionalLabelValues),
1329 CounterResultEq(::testing::Eq(kCounterResult)))))));
1330 }
1331
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordDoubleCounter)1332 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleCounter) {
1333 constexpr absl::string_view kMetricName = "double_counter";
1334 constexpr double kCounterValues[] = {1.23, 2.34, 3.45};
1335 constexpr double kCounterResult = 7.02;
1336 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1337 "label_key_2"};
1338 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1339 "optional_label_key_1", "optional_label_key_2"};
1340 constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1341 "label_value_2"};
1342 constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1343 "optional_label_value_1", "optional_label_value_2"};
1344 auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleCounter(
1345 kMetricName, "A simple double counter.", "unit", kLabelKeys,
1346 kOptionalLabelKeys, /*enable_by_default=*/false);
1347 Init(std::move(Options()
1348 .set_metric_names({kMetricName})
1349 .set_channel_scope_filter(
1350 [](const OpenTelemetryPluginBuilder::ChannelScope&
1351 channel_scope) {
1352 return absl::StartsWith(channel_scope.target(),
1353 "dns:///");
1354 })
1355 .add_optional_label(kOptionalLabelKeys[0])
1356 .add_optional_label(kOptionalLabelKeys[1])));
1357 auto stats_plugins =
1358 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1359 grpc_core::experimental::StatsPluginChannelScope(
1360 "dns:///localhost:8080", ""));
1361 for (auto v : kCounterValues) {
1362 stats_plugins.AddCounter(handle, v, kLabelValues, kOptionalLabelValues);
1363 }
1364 auto data = ReadCurrentMetricsData(
1365 [&](const absl::flat_hash_map<
1366 std::string,
1367 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1368 data) { return !data.contains(kMetricName); });
1369 EXPECT_THAT(data,
1370 ::testing::ElementsAre(::testing::Pair(
1371 kMetricName,
1372 ::testing::ElementsAre(::testing::AllOf(
1373 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1374 kOptionalLabelValues),
1375 CounterResultEq(::testing::DoubleEq(kCounterResult)))))));
1376 }
1377
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordUInt64Histogram)1378 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordUInt64Histogram) {
1379 constexpr absl::string_view kMetricName = "uint64_histogram";
1380 constexpr int kHistogramValues[] = {1, 1, 2, 3, 4, 4, 5, 6};
1381 constexpr int64_t kSum = 26;
1382 constexpr int64_t kMin = 1;
1383 constexpr int64_t kMax = 6;
1384 constexpr int64_t kCount = 8;
1385 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1386 "label_key_2"};
1387 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1388 "optional_label_key_1", "optional_label_key_2"};
1389 constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1390 "label_value_2"};
1391 constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1392 "optional_label_value_1", "optional_label_value_2"};
1393 auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterUInt64Histogram(
1394 kMetricName, "A simple uint64 histogram.", "unit", kLabelKeys,
1395 kOptionalLabelKeys, /*enable_by_default=*/true);
1396 Init(std::move(
1397 Options()
1398 .set_metric_names({kMetricName})
1399 .set_server_selector([](const grpc_core::ChannelArgs& args) {
1400 return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1401 GRPC_ARG_SERVER_SELECTOR_VALUE;
1402 })
1403 .add_optional_label(kOptionalLabelKeys[0])
1404 .add_optional_label(kOptionalLabelKeys[1])));
1405 grpc_core::ChannelArgs args;
1406 args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1407 auto stats_plugins =
1408 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1409 for (auto v : kHistogramValues) {
1410 stats_plugins.RecordHistogram(handle, v, kLabelValues,
1411 kOptionalLabelValues);
1412 }
1413 auto data = ReadCurrentMetricsData(
1414 [&](const absl::flat_hash_map<
1415 std::string,
1416 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1417 data) { return !data.contains(kMetricName); });
1418 EXPECT_THAT(
1419 data, ::testing::ElementsAre(::testing::Pair(
1420 kMetricName,
1421 ::testing::ElementsAre(::testing::AllOf(
1422 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1423 kOptionalLabelValues),
1424 HistogramResultEq(::testing::Eq(kSum), ::testing::Eq(kMin),
1425 ::testing::Eq(kMax), kCount))))));
1426 }
1427
TEST_F(OpenTelemetryPluginNPCMetricsTest,RecordDoubleHistogram)1428 TEST_F(OpenTelemetryPluginNPCMetricsTest, RecordDoubleHistogram) {
1429 constexpr absl::string_view kMetricName = "double_histogram";
1430 constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1431 4.4, 4.5, 5.5, 6.6};
1432 constexpr double kSum = 28.8;
1433 constexpr double kMin = 1.1;
1434 constexpr double kMax = 6.6;
1435 constexpr double kCount = 8;
1436 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1437 "label_key_2"};
1438 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1439 "optional_label_key_1", "optional_label_key_2"};
1440 constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1441 "label_value_2"};
1442 constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1443 "optional_label_value_1", "optional_label_value_2"};
1444 auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1445 kMetricName, "A simple double histogram.", "unit", kLabelKeys,
1446 kOptionalLabelKeys, /*enable_by_default=*/true);
1447 Init(std::move(
1448 Options()
1449 .set_metric_names({kMetricName})
1450 .set_server_selector([](const grpc_core::ChannelArgs& args) {
1451 return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1452 GRPC_ARG_SERVER_SELECTOR_VALUE;
1453 })
1454 .add_optional_label(kOptionalLabelKeys[0])
1455 .add_optional_label(kOptionalLabelKeys[1])));
1456 grpc_core::ChannelArgs args;
1457 args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1458 auto stats_plugins =
1459 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1460 for (auto v : kHistogramValues) {
1461 stats_plugins.RecordHistogram(handle, v, kLabelValues,
1462 kOptionalLabelValues);
1463 }
1464 auto data = ReadCurrentMetricsData(
1465 [&](const absl::flat_hash_map<
1466 std::string,
1467 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1468 data) { return !data.contains(kMetricName); });
1469 EXPECT_THAT(data,
1470 ::testing::ElementsAre(::testing::Pair(
1471 kMetricName,
1472 ::testing::ElementsAre(::testing::AllOf(
1473 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1474 kOptionalLabelValues),
1475 HistogramResultEq(::testing::DoubleEq(kSum),
1476 ::testing::DoubleEq(kMin),
1477 ::testing::DoubleEq(kMax), kCount))))));
1478 }
1479
TEST_F(OpenTelemetryPluginNPCMetricsTest,RegisterMultipleOpenTelemetryPlugins)1480 TEST_F(OpenTelemetryPluginNPCMetricsTest,
1481 RegisterMultipleOpenTelemetryPlugins) {
1482 constexpr absl::string_view kMetricName = "yet_another_double_histogram";
1483 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1484 "label_key_2"};
1485 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1486 "optional_label_key_1", "optional_label_key_2"};
1487 constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1488 "label_value_2"};
1489 constexpr std::array<absl::string_view, 2> kOptionalLabelValues = {
1490 "optional_label_value_1", "optional_label_value_2"};
1491 auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1492 kMetricName, "A simple double histogram.", "unit", kLabelKeys,
1493 kOptionalLabelKeys, /*enable_by_default=*/true);
1494 // Build and register a separate OpenTelemetryPlugin and verify its histogram
1495 // recording.
1496 grpc::internal::OpenTelemetryPluginBuilderImpl ot_builder;
1497 auto reader = BuildAndRegisterOpenTelemetryPlugin(std::move(
1498 Options()
1499 .set_metric_names({kMetricName})
1500 .set_server_selector([](const grpc_core::ChannelArgs& args) {
1501 return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1502 GRPC_ARG_SERVER_SELECTOR_VALUE;
1503 })
1504 .add_optional_label(kOptionalLabelKeys[0])
1505 .add_optional_label(kOptionalLabelKeys[1])));
1506 EXPECT_EQ(ot_builder.BuildAndRegisterGlobal(), absl::OkStatus());
1507 grpc_core::ChannelArgs args;
1508 args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1509 {
1510 constexpr double kHistogramValues[] = {1.23, 2.34, 3.45, 4.56};
1511 constexpr double kSum = 11.58;
1512 constexpr double kMin = 1.23;
1513 constexpr double kMax = 4.56;
1514 constexpr int kCount = 4;
1515 auto stats_plugins =
1516 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1517 for (auto v : kHistogramValues) {
1518 stats_plugins.RecordHistogram(handle, v, kLabelValues,
1519 kOptionalLabelValues);
1520 }
1521 auto data = ReadCurrentMetricsData(
1522 [&](const absl::flat_hash_map<
1523 std::string,
1524 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1525 data) { return !data.contains(kMetricName); },
1526 reader.get());
1527 EXPECT_THAT(
1528 data, ::testing::ElementsAre(::testing::Pair(
1529 kMetricName,
1530 ::testing::ElementsAre(::testing::AllOf(
1531 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1532 kOptionalLabelValues),
1533 HistogramResultEq(::testing::DoubleEq(kSum),
1534 ::testing::DoubleEq(kMin),
1535 ::testing::DoubleEq(kMax), kCount))))));
1536 }
1537 // Now build and register another OpenTelemetryPlugin using the test fixture
1538 // and record histogram.
1539 constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1540 4.4, 4.5, 5.5, 6.6};
1541 constexpr double kSum = 28.8;
1542 constexpr double kMin = 1.1;
1543 constexpr double kMax = 6.6;
1544 constexpr int kCount = 8;
1545 Init(std::move(
1546 Options()
1547 .set_metric_names({kMetricName})
1548 .set_server_selector([](const grpc_core::ChannelArgs& args) {
1549 return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1550 GRPC_ARG_SERVER_SELECTOR_VALUE;
1551 })
1552 .add_optional_label(kOptionalLabelKeys[0])
1553 .add_optional_label(kOptionalLabelKeys[1])));
1554 auto stats_plugins =
1555 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1556 for (auto v : kHistogramValues) {
1557 stats_plugins.RecordHistogram(handle, v, kLabelValues,
1558 kOptionalLabelValues);
1559 }
1560 auto data = ReadCurrentMetricsData(
1561 [&](const absl::flat_hash_map<
1562 std::string,
1563 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1564 data) { return !data.contains(kMetricName); });
1565 EXPECT_THAT(data,
1566 ::testing::ElementsAre(::testing::Pair(
1567 kMetricName,
1568 ::testing::ElementsAre(::testing::AllOf(
1569 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1570 kOptionalLabelValues),
1571 HistogramResultEq(::testing::DoubleEq(kSum),
1572 ::testing::DoubleEq(kMin),
1573 ::testing::DoubleEq(kMax), kCount))))));
1574 // Verify that the first plugin gets the data as well.
1575 data = ReadCurrentMetricsData(
1576 [&](const absl::flat_hash_map<
1577 std::string,
1578 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1579 data) { return !data.contains(kMetricName); },
1580 reader.get());
1581 EXPECT_THAT(data,
1582 ::testing::ElementsAre(::testing::Pair(
1583 kMetricName,
1584 ::testing::ElementsAre(::testing::AllOf(
1585 AttributesEq(kLabelKeys, kLabelValues, kOptionalLabelKeys,
1586 kOptionalLabelValues),
1587 HistogramResultEq(::testing::DoubleEq(kSum),
1588 ::testing::DoubleEq(kMin),
1589 ::testing::DoubleEq(kMax), kCount))))));
1590 }
1591
TEST_F(OpenTelemetryPluginNPCMetricsTest,DisabledOptionalLabelKeysShouldNotBeRecorded)1592 TEST_F(OpenTelemetryPluginNPCMetricsTest,
1593 DisabledOptionalLabelKeysShouldNotBeRecorded) {
1594 constexpr absl::string_view kMetricName =
1595 "yet_another_yet_another_double_histogram";
1596 constexpr double kHistogramValues[] = {1.1, 1.2, 2.2, 3.3,
1597 4.4, 4.5, 5.5, 6.6};
1598 constexpr double kSum = 28.8;
1599 constexpr double kMin = 1.1;
1600 constexpr double kMax = 6.6;
1601 constexpr double kCount = 8;
1602 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1603 "label_key_2"};
1604 constexpr std::array<absl::string_view, 4> kOptionalLabelKeys = {
1605 "optional_label_key_1", "optional_label_key_2", "optional_label_key_3",
1606 "optional_label_key_4"};
1607 constexpr std::array<absl::string_view, 3> kActualOptionalLabelKeys = {
1608 "optional_label_key_1", "optional_label_key_2", "optional_label_key_4"};
1609 constexpr std::array<absl::string_view, 2> kLabelValues = {"label_value_1",
1610 "label_value_2"};
1611 constexpr std::array<absl::string_view, 4> kOptionalLabelValues = {
1612 "optional_label_value_1", "optional_label_value_2",
1613 "optional_label_value_3", "optional_label_value_4"};
1614 constexpr std::array<absl::string_view, 3> kActualOptionalLabelValues = {
1615 "optional_label_value_1", "optional_label_value_2",
1616 "optional_label_value_4"};
1617 auto handle = grpc_core::GlobalInstrumentsRegistry::RegisterDoubleHistogram(
1618 kMetricName, "A simple double histogram.", "unit", kLabelKeys,
1619 kOptionalLabelKeys, /*enable_by_default=*/true);
1620 Init(std::move(
1621 Options()
1622 .set_metric_names({kMetricName})
1623 .set_server_selector([](const grpc_core::ChannelArgs& args) {
1624 return args.GetString(GRPC_ARG_SERVER_SELECTOR_KEY) ==
1625 GRPC_ARG_SERVER_SELECTOR_VALUE;
1626 })
1627 .add_optional_label(kOptionalLabelKeys[0])
1628 .add_optional_label(kOptionalLabelKeys[1])
1629 .add_optional_label(kOptionalLabelKeys[3])));
1630 grpc_core::ChannelArgs args;
1631 args = args.Set(GRPC_ARG_SERVER_SELECTOR_KEY, GRPC_ARG_SERVER_SELECTOR_VALUE);
1632 auto stats_plugins =
1633 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForServer(args);
1634 for (auto v : kHistogramValues) {
1635 stats_plugins.RecordHistogram(handle, v, kLabelValues,
1636 kOptionalLabelValues);
1637 }
1638 auto data = ReadCurrentMetricsData(
1639 [&](const absl::flat_hash_map<
1640 std::string,
1641 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1642 data) { return !data.contains(kMetricName); });
1643 EXPECT_THAT(
1644 data,
1645 ::testing::ElementsAre(::testing::Pair(
1646 kMetricName,
1647 ::testing::ElementsAre(::testing::AllOf(
1648 AttributesEq(kLabelKeys, kLabelValues, kActualOptionalLabelKeys,
1649 kActualOptionalLabelValues),
1650 HistogramResultEq(::testing::DoubleEq(kSum),
1651 ::testing::DoubleEq(kMin),
1652 ::testing::DoubleEq(kMax), kCount))))));
1653 }
1654
1655 using OpenTelemetryPluginCallbackMetricsTest = OpenTelemetryPluginEnd2EndTest;
1656
1657 // The callback minimal interval is longer than the OT reporting interval, so we
1658 // expect to collect duplicated (cached) values.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDurationLongerThanCollectDuration)1659 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
1660 ReportDurationLongerThanCollectDuration) {
1661 constexpr absl::string_view kInt64CallbackGaugeMetric =
1662 "int64_callback_gauge";
1663 constexpr absl::string_view kDoubleCallbackGaugeMetric =
1664 "double_callback_gauge";
1665 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1666 "label_key_2"};
1667 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1668 "optional_label_key_1", "optional_label_key_2"};
1669 constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
1670 "label_value_set_1", "label_value_set_1"};
1671 constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
1672 "optional_label_value_set_1", "optional_label_value_set_1"};
1673 constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
1674 "label_value_set_2", "label_value_set_2"};
1675 constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
1676 "optional_label_value_set_2", "optional_label_value_set_2"};
1677 auto integer_gauge_handle =
1678 grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1679 kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1680 kLabelKeys, kOptionalLabelKeys,
1681 /*enable_by_default=*/true);
1682 auto double_gauge_handle =
1683 grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1684 kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1685 kLabelKeys, kOptionalLabelKeys,
1686 /*enable_by_default=*/true);
1687 Init(std::move(Options()
1688 .set_metric_names({kInt64CallbackGaugeMetric,
1689 kDoubleCallbackGaugeMetric})
1690 .add_optional_label(kOptionalLabelKeys[0])
1691 .add_optional_label(kOptionalLabelKeys[1])));
1692 auto stats_plugins =
1693 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1694 grpc_core::experimental::StatsPluginChannelScope(
1695 "dns:///localhost:8080", ""));
1696 // Multiple callbacks for the same metrics, each reporting different label
1697 // values.
1698 int report_count_1 = 0;
1699 int64_t int_value_1 = 1;
1700 double double_value_1 = 0.5;
1701 auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
1702 [&](grpc_core::CallbackMetricReporter& reporter) {
1703 ++report_count_1;
1704 reporter.Report(integer_gauge_handle, int_value_1, kLabelValuesSet1,
1705 kOptionalLabelValuesSet1);
1706 reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet2,
1707 kOptionalLabelValuesSet2);
1708 reporter.Report(double_gauge_handle, double_value_1, kLabelValuesSet1,
1709 kOptionalLabelValuesSet1);
1710 reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet2,
1711 kOptionalLabelValuesSet2);
1712 },
1713 {integer_gauge_handle, double_gauge_handle},
1714 grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor());
1715 int report_count_2 = 0;
1716 int64_t int_value_2 = 1;
1717 double double_value_2 = 0.5;
1718 auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
1719 [&](grpc_core::CallbackMetricReporter& reporter) {
1720 ++report_count_2;
1721 reporter.Report(integer_gauge_handle, int_value_2, kLabelValuesSet1,
1722 kOptionalLabelValuesSet1);
1723 reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
1724 kOptionalLabelValuesSet2);
1725 reporter.Report(double_gauge_handle, double_value_2, kLabelValuesSet1,
1726 kOptionalLabelValuesSet1);
1727 reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
1728 kOptionalLabelValuesSet2);
1729 },
1730 {integer_gauge_handle, double_gauge_handle},
1731 grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor());
1732 constexpr int kIterations = 100;
1733 MetricsCollectorThread collector{
1734 this, grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor(),
1735 kIterations,
1736 [&](const absl::flat_hash_map<
1737 std::string,
1738 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1739 data) {
1740 return !data.contains(kInt64CallbackGaugeMetric) ||
1741 !data.contains(kDoubleCallbackGaugeMetric);
1742 }};
1743 absl::flat_hash_map<
1744 std::string,
1745 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
1746 data = collector.Stop();
1747 // Verify that data is incremental with duplications (cached values).
1748 EXPECT_LT(report_count_1, kIterations);
1749 EXPECT_LT(report_count_2, kIterations);
1750 EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
1751 data[kDoubleCallbackGaugeMetric].size());
1752 // Verify labels.
1753 ASSERT_THAT(
1754 data,
1755 ::testing::UnorderedElementsAre(
1756 ::testing::Pair(
1757 kInt64CallbackGaugeMetric,
1758 ::testing::Each(::testing::AnyOf(
1759 AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1760 kOptionalLabelValuesSet1),
1761 AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1762 kOptionalLabelValuesSet2)))),
1763 ::testing::Pair(
1764 kDoubleCallbackGaugeMetric,
1765 ::testing::Each(::testing::AnyOf(
1766 AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1767 kOptionalLabelValuesSet1),
1768 AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1769 kOptionalLabelValuesSet2))))));
1770 EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1771 kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1772 kOptionalLabelKeys, kOptionalLabelValuesSet1,
1773 int64_t(0), false));
1774 EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1775 kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1776 kOptionalLabelKeys, kOptionalLabelValuesSet2,
1777 int64_t(0), false));
1778 EXPECT_THAT(data,
1779 GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1780 kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1781 kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, false));
1782 EXPECT_THAT(data,
1783 GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1784 kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1785 kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, false));
1786 }
1787
1788 // The callback minimal interval is shorter than the OT reporting interval, so
1789 // for each collect we should go update the cache and report the latest values.
TEST_F(OpenTelemetryPluginCallbackMetricsTest,ReportDurationShorterThanCollectDuration)1790 TEST_F(OpenTelemetryPluginCallbackMetricsTest,
1791 ReportDurationShorterThanCollectDuration) {
1792 constexpr absl::string_view kInt64CallbackGaugeMetric =
1793 "yet_another_int64_callback_gauge";
1794 constexpr absl::string_view kDoubleCallbackGaugeMetric =
1795 "yet_another_double_callback_gauge";
1796 constexpr std::array<absl::string_view, 2> kLabelKeys = {"label_key_1",
1797 "label_key_2"};
1798 constexpr std::array<absl::string_view, 2> kOptionalLabelKeys = {
1799 "optional_label_key_1", "optional_label_key_2"};
1800 constexpr std::array<absl::string_view, 2> kLabelValuesSet1 = {
1801 "label_value_set_1", "label_value_set_1"};
1802 constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet1 = {
1803 "optional_label_value_set_1", "optional_label_value_set_1"};
1804 constexpr std::array<absl::string_view, 2> kLabelValuesSet2 = {
1805 "label_value_set_2", "label_value_set_2"};
1806 constexpr std::array<absl::string_view, 2> kOptionalLabelValuesSet2 = {
1807 "optional_label_value_set_2", "optional_label_value_set_2"};
1808 auto integer_gauge_handle =
1809 grpc_core::GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
1810 kInt64CallbackGaugeMetric, "An int64 callback gauge.", "unit",
1811 kLabelKeys, kOptionalLabelKeys,
1812 /*enable_by_default=*/true);
1813 auto double_gauge_handle =
1814 grpc_core::GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
1815 kDoubleCallbackGaugeMetric, "A double callback gauge.", "unit",
1816 kLabelKeys, kOptionalLabelKeys,
1817 /*enable_by_default=*/true);
1818 Init(std::move(Options()
1819 .set_metric_names({kInt64CallbackGaugeMetric,
1820 kDoubleCallbackGaugeMetric})
1821 .add_optional_label(kOptionalLabelKeys[0])
1822 .add_optional_label(kOptionalLabelKeys[1])));
1823 auto stats_plugins =
1824 grpc_core::GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
1825 grpc_core::experimental::StatsPluginChannelScope(
1826 "dns:///localhost:8080", ""));
1827 // Multiple callbacks for the same metrics, each reporting different label
1828 // values.
1829 int report_count_1 = 0;
1830 int64_t int_value_1 = 1;
1831 double double_value_1 = 0.5;
1832 auto registered_metric_callback_1 = stats_plugins.RegisterCallback(
1833 [&](grpc_core::CallbackMetricReporter& reporter) {
1834 ++report_count_1;
1835 reporter.Report(integer_gauge_handle, int_value_1, kLabelValuesSet1,
1836 kOptionalLabelValuesSet1);
1837 reporter.Report(integer_gauge_handle, int_value_1++, kLabelValuesSet2,
1838 kOptionalLabelValuesSet2);
1839 reporter.Report(double_gauge_handle, double_value_1, kLabelValuesSet1,
1840 kOptionalLabelValuesSet1);
1841 reporter.Report(double_gauge_handle, double_value_1++, kLabelValuesSet2,
1842 kOptionalLabelValuesSet2);
1843 },
1844 {integer_gauge_handle, double_gauge_handle},
1845 grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor());
1846 int report_count_2 = 0;
1847 int64_t int_value_2 = 1;
1848 double double_value_2 = 0.5;
1849 auto registered_metric_callback_2 = stats_plugins.RegisterCallback(
1850 [&](grpc_core::CallbackMetricReporter& reporter) {
1851 ++report_count_2;
1852 reporter.Report(integer_gauge_handle, int_value_2, kLabelValuesSet1,
1853 kOptionalLabelValuesSet1);
1854 reporter.Report(integer_gauge_handle, int_value_2++, kLabelValuesSet2,
1855 kOptionalLabelValuesSet2);
1856 reporter.Report(double_gauge_handle, double_value_2, kLabelValuesSet1,
1857 kOptionalLabelValuesSet1);
1858 reporter.Report(double_gauge_handle, double_value_2++, kLabelValuesSet2,
1859 kOptionalLabelValuesSet2);
1860 },
1861 {integer_gauge_handle, double_gauge_handle},
1862 grpc_core::Duration::Milliseconds(10) * grpc_test_slowdown_factor());
1863 constexpr int kIterations = 100;
1864 MetricsCollectorThread collector{
1865 this,
1866 grpc_core::Duration::Milliseconds(100) * grpc_test_slowdown_factor(),
1867 kIterations,
1868 [&](const absl::flat_hash_map<
1869 std::string,
1870 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>&
1871 data) {
1872 return !data.contains(kInt64CallbackGaugeMetric) ||
1873 !data.contains(kDoubleCallbackGaugeMetric);
1874 }};
1875 absl::flat_hash_map<
1876 std::string,
1877 std::vector<opentelemetry::sdk::metrics::PointDataAttributes>>
1878 data = collector.Stop();
1879 // Verify that data is incremental without duplications (cached values).
1880 EXPECT_EQ(report_count_1, kIterations);
1881 EXPECT_EQ(report_count_2, kIterations);
1882 EXPECT_EQ(data[kInt64CallbackGaugeMetric].size(),
1883 data[kDoubleCallbackGaugeMetric].size());
1884 // Verify labels.
1885 ASSERT_THAT(
1886 data,
1887 ::testing::UnorderedElementsAre(
1888 ::testing::Pair(
1889 kInt64CallbackGaugeMetric,
1890 ::testing::Each(::testing::AnyOf(
1891 AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1892 kOptionalLabelValuesSet1),
1893 AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1894 kOptionalLabelValuesSet2)))),
1895 ::testing::Pair(
1896 kDoubleCallbackGaugeMetric,
1897 ::testing::Each(::testing::AnyOf(
1898 AttributesEq(kLabelKeys, kLabelValuesSet1, kOptionalLabelKeys,
1899 kOptionalLabelValuesSet1),
1900 AttributesEq(kLabelKeys, kLabelValuesSet2, kOptionalLabelKeys,
1901 kOptionalLabelValuesSet2))))));
1902 EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1903 kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1904 kOptionalLabelKeys, kOptionalLabelValuesSet1,
1905 int64_t(0), true));
1906 EXPECT_THAT(data, GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1907 kInt64CallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1908 kOptionalLabelKeys, kOptionalLabelValuesSet2,
1909 int64_t(0), true));
1910 EXPECT_THAT(data,
1911 GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1912 kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet1,
1913 kOptionalLabelKeys, kOptionalLabelValuesSet1, 0.0, true));
1914 EXPECT_THAT(data,
1915 GaugeDataIsIncrementalForSpecificMetricAndLabelSet(
1916 kDoubleCallbackGaugeMetric, kLabelKeys, kLabelValuesSet2,
1917 kOptionalLabelKeys, kOptionalLabelValuesSet2, 0.0, true));
1918 }
1919
TEST(OpenTelemetryPluginMetricsEnablingDisablingTest,TestEnableDisableAPIs)1920 TEST(OpenTelemetryPluginMetricsEnablingDisablingTest, TestEnableDisableAPIs) {
1921 grpc::internal::OpenTelemetryPluginBuilderImpl builder;
1922 // First disable all metrics
1923 builder.DisableAllMetrics();
1924 EXPECT_TRUE(builder.TestOnlyEnabledMetrics().empty());
1925 // Add in a few metrics
1926 builder.EnableMetrics(
1927 {"grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"});
1928 EXPECT_THAT(
1929 builder.TestOnlyEnabledMetrics(),
1930 ::testing::UnorderedElementsAre(
1931 "grpc.test.metric_1", "grpc.test.metric_2", "grpc.test.metric_3"));
1932 // Now remove a few metrics
1933 builder.DisableMetrics({"grpc.test.metric_1", "grpc.test.metric_2"});
1934 EXPECT_THAT(builder.TestOnlyEnabledMetrics(),
1935 ::testing::UnorderedElementsAre("grpc.test.metric_3"));
1936 }
1937
1938 } // namespace
1939 } // namespace testing
1940 } // namespace grpc
1941
main(int argc,char ** argv)1942 int main(int argc, char** argv) {
1943 grpc::testing::TestEnvironment env(&argc, argv);
1944 ::testing::InitGoogleTest(&argc, argv);
1945 return RUN_ALL_TESTS();
1946 }
1947