mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
529 lines
23 KiB
529 lines
23 KiB
10 months ago
|
// Copyright 2024 The gRPC Authors.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
#include "src/core/lib/channel/metrics.h"
|
||
|
|
||
|
#include <memory>
|
||
|
|
||
|
#include "absl/container/flat_hash_map.h"
|
||
|
#include "absl/strings/match.h"
|
||
|
#include "absl/strings/str_cat.h"
|
||
|
#include "absl/strings/str_join.h"
|
||
|
#include "gmock/gmock.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
#include "test/core/util/test_config.h"
|
||
|
|
||
|
namespace grpc_core {
|
||
|
namespace {
|
||
|
|
||
|
void AddKeyValuePairs(absl::Span<const absl::string_view> keys,
|
||
|
absl::Span<const absl::string_view> values,
|
||
|
std::vector<std::string>* key_value_pairs) {
|
||
|
GPR_ASSERT(keys.size() == values.size());
|
||
|
for (size_t i = 0; i < keys.size(); ++i) {
|
||
|
key_value_pairs->push_back(absl::StrCat(keys[i], "=", values[i]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::string MakeLabelString(
|
||
|
absl::Span<const absl::string_view> label_keys,
|
||
|
absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_label_keys,
|
||
|
absl::Span<const absl::string_view> optional_values) {
|
||
|
std::vector<std::string> key_value_pairs;
|
||
|
AddKeyValuePairs(label_keys, label_values, &key_value_pairs);
|
||
|
AddKeyValuePairs(optional_label_keys, optional_values, &key_value_pairs);
|
||
|
return absl::StrJoin(key_value_pairs, ",");
|
||
|
}
|
||
|
|
||
|
// TODO(yijiem): Move this to test/core/util/fake_stats_plugin.h
|
||
|
class FakeStatsPlugin : public StatsPlugin {
|
||
|
public:
|
||
|
bool IsEnabledForChannel(
|
||
|
const StatsPlugin::ChannelScope& scope) const override {
|
||
|
return channel_filter_(scope);
|
||
|
}
|
||
|
|
||
|
bool IsEnabledForServer(const ChannelArgs& /*args*/) const override {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void AddCounter(
|
||
|
GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
|
||
|
uint64_t value, absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) override {
|
||
|
// The problem with this approach is that we initialize uint64_counters_ in
|
||
|
// BuildAndRegister by querying the GlobalInstrumentsRegistry at the time.
|
||
|
// If the GlobalInstrumentsRegistry has changed since then (which we
|
||
|
// currently don't allow), we might not have seen that descriptor nor have
|
||
|
// we created an instrument for it. We probably could copy the existing
|
||
|
// instruments at build time and for the handle that we haven't seen we will
|
||
|
// just ignore it here. This would also prevent us from having to lock the
|
||
|
// GlobalInstrumentsRegistry everytime a metric is recorded. But this is not
|
||
|
// a concern for now.
|
||
|
auto iter = uint64_counters_.find(handle.index);
|
||
|
if (iter == uint64_counters_.end()) {
|
||
|
return;
|
||
|
}
|
||
|
iter->second.Add(value, label_values, optional_values);
|
||
|
}
|
||
|
void AddCounter(
|
||
|
GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle, double value,
|
||
|
absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) override {
|
||
|
auto iter = double_counters_.find(handle.index);
|
||
|
if (iter == double_counters_.end()) {
|
||
|
return;
|
||
|
}
|
||
|
iter->second.Add(value, label_values, optional_values);
|
||
|
}
|
||
|
void RecordHistogram(
|
||
|
GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,
|
||
|
uint64_t value, absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) override {
|
||
|
auto iter = uint64_histograms_.find(handle.index);
|
||
|
if (iter == uint64_histograms_.end()) {
|
||
|
return;
|
||
|
}
|
||
|
iter->second.Record(value, label_values, optional_values);
|
||
|
}
|
||
|
void RecordHistogram(
|
||
|
GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
|
||
|
double value, absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) override {
|
||
|
auto iter = double_histograms_.find(handle.index);
|
||
|
if (iter == double_histograms_.end()) {
|
||
|
return;
|
||
|
}
|
||
|
iter->second.Record(value, label_values, optional_values);
|
||
|
}
|
||
|
|
||
|
absl::optional<uint64_t> GetCounterValue(
|
||
|
GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
|
||
|
absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) {
|
||
|
auto iter = uint64_counters_.find(handle.index);
|
||
|
if (iter == uint64_counters_.end()) {
|
||
|
return absl::nullopt;
|
||
|
}
|
||
|
return iter->second.GetValue(label_values, optional_values);
|
||
|
}
|
||
|
absl::optional<double> GetCounterValue(
|
||
|
GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle,
|
||
|
absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) {
|
||
|
auto iter = double_counters_.find(handle.index);
|
||
|
if (iter == double_counters_.end()) {
|
||
|
return absl::nullopt;
|
||
|
}
|
||
|
return iter->second.GetValue(label_values, optional_values);
|
||
|
}
|
||
|
absl::optional<std::vector<uint64_t>> GetHistogramValue(
|
||
|
GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,
|
||
|
absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) {
|
||
|
auto iter = uint64_histograms_.find(handle.index);
|
||
|
if (iter == uint64_histograms_.end()) {
|
||
|
return absl::nullopt;
|
||
|
}
|
||
|
return iter->second.GetValues(label_values, optional_values);
|
||
|
}
|
||
|
absl::optional<std::vector<double>> GetHistogramValue(
|
||
|
GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
|
||
|
absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) {
|
||
|
auto iter = double_histograms_.find(handle.index);
|
||
|
if (iter == double_histograms_.end()) {
|
||
|
return absl::nullopt;
|
||
|
}
|
||
|
return iter->second.GetValues(label_values, optional_values);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
friend class FakeStatsPluginBuilder;
|
||
|
|
||
|
explicit FakeStatsPlugin(
|
||
|
absl::AnyInvocable<bool(const StatsPlugin::ChannelScope& /*scope*/) const>
|
||
|
channel_filter)
|
||
|
: channel_filter_(std::move(channel_filter)) {
|
||
|
GlobalInstrumentsRegistry::ForEach(
|
||
|
[this](const GlobalInstrumentsRegistry::GlobalInstrumentDescriptor&
|
||
|
descriptor) {
|
||
|
if (!descriptor.enable_by_default) {
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
class Counter {
|
||
|
public:
|
||
|
explicit Counter(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 Add(T t, 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()) {
|
||
|
iter->second += t;
|
||
|
} else {
|
||
|
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_;
|
||
|
// Aggregation of the same key attributes.
|
||
|
absl::flat_hash_map<std::string, T> storage_;
|
||
|
};
|
||
|
|
||
|
template <class T>
|
||
|
class Histogram {
|
||
|
public:
|
||
|
explicit Histogram(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 Record(T t, absl::Span<const absl::string_view> label_values,
|
||
|
absl::Span<const absl::string_view> optional_values) {
|
||
|
std::string key = MakeLabelString(label_keys_, label_values,
|
||
|
optional_label_keys_, optional_values);
|
||
|
auto iter = storage_.find(key);
|
||
|
if (iter == storage_.end()) {
|
||
|
storage_.emplace(key, std::initializer_list<T>{t});
|
||
|
} else {
|
||
|
iter->second.push_back(t);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
absl::optional<std::vector<T>> GetValues(
|
||
|
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, std::vector<T>> storage_;
|
||
|
};
|
||
|
|
||
|
absl::AnyInvocable<bool(const StatsPlugin::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_;
|
||
|
};
|
||
|
|
||
|
// TODO(yijiem): Move this to test/core/util/fake_stats_plugin.h
|
||
|
class FakeStatsPluginBuilder {
|
||
|
public:
|
||
|
FakeStatsPluginBuilder& SetChannelFilter(
|
||
|
absl::AnyInvocable<bool(const StatsPlugin::ChannelScope& /*scope*/) const>
|
||
|
channel_filter) {
|
||
|
channel_filter_ = std::move(channel_filter);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<FakeStatsPlugin> BuildAndRegister() {
|
||
|
auto f = std::shared_ptr<FakeStatsPlugin>(
|
||
|
new FakeStatsPlugin(std::move(channel_filter_)));
|
||
|
GlobalStatsPluginRegistry::RegisterStatsPlugin(f);
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
absl::AnyInvocable<bool(const StatsPlugin::ChannelScope& /*scope*/) const>
|
||
|
channel_filter_;
|
||
|
};
|
||
|
|
||
|
std::shared_ptr<FakeStatsPlugin> MakeStatsPluginForTarget(
|
||
|
absl::string_view target_suffix) {
|
||
|
return FakeStatsPluginBuilder()
|
||
|
.SetChannelFilter(
|
||
|
[target_suffix](const StatsPlugin::ChannelScope& scope) {
|
||
|
return absl::EndsWith(scope.target(), target_suffix);
|
||
|
})
|
||
|
.BuildAndRegister();
|
||
|
}
|
||
|
|
||
|
class MetricsTest : public testing::Test {
|
||
|
public:
|
||
|
void TearDown() override {
|
||
|
GlobalInstrumentsRegistry::TestOnlyResetGlobalInstrumentsRegistry();
|
||
|
GlobalStatsPluginRegistry::TestOnlyResetGlobalStatsPluginRegistry();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
TEST_F(MetricsTest, UInt64Counter) {
|
||
|
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 uint64_counter_handle = GlobalInstrumentsRegistry::RegisterUInt64Counter(
|
||
|
"uint64_counter", "A simple uint64 counter.", "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, ""))
|
||
|
.AddCounter(uint64_counter_handle, 1, kLabelValues, kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain2To4, ""))
|
||
|
.AddCounter(uint64_counter_handle, 2, kLabelValues, kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain3To4, ""))
|
||
|
.AddCounter(uint64_counter_handle, 3, kLabelValues, kOptionalLabelValues);
|
||
|
EXPECT_THAT(plugin1->GetCounterValue(uint64_counter_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(1));
|
||
|
EXPECT_THAT(plugin2->GetCounterValue(uint64_counter_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(3));
|
||
|
EXPECT_THAT(plugin3->GetCounterValue(uint64_counter_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(6));
|
||
|
}
|
||
|
|
||
|
TEST_F(MetricsTest, DoubleCounter) {
|
||
|
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_counter_handle = GlobalInstrumentsRegistry::RegisterDoubleCounter(
|
||
|
"double_counter", "A simple double counter.", "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, ""))
|
||
|
.AddCounter(double_counter_handle, 1.23, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain2To4, ""))
|
||
|
.AddCounter(double_counter_handle, 2.34, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain3To4, ""))
|
||
|
.AddCounter(double_counter_handle, 3.45, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
EXPECT_THAT(plugin1->GetCounterValue(double_counter_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(1.23));
|
||
|
EXPECT_THAT(plugin2->GetCounterValue(double_counter_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(3.57));
|
||
|
EXPECT_THAT(plugin3->GetCounterValue(double_counter_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(7.02));
|
||
|
}
|
||
|
|
||
|
TEST_F(MetricsTest, UInt64Histogram) {
|
||
|
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 uint64_histogram_handle =
|
||
|
GlobalInstrumentsRegistry::RegisterUInt64Histogram(
|
||
|
"uint64_histogram", "A simple uint64 histogram.", "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, ""))
|
||
|
.RecordHistogram(uint64_histogram_handle, 1, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain2To4, ""))
|
||
|
.RecordHistogram(uint64_histogram_handle, 2, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain3To4, ""))
|
||
|
.RecordHistogram(uint64_histogram_handle, 3, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
EXPECT_THAT(plugin1->GetHistogramValue(uint64_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(::testing::UnorderedElementsAre(1)));
|
||
|
EXPECT_THAT(plugin2->GetHistogramValue(uint64_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(::testing::UnorderedElementsAre(1, 2)));
|
||
|
EXPECT_THAT(plugin3->GetHistogramValue(uint64_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(::testing::UnorderedElementsAre(1, 2, 3)));
|
||
|
}
|
||
|
|
||
|
TEST_F(MetricsTest, DoubleHistogram) {
|
||
|
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_histogram_handle =
|
||
|
GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
||
|
"double_histogram", "A simple double histogram.", "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, ""))
|
||
|
.RecordHistogram(double_histogram_handle, 1.23, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain2To4, ""))
|
||
|
.RecordHistogram(double_histogram_handle, 2.34, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain3To4, ""))
|
||
|
.RecordHistogram(double_histogram_handle, 3.45, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
EXPECT_THAT(plugin1->GetHistogramValue(double_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(::testing::UnorderedElementsAre(1.23)));
|
||
|
EXPECT_THAT(plugin2->GetHistogramValue(double_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(::testing::UnorderedElementsAre(1.23, 2.34)));
|
||
|
EXPECT_THAT(
|
||
|
plugin3->GetHistogramValue(double_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
::testing::Optional(::testing::UnorderedElementsAre(1.23, 2.34, 3.45)));
|
||
|
}
|
||
|
|
||
|
TEST_F(MetricsTest, DisableByDefaultMetricIsNotRecordedByFakeStatsPlugin) {
|
||
|
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_histogram_handle =
|
||
|
GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
||
|
"double_histogram", "A simple double histogram.", "unit", kLabelKeys,
|
||
|
kOptionalLabelKeys, /*enable_by_default=*/false);
|
||
|
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";
|
||
|
auto plugin = MakeStatsPluginForTarget(kDomain1To4);
|
||
|
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
|
||
|
StatsPlugin::ChannelScope(kDomain1To4, ""))
|
||
|
.RecordHistogram(double_histogram_handle, 1.23, kLabelValues,
|
||
|
kOptionalLabelValues);
|
||
|
EXPECT_EQ(plugin->GetHistogramValue(double_histogram_handle, kLabelValues,
|
||
|
kOptionalLabelValues),
|
||
|
absl::nullopt);
|
||
|
}
|
||
|
|
||
|
using MetricsDeathTest = MetricsTest;
|
||
|
|
||
|
TEST_F(MetricsDeathTest, RegisterTheSameMetricNameWouldCrash) {
|
||
|
const absl::string_view kLabelKeys[] = {"label_key_1", "label_key_2"};
|
||
|
const absl::string_view kOptionalLabelKeys[] = {"optional_label_key_1",
|
||
|
"optional_label_key_2"};
|
||
|
(void)GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
||
|
"double_histogram", "A simple double histogram.", "unit", kLabelKeys,
|
||
|
kOptionalLabelKeys, true);
|
||
|
EXPECT_DEATH(GlobalInstrumentsRegistry::RegisterDoubleHistogram(
|
||
|
"double_histogram", "A simple double histogram.", "unit",
|
||
|
kLabelKeys, kOptionalLabelKeys, true),
|
||
|
"Metric name double_histogram has already been registered.");
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
} // namespace grpc_core
|
||
|
|
||
|
int main(int argc, char** argv) {
|
||
|
grpc::testing::TestEnvironment env(&argc, argv);
|
||
|
::testing::InitGoogleTest(&argc, argv);
|
||
|
int ret = RUN_ALL_TESTS();
|
||
|
return ret;
|
||
|
}
|