[RLS] implement non-per-call metrics (#36001)
Closes #36001
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36001 from markdroth:non_per_call_metrics_rls b713980f21
PiperOrigin-RevId: 612532005
This commit is contained in:
parent
0213523907
commit
c43f1a63b0
|
|
@ -2278,6 +2278,7 @@ add_library(grpc
|
|||
src/core/lib/gprpp/status_helper.cc
|
||||
src/core/lib/gprpp/time.cc
|
||||
src/core/lib/gprpp/time_averaged_stats.cc
|
||||
src/core/lib/gprpp/uuid_v4.cc
|
||||
src/core/lib/gprpp/validation_errors.cc
|
||||
src/core/lib/gprpp/windows/directory_reader.cc
|
||||
src/core/lib/gprpp/work_serializer.cc
|
||||
|
|
@ -3046,6 +3047,7 @@ add_library(grpc_unsecure
|
|||
src/core/lib/gprpp/status_helper.cc
|
||||
src/core/lib/gprpp/time.cc
|
||||
src/core/lib/gprpp/time_averaged_stats.cc
|
||||
src/core/lib/gprpp/uuid_v4.cc
|
||||
src/core/lib/gprpp/validation_errors.cc
|
||||
src/core/lib/gprpp/work_serializer.cc
|
||||
src/core/lib/handshaker/proxy_mapper_registry.cc
|
||||
|
|
@ -25839,6 +25841,7 @@ add_executable(rls_end2end_test
|
|||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
|
||||
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
|
||||
test/core/util/fake_stats_plugin.cc
|
||||
test/core/util/test_lb_policies.cc
|
||||
test/cpp/end2end/rls_end2end_test.cc
|
||||
test/cpp/end2end/rls_server.cc
|
||||
|
|
@ -31537,7 +31540,6 @@ endif()
|
|||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(uuid_v4_test
|
||||
src/core/lib/gprpp/uuid_v4.cc
|
||||
test/core/gprpp/uuid_v4_test.cc
|
||||
)
|
||||
if(WIN32 AND MSVC)
|
||||
|
|
|
|||
|
|
@ -1459,6 +1459,7 @@ LIBGRPC_SRC = \
|
|||
src/core/lib/gprpp/status_helper.cc \
|
||||
src/core/lib/gprpp/time.cc \
|
||||
src/core/lib/gprpp/time_averaged_stats.cc \
|
||||
src/core/lib/gprpp/uuid_v4.cc \
|
||||
src/core/lib/gprpp/validation_errors.cc \
|
||||
src/core/lib/gprpp/windows/directory_reader.cc \
|
||||
src/core/lib/gprpp/work_serializer.cc \
|
||||
|
|
@ -2060,6 +2061,7 @@ LIBGRPC_UNSECURE_SRC = \
|
|||
src/core/lib/gprpp/status_helper.cc \
|
||||
src/core/lib/gprpp/time.cc \
|
||||
src/core/lib/gprpp/time_averaged_stats.cc \
|
||||
src/core/lib/gprpp/uuid_v4.cc \
|
||||
src/core/lib/gprpp/validation_errors.cc \
|
||||
src/core/lib/gprpp/work_serializer.cc \
|
||||
src/core/lib/handshaker/proxy_mapper_registry.cc \
|
||||
|
|
|
|||
|
|
@ -1393,6 +1393,8 @@ let package = Package(
|
|||
"src/core/lib/gprpp/time_util.h",
|
||||
"src/core/lib/gprpp/type_list.h",
|
||||
"src/core/lib/gprpp/unique_type_name.h",
|
||||
"src/core/lib/gprpp/uuid_v4.cc",
|
||||
"src/core/lib/gprpp/uuid_v4.h",
|
||||
"src/core/lib/gprpp/validation_errors.cc",
|
||||
"src/core/lib/gprpp/validation_errors.h",
|
||||
"src/core/lib/gprpp/windows/directory_reader.cc",
|
||||
|
|
@ -1888,6 +1890,7 @@ let package = Package(
|
|||
"src/core/load_balancing/ring_hash/ring_hash.cc",
|
||||
"src/core/load_balancing/ring_hash/ring_hash.h",
|
||||
"src/core/load_balancing/rls/rls.cc",
|
||||
"src/core/load_balancing/rls/rls.h",
|
||||
"src/core/load_balancing/round_robin/round_robin.cc",
|
||||
"src/core/load_balancing/subchannel_interface.h",
|
||||
"src/core/load_balancing/subchannel_list.h",
|
||||
|
|
|
|||
|
|
@ -926,6 +926,7 @@ libs:
|
|||
- src/core/lib/gprpp/time_averaged_stats.h
|
||||
- src/core/lib/gprpp/type_list.h
|
||||
- src/core/lib/gprpp/unique_type_name.h
|
||||
- src/core/lib/gprpp/uuid_v4.h
|
||||
- src/core/lib/gprpp/validation_errors.h
|
||||
- src/core/lib/gprpp/work_serializer.h
|
||||
- src/core/lib/gprpp/xxhash_inline.h
|
||||
|
|
@ -1178,6 +1179,7 @@ libs:
|
|||
- src/core/load_balancing/outlier_detection/outlier_detection.h
|
||||
- src/core/load_balancing/pick_first/pick_first.h
|
||||
- src/core/load_balancing/ring_hash/ring_hash.h
|
||||
- src/core/load_balancing/rls/rls.h
|
||||
- src/core/load_balancing/subchannel_interface.h
|
||||
- src/core/load_balancing/subchannel_list.h
|
||||
- src/core/load_balancing/weighted_round_robin/static_stride_scheduler.h
|
||||
|
|
@ -1738,6 +1740,7 @@ libs:
|
|||
- src/core/lib/gprpp/status_helper.cc
|
||||
- src/core/lib/gprpp/time.cc
|
||||
- src/core/lib/gprpp/time_averaged_stats.cc
|
||||
- src/core/lib/gprpp/uuid_v4.cc
|
||||
- src/core/lib/gprpp/validation_errors.cc
|
||||
- src/core/lib/gprpp/windows/directory_reader.cc
|
||||
- src/core/lib/gprpp/work_serializer.cc
|
||||
|
|
@ -2428,6 +2431,7 @@ libs:
|
|||
- src/core/lib/gprpp/time_averaged_stats.h
|
||||
- src/core/lib/gprpp/type_list.h
|
||||
- src/core/lib/gprpp/unique_type_name.h
|
||||
- src/core/lib/gprpp/uuid_v4.h
|
||||
- src/core/lib/gprpp/validation_errors.h
|
||||
- src/core/lib/gprpp/work_serializer.h
|
||||
- src/core/lib/handshaker/proxy_mapper.h
|
||||
|
|
@ -2644,6 +2648,7 @@ libs:
|
|||
- src/core/load_balancing/oob_backend_metric_internal.h
|
||||
- src/core/load_balancing/outlier_detection/outlier_detection.h
|
||||
- src/core/load_balancing/pick_first/pick_first.h
|
||||
- src/core/load_balancing/rls/rls.h
|
||||
- src/core/load_balancing/subchannel_interface.h
|
||||
- src/core/load_balancing/subchannel_list.h
|
||||
- src/core/load_balancing/weighted_round_robin/static_stride_scheduler.h
|
||||
|
|
@ -2863,6 +2868,7 @@ libs:
|
|||
- src/core/lib/gprpp/status_helper.cc
|
||||
- src/core/lib/gprpp/time.cc
|
||||
- src/core/lib/gprpp/time_averaged_stats.cc
|
||||
- src/core/lib/gprpp/uuid_v4.cc
|
||||
- src/core/lib/gprpp/validation_errors.cc
|
||||
- src/core/lib/gprpp/work_serializer.cc
|
||||
- src/core/lib/handshaker/proxy_mapper_registry.cc
|
||||
|
|
@ -16869,6 +16875,7 @@ targets:
|
|||
run: false
|
||||
language: c++
|
||||
headers:
|
||||
- test/core/util/fake_stats_plugin.h
|
||||
- test/core/util/test_lb_policies.h
|
||||
- test/cpp/end2end/counted_service.h
|
||||
- test/cpp/end2end/rls_server.h
|
||||
|
|
@ -16880,6 +16887,7 @@ targets:
|
|||
- src/proto/grpc/testing/echo_messages.proto
|
||||
- src/proto/grpc/testing/simple_messages.proto
|
||||
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
|
||||
- test/core/util/fake_stats_plugin.cc
|
||||
- test/core/util/test_lb_policies.cc
|
||||
- test/cpp/end2end/rls_end2end_test.cc
|
||||
- test/cpp/end2end/rls_server.cc
|
||||
|
|
@ -19503,10 +19511,8 @@ targets:
|
|||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers:
|
||||
- src/core/lib/gprpp/uuid_v4.h
|
||||
headers: []
|
||||
src:
|
||||
- src/core/lib/gprpp/uuid_v4.cc
|
||||
- test/core/gprpp/uuid_v4_test.cc
|
||||
deps:
|
||||
- gtest
|
||||
|
|
|
|||
|
|
@ -584,6 +584,7 @@ if test "$PHP_GRPC" != "no"; then
|
|||
src/core/lib/gprpp/time.cc \
|
||||
src/core/lib/gprpp/time_averaged_stats.cc \
|
||||
src/core/lib/gprpp/time_util.cc \
|
||||
src/core/lib/gprpp/uuid_v4.cc \
|
||||
src/core/lib/gprpp/validation_errors.cc \
|
||||
src/core/lib/gprpp/windows/directory_reader.cc \
|
||||
src/core/lib/gprpp/windows/env.cc \
|
||||
|
|
|
|||
|
|
@ -549,6 +549,7 @@ if (PHP_GRPC != "no") {
|
|||
"src\\core\\lib\\gprpp\\time.cc " +
|
||||
"src\\core\\lib\\gprpp\\time_averaged_stats.cc " +
|
||||
"src\\core\\lib\\gprpp\\time_util.cc " +
|
||||
"src\\core\\lib\\gprpp\\uuid_v4.cc " +
|
||||
"src\\core\\lib\\gprpp\\validation_errors.cc " +
|
||||
"src\\core\\lib\\gprpp\\windows\\directory_reader.cc " +
|
||||
"src\\core\\lib\\gprpp\\windows\\env.cc " +
|
||||
|
|
|
|||
|
|
@ -1032,6 +1032,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/time_util.h',
|
||||
'src/core/lib/gprpp/type_list.h',
|
||||
'src/core/lib/gprpp/unique_type_name.h',
|
||||
'src/core/lib/gprpp/uuid_v4.h',
|
||||
'src/core/lib/gprpp/validation_errors.h',
|
||||
'src/core/lib/gprpp/work_serializer.h',
|
||||
'src/core/lib/gprpp/xxhash_inline.h',
|
||||
|
|
@ -1284,6 +1285,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/load_balancing/outlier_detection/outlier_detection.h',
|
||||
'src/core/load_balancing/pick_first/pick_first.h',
|
||||
'src/core/load_balancing/ring_hash/ring_hash.h',
|
||||
'src/core/load_balancing/rls/rls.h',
|
||||
'src/core/load_balancing/subchannel_interface.h',
|
||||
'src/core/load_balancing/subchannel_list.h',
|
||||
'src/core/load_balancing/weighted_round_robin/static_stride_scheduler.h',
|
||||
|
|
@ -2293,6 +2295,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/time_util.h',
|
||||
'src/core/lib/gprpp/type_list.h',
|
||||
'src/core/lib/gprpp/unique_type_name.h',
|
||||
'src/core/lib/gprpp/uuid_v4.h',
|
||||
'src/core/lib/gprpp/validation_errors.h',
|
||||
'src/core/lib/gprpp/work_serializer.h',
|
||||
'src/core/lib/gprpp/xxhash_inline.h',
|
||||
|
|
@ -2545,6 +2548,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/load_balancing/outlier_detection/outlier_detection.h',
|
||||
'src/core/load_balancing/pick_first/pick_first.h',
|
||||
'src/core/load_balancing/ring_hash/ring_hash.h',
|
||||
'src/core/load_balancing/rls/rls.h',
|
||||
'src/core/load_balancing/subchannel_interface.h',
|
||||
'src/core/load_balancing/subchannel_list.h',
|
||||
'src/core/load_balancing/weighted_round_robin/static_stride_scheduler.h',
|
||||
|
|
|
|||
|
|
@ -1507,6 +1507,8 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/time_util.h',
|
||||
'src/core/lib/gprpp/type_list.h',
|
||||
'src/core/lib/gprpp/unique_type_name.h',
|
||||
'src/core/lib/gprpp/uuid_v4.cc',
|
||||
'src/core/lib/gprpp/uuid_v4.h',
|
||||
'src/core/lib/gprpp/validation_errors.cc',
|
||||
'src/core/lib/gprpp/validation_errors.h',
|
||||
'src/core/lib/gprpp/windows/directory_reader.cc',
|
||||
|
|
@ -1998,6 +2000,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/load_balancing/ring_hash/ring_hash.cc',
|
||||
'src/core/load_balancing/ring_hash/ring_hash.h',
|
||||
'src/core/load_balancing/rls/rls.cc',
|
||||
'src/core/load_balancing/rls/rls.h',
|
||||
'src/core/load_balancing/round_robin/round_robin.cc',
|
||||
'src/core/load_balancing/subchannel_interface.h',
|
||||
'src/core/load_balancing/subchannel_list.h',
|
||||
|
|
@ -3073,6 +3076,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/time_util.h',
|
||||
'src/core/lib/gprpp/type_list.h',
|
||||
'src/core/lib/gprpp/unique_type_name.h',
|
||||
'src/core/lib/gprpp/uuid_v4.h',
|
||||
'src/core/lib/gprpp/validation_errors.h',
|
||||
'src/core/lib/gprpp/work_serializer.h',
|
||||
'src/core/lib/gprpp/xxhash_inline.h',
|
||||
|
|
@ -3325,6 +3329,7 @@ Pod::Spec.new do |s|
|
|||
'src/core/load_balancing/outlier_detection/outlier_detection.h',
|
||||
'src/core/load_balancing/pick_first/pick_first.h',
|
||||
'src/core/load_balancing/ring_hash/ring_hash.h',
|
||||
'src/core/load_balancing/rls/rls.h',
|
||||
'src/core/load_balancing/subchannel_interface.h',
|
||||
'src/core/load_balancing/subchannel_list.h',
|
||||
'src/core/load_balancing/weighted_round_robin/static_stride_scheduler.h',
|
||||
|
|
|
|||
|
|
@ -1399,6 +1399,8 @@ Gem::Specification.new do |s|
|
|||
s.files += %w( src/core/lib/gprpp/time_util.h )
|
||||
s.files += %w( src/core/lib/gprpp/type_list.h )
|
||||
s.files += %w( src/core/lib/gprpp/unique_type_name.h )
|
||||
s.files += %w( src/core/lib/gprpp/uuid_v4.cc )
|
||||
s.files += %w( src/core/lib/gprpp/uuid_v4.h )
|
||||
s.files += %w( src/core/lib/gprpp/validation_errors.cc )
|
||||
s.files += %w( src/core/lib/gprpp/validation_errors.h )
|
||||
s.files += %w( src/core/lib/gprpp/windows/directory_reader.cc )
|
||||
|
|
@ -1890,6 +1892,7 @@ Gem::Specification.new do |s|
|
|||
s.files += %w( src/core/load_balancing/ring_hash/ring_hash.cc )
|
||||
s.files += %w( src/core/load_balancing/ring_hash/ring_hash.h )
|
||||
s.files += %w( src/core/load_balancing/rls/rls.cc )
|
||||
s.files += %w( src/core/load_balancing/rls/rls.h )
|
||||
s.files += %w( src/core/load_balancing/round_robin/round_robin.cc )
|
||||
s.files += %w( src/core/load_balancing/subchannel_interface.h )
|
||||
s.files += %w( src/core/load_balancing/subchannel_list.h )
|
||||
|
|
|
|||
|
|
@ -774,6 +774,7 @@
|
|||
'src/core/lib/gprpp/status_helper.cc',
|
||||
'src/core/lib/gprpp/time.cc',
|
||||
'src/core/lib/gprpp/time_averaged_stats.cc',
|
||||
'src/core/lib/gprpp/uuid_v4.cc',
|
||||
'src/core/lib/gprpp/validation_errors.cc',
|
||||
'src/core/lib/gprpp/windows/directory_reader.cc',
|
||||
'src/core/lib/gprpp/work_serializer.cc',
|
||||
|
|
@ -1316,6 +1317,7 @@
|
|||
'src/core/lib/gprpp/status_helper.cc',
|
||||
'src/core/lib/gprpp/time.cc',
|
||||
'src/core/lib/gprpp/time_averaged_stats.cc',
|
||||
'src/core/lib/gprpp/uuid_v4.cc',
|
||||
'src/core/lib/gprpp/validation_errors.cc',
|
||||
'src/core/lib/gprpp/work_serializer.cc',
|
||||
'src/core/lib/handshaker/proxy_mapper_registry.cc',
|
||||
|
|
|
|||
|
|
@ -1381,6 +1381,8 @@
|
|||
<file baseinstalldir="/" name="src/core/lib/gprpp/time_util.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/type_list.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/unique_type_name.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/uuid_v4.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/uuid_v4.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/validation_errors.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/validation_errors.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/windows/directory_reader.cc" role="src" />
|
||||
|
|
@ -1872,6 +1874,7 @@
|
|||
<file baseinstalldir="/" name="src/core/load_balancing/ring_hash/ring_hash.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/load_balancing/ring_hash/ring_hash.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/load_balancing/rls/rls.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/load_balancing/rls/rls.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/load_balancing/round_robin/round_robin.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/load_balancing/subchannel_interface.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/load_balancing/subchannel_list.h" role="src" />
|
||||
|
|
|
|||
|
|
@ -4802,9 +4802,13 @@ grpc_cc_library(
|
|||
srcs = [
|
||||
"load_balancing/rls/rls.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"load_balancing/rls/rls.h",
|
||||
],
|
||||
external_deps = [
|
||||
"absl/base:core_headers",
|
||||
"absl/hash",
|
||||
"absl/random",
|
||||
"absl/status",
|
||||
"absl/status:statusor",
|
||||
"absl/strings",
|
||||
|
|
@ -4830,11 +4834,14 @@ grpc_cc_library(
|
|||
"lb_policy",
|
||||
"lb_policy_factory",
|
||||
"lb_policy_registry",
|
||||
"match",
|
||||
"metrics",
|
||||
"pollset_set",
|
||||
"slice",
|
||||
"slice_refcount",
|
||||
"status_helper",
|
||||
"time",
|
||||
"uuid_v4",
|
||||
"validation_errors",
|
||||
"//:backoff",
|
||||
"//:channel",
|
||||
|
|
@ -7560,6 +7567,7 @@ grpc_cc_library(
|
|||
],
|
||||
external_deps = [
|
||||
"absl/container:flat_hash_map",
|
||||
"absl/functional:any_invocable",
|
||||
"absl/functional:function_ref",
|
||||
"absl/strings",
|
||||
"absl/types:span",
|
||||
|
|
@ -7568,6 +7576,7 @@ grpc_cc_library(
|
|||
deps = [
|
||||
"channel_args",
|
||||
"no_destruct",
|
||||
"time",
|
||||
"//:gpr",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -149,6 +149,122 @@ GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
|||
return handle;
|
||||
}
|
||||
|
||||
GlobalInstrumentsRegistry::GlobalInt64GaugeHandle
|
||||
GlobalInstrumentsRegistry::RegisterInt64Gauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default) {
|
||||
auto& instruments = GetInstrumentList();
|
||||
if (instruments.find(name) != instruments.end()) {
|
||||
Crash(absl::StrFormat("Metric name %s has already been registered.", name));
|
||||
}
|
||||
uint32_t index = instruments.size();
|
||||
GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
|
||||
GlobalInstrumentDescriptor descriptor;
|
||||
descriptor.value_type = ValueType::kInt64;
|
||||
descriptor.instrument_type = InstrumentType::kGauge;
|
||||
descriptor.index = index;
|
||||
descriptor.enable_by_default = enable_by_default;
|
||||
descriptor.name = name;
|
||||
descriptor.description = description;
|
||||
descriptor.unit = unit;
|
||||
descriptor.label_keys = {label_keys.begin(), label_keys.end()};
|
||||
descriptor.optional_label_keys = {optional_label_keys.begin(),
|
||||
optional_label_keys.end()};
|
||||
instruments.emplace(name, std::move(descriptor));
|
||||
GlobalInt64GaugeHandle handle;
|
||||
handle.index = index;
|
||||
return handle;
|
||||
}
|
||||
|
||||
GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle
|
||||
GlobalInstrumentsRegistry::RegisterDoubleGauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default) {
|
||||
auto& instruments = GetInstrumentList();
|
||||
if (instruments.find(name) != instruments.end()) {
|
||||
Crash(absl::StrFormat("Metric name %s has already been registered.", name));
|
||||
}
|
||||
uint32_t index = instruments.size();
|
||||
GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
|
||||
GlobalInstrumentDescriptor descriptor;
|
||||
descriptor.value_type = ValueType::kDouble;
|
||||
descriptor.instrument_type = InstrumentType::kGauge;
|
||||
descriptor.index = index;
|
||||
descriptor.enable_by_default = enable_by_default;
|
||||
descriptor.name = name;
|
||||
descriptor.description = description;
|
||||
descriptor.unit = unit;
|
||||
descriptor.label_keys = {label_keys.begin(), label_keys.end()};
|
||||
descriptor.optional_label_keys = {optional_label_keys.begin(),
|
||||
optional_label_keys.end()};
|
||||
instruments.emplace(name, std::move(descriptor));
|
||||
GlobalDoubleGaugeHandle handle;
|
||||
handle.index = index;
|
||||
return handle;
|
||||
}
|
||||
|
||||
GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle
|
||||
GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default) {
|
||||
auto& instruments = GetInstrumentList();
|
||||
if (instruments.find(name) != instruments.end()) {
|
||||
Crash(absl::StrFormat("Metric name %s has already been registered.", name));
|
||||
}
|
||||
uint32_t index = instruments.size();
|
||||
GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
|
||||
GlobalInstrumentDescriptor descriptor;
|
||||
descriptor.value_type = ValueType::kInt64;
|
||||
descriptor.instrument_type = InstrumentType::kCallbackGauge;
|
||||
descriptor.index = index;
|
||||
descriptor.enable_by_default = enable_by_default;
|
||||
descriptor.name = name;
|
||||
descriptor.description = description;
|
||||
descriptor.unit = unit;
|
||||
descriptor.label_keys = {label_keys.begin(), label_keys.end()};
|
||||
descriptor.optional_label_keys = {optional_label_keys.begin(),
|
||||
optional_label_keys.end()};
|
||||
instruments.emplace(name, std::move(descriptor));
|
||||
GlobalCallbackInt64GaugeHandle handle;
|
||||
handle.index = index;
|
||||
return handle;
|
||||
}
|
||||
|
||||
GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle
|
||||
GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default) {
|
||||
auto& instruments = GetInstrumentList();
|
||||
if (instruments.find(name) != instruments.end()) {
|
||||
Crash(absl::StrFormat("Metric name %s has already been registered.", name));
|
||||
}
|
||||
uint32_t index = instruments.size();
|
||||
GPR_ASSERT(index < std::numeric_limits<uint32_t>::max());
|
||||
GlobalInstrumentDescriptor descriptor;
|
||||
descriptor.value_type = ValueType::kDouble;
|
||||
descriptor.instrument_type = InstrumentType::kCallbackGauge;
|
||||
descriptor.index = index;
|
||||
descriptor.enable_by_default = enable_by_default;
|
||||
descriptor.name = name;
|
||||
descriptor.description = description;
|
||||
descriptor.unit = unit;
|
||||
descriptor.label_keys = {label_keys.begin(), label_keys.end()};
|
||||
descriptor.optional_label_keys = {optional_label_keys.begin(),
|
||||
optional_label_keys.end()};
|
||||
instruments.emplace(name, std::move(descriptor));
|
||||
GlobalCallbackDoubleGaugeHandle handle;
|
||||
handle.index = index;
|
||||
return handle;
|
||||
}
|
||||
|
||||
void GlobalInstrumentsRegistry::ForEach(
|
||||
absl::FunctionRef<void(const GlobalInstrumentDescriptor&)> f) {
|
||||
for (const auto& instrument : GetInstrumentList()) {
|
||||
|
|
@ -156,6 +272,35 @@ void GlobalInstrumentsRegistry::ForEach(
|
|||
}
|
||||
}
|
||||
|
||||
RegisteredMetricCallback::RegisteredMetricCallback(
|
||||
GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group,
|
||||
absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
|
||||
std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
|
||||
Duration min_interval)
|
||||
: stats_plugin_group_(stats_plugin_group),
|
||||
callback_(std::move(callback)),
|
||||
metrics_(std::move(metrics)),
|
||||
min_interval_(min_interval) {
|
||||
for (auto& plugin : stats_plugin_group_.plugins_) {
|
||||
plugin->AddCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
RegisteredMetricCallback::~RegisteredMetricCallback() {
|
||||
for (auto& plugin : stats_plugin_group_.plugins_) {
|
||||
plugin->RemoveCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<RegisteredMetricCallback>
|
||||
GlobalStatsPluginRegistry::StatsPluginGroup::RegisterCallback(
|
||||
absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
|
||||
std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
|
||||
Duration min_interval) {
|
||||
return std::make_unique<RegisteredMetricCallback>(
|
||||
*this, std::move(callback), std::move(metrics), min_interval);
|
||||
}
|
||||
|
||||
NoDestruct<Mutex> GlobalStatsPluginRegistry::mutex_;
|
||||
NoDestruct<std::vector<std::shared_ptr<StatsPlugin>>>
|
||||
GlobalStatsPluginRegistry::plugins_;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/functional/function_ref.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/span.h"
|
||||
|
|
@ -31,20 +32,22 @@
|
|||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/gprpp/no_destruct.h"
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/gprpp/time.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
constexpr absl::string_view kMetricLabelTarget = "grpc.target";
|
||||
|
||||
// A global registry of instruments(metrics). This API is designed to be used to
|
||||
// register instruments (Counter and Histogram) as part of program startup,
|
||||
// before the execution of the main function (during dynamic initialization
|
||||
// time). Using this API after the main function begins may result into missing
|
||||
// instruments. This API is thread-unsafe.
|
||||
// A global registry of instruments(metrics). This API is designed to be used
|
||||
// to register instruments (Counter, Histogram, and Gauge) as part of program
|
||||
// startup, before the execution of the main function (during dynamic
|
||||
// initialization time). Using this API after the main function begins may
|
||||
// result into missing instruments. This API is thread-unsafe.
|
||||
class GlobalInstrumentsRegistry {
|
||||
public:
|
||||
enum class ValueType {
|
||||
kUndefined,
|
||||
kInt64,
|
||||
kUInt64,
|
||||
kDouble,
|
||||
};
|
||||
|
|
@ -52,6 +55,8 @@ class GlobalInstrumentsRegistry {
|
|||
kUndefined,
|
||||
kCounter,
|
||||
kHistogram,
|
||||
kGauge,
|
||||
kCallbackGauge,
|
||||
};
|
||||
struct GlobalInstrumentDescriptor {
|
||||
ValueType value_type;
|
||||
|
|
@ -75,6 +80,11 @@ class GlobalInstrumentsRegistry {
|
|||
struct GlobalDoubleCounterHandle : public GlobalHandle {};
|
||||
struct GlobalUInt64HistogramHandle : public GlobalHandle {};
|
||||
struct GlobalDoubleHistogramHandle : public GlobalHandle {};
|
||||
struct GlobalInt64GaugeHandle : public GlobalHandle {};
|
||||
struct GlobalDoubleGaugeHandle : public GlobalHandle {};
|
||||
struct GlobalCallbackHandle : public GlobalHandle {};
|
||||
struct GlobalCallbackInt64GaugeHandle : public GlobalCallbackHandle {};
|
||||
struct GlobalCallbackDoubleGaugeHandle : public GlobalCallbackHandle {};
|
||||
|
||||
// Creates instrument in the GlobalInstrumentsRegistry.
|
||||
static GlobalUInt64CounterHandle RegisterUInt64Counter(
|
||||
|
|
@ -97,6 +107,27 @@ class GlobalInstrumentsRegistry {
|
|||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default);
|
||||
static GlobalInt64GaugeHandle RegisterInt64Gauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default);
|
||||
static GlobalDoubleGaugeHandle RegisterDoubleGauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default);
|
||||
static GlobalCallbackInt64GaugeHandle RegisterCallbackInt64Gauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default);
|
||||
static GlobalCallbackDoubleGaugeHandle RegisterCallbackDoubleGauge(
|
||||
absl::string_view name, absl::string_view description,
|
||||
absl::string_view unit, absl::Span<const absl::string_view> label_keys,
|
||||
absl::Span<const absl::string_view> optional_label_keys,
|
||||
bool enable_by_default);
|
||||
|
||||
static void ForEach(
|
||||
absl::FunctionRef<void(const GlobalInstrumentDescriptor&)> f);
|
||||
|
||||
|
|
@ -110,6 +141,24 @@ class GlobalInstrumentsRegistry {
|
|||
GetInstrumentList();
|
||||
};
|
||||
|
||||
// An interface for implementing callback-style metrics.
|
||||
// To be implemented by stats plugins.
|
||||
class CallbackMetricReporter {
|
||||
public:
|
||||
virtual ~CallbackMetricReporter() = default;
|
||||
|
||||
virtual void Report(
|
||||
GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
|
||||
int64_t value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) = 0;
|
||||
virtual void Report(
|
||||
GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,
|
||||
double value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) = 0;
|
||||
};
|
||||
|
||||
class RegisteredMetricCallback;
|
||||
|
||||
// The StatsPlugin interface.
|
||||
class StatsPlugin {
|
||||
public:
|
||||
|
|
@ -147,6 +196,22 @@ class StatsPlugin {
|
|||
GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
|
||||
double value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) = 0;
|
||||
virtual void SetGauge(
|
||||
GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle, int64_t value,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) = 0;
|
||||
virtual void SetGauge(
|
||||
GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle, double value,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) = 0;
|
||||
|
||||
// Adds a callback to be invoked when the stats plugin wants to
|
||||
// populate the corresponding metrics (see callback->metrics() for list).
|
||||
virtual void AddCallback(RegisteredMetricCallback* callback) = 0;
|
||||
// Removes a callback previously added via AddCallback(). The stats
|
||||
// plugin may not use the callback after this method returns.
|
||||
virtual void RemoveCallback(RegisteredMetricCallback* callback) = 0;
|
||||
|
||||
// TODO(yijiem): Details pending.
|
||||
// std::unique_ptr<AsyncInstrument> GetObservableGauge(
|
||||
// absl::string_view name, absl::string_view description,
|
||||
|
|
@ -208,8 +273,39 @@ class GlobalStatsPluginRegistry {
|
|||
plugin->RecordHistogram(handle, value, label_values, optional_values);
|
||||
}
|
||||
}
|
||||
void SetGauge(GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,
|
||||
int64_t value,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
for (auto& plugin : plugins_) {
|
||||
plugin->SetGauge(handle, value, label_values, optional_values);
|
||||
}
|
||||
}
|
||||
void SetGauge(GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,
|
||||
double value,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
for (auto& plugin : plugins_) {
|
||||
plugin->SetGauge(handle, value, label_values, optional_values);
|
||||
}
|
||||
}
|
||||
|
||||
// Registers a callback to be used to populate callback metrics.
|
||||
// The callback will update the specified metrics. The callback
|
||||
// will be invoked no more often than min_interval.
|
||||
//
|
||||
// The returned object is a handle that allows the caller to control
|
||||
// the lifetime of the callback; when the returned object is
|
||||
// destroyed, the callback is de-registered. The returned object
|
||||
// must not outlive the StatsPluginGroup object that created it.
|
||||
std::unique_ptr<RegisteredMetricCallback> RegisterCallback(
|
||||
absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
|
||||
std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
|
||||
Duration min_interval = Duration::Seconds(5));
|
||||
|
||||
private:
|
||||
friend class RegisteredMetricCallback;
|
||||
|
||||
std::vector<std::shared_ptr<StatsPlugin>> plugins_;
|
||||
};
|
||||
|
||||
|
|
@ -231,6 +327,37 @@ class GlobalStatsPluginRegistry {
|
|||
ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
// A metric callback that is registered with a stats plugin group.
|
||||
class RegisteredMetricCallback {
|
||||
public:
|
||||
RegisteredMetricCallback(
|
||||
GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group,
|
||||
absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
|
||||
std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics,
|
||||
Duration min_interval);
|
||||
|
||||
~RegisteredMetricCallback();
|
||||
|
||||
// Invokes the callback. The callback will report metric data via reporter.
|
||||
void Run(CallbackMetricReporter& reporter) { callback_(reporter); }
|
||||
|
||||
// Returns the set of metrics that this callback will modify.
|
||||
const std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle>& metrics()
|
||||
const {
|
||||
return metrics_;
|
||||
}
|
||||
|
||||
// Returns the minimum interval at which a stats plugin may invoke the
|
||||
// callback.
|
||||
Duration min_interval() const { return min_interval_; }
|
||||
|
||||
private:
|
||||
GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group_;
|
||||
absl::AnyInvocable<void(CallbackMetricReporter&)> callback_;
|
||||
std::vector<GlobalInstrumentsRegistry::GlobalCallbackHandle> metrics_;
|
||||
Duration min_interval_;
|
||||
};
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_SRC_CORE_LIB_CHANNEL_METRICS_H
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
#include "src/core/load_balancing/rls/rls.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -41,6 +43,7 @@
|
|||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/hash/hash.h"
|
||||
#include "absl/random/random.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
|
@ -68,15 +71,18 @@
|
|||
#include "src/core/lib/backoff/backoff.h"
|
||||
#include "src/core/lib/channel/channel_args.h"
|
||||
#include "src/core/lib/channel/channelz.h"
|
||||
#include "src/core/lib/channel/metrics.h"
|
||||
#include "src/core/lib/config/core_configuration.h"
|
||||
#include "src/core/lib/debug/trace.h"
|
||||
#include "src/core/lib/gprpp/debug_location.h"
|
||||
#include "src/core/lib/gprpp/dual_ref_counted.h"
|
||||
#include "src/core/lib/gprpp/match.h"
|
||||
#include "src/core/lib/gprpp/orphanable.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/gprpp/status_helper.h"
|
||||
#include "src/core/lib/gprpp/sync.h"
|
||||
#include "src/core/lib/gprpp/time.h"
|
||||
#include "src/core/lib/gprpp/uuid_v4.h"
|
||||
#include "src/core/lib/gprpp/validation_errors.h"
|
||||
#include "src/core/lib/gprpp/work_serializer.h"
|
||||
#include "src/core/lib/iomgr/closure.h"
|
||||
|
|
@ -103,13 +109,66 @@
|
|||
#include "src/core/resolver/resolver_registry.h"
|
||||
#include "src/proto/grpc/lookup/v1/rls.upb.h"
|
||||
|
||||
using ::grpc_event_engine::experimental::EventEngine;
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
TraceFlag grpc_lb_rls_trace(false, "rls_lb");
|
||||
|
||||
namespace {
|
||||
|
||||
using ::grpc_event_engine::experimental::EventEngine;
|
||||
constexpr absl::string_view kMetricLabelRlsServerTarget =
|
||||
"grpc.lb.rls.server_target";
|
||||
constexpr absl::string_view kMetricLabelRlsInstanceUuid =
|
||||
"grpc.lb.rls.instance_uuid";
|
||||
constexpr absl::string_view kMetricRlsDataPlaneTarget =
|
||||
"grpc.lb.rls.data_plane_target";
|
||||
constexpr absl::string_view kMetricLabelPickResult = "grpc.lb.pick_result";
|
||||
|
||||
const auto kMetricCacheSize =
|
||||
GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
|
||||
"grpc.lb.rls.cache_size", "EXPERIMENTAL. Size of the RLS cache.",
|
||||
"By",
|
||||
{kMetricLabelTarget, kMetricLabelRlsServerTarget,
|
||||
kMetricLabelRlsInstanceUuid},
|
||||
{}, false);
|
||||
|
||||
const auto kMetricCacheEntries =
|
||||
GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
|
||||
"grpc.lb.rls.cache_entries",
|
||||
"EXPERIMENTAL. Number of entries in the RLS cache.", "{entry}",
|
||||
{kMetricLabelTarget, kMetricLabelRlsServerTarget,
|
||||
kMetricLabelRlsInstanceUuid},
|
||||
{}, false);
|
||||
|
||||
const auto kMetricDefaultTargetPicks =
|
||||
GlobalInstrumentsRegistry::RegisterUInt64Counter(
|
||||
"grpc.lb.rls.default_target_picks",
|
||||
"EXPERIMENTAL. Number of LB picks sent to the default target.",
|
||||
"{pick}",
|
||||
{kMetricLabelTarget, kMetricLabelRlsServerTarget,
|
||||
kMetricRlsDataPlaneTarget, kMetricLabelPickResult},
|
||||
{}, false);
|
||||
|
||||
const auto kMetricTargetPicks =
|
||||
GlobalInstrumentsRegistry::RegisterUInt64Counter(
|
||||
"grpc.lb.rls.target_picks",
|
||||
"EXPERIMENTAL. Number of LB picks sent to each RLS target. Note that "
|
||||
"if the default target is also returned by the RLS server, RPCs sent "
|
||||
"to that target from the cache will be counted in this metric, not "
|
||||
"in grpc.rls.default_target_picks.",
|
||||
"{pick}",
|
||||
{kMetricLabelTarget, kMetricLabelRlsServerTarget,
|
||||
kMetricRlsDataPlaneTarget, kMetricLabelPickResult},
|
||||
{}, false);
|
||||
|
||||
const auto kMetricFailedPicks =
|
||||
GlobalInstrumentsRegistry::RegisterUInt64Counter(
|
||||
"grpc.lb.rls.failed_picks",
|
||||
"EXPERIMENTAL. Number of LB picks failed due to either a failed RLS "
|
||||
"request or the RLS channel being throttled.",
|
||||
"{pick}", {kMetricLabelTarget, kMetricLabelRlsServerTarget}, {},
|
||||
false);
|
||||
|
||||
constexpr absl::string_view kRls = "rls_experimental";
|
||||
const char kGrpc[] = "grpc";
|
||||
|
|
@ -365,6 +424,10 @@ class RlsLb : public LoadBalancingPolicy {
|
|||
PickResult Pick(PickArgs args) override;
|
||||
|
||||
private:
|
||||
PickResult PickFromDefaultTargetOrFail(const char* reason, PickArgs args,
|
||||
absl::Status status)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&RlsLb::mu_);
|
||||
|
||||
RefCountedPtr<RlsLb> lb_policy_;
|
||||
RefCountedPtr<RlsLbConfig> config_;
|
||||
RefCountedPtr<ChildPolicyWrapper> default_child_policy_;
|
||||
|
|
@ -516,6 +579,9 @@ class RlsLb : public LoadBalancingPolicy {
|
|||
// Shutdown the cache; clean-up and orphan all the stored cache entries.
|
||||
void Shutdown() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&RlsLb::mu_);
|
||||
|
||||
void ReportMetricsLocked(CallbackMetricReporter& reporter)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(&RlsLb::mu_);
|
||||
|
||||
private:
|
||||
// Shared logic for starting the cleanup timer
|
||||
void StartCleanupTimer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&RlsLb::mu_);
|
||||
|
|
@ -690,6 +756,12 @@ class RlsLb : public LoadBalancingPolicy {
|
|||
// Updates the picker in the work serializer.
|
||||
void UpdatePickerLocked() ABSL_LOCKS_EXCLUDED(&mu_);
|
||||
|
||||
void MaybeExportPickCount(
|
||||
GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
|
||||
absl::string_view target, const PickResult& pick_result);
|
||||
|
||||
const std::string instance_uuid_;
|
||||
|
||||
// Mutex to guard LB policy state that is accessed by the picker.
|
||||
Mutex mu_;
|
||||
bool is_shutdown_ ABSL_GUARDED_BY(mu_) = false;
|
||||
|
|
@ -712,6 +784,9 @@ class RlsLb : public LoadBalancingPolicy {
|
|||
RefCountedPtr<RlsLbConfig> config_;
|
||||
RefCountedPtr<ChildPolicyWrapper> default_child_policy_;
|
||||
std::map<std::string /*target*/, ChildPolicyWrapper*> child_policy_map_;
|
||||
|
||||
// Must be after mu_, so that it is destroyed before mu_.
|
||||
std::unique_ptr<RegisteredMetricCallback> registered_metric_callback_;
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -992,21 +1067,8 @@ LoadBalancingPolicy::PickResult RlsLb::Picker::Pick(PickArgs args) {
|
|||
// If there is no non-expired data in the cache, then we use the
|
||||
// default target if set, or else we fail the pick.
|
||||
if (entry == nullptr || entry->data_expiration_time() < now) {
|
||||
if (default_child_policy_ != nullptr) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO,
|
||||
"[rlslb %p] picker=%p: RLS call throttled; "
|
||||
"using default target",
|
||||
lb_policy_.get(), this);
|
||||
}
|
||||
return default_child_policy_->Pick(args);
|
||||
}
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO,
|
||||
"[rlslb %p] picker=%p: RLS call throttled; failing pick",
|
||||
lb_policy_.get(), this);
|
||||
}
|
||||
return PickResult::Fail(
|
||||
return PickFromDefaultTargetOrFail(
|
||||
"RLS call throttled", args,
|
||||
absl::UnavailableError("RLS request throttled"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1028,22 +1090,10 @@ LoadBalancingPolicy::PickResult RlsLb::Picker::Pick(PickArgs args) {
|
|||
// If the entry is in backoff, then use the default target if set,
|
||||
// or else fail the pick.
|
||||
if (entry->backoff_time() >= now) {
|
||||
if (default_child_policy_ != nullptr) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(
|
||||
GPR_INFO,
|
||||
"[rlslb %p] picker=%p: RLS call in backoff; using default target",
|
||||
lb_policy_.get(), this);
|
||||
}
|
||||
return default_child_policy_->Pick(args);
|
||||
}
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO,
|
||||
"[rlslb %p] picker=%p: RLS call in backoff; failing pick",
|
||||
lb_policy_.get(), this);
|
||||
}
|
||||
return PickResult::Fail(absl::UnavailableError(
|
||||
absl::StrCat("RLS request failed: ", entry->status().ToString())));
|
||||
return PickFromDefaultTargetOrFail(
|
||||
"RLS call in backoff", args,
|
||||
absl::UnavailableError(absl::StrCat(
|
||||
"RLS request failed: ", entry->status().ToString())));
|
||||
}
|
||||
}
|
||||
// RLS call pending. Queue the pick.
|
||||
|
|
@ -1054,6 +1104,31 @@ LoadBalancingPolicy::PickResult RlsLb::Picker::Pick(PickArgs args) {
|
|||
return PickResult::Queue();
|
||||
}
|
||||
|
||||
LoadBalancingPolicy::PickResult RlsLb::Picker::PickFromDefaultTargetOrFail(
|
||||
const char* reason, PickArgs args, absl::Status status) {
|
||||
if (default_child_policy_ != nullptr) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO, "[rlslb %p] picker=%p: %s; using default target",
|
||||
lb_policy_.get(), this, reason);
|
||||
}
|
||||
auto pick_result = default_child_policy_->Pick(args);
|
||||
lb_policy_->MaybeExportPickCount(
|
||||
kMetricDefaultTargetPicks, config_->default_target(), pick_result);
|
||||
return pick_result;
|
||||
}
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO, "[rlslb %p] picker=%p: %s; failing pick",
|
||||
lb_policy_.get(), this, reason);
|
||||
}
|
||||
auto& stats_plugins =
|
||||
lb_policy_->channel_control_helper()->GetStatsPluginGroup();
|
||||
stats_plugins.AddCounter(
|
||||
kMetricFailedPicks, 1,
|
||||
{lb_policy_->channel_control_helper()->GetTarget(),
|
||||
config_->lookup_service()}, {});
|
||||
return PickResult::Fail(std::move(status));
|
||||
}
|
||||
|
||||
//
|
||||
// RlsLb::Cache::Entry::BackoffTimer
|
||||
//
|
||||
|
|
@ -1195,7 +1270,10 @@ LoadBalancingPolicy::PickResult RlsLb::Cache::Entry::Pick(PickArgs args) {
|
|||
strcpy(copied_header_data, header_data_.c_str());
|
||||
args.initial_metadata->Add(kRlsHeaderKey, copied_header_data);
|
||||
}
|
||||
return child_policy_wrapper->Pick(args);
|
||||
auto pick_result = child_policy_wrapper->Pick(args);
|
||||
lb_policy_->MaybeExportPickCount(
|
||||
kMetricTargetPicks, child_policy_wrapper->target(), pick_result);
|
||||
return pick_result;
|
||||
}
|
||||
|
||||
void RlsLb::Cache::Entry::ResetBackoff() {
|
||||
|
|
@ -1374,6 +1452,19 @@ void RlsLb::Cache::Shutdown() {
|
|||
cleanup_timer_handle_.reset();
|
||||
}
|
||||
|
||||
void RlsLb::Cache::ReportMetricsLocked(CallbackMetricReporter& reporter) {
|
||||
reporter.Report(kMetricCacheSize, size_,
|
||||
{lb_policy_->channel_control_helper()->GetTarget(),
|
||||
lb_policy_->config_->lookup_service(),
|
||||
lb_policy_->instance_uuid_},
|
||||
{});
|
||||
reporter.Report(kMetricCacheEntries, map_.size(),
|
||||
{lb_policy_->channel_control_helper()->GetTarget(),
|
||||
lb_policy_->config_->lookup_service(),
|
||||
lb_policy_->instance_uuid_},
|
||||
{});
|
||||
}
|
||||
|
||||
void RlsLb::Cache::StartCleanupTimer() {
|
||||
cleanup_timer_handle_ =
|
||||
lb_policy_->channel_control_helper()->GetEventEngine()->RunAfter(
|
||||
|
|
@ -1846,7 +1937,27 @@ RlsLb::ResponseInfo RlsLb::RlsRequest::ParseResponseProto() {
|
|||
// RlsLb
|
||||
//
|
||||
|
||||
RlsLb::RlsLb(Args args) : LoadBalancingPolicy(std::move(args)), cache_(this) {
|
||||
std::string GenerateUUID() {
|
||||
absl::uniform_int_distribution<uint64_t> distribution;
|
||||
absl::BitGen bitgen;
|
||||
uint64_t hi = distribution(bitgen);
|
||||
uint64_t lo = distribution(bitgen);
|
||||
return GenerateUUIDv4(hi, lo);
|
||||
}
|
||||
|
||||
RlsLb::RlsLb(Args args)
|
||||
: LoadBalancingPolicy(std::move(args)),
|
||||
instance_uuid_(
|
||||
channel_args().GetOwnedString(GRPC_ARG_TEST_ONLY_RLS_INSTANCE_ID)
|
||||
.value_or(GenerateUUID())),
|
||||
cache_(this),
|
||||
registered_metric_callback_(
|
||||
channel_control_helper()->GetStatsPluginGroup().RegisterCallback(
|
||||
[this](CallbackMetricReporter& reporter) {
|
||||
MutexLock lock(&mu_);
|
||||
cache_.ReportMetricsLocked(reporter);
|
||||
},
|
||||
{kMetricCacheSize, kMetricCacheEntries})) {
|
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO, "[rlslb %p] policy created", this);
|
||||
}
|
||||
|
|
@ -2025,6 +2136,7 @@ void RlsLb::ShutdownLocked() {
|
|||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) {
|
||||
gpr_log(GPR_INFO, "[rlslb %p] policy shutdown", this);
|
||||
}
|
||||
registered_metric_callback_.reset();
|
||||
MutexLock lock(&mu_);
|
||||
is_shutdown_ = true;
|
||||
config_.reset(DEBUG_LOCATION, "ShutdownLocked");
|
||||
|
|
@ -2114,6 +2226,32 @@ void RlsLb::UpdatePickerLocked() {
|
|||
MakeRefCounted<Picker>(RefAsSubclass<RlsLb>(DEBUG_LOCATION, "Picker")));
|
||||
}
|
||||
|
||||
void RlsLb::MaybeExportPickCount(
|
||||
GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
|
||||
absl::string_view target, const PickResult& pick_result) {
|
||||
absl::string_view pick_result_string =
|
||||
Match(pick_result.result,
|
||||
[](const LoadBalancingPolicy::PickResult::Complete&) {
|
||||
return "complete";
|
||||
},
|
||||
[](const LoadBalancingPolicy::PickResult::Queue&) {
|
||||
return "";
|
||||
},
|
||||
[](const LoadBalancingPolicy::PickResult::Fail&) {
|
||||
return "fail";
|
||||
},
|
||||
[](const LoadBalancingPolicy::PickResult::Drop&) {
|
||||
return "drop";
|
||||
});
|
||||
if (pick_result_string.empty()) return; // Don't report queued picks.
|
||||
auto& stats_plugins = channel_control_helper()->GetStatsPluginGroup();
|
||||
stats_plugins.AddCounter(
|
||||
handle, 1,
|
||||
{channel_control_helper()->GetTarget(), config_->lookup_service(),
|
||||
target, pick_result_string},
|
||||
{});
|
||||
}
|
||||
|
||||
//
|
||||
// RlsLbFactory
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// Copyright 2024 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#ifndef GRPC_SRC_CORE_LOAD_BALANCING_RLS_RLS_H
|
||||
#define GRPC_SRC_CORE_LOAD_BALANCING_RLS_RLS_H
|
||||
|
||||
#include <grpc/support/port_platform.h>
|
||||
|
||||
// A test-only channel arg to set the instance ID of the RLS LB
|
||||
// policy for use in metric labels.
|
||||
#define GRPC_ARG_TEST_ONLY_RLS_INSTANCE_ID "grpc.test-only.rls.instance_id"
|
||||
|
||||
#endif // GRPC_SRC_CORE_LOAD_BALANCING_RLS_RLS_H
|
||||
|
|
@ -558,6 +558,7 @@ CORE_SOURCE_FILES = [
|
|||
'src/core/lib/gprpp/time.cc',
|
||||
'src/core/lib/gprpp/time_averaged_stats.cc',
|
||||
'src/core/lib/gprpp/time_util.cc',
|
||||
'src/core/lib/gprpp/uuid_v4.cc',
|
||||
'src/core/lib/gprpp/validation_errors.cc',
|
||||
'src/core/lib/gprpp/windows/directory_reader.cc',
|
||||
'src/core/lib/gprpp/windows/env.cc',
|
||||
|
|
|
|||
|
|
@ -197,6 +197,492 @@ TEST_F(MetricsTest, DoubleHistogram) {
|
|||
::testing::Optional(::testing::UnorderedElementsAre(1.23, 2.34, 3.45)));
|
||||
}
|
||||
|
||||
TEST_F(MetricsTest, Int64Gauge) {
|
||||
const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
|
||||
const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
|
||||
"optional_label_key_2"};
|
||||
auto int64_gauge_handle = GlobalInstrumentsRegistry::RegisterInt64Gauge(
|
||||
"int64_gauge", "A simple int64 gauge.", "unit", kLabelKeys,
|
||||
kOptionalLabelKeys, true);
|
||||
constexpr absl::string_view kLabelValues[] = {"label_value_1",
|
||||
"label_value_2"};
|
||||
constexpr absl::string_view kOptionalLabelValues[] = {
|
||||
"optional_label_value_1", "optional_label_value_2"};
|
||||
constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain3To4 = "domain3.domain4";
|
||||
auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
|
||||
auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
|
||||
auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
|
||||
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain1To4, ""))
|
||||
.SetGauge(int64_gauge_handle, 1, kLabelValues, kOptionalLabelValues);
|
||||
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain2To4, ""))
|
||||
.SetGauge(int64_gauge_handle, 2, kLabelValues, kOptionalLabelValues);
|
||||
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain3To4, ""))
|
||||
.SetGauge(int64_gauge_handle, 3, kLabelValues, kOptionalLabelValues);
|
||||
EXPECT_THAT(plugin1->GetGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(plugin2->GetGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(2));
|
||||
EXPECT_THAT(plugin3->GetGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3));
|
||||
}
|
||||
|
||||
TEST_F(MetricsTest, DoubleGauge) {
|
||||
const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
|
||||
const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
|
||||
"optional_label_key_2"};
|
||||
auto double_gauge_handle = GlobalInstrumentsRegistry::RegisterDoubleGauge(
|
||||
"double_gauge", "A simple double gauge.", "unit", kLabelKeys,
|
||||
kOptionalLabelKeys, true);
|
||||
constexpr absl::string_view kLabelValues[] = {"label_value_1",
|
||||
"label_value_2"};
|
||||
constexpr absl::string_view kOptionalLabelValues[] = {
|
||||
"optional_label_value_1", "optional_label_value_2"};
|
||||
constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain3To4 = "domain3.domain4";
|
||||
auto plugin1 = MakeStatsPluginForTarget(kDomain1To4);
|
||||
auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
|
||||
auto plugin3 = MakeStatsPluginForTarget(kDomain3To4);
|
||||
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain1To4, ""))
|
||||
.SetGauge(double_gauge_handle, 1.23, kLabelValues, kOptionalLabelValues);
|
||||
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain2To4, ""))
|
||||
.SetGauge(double_gauge_handle, 2.34, kLabelValues, kOptionalLabelValues);
|
||||
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain3To4, ""))
|
||||
.SetGauge(double_gauge_handle, 3.45, kLabelValues, kOptionalLabelValues);
|
||||
EXPECT_THAT(plugin1->GetGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(1.23));
|
||||
EXPECT_THAT(plugin2->GetGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(2.34));
|
||||
EXPECT_THAT(plugin3->GetGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3.45));
|
||||
}
|
||||
|
||||
TEST_F(MetricsTest, Int64CallbackGauge) {
|
||||
const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
|
||||
const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
|
||||
"optional_label_key_2"};
|
||||
auto int64_gauge_handle =
|
||||
GlobalInstrumentsRegistry::RegisterCallbackInt64Gauge(
|
||||
"int64_gauge", "A simple int64 gauge.", "unit", kLabelKeys,
|
||||
kOptionalLabelKeys, true);
|
||||
constexpr absl::string_view kLabelValues[] = {"label_value_1",
|
||||
"label_value_2"};
|
||||
constexpr absl::string_view kLabelValues2[] = {"label_value_3",
|
||||
"label_value_2"};
|
||||
constexpr absl::string_view kOptionalLabelValues[] = {
|
||||
"optional_label_value_1", "optional_label_value_2"};
|
||||
constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain3To4 = "domain3.domain4";
|
||||
auto plugin1 = MakeStatsPluginForTarget(kDomain3To4);
|
||||
auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
|
||||
auto plugin3 = MakeStatsPluginForTarget(kDomain1To4);
|
||||
// Register two callbacks that set the same metric but with different
|
||||
// label values. The callbacks get used only by plugin1.
|
||||
gpr_log(GPR_INFO, "testing callbacks for: plugin1");
|
||||
auto group1 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain3To4, ""));
|
||||
auto callback1 = group1.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(int64_gauge_handle, 1, kLabelValues,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{int64_gauge_handle});
|
||||
auto callback2 = group1.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(int64_gauge_handle, 2, kLabelValues2,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{int64_gauge_handle});
|
||||
// No plugins have data yet.
|
||||
EXPECT_EQ(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// Now invoke the callbacks.
|
||||
plugin1->TriggerCallbacks();
|
||||
plugin2->TriggerCallbacks();
|
||||
plugin3->TriggerCallbacks();
|
||||
// Now plugin1 should have data, but the others should not.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(2));
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// De-register the callbacks.
|
||||
callback1.reset();
|
||||
callback2.reset();
|
||||
// Now register callbacks that hit both plugin1 and plugin2.
|
||||
gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2");
|
||||
auto group2 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain2To4, ""));
|
||||
callback1 = group2.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(int64_gauge_handle, 3, kLabelValues,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{int64_gauge_handle});
|
||||
callback2 = group2.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(int64_gauge_handle, 4, kLabelValues2,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{int64_gauge_handle});
|
||||
// Plugin1 still has data from before, but the others have none.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(2));
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// Now invoke the callbacks.
|
||||
plugin1->TriggerCallbacks();
|
||||
plugin2->TriggerCallbacks();
|
||||
plugin3->TriggerCallbacks();
|
||||
// Now plugin1 and plugin2 should have data, but plugin3 should not.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4));
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// De-register the callbacks.
|
||||
callback1.reset();
|
||||
callback2.reset();
|
||||
// Now register callbacks that hit all three plugins.
|
||||
gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2, plugin3");
|
||||
auto group3 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain1To4, ""));
|
||||
callback1 = group3.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(int64_gauge_handle, 5, kLabelValues,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{int64_gauge_handle});
|
||||
callback2 = group3.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(int64_gauge_handle, 6, kLabelValues2,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{int64_gauge_handle});
|
||||
// Plugin1 and plugin2 still has data from before, but plugin3 has none.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4));
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// Now invoke the callbacks.
|
||||
plugin1->TriggerCallbacks();
|
||||
plugin2->TriggerCallbacks();
|
||||
plugin3->TriggerCallbacks();
|
||||
// Now plugin1 and plugin2 should have data, but plugin3 should not.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(5));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(6));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(5));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(6));
|
||||
EXPECT_THAT(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(5));
|
||||
EXPECT_THAT(plugin3->GetCallbackGaugeValue(int64_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(6));
|
||||
// Need to destroy callbacks before the plugin group that created them.
|
||||
callback1.reset();
|
||||
callback2.reset();
|
||||
}
|
||||
|
||||
TEST_F(MetricsTest, DoubleCallbackGauge) {
|
||||
const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
|
||||
const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
|
||||
"optional_label_key_2"};
|
||||
auto double_gauge_handle =
|
||||
GlobalInstrumentsRegistry::RegisterCallbackDoubleGauge(
|
||||
"double_gauge", "A simple double gauge.", "unit", kLabelKeys,
|
||||
kOptionalLabelKeys, true);
|
||||
constexpr absl::string_view kLabelValues[] = {"label_value_1",
|
||||
"label_value_2"};
|
||||
constexpr absl::string_view kLabelValues2[] = {"label_value_3",
|
||||
"label_value_2"};
|
||||
constexpr absl::string_view kOptionalLabelValues[] = {
|
||||
"optional_label_value_1", "optional_label_value_2"};
|
||||
constexpr absl::string_view kDomain1To4 = "domain1.domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain2To4 = "domain2.domain3.domain4";
|
||||
constexpr absl::string_view kDomain3To4 = "domain3.domain4";
|
||||
auto plugin1 = MakeStatsPluginForTarget(kDomain3To4);
|
||||
auto plugin2 = MakeStatsPluginForTarget(kDomain2To4);
|
||||
auto plugin3 = MakeStatsPluginForTarget(kDomain1To4);
|
||||
// Register two callbacks that set the same metric but with different
|
||||
// label values. The callbacks get used only by plugin1.
|
||||
gpr_log(GPR_INFO, "testing callbacks for: plugin1");
|
||||
auto group1 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain3To4, ""));
|
||||
auto callback1 = group1.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(double_gauge_handle, 1.23, kLabelValues,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{double_gauge_handle});
|
||||
auto callback2 = group1.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(double_gauge_handle, 2.34, kLabelValues2,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{double_gauge_handle});
|
||||
// No plugins have data yet.
|
||||
EXPECT_EQ(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// Now invoke the callbacks.
|
||||
plugin1->TriggerCallbacks();
|
||||
plugin2->TriggerCallbacks();
|
||||
plugin3->TriggerCallbacks();
|
||||
// Now plugin1 should have data, but the others should not.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(1.23));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(2.34));
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// De-register the callbacks.
|
||||
callback1.reset();
|
||||
callback2.reset();
|
||||
// Now register callbacks that hit both plugin1 and plugin2.
|
||||
gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2");
|
||||
auto group2 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain2To4, ""));
|
||||
callback1 = group2.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(double_gauge_handle, 3.45, kLabelValues,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{double_gauge_handle});
|
||||
callback2 = group2.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(double_gauge_handle, 4.56, kLabelValues2,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{double_gauge_handle});
|
||||
// Plugin1 still has data from before, but the others have none.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(1.23));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(2.34));
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// Now invoke the callbacks.
|
||||
plugin1->TriggerCallbacks();
|
||||
plugin2->TriggerCallbacks();
|
||||
plugin3->TriggerCallbacks();
|
||||
// Now plugin1 and plugin2 should have data, but plugin3 should not.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3.45));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4.56));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3.45));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4.56));
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// De-register the callbacks.
|
||||
callback1.reset();
|
||||
callback2.reset();
|
||||
// Now register callbacks that hit all three plugins.
|
||||
gpr_log(GPR_INFO, "testing callbacks for: plugin1, plugin2, plugin3");
|
||||
auto group3 = GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||||
StatsPlugin::ChannelScope(kDomain1To4, ""));
|
||||
callback1 = group3.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(double_gauge_handle, 5.67, kLabelValues,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{double_gauge_handle});
|
||||
callback2 = group3.RegisterCallback(
|
||||
[&](CallbackMetricReporter& reporter) {
|
||||
reporter.Report(double_gauge_handle, 6.78, kLabelValues2,
|
||||
kOptionalLabelValues);
|
||||
},
|
||||
{double_gauge_handle});
|
||||
// Plugin1 and plugin2 still has data from before, but plugin3 has none.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3.45));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4.56));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(3.45));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(4.56));
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
absl::nullopt);
|
||||
// Now invoke the callbacks.
|
||||
plugin1->TriggerCallbacks();
|
||||
plugin2->TriggerCallbacks();
|
||||
plugin3->TriggerCallbacks();
|
||||
// Now plugin1 and plugin2 should have data, but plugin3 should not.
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(5.67));
|
||||
EXPECT_THAT(plugin1->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(6.78));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(5.67));
|
||||
EXPECT_THAT(plugin2->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(6.78));
|
||||
EXPECT_THAT(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(5.67));
|
||||
EXPECT_THAT(plugin3->GetCallbackGaugeValue(double_gauge_handle, kLabelValues2,
|
||||
kOptionalLabelValues),
|
||||
::testing::Optional(6.78));
|
||||
// Need to destroy callbacks before the plugin group that created them.
|
||||
callback1.reset();
|
||||
callback2.reset();
|
||||
}
|
||||
|
||||
TEST_F(MetricsTest, DisableByDefaultMetricIsNotRecordedByFakeStatsPlugin) {
|
||||
const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
|
||||
const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
|
||||
|
|
|
|||
|
|
@ -175,6 +175,44 @@ GlobalInstrumentsRegistryTestPeer::FindDoubleHistogramHandleByName(
|
|||
GlobalInstrumentsRegistry::InstrumentType::kHistogram);
|
||||
}
|
||||
|
||||
absl::optional<GlobalInstrumentsRegistry::GlobalInt64GaugeHandle>
|
||||
GlobalInstrumentsRegistryTestPeer::FindInt64GaugeHandleByName(
|
||||
absl::string_view name) {
|
||||
return FindInstrument<GlobalInstrumentsRegistry::GlobalInt64GaugeHandle>(
|
||||
GlobalInstrumentsRegistry::GetInstrumentList(), name,
|
||||
GlobalInstrumentsRegistry::ValueType::kInt64,
|
||||
GlobalInstrumentsRegistry::InstrumentType::kGauge);
|
||||
}
|
||||
|
||||
absl::optional<GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle>
|
||||
GlobalInstrumentsRegistryTestPeer::FindDoubleGaugeHandleByName(
|
||||
absl::string_view name) {
|
||||
return FindInstrument<GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle>(
|
||||
GlobalInstrumentsRegistry::GetInstrumentList(), name,
|
||||
GlobalInstrumentsRegistry::ValueType::kDouble,
|
||||
GlobalInstrumentsRegistry::InstrumentType::kGauge);
|
||||
}
|
||||
|
||||
absl::optional<GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle>
|
||||
GlobalInstrumentsRegistryTestPeer::FindCallbackInt64GaugeHandleByName(
|
||||
absl::string_view name) {
|
||||
return FindInstrument<
|
||||
GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle>(
|
||||
GlobalInstrumentsRegistry::GetInstrumentList(), name,
|
||||
GlobalInstrumentsRegistry::ValueType::kInt64,
|
||||
GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge);
|
||||
}
|
||||
|
||||
absl::optional<GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle>
|
||||
GlobalInstrumentsRegistryTestPeer::FindCallbackDoubleGaugeHandleByName(
|
||||
absl::string_view name) {
|
||||
return FindInstrument<
|
||||
GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle>(
|
||||
GlobalInstrumentsRegistry::GetInstrumentList(), name,
|
||||
GlobalInstrumentsRegistry::ValueType::kDouble,
|
||||
GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge);
|
||||
}
|
||||
|
||||
GlobalInstrumentsRegistry::GlobalInstrumentDescriptor*
|
||||
GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName(
|
||||
absl::string_view name) {
|
||||
|
|
|
|||
|
|
@ -219,23 +219,41 @@ class FakeStatsPlugin : public StatsPlugin {
|
|||
std::string(descriptor.name).c_str());
|
||||
return;
|
||||
}
|
||||
if (descriptor.instrument_type ==
|
||||
GlobalInstrumentsRegistry::InstrumentType::kCounter) {
|
||||
if (descriptor.value_type ==
|
||||
GlobalInstrumentsRegistry::ValueType::kUInt64) {
|
||||
uint64_counters_.emplace(descriptor.index, descriptor);
|
||||
} else {
|
||||
double_counters_.emplace(descriptor.index, descriptor);
|
||||
}
|
||||
} else {
|
||||
EXPECT_EQ(descriptor.instrument_type,
|
||||
GlobalInstrumentsRegistry::InstrumentType::kHistogram);
|
||||
if (descriptor.value_type ==
|
||||
GlobalInstrumentsRegistry::ValueType::kUInt64) {
|
||||
uint64_histograms_.emplace(descriptor.index, descriptor);
|
||||
} else {
|
||||
double_histograms_.emplace(descriptor.index, descriptor);
|
||||
}
|
||||
switch (descriptor.instrument_type) {
|
||||
case GlobalInstrumentsRegistry::InstrumentType::kCounter:
|
||||
if (descriptor.value_type ==
|
||||
GlobalInstrumentsRegistry::ValueType::kUInt64) {
|
||||
uint64_counters_.emplace(descriptor.index, descriptor);
|
||||
} else {
|
||||
double_counters_.emplace(descriptor.index, descriptor);
|
||||
}
|
||||
break;
|
||||
case GlobalInstrumentsRegistry::InstrumentType::kHistogram:
|
||||
if (descriptor.value_type ==
|
||||
GlobalInstrumentsRegistry::ValueType::kUInt64) {
|
||||
uint64_histograms_.emplace(descriptor.index, descriptor);
|
||||
} else {
|
||||
double_histograms_.emplace(descriptor.index, descriptor);
|
||||
}
|
||||
break;
|
||||
case GlobalInstrumentsRegistry::InstrumentType::kGauge:
|
||||
if (descriptor.value_type ==
|
||||
GlobalInstrumentsRegistry::ValueType::kInt64) {
|
||||
int64_gauges_.emplace(descriptor.index, descriptor);
|
||||
} else {
|
||||
double_gauges_.emplace(descriptor.index, descriptor);
|
||||
}
|
||||
break;
|
||||
case GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge:
|
||||
if (descriptor.value_type ==
|
||||
GlobalInstrumentsRegistry::ValueType::kInt64) {
|
||||
int64_callback_gauges_.emplace(descriptor.index, descriptor);
|
||||
} else {
|
||||
double_callback_gauges_.emplace(descriptor.index, descriptor);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Crash("unknown instrument type");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -314,6 +332,41 @@ class FakeStatsPlugin : public StatsPlugin {
|
|||
if (iter == double_histograms_.end()) return;
|
||||
iter->second.Record(value, label_values, optional_values);
|
||||
}
|
||||
void SetGauge(GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,
|
||||
int64_t value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) override {
|
||||
gpr_log(GPR_INFO,
|
||||
"FakeStatsPlugin[%p]::RecordGauge(index=%u, value=(uint64)%lu, "
|
||||
"label_values={%s}, optional_label_values={%s}",
|
||||
this, handle.index, value,
|
||||
absl::StrJoin(label_values, ", ").c_str(),
|
||||
absl::StrJoin(optional_values, ", ").c_str());
|
||||
auto iter = int64_gauges_.find(handle.index);
|
||||
if (iter == int64_gauges_.end()) return;
|
||||
iter->second.Set(value, label_values, optional_values);
|
||||
}
|
||||
void SetGauge(GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,
|
||||
double value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) override {
|
||||
gpr_log(GPR_INFO,
|
||||
"FakeStatsPlugin[%p]::RecordGauge(index=%u, value=(double)%f, "
|
||||
"label_values={%s}, optional_label_values={%s}",
|
||||
this, handle.index, value,
|
||||
absl::StrJoin(label_values, ", ").c_str(),
|
||||
absl::StrJoin(optional_values, ", ").c_str());
|
||||
auto iter = double_gauges_.find(handle.index);
|
||||
if (iter == double_gauges_.end()) return;
|
||||
iter->second.Set(value, label_values, optional_values);
|
||||
}
|
||||
void AddCallback(RegisteredMetricCallback* callback) override {
|
||||
gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::AddCallback(%p)", this, callback);
|
||||
callbacks_.insert(callback);
|
||||
}
|
||||
void RemoveCallback(RegisteredMetricCallback* callback) override {
|
||||
gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::RemoveCallback(%p)", this,
|
||||
callback);
|
||||
callbacks_.erase(callback);
|
||||
}
|
||||
|
||||
absl::optional<uint64_t> GetCounterValue(
|
||||
GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
|
||||
|
|
@ -355,8 +408,96 @@ class FakeStatsPlugin : public StatsPlugin {
|
|||
}
|
||||
return iter->second.GetValues(label_values, optional_values);
|
||||
}
|
||||
absl::optional<int64_t> GetGaugeValue(
|
||||
GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
auto iter = int64_gauges_.find(handle.index);
|
||||
if (iter == int64_gauges_.end()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return iter->second.GetValue(label_values, optional_values);
|
||||
}
|
||||
absl::optional<double> GetGaugeValue(
|
||||
GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
auto iter = double_gauges_.find(handle.index);
|
||||
if (iter == double_gauges_.end()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return iter->second.GetValue(label_values, optional_values);
|
||||
}
|
||||
void TriggerCallbacks() {
|
||||
gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::TriggerCallbacks(): START", this);
|
||||
Reporter reporter(*this);
|
||||
for (auto* callback : callbacks_) {
|
||||
callback->Run(reporter);
|
||||
}
|
||||
gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::TriggerCallbacks(): END", this);
|
||||
}
|
||||
absl::optional<int64_t> GetCallbackGaugeValue(
|
||||
GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
auto iter = int64_callback_gauges_.find(handle.index);
|
||||
if (iter == int64_callback_gauges_.end()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return iter->second.GetValue(label_values, optional_values);
|
||||
}
|
||||
absl::optional<double> GetCallbackGaugeValue(
|
||||
GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
auto iter = double_callback_gauges_.find(handle.index);
|
||||
if (iter == double_callback_gauges_.end()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return iter->second.GetValue(label_values, optional_values);
|
||||
}
|
||||
|
||||
private:
|
||||
class Reporter : public CallbackMetricReporter {
|
||||
public:
|
||||
explicit Reporter(FakeStatsPlugin& plugin) : plugin_(plugin) {}
|
||||
|
||||
void Report(
|
||||
GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
|
||||
int64_t value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) override {
|
||||
gpr_log(GPR_INFO,
|
||||
"FakeStatsPlugin[%p]::Reporter::Report(index=%u, "
|
||||
"value=(uint64)%ld, label_values={%s}, "
|
||||
"optional_label_values={%s}",
|
||||
this, handle.index, value,
|
||||
absl::StrJoin(label_values, ", ").c_str(),
|
||||
absl::StrJoin(optional_values, ", ").c_str());
|
||||
auto iter = plugin_.int64_callback_gauges_.find(handle.index);
|
||||
if (iter == plugin_.int64_callback_gauges_.end()) return;
|
||||
iter->second.Set(value, label_values, optional_values);
|
||||
}
|
||||
|
||||
void Report(
|
||||
GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,
|
||||
double value, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) override {
|
||||
gpr_log(GPR_INFO,
|
||||
"FakeStatsPlugin[%p]::Reporter::Report(index=%u, "
|
||||
"value=(double)%f, label_values={%s}, "
|
||||
"optional_label_values={%s}",
|
||||
this, handle.index, value,
|
||||
absl::StrJoin(label_values, ", ").c_str(),
|
||||
absl::StrJoin(optional_values, ", ").c_str());
|
||||
auto iter = plugin_.double_callback_gauges_.find(handle.index);
|
||||
if (iter == plugin_.double_callback_gauges_.end()) return;
|
||||
iter->second.Set(value, label_values, optional_values);
|
||||
}
|
||||
|
||||
private:
|
||||
FakeStatsPlugin& plugin_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Counter {
|
||||
public:
|
||||
|
|
@ -442,12 +583,53 @@ class FakeStatsPlugin : public StatsPlugin {
|
|||
absl::flat_hash_map<std::string, std::vector<T>> storage_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class Gauge {
|
||||
public:
|
||||
explicit Gauge(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)
|
||||
: name_(u.name),
|
||||
description_(u.description),
|
||||
unit_(u.unit),
|
||||
label_keys_(std::move(u.label_keys)),
|
||||
optional_label_keys_(std::move(u.optional_label_keys)) {}
|
||||
|
||||
void Set(T t, absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
storage_[MakeLabelString(label_keys_, label_values, optional_label_keys_,
|
||||
optional_values)] = t;
|
||||
}
|
||||
|
||||
absl::optional<T> GetValue(
|
||||
absl::Span<const absl::string_view> label_values,
|
||||
absl::Span<const absl::string_view> optional_values) {
|
||||
auto iter = storage_.find(MakeLabelString(
|
||||
label_keys_, label_values, optional_label_keys_, optional_values));
|
||||
if (iter == storage_.end()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
private:
|
||||
absl::string_view name_;
|
||||
absl::string_view description_;
|
||||
absl::string_view unit_;
|
||||
std::vector<absl::string_view> label_keys_;
|
||||
std::vector<absl::string_view> optional_label_keys_;
|
||||
absl::flat_hash_map<std::string, T> storage_;
|
||||
};
|
||||
|
||||
absl::AnyInvocable<bool(const ChannelScope& /*scope*/) const> channel_filter_;
|
||||
// Instruments.
|
||||
absl::flat_hash_map<uint32_t, Counter<uint64_t>> uint64_counters_;
|
||||
absl::flat_hash_map<uint32_t, Counter<double>> double_counters_;
|
||||
absl::flat_hash_map<uint32_t, Histogram<uint64_t>> uint64_histograms_;
|
||||
absl::flat_hash_map<uint32_t, Histogram<double>> double_histograms_;
|
||||
absl::flat_hash_map<uint32_t, Gauge<int64_t>> int64_gauges_;
|
||||
absl::flat_hash_map<uint32_t, Gauge<double>> double_gauges_;
|
||||
absl::flat_hash_map<uint32_t, Gauge<int64_t>> int64_callback_gauges_;
|
||||
absl::flat_hash_map<uint32_t, Gauge<double>> double_callback_gauges_;
|
||||
std::set<RegisteredMetricCallback*> callbacks_;
|
||||
};
|
||||
|
||||
class FakeStatsPluginBuilder {
|
||||
|
|
@ -492,6 +674,16 @@ class GlobalInstrumentsRegistryTestPeer {
|
|||
FindUInt64HistogramHandleByName(absl::string_view name);
|
||||
static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle>
|
||||
FindDoubleHistogramHandleByName(absl::string_view name);
|
||||
static absl::optional<GlobalInstrumentsRegistry::GlobalInt64GaugeHandle>
|
||||
FindInt64GaugeHandleByName(absl::string_view name);
|
||||
static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle>
|
||||
FindDoubleGaugeHandleByName(absl::string_view name);
|
||||
static absl::optional<
|
||||
GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle>
|
||||
FindCallbackInt64GaugeHandleByName(absl::string_view name);
|
||||
static absl::optional<
|
||||
GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle>
|
||||
FindCallbackDoubleGaugeHandleByName(absl::string_view name);
|
||||
|
||||
static GlobalInstrumentsRegistry::GlobalInstrumentDescriptor*
|
||||
FindMetricDescriptorByName(absl::string_view name);
|
||||
|
|
|
|||
|
|
@ -568,6 +568,7 @@ grpc_cc_test(
|
|||
"//src/proto/grpc/testing:echo_messages_proto",
|
||||
"//src/proto/grpc/testing:echo_proto",
|
||||
"//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
|
||||
"//test/core/util:fake_stats_plugin",
|
||||
"//test/core/util:grpc_test_util",
|
||||
"//test/core/util:test_lb_policies",
|
||||
"//test/cpp/util:test_config",
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "src/core/lib/iomgr/sockaddr.h"
|
||||
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
|
||||
#include "src/core/lib/uri/uri_parser.h"
|
||||
#include "src/core/load_balancing/rls/rls.h"
|
||||
#include "src/core/resolver/fake/fake_resolver.h"
|
||||
#include "src/core/service_config/service_config_impl.h"
|
||||
#include "src/cpp/client/secure_credentials.h"
|
||||
|
|
@ -56,6 +57,7 @@
|
|||
#include "src/proto/grpc/lookup/v1/rls.grpc.pb.h"
|
||||
#include "src/proto/grpc/lookup/v1/rls.pb.h"
|
||||
#include "src/proto/grpc/testing/echo.grpc.pb.h"
|
||||
#include "test/core/util/fake_stats_plugin.h"
|
||||
#include "test/core/util/port.h"
|
||||
#include "test/core/util/resolve_localhost_ip46.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
|
@ -73,6 +75,7 @@ namespace {
|
|||
|
||||
const char* kServerName = "test.google.fr";
|
||||
const char* kRequestMessage = "Live long and prosper.";
|
||||
const char* kRlsInstanceUuid = "rls_instance_uuid";
|
||||
|
||||
const char* kCallCredsMdKey = "call_cred_name";
|
||||
const char* kCallCredsMdValue = "call_cred_value";
|
||||
|
|
@ -182,6 +185,7 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
EXPECT_EQ(ctx->ExperimentalGetAuthority(), kServerName);
|
||||
});
|
||||
rls_server_->Start();
|
||||
rls_server_target_ = absl::StrFormat("localhost:%d", rls_server_->port_);
|
||||
// Set up client.
|
||||
resolver_response_generator_ =
|
||||
std::make_unique<FakeResolverResponseGeneratorWrapper>();
|
||||
|
|
@ -189,6 +193,7 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR,
|
||||
resolver_response_generator_->Get());
|
||||
args.SetString(GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS, kServerName);
|
||||
args.SetString(GRPC_ARG_TEST_ONLY_RLS_INSTANCE_ID, kRlsInstanceUuid);
|
||||
grpc_channel_credentials* channel_creds =
|
||||
grpc_fake_transport_security_credentials_create();
|
||||
grpc_call_credentials* call_creds = grpc_md_only_test_credentials_create(
|
||||
|
|
@ -198,8 +203,8 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
nullptr));
|
||||
call_creds->Unref();
|
||||
channel_creds->Unref();
|
||||
channel_ = grpc::CreateCustomChannel(absl::StrCat("fake:///", kServerName),
|
||||
std::move(creds), args);
|
||||
target_uri_ = absl::StrCat("fake:///", kServerName);
|
||||
channel_ = grpc::CreateCustomChannel(target_uri_, std::move(creds), args);
|
||||
stub_ = grpc::testing::EchoTestService::NewStub(channel_);
|
||||
}
|
||||
|
||||
|
|
@ -295,8 +300,8 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
|
||||
class ServiceConfigBuilder {
|
||||
public:
|
||||
explicit ServiceConfigBuilder(int rls_server_port)
|
||||
: rls_server_port_(rls_server_port) {}
|
||||
explicit ServiceConfigBuilder(absl::string_view rls_server_target)
|
||||
: rls_server_target_(rls_server_target) {}
|
||||
|
||||
ServiceConfigBuilder& set_lookup_service_timeout(
|
||||
grpc_core::Duration timeout) {
|
||||
|
|
@ -333,7 +338,7 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
// First build parts of routeLookupConfig.
|
||||
std::vector<std::string> route_lookup_config_parts;
|
||||
route_lookup_config_parts.push_back(absl::StrFormat(
|
||||
" \"lookupService\":\"localhost:%d\"", rls_server_port_));
|
||||
" \"lookupService\":\"%s\"", rls_server_target_));
|
||||
if (lookup_service_timeout_ > grpc_core::Duration::Zero()) {
|
||||
route_lookup_config_parts.push_back(
|
||||
absl::StrFormat(" \"lookupServiceTimeout\":\"%fs\"",
|
||||
|
|
@ -382,7 +387,7 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
}
|
||||
|
||||
private:
|
||||
int rls_server_port_;
|
||||
absl::string_view rls_server_target_;
|
||||
grpc_core::Duration lookup_service_timeout_;
|
||||
std::string default_target_;
|
||||
grpc_core::Duration max_age_;
|
||||
|
|
@ -392,7 +397,7 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
};
|
||||
|
||||
ServiceConfigBuilder MakeServiceConfigBuilder() {
|
||||
return ServiceConfigBuilder(rls_server_->port_);
|
||||
return ServiceConfigBuilder(rls_server_target_);
|
||||
}
|
||||
|
||||
void SetNextResolution(absl::string_view service_config_json) {
|
||||
|
|
@ -456,9 +461,11 @@ class RlsEnd2endTest : public ::testing::Test {
|
|||
};
|
||||
|
||||
std::vector<std::unique_ptr<ServerThread<MyTestServiceImpl>>> backends_;
|
||||
std::string rls_server_target_;
|
||||
std::unique_ptr<ServerThread<RlsServiceImpl>> rls_server_;
|
||||
std::unique_ptr<FakeResolverResponseGeneratorWrapper>
|
||||
resolver_response_generator_;
|
||||
std::string target_uri_;
|
||||
std::shared_ptr<grpc::Channel> channel_;
|
||||
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
|
||||
};
|
||||
|
|
@ -1370,6 +1377,309 @@ TEST_F(RlsEnd2endTest, ConnectivityStateTransientFailure) {
|
|||
channel_->GetState(/*try_to_connect=*/false));
|
||||
}
|
||||
|
||||
class RlsMetricsEnd2endTest : public RlsEnd2endTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Register stats plugin before initializing client.
|
||||
stats_plugin_ = grpc_core::FakeStatsPluginBuilder()
|
||||
.UseDisabledByDefaultMetrics(true)
|
||||
.BuildAndRegister();
|
||||
RlsEnd2endTest::SetUp();
|
||||
}
|
||||
|
||||
std::shared_ptr<grpc_core::FakeStatsPlugin> stats_plugin_;
|
||||
};
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricDefinitionDefaultTargetPicks) {
|
||||
const auto* descriptor =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName(
|
||||
"grpc.lb.rls.default_target_picks");
|
||||
ASSERT_NE(descriptor, nullptr);
|
||||
EXPECT_EQ(descriptor->value_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::ValueType::kUInt64);
|
||||
EXPECT_EQ(descriptor->instrument_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::InstrumentType::kCounter);
|
||||
EXPECT_EQ(descriptor->enable_by_default, false);
|
||||
EXPECT_EQ(descriptor->name, "grpc.lb.rls.default_target_picks");
|
||||
EXPECT_EQ(descriptor->unit, "{pick}");
|
||||
EXPECT_THAT(descriptor->label_keys,
|
||||
::testing::ElementsAre("grpc.target", "grpc.lb.rls.server_target",
|
||||
"grpc.lb.rls.data_plane_target",
|
||||
"grpc.lb.pick_result"));
|
||||
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricDefinitionTargetPicks) {
|
||||
const auto* descriptor =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName(
|
||||
"grpc.lb.rls.target_picks");
|
||||
ASSERT_NE(descriptor, nullptr);
|
||||
EXPECT_EQ(descriptor->value_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::ValueType::kUInt64);
|
||||
EXPECT_EQ(descriptor->instrument_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::InstrumentType::kCounter);
|
||||
EXPECT_EQ(descriptor->enable_by_default, false);
|
||||
EXPECT_EQ(descriptor->name, "grpc.lb.rls.target_picks");
|
||||
EXPECT_EQ(descriptor->unit, "{pick}");
|
||||
EXPECT_THAT(descriptor->label_keys,
|
||||
::testing::ElementsAre("grpc.target", "grpc.lb.rls.server_target",
|
||||
"grpc.lb.rls.data_plane_target",
|
||||
"grpc.lb.pick_result"));
|
||||
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricDefinitionFailedPicks) {
|
||||
const auto* descriptor =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName(
|
||||
"grpc.lb.rls.failed_picks");
|
||||
ASSERT_NE(descriptor, nullptr);
|
||||
EXPECT_EQ(descriptor->value_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::ValueType::kUInt64);
|
||||
EXPECT_EQ(descriptor->instrument_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::InstrumentType::kCounter);
|
||||
EXPECT_EQ(descriptor->enable_by_default, false);
|
||||
EXPECT_EQ(descriptor->name, "grpc.lb.rls.failed_picks");
|
||||
EXPECT_EQ(descriptor->unit, "{pick}");
|
||||
EXPECT_THAT(
|
||||
descriptor->label_keys,
|
||||
::testing::ElementsAre("grpc.target", "grpc.lb.rls.server_target"));
|
||||
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricDefinitionCacheEntries) {
|
||||
const auto* descriptor =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName(
|
||||
"grpc.lb.rls.cache_entries");
|
||||
ASSERT_NE(descriptor, nullptr);
|
||||
EXPECT_EQ(descriptor->value_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::ValueType::kInt64);
|
||||
EXPECT_EQ(
|
||||
descriptor->instrument_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge);
|
||||
EXPECT_EQ(descriptor->enable_by_default, false);
|
||||
EXPECT_EQ(descriptor->name, "grpc.lb.rls.cache_entries");
|
||||
EXPECT_EQ(descriptor->unit, "{entry}");
|
||||
EXPECT_THAT(descriptor->label_keys,
|
||||
::testing::ElementsAre("grpc.target", "grpc.lb.rls.server_target",
|
||||
"grpc.lb.rls.instance_uuid"));
|
||||
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricDefinitionCacheSize) {
|
||||
const auto* descriptor =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::FindMetricDescriptorByName(
|
||||
"grpc.lb.rls.cache_size");
|
||||
ASSERT_NE(descriptor, nullptr);
|
||||
EXPECT_EQ(descriptor->value_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::ValueType::kInt64);
|
||||
EXPECT_EQ(
|
||||
descriptor->instrument_type,
|
||||
grpc_core::GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge);
|
||||
EXPECT_EQ(descriptor->enable_by_default, false);
|
||||
EXPECT_EQ(descriptor->name, "grpc.lb.rls.cache_size");
|
||||
EXPECT_EQ(descriptor->unit, "By");
|
||||
EXPECT_THAT(descriptor->label_keys,
|
||||
::testing::ElementsAre("grpc.target", "grpc.lb.rls.server_target",
|
||||
"grpc.lb.rls.instance_uuid"));
|
||||
EXPECT_THAT(descriptor->optional_label_keys, ::testing::ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricValues) {
|
||||
auto kMetricTargetPicks =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::
|
||||
FindUInt64CounterHandleByName("grpc.lb.rls.target_picks")
|
||||
.value();
|
||||
auto kMetricFailedPicks =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::
|
||||
FindUInt64CounterHandleByName("grpc.lb.rls.failed_picks")
|
||||
.value();
|
||||
auto kMetricCacheEntries =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::
|
||||
FindCallbackInt64GaugeHandleByName("grpc.lb.rls.cache_entries")
|
||||
.value();
|
||||
auto kMetricCacheSize =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::
|
||||
FindCallbackInt64GaugeHandleByName("grpc.lb.rls.cache_size")
|
||||
.value();
|
||||
StartBackends(2);
|
||||
SetNextResolution(
|
||||
MakeServiceConfigBuilder()
|
||||
.AddKeyBuilder(absl::StrFormat("\"names\":[{"
|
||||
" \"service\":\"%s\","
|
||||
" \"method\":\"%s\""
|
||||
"}],"
|
||||
"\"headers\":["
|
||||
" {"
|
||||
" \"key\":\"%s\","
|
||||
" \"names\":["
|
||||
" \"key1\""
|
||||
" ]"
|
||||
" }"
|
||||
"]",
|
||||
kServiceValue, kMethodValue, kTestKey))
|
||||
.Build());
|
||||
const std::string rls_target0 = grpc_core::LocalIpUri(backends_[0]->port_);
|
||||
const std::string rls_target1 = grpc_core::LocalIpUri(backends_[1]->port_);
|
||||
// Send an RPC to the target for backend 0.
|
||||
rls_server_->service_.SetResponse(BuildRlsRequest({{kTestKey, rls_target0}}),
|
||||
BuildRlsResponse({rls_target0}));
|
||||
CheckRpcSendOk(DEBUG_LOCATION,
|
||||
RpcOptions().set_metadata({{"key1", rls_target0}}));
|
||||
EXPECT_EQ(rls_server_->service_.request_count(), 1);
|
||||
EXPECT_EQ(rls_server_->service_.response_count(), 1);
|
||||
EXPECT_EQ(backends_[0]->service_.request_count(), 1);
|
||||
EXPECT_EQ(backends_[1]->service_.request_count(), 0);
|
||||
// Check exported metrics.
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricTargetPicks,
|
||||
{target_uri_, rls_server_target_, rls_target0, "complete"}, {}),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricTargetPicks,
|
||||
{target_uri_, rls_server_target_, rls_target1, "complete"}, {}),
|
||||
absl::nullopt);
|
||||
EXPECT_EQ(stats_plugin_->GetCounterValue(
|
||||
kMetricFailedPicks, {target_uri_, rls_server_target_}, {}),
|
||||
absl::nullopt);
|
||||
stats_plugin_->TriggerCallbacks();
|
||||
EXPECT_THAT(stats_plugin_->GetCallbackGaugeValue(
|
||||
kMetricCacheEntries,
|
||||
{target_uri_, rls_server_target_, kRlsInstanceUuid}, {}),
|
||||
::testing::Optional(1));
|
||||
auto cache_size = stats_plugin_->GetCallbackGaugeValue(
|
||||
kMetricCacheSize, {target_uri_, rls_server_target_, kRlsInstanceUuid},
|
||||
{});
|
||||
EXPECT_THAT(cache_size, ::testing::Optional(::testing::Ge(1)));
|
||||
// Send an RPC to the target for backend 1.
|
||||
rls_server_->service_.SetResponse(BuildRlsRequest({{kTestKey, rls_target1}}),
|
||||
BuildRlsResponse({rls_target1}));
|
||||
CheckRpcSendOk(DEBUG_LOCATION,
|
||||
RpcOptions().set_metadata({{"key1", rls_target1}}));
|
||||
EXPECT_EQ(rls_server_->service_.request_count(), 2);
|
||||
EXPECT_EQ(rls_server_->service_.response_count(), 2);
|
||||
EXPECT_EQ(backends_[0]->service_.request_count(), 1);
|
||||
EXPECT_EQ(backends_[1]->service_.request_count(), 1);
|
||||
// Check exported metrics.
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricTargetPicks,
|
||||
{target_uri_, rls_server_target_, rls_target0, "complete"}, {}),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricTargetPicks,
|
||||
{target_uri_, rls_server_target_, rls_target1, "complete"}, {}),
|
||||
::testing::Optional(1));
|
||||
EXPECT_EQ(stats_plugin_->GetCounterValue(
|
||||
kMetricFailedPicks, {target_uri_, rls_server_target_}, {}),
|
||||
absl::nullopt);
|
||||
stats_plugin_->TriggerCallbacks();
|
||||
EXPECT_THAT(stats_plugin_->GetCallbackGaugeValue(
|
||||
kMetricCacheEntries,
|
||||
{target_uri_, rls_server_target_, kRlsInstanceUuid}, {}),
|
||||
::testing::Optional(2));
|
||||
auto cache_size2 = stats_plugin_->GetCallbackGaugeValue(
|
||||
kMetricCacheSize, {target_uri_, rls_server_target_, kRlsInstanceUuid},
|
||||
{});
|
||||
EXPECT_THAT(cache_size2, ::testing::Optional(::testing::Ge(2)));
|
||||
if (cache_size.has_value() && cache_size2.has_value()) {
|
||||
EXPECT_GT(*cache_size2, *cache_size);
|
||||
}
|
||||
// Send an RPC for which the RLS server has no response, which means
|
||||
// that the RLS request will fail. There is no default target, so the
|
||||
// data plane RPC will fail.
|
||||
CheckRpcSendFailure(DEBUG_LOCATION, StatusCode::UNAVAILABLE,
|
||||
"RLS request failed: INTERNAL: no response entry",
|
||||
RpcOptions().set_metadata({{"key1", kTestValue}}));
|
||||
EXPECT_THAT(
|
||||
rls_server_->service_.GetUnmatchedRequests(),
|
||||
::testing::ElementsAre(
|
||||
// TODO(roth): Change this to use ::testing::ProtoEquals()
|
||||
// once that becomes available in OSS.
|
||||
::testing::Property(
|
||||
&RouteLookupRequest::DebugString,
|
||||
BuildRlsRequest({{kTestKey, kTestValue}}).DebugString())));
|
||||
EXPECT_EQ(rls_server_->service_.request_count(), 3);
|
||||
EXPECT_EQ(rls_server_->service_.response_count(), 2);
|
||||
EXPECT_EQ(backends_[0]->service_.request_count(), 1);
|
||||
EXPECT_EQ(backends_[1]->service_.request_count(), 1);
|
||||
// Check exported metrics.
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricTargetPicks,
|
||||
{target_uri_, rls_server_target_, rls_target0, "complete"}, {}),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricTargetPicks,
|
||||
{target_uri_, rls_server_target_, rls_target1, "complete"}, {}),
|
||||
::testing::Optional(1));
|
||||
EXPECT_THAT(stats_plugin_->GetCounterValue(
|
||||
kMetricFailedPicks, {target_uri_, rls_server_target_}, {}),
|
||||
::testing::Optional(1));
|
||||
stats_plugin_->TriggerCallbacks();
|
||||
EXPECT_THAT(stats_plugin_->GetCallbackGaugeValue(
|
||||
kMetricCacheEntries,
|
||||
{target_uri_, rls_server_target_, kRlsInstanceUuid}, {}),
|
||||
::testing::Optional(3));
|
||||
auto cache_size3 = stats_plugin_->GetCallbackGaugeValue(
|
||||
kMetricCacheSize, {target_uri_, rls_server_target_, kRlsInstanceUuid},
|
||||
{});
|
||||
EXPECT_THAT(cache_size3, ::testing::Optional(::testing::Ge(3)));
|
||||
if (cache_size.has_value() && cache_size3.has_value()) {
|
||||
EXPECT_GT(*cache_size3, *cache_size);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RlsMetricsEnd2endTest, MetricValuesDefaultTargetRpcs) {
|
||||
auto kMetricDefaultTargetPicks =
|
||||
grpc_core::GlobalInstrumentsRegistryTestPeer::
|
||||
FindUInt64CounterHandleByName("grpc.lb.rls.default_target_picks")
|
||||
.value();
|
||||
StartBackends(1);
|
||||
const std::string default_target = grpc_core::LocalIpUri(backends_[0]->port_);
|
||||
SetNextResolution(
|
||||
MakeServiceConfigBuilder()
|
||||
.AddKeyBuilder(absl::StrFormat("\"names\":[{"
|
||||
" \"service\":\"%s\","
|
||||
" \"method\":\"%s\""
|
||||
"}],"
|
||||
"\"headers\":["
|
||||
" {"
|
||||
" \"key\":\"%s\","
|
||||
" \"names\":["
|
||||
" \"key1\""
|
||||
" ]"
|
||||
" }"
|
||||
"]",
|
||||
kServiceValue, kMethodValue, kTestKey))
|
||||
.set_default_target(default_target)
|
||||
.Build());
|
||||
// Don't give the RLS server a response, so the RLS request will fail.
|
||||
// The data plane RPC should be sent to the default target.
|
||||
CheckRpcSendOk(DEBUG_LOCATION,
|
||||
RpcOptions().set_metadata({{"key1", kTestValue}}));
|
||||
EXPECT_THAT(
|
||||
rls_server_->service_.GetUnmatchedRequests(),
|
||||
::testing::ElementsAre(
|
||||
// TODO(roth): Change this to use ::testing::ProtoEquals()
|
||||
// once that becomes available in OSS.
|
||||
::testing::Property(
|
||||
&RouteLookupRequest::DebugString,
|
||||
BuildRlsRequest({{kTestKey, kTestValue}}).DebugString())));
|
||||
EXPECT_EQ(rls_server_->service_.request_count(), 1);
|
||||
EXPECT_EQ(rls_server_->service_.response_count(), 0);
|
||||
EXPECT_EQ(backends_[0]->service_.request_count(), 1);
|
||||
// Check expected metrics.
|
||||
EXPECT_THAT(
|
||||
stats_plugin_->GetCounterValue(
|
||||
kMetricDefaultTargetPicks,
|
||||
{target_uri_, rls_server_target_, default_target, "complete"}, {}),
|
||||
::testing::Optional(1));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
|
|
|||
|
|
@ -2398,6 +2398,8 @@ src/core/lib/gprpp/time_util.cc \
|
|||
src/core/lib/gprpp/time_util.h \
|
||||
src/core/lib/gprpp/type_list.h \
|
||||
src/core/lib/gprpp/unique_type_name.h \
|
||||
src/core/lib/gprpp/uuid_v4.cc \
|
||||
src/core/lib/gprpp/uuid_v4.h \
|
||||
src/core/lib/gprpp/validation_errors.cc \
|
||||
src/core/lib/gprpp/validation_errors.h \
|
||||
src/core/lib/gprpp/windows/directory_reader.cc \
|
||||
|
|
@ -2889,6 +2891,7 @@ src/core/load_balancing/priority/priority.cc \
|
|||
src/core/load_balancing/ring_hash/ring_hash.cc \
|
||||
src/core/load_balancing/ring_hash/ring_hash.h \
|
||||
src/core/load_balancing/rls/rls.cc \
|
||||
src/core/load_balancing/rls/rls.h \
|
||||
src/core/load_balancing/round_robin/round_robin.cc \
|
||||
src/core/load_balancing/subchannel_interface.h \
|
||||
src/core/load_balancing/subchannel_list.h \
|
||||
|
|
|
|||
|
|
@ -2172,6 +2172,8 @@ src/core/lib/gprpp/time_util.cc \
|
|||
src/core/lib/gprpp/time_util.h \
|
||||
src/core/lib/gprpp/type_list.h \
|
||||
src/core/lib/gprpp/unique_type_name.h \
|
||||
src/core/lib/gprpp/uuid_v4.cc \
|
||||
src/core/lib/gprpp/uuid_v4.h \
|
||||
src/core/lib/gprpp/validation_errors.cc \
|
||||
src/core/lib/gprpp/validation_errors.h \
|
||||
src/core/lib/gprpp/windows/directory_reader.cc \
|
||||
|
|
@ -2666,6 +2668,7 @@ src/core/load_balancing/priority/priority.cc \
|
|||
src/core/load_balancing/ring_hash/ring_hash.cc \
|
||||
src/core/load_balancing/ring_hash/ring_hash.h \
|
||||
src/core/load_balancing/rls/rls.cc \
|
||||
src/core/load_balancing/rls/rls.h \
|
||||
src/core/load_balancing/round_robin/round_robin.cc \
|
||||
src/core/load_balancing/subchannel_interface.h \
|
||||
src/core/load_balancing/subchannel_list.h \
|
||||
|
|
|
|||
Loading…
Reference in New Issue