|
|
|
@ -19,7 +19,16 @@ |
|
|
|
|
#include <string> |
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
|
#include "absl/container/flat_hash_map.h" |
|
|
|
|
#include "absl/functional/any_invocable.h" |
|
|
|
|
#include "absl/status/status.h" |
|
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
|
#include "absl/types/optional.h" |
|
|
|
|
#include "absl/types/span.h" |
|
|
|
|
#include "gmock/gmock.h" |
|
|
|
|
|
|
|
|
|
#include "src/core/lib/channel/call_tracer.h" |
|
|
|
|
#include "src/core/lib/channel/metrics.h" |
|
|
|
|
#include "src/core/lib/channel/promise_based_filter.h" |
|
|
|
|
#include "src/core/lib/channel/tcp_tracer.h" |
|
|
|
|
|
|
|
|
@ -187,6 +196,315 @@ class FakeServerCallTracer : public ServerCallTracer { |
|
|
|
|
std::vector<std::string>* annotation_logger_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
class FakeStatsPlugin : public StatsPlugin { |
|
|
|
|
public: |
|
|
|
|
explicit FakeStatsPlugin( |
|
|
|
|
absl::AnyInvocable<bool(const ChannelScope& /*scope*/) const> |
|
|
|
|
channel_filter = nullptr, |
|
|
|
|
bool use_disabled_by_default_metrics = false) |
|
|
|
|
: channel_filter_(std::move(channel_filter)) { |
|
|
|
|
GlobalInstrumentsRegistry::ForEach( |
|
|
|
|
[&](const GlobalInstrumentsRegistry::GlobalInstrumentDescriptor& |
|
|
|
|
descriptor) { |
|
|
|
|
if (!use_disabled_by_default_metrics && |
|
|
|
|
!descriptor.enable_by_default) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"FakeStatsPlugin[%p]: skipping disabled metric: %s", this, |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool IsEnabledForChannel(const ChannelScope& scope) const override { |
|
|
|
|
if (channel_filter_ == nullptr) return true; |
|
|
|
|
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.
|
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"FakeStatsPlugin[%p]::AddCounter(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 = 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 { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"FakeStatsPlugin[%p]::AddCounter(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_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 { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"FakeStatsPlugin[%p]::RecordHistogram(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 = 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 { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"FakeStatsPlugin[%p]::RecordHistogram(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_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: |
|
|
|
|
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 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_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class FakeStatsPluginBuilder { |
|
|
|
|
public: |
|
|
|
|
FakeStatsPluginBuilder& SetChannelFilter( |
|
|
|
|
absl::AnyInvocable<bool(const StatsPlugin::ChannelScope& /*scope*/) const> |
|
|
|
|
channel_filter) { |
|
|
|
|
channel_filter_ = std::move(channel_filter); |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FakeStatsPluginBuilder& UseDisabledByDefaultMetrics(bool value) { |
|
|
|
|
use_disabled_by_default_metrics_ = value; |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::shared_ptr<FakeStatsPlugin> BuildAndRegister() { |
|
|
|
|
auto f = std::make_shared<FakeStatsPlugin>( |
|
|
|
|
std::move(channel_filter_), use_disabled_by_default_metrics_); |
|
|
|
|
GlobalStatsPluginRegistry::RegisterStatsPlugin(f); |
|
|
|
|
return f; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
absl::AnyInvocable<bool(const StatsPlugin::ChannelScope& /*scope*/) const> |
|
|
|
|
channel_filter_; |
|
|
|
|
bool use_disabled_by_default_metrics_ = false; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
std::shared_ptr<FakeStatsPlugin> MakeStatsPluginForTarget( |
|
|
|
|
absl::string_view target_suffix); |
|
|
|
|
|
|
|
|
|
class GlobalInstrumentsRegistryTestPeer { |
|
|
|
|
public: |
|
|
|
|
static void ResetGlobalInstrumentsRegistry(); |
|
|
|
|
|
|
|
|
|
static absl::optional<GlobalInstrumentsRegistry::GlobalUInt64CounterHandle> |
|
|
|
|
FindUInt64CounterHandleByName(absl::string_view name); |
|
|
|
|
static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleCounterHandle> |
|
|
|
|
FindDoubleCounterHandleByName(absl::string_view name); |
|
|
|
|
static absl::optional<GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle> |
|
|
|
|
FindUInt64HistogramHandleByName(absl::string_view name); |
|
|
|
|
static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle> |
|
|
|
|
FindDoubleHistogramHandleByName(absl::string_view name); |
|
|
|
|
|
|
|
|
|
static GlobalInstrumentsRegistry::GlobalInstrumentDescriptor* |
|
|
|
|
FindMetricDescriptorByName(absl::string_view name); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class GlobalStatsPluginRegistryTestPeer { |
|
|
|
|
public: |
|
|
|
|
static void ResetGlobalStatsPluginRegistry() { |
|
|
|
|
MutexLock lock(&*GlobalStatsPluginRegistry::mutex_); |
|
|
|
|
GlobalStatsPluginRegistry::plugins_->clear(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|
|
|
|
|
|
|
#endif // GRPC_TEST_CORE_UTIL_FAKE_STATS_PLUGIN_H
|
|
|
|
|