xref: /aosp_15_r20/external/grpc-grpc/test/core/util/fake_stats_plugin.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2023 The gRPC Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_TEST_CORE_UTIL_FAKE_STATS_PLUGIN_H
16 #define GRPC_TEST_CORE_UTIL_FAKE_STATS_PLUGIN_H
17 
18 #include <memory>
19 #include <string>
20 #include <vector>
21 
22 #include "absl/container/flat_hash_map.h"
23 #include "absl/functional/any_invocable.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/string_view.h"
26 #include "absl/types/optional.h"
27 #include "absl/types/span.h"
28 #include "gmock/gmock.h"
29 
30 #include "src/core/lib/channel/call_tracer.h"
31 #include "src/core/lib/channel/metrics.h"
32 #include "src/core/lib/channel/promise_based_filter.h"
33 #include "src/core/lib/channel/tcp_tracer.h"
34 
35 namespace grpc_core {
36 
37 // Registers a FakeStatsClientFilter as a client channel filter if there is a
38 // FakeClientCallTracerFactory in the channel args. This filter will use the
39 // FakeClientCallTracerFactory to create and inject a FakeClientCallTracer into
40 // the call context.
41 // Example usage:
42 //   RegisterFakeStatsPlugin();  // before grpc_init()
43 //
44 //   // Creates a FakeClientCallTracerFactory and adds it into the channel args.
45 //   FakeClientCallTracerFactory fake_client_call_tracer_factory;
46 //   ChannelArguments channel_args;
47 //   channel_args.SetPointer(GRPC_ARG_INJECT_FAKE_CLIENT_CALL_TRACER_FACTORY,
48 //                           &fake_client_call_tracer_factory);
49 //
50 //   // After the system under test has been executed (e.g. an RPC has been
51 //   // sent), use the FakeClientCallTracerFactory to verify certain
52 //   // expectations.
53 //   EXPECT_THAT(fake_client_call_tracer_factory.GetLastFakeClientCallTracer()
54 //                   ->GetLastCallAttemptTracer()
55 //                   ->GetOptionalLabels(),
56 //               VerifyCsmServiceLabels());
57 void RegisterFakeStatsPlugin();
58 
59 class FakeClientCallTracer : public ClientCallTracer {
60  public:
61   class FakeClientCallAttemptTracer
62       : public ClientCallTracer::CallAttemptTracer {
63    public:
FakeClientCallAttemptTracer(std::vector<std::string> * annotation_logger)64     explicit FakeClientCallAttemptTracer(
65         std::vector<std::string>* annotation_logger)
66         : annotation_logger_(annotation_logger) {}
~FakeClientCallAttemptTracer()67     ~FakeClientCallAttemptTracer() override {}
RecordSendInitialMetadata(grpc_metadata_batch *)68     void RecordSendInitialMetadata(
69         grpc_metadata_batch* /*send_initial_metadata*/) override {}
RecordSendTrailingMetadata(grpc_metadata_batch *)70     void RecordSendTrailingMetadata(
71         grpc_metadata_batch* /*send_trailing_metadata*/) override {}
RecordSendMessage(const SliceBuffer &)72     void RecordSendMessage(const SliceBuffer& /*send_message*/) override {}
RecordSendCompressedMessage(const SliceBuffer &)73     void RecordSendCompressedMessage(
74         const SliceBuffer& /*send_compressed_message*/) override {}
RecordReceivedInitialMetadata(grpc_metadata_batch *)75     void RecordReceivedInitialMetadata(
76         grpc_metadata_batch* /*recv_initial_metadata*/) override {}
RecordReceivedMessage(const SliceBuffer &)77     void RecordReceivedMessage(const SliceBuffer& /*recv_message*/) override {}
RecordReceivedDecompressedMessage(const SliceBuffer &)78     void RecordReceivedDecompressedMessage(
79         const SliceBuffer& /*recv_decompressed_message*/) override {}
RecordCancel(grpc_error_handle)80     void RecordCancel(grpc_error_handle /*cancel_error*/) override {}
RecordReceivedTrailingMetadata(absl::Status,grpc_metadata_batch *,const grpc_transport_stream_stats *)81     void RecordReceivedTrailingMetadata(
82         absl::Status /*status*/,
83         grpc_metadata_batch* /*recv_trailing_metadata*/,
84         const grpc_transport_stream_stats* /*transport_stream_stats*/)
85         override {}
RecordEnd(const gpr_timespec &)86     void RecordEnd(const gpr_timespec& /*latency*/) override {}
RecordAnnotation(absl::string_view annotation)87     void RecordAnnotation(absl::string_view annotation) override {
88       annotation_logger_->push_back(std::string(annotation));
89     }
RecordAnnotation(const Annotation &)90     void RecordAnnotation(const Annotation& /*annotation*/) override {}
StartNewTcpTrace()91     std::shared_ptr<TcpTracerInterface> StartNewTcpTrace() override {
92       return nullptr;
93     }
SetOptionalLabel(OptionalLabelKey key,RefCountedStringValue value)94     void SetOptionalLabel(OptionalLabelKey key,
95                           RefCountedStringValue value) override {
96       optional_labels_.emplace(key, std::move(value));
97     }
TraceId()98     std::string TraceId() override { return ""; }
SpanId()99     std::string SpanId() override { return ""; }
IsSampled()100     bool IsSampled() override { return false; }
101 
GetOptionalLabels()102     const std::map<OptionalLabelKey, RefCountedStringValue>& GetOptionalLabels()
103         const {
104       return optional_labels_;
105     }
106 
107    private:
108     std::vector<std::string>* annotation_logger_;
109     std::map<OptionalLabelKey, RefCountedStringValue> optional_labels_;
110   };
111 
FakeClientCallTracer(std::vector<std::string> * annotation_logger)112   explicit FakeClientCallTracer(std::vector<std::string>* annotation_logger)
113       : annotation_logger_(annotation_logger) {}
~FakeClientCallTracer()114   ~FakeClientCallTracer() override {}
StartNewAttempt(bool)115   CallAttemptTracer* StartNewAttempt(bool /*is_transparent_retry*/) override {
116     call_attempt_tracers_.emplace_back(
117         new FakeClientCallAttemptTracer(annotation_logger_));
118     return call_attempt_tracers_.back().get();
119   }
120 
RecordAnnotation(absl::string_view annotation)121   void RecordAnnotation(absl::string_view annotation) override {
122     annotation_logger_->push_back(std::string(annotation));
123   }
RecordAnnotation(const Annotation &)124   void RecordAnnotation(const Annotation& /*annotation*/) override {}
TraceId()125   std::string TraceId() override { return ""; }
SpanId()126   std::string SpanId() override { return ""; }
IsSampled()127   bool IsSampled() override { return false; }
128 
GetLastCallAttemptTracer()129   FakeClientCallAttemptTracer* GetLastCallAttemptTracer() const {
130     return call_attempt_tracers_.back().get();
131   }
132 
133  private:
134   std::vector<std::string>* annotation_logger_;
135   std::vector<std::unique_ptr<FakeClientCallAttemptTracer>>
136       call_attempt_tracers_;
137 };
138 
139 #define GRPC_ARG_INJECT_FAKE_CLIENT_CALL_TRACER_FACTORY \
140   "grpc.testing.inject_fake_client_call_tracer_factory"
141 
142 class FakeClientCallTracerFactory {
143  public:
CreateFakeClientCallTracer()144   FakeClientCallTracer* CreateFakeClientCallTracer() {
145     fake_client_call_tracers_.emplace_back(
146         new FakeClientCallTracer(&annotation_logger_));
147     return fake_client_call_tracers_.back().get();
148   }
149 
GetLastFakeClientCallTracer()150   FakeClientCallTracer* GetLastFakeClientCallTracer() {
151     return fake_client_call_tracers_.back().get();
152   }
153 
154  private:
155   std::vector<std::string> annotation_logger_;
156   std::vector<std::unique_ptr<FakeClientCallTracer>> fake_client_call_tracers_;
157 };
158 
159 class FakeServerCallTracer : public ServerCallTracer {
160  public:
FakeServerCallTracer(std::vector<std::string> * annotation_logger)161   explicit FakeServerCallTracer(std::vector<std::string>* annotation_logger)
162       : annotation_logger_(annotation_logger) {}
~FakeServerCallTracer()163   ~FakeServerCallTracer() override {}
RecordSendInitialMetadata(grpc_metadata_batch *)164   void RecordSendInitialMetadata(
165       grpc_metadata_batch* /*send_initial_metadata*/) override {}
RecordSendTrailingMetadata(grpc_metadata_batch *)166   void RecordSendTrailingMetadata(
167       grpc_metadata_batch* /*send_trailing_metadata*/) override {}
RecordSendMessage(const SliceBuffer &)168   void RecordSendMessage(const SliceBuffer& /*send_message*/) override {}
RecordSendCompressedMessage(const SliceBuffer &)169   void RecordSendCompressedMessage(
170       const SliceBuffer& /*send_compressed_message*/) override {}
RecordReceivedInitialMetadata(grpc_metadata_batch *)171   void RecordReceivedInitialMetadata(
172       grpc_metadata_batch* /*recv_initial_metadata*/) override {}
RecordReceivedMessage(const SliceBuffer &)173   void RecordReceivedMessage(const SliceBuffer& /*recv_message*/) override {}
RecordReceivedDecompressedMessage(const SliceBuffer &)174   void RecordReceivedDecompressedMessage(
175       const SliceBuffer& /*recv_decompressed_message*/) override {}
RecordCancel(grpc_error_handle)176   void RecordCancel(grpc_error_handle /*cancel_error*/) override {}
RecordReceivedTrailingMetadata(grpc_metadata_batch *)177   void RecordReceivedTrailingMetadata(
178       grpc_metadata_batch* /*recv_trailing_metadata*/) override {}
RecordEnd(const grpc_call_final_info *)179   void RecordEnd(const grpc_call_final_info* /*final_info*/) override {}
RecordAnnotation(absl::string_view annotation)180   void RecordAnnotation(absl::string_view annotation) override {
181     annotation_logger_->push_back(std::string(annotation));
182   }
RecordAnnotation(const Annotation &)183   void RecordAnnotation(const Annotation& /*annotation*/) override {}
StartNewTcpTrace()184   std::shared_ptr<TcpTracerInterface> StartNewTcpTrace() override {
185     return nullptr;
186   }
TraceId()187   std::string TraceId() override { return ""; }
SpanId()188   std::string SpanId() override { return ""; }
IsSampled()189   bool IsSampled() override { return false; }
190 
191  private:
192   std::vector<std::string>* annotation_logger_;
193 };
194 
195 std::string MakeLabelString(
196     absl::Span<const absl::string_view> label_keys,
197     absl::Span<const absl::string_view> label_values,
198     absl::Span<const absl::string_view> optional_label_keys,
199     absl::Span<const absl::string_view> optional_values);
200 
201 class FakeStatsPlugin : public StatsPlugin {
202  public:
203   class ScopeConfig : public StatsPlugin::ScopeConfig {};
204 
205   explicit FakeStatsPlugin(
206       absl::AnyInvocable<
207           bool(const experimental::StatsPluginChannelScope& /*scope*/) const>
208           channel_filter = nullptr,
209       bool use_disabled_by_default_metrics = false)
channel_filter_(std::move (channel_filter))210       : channel_filter_(std::move(channel_filter)) {
211     GlobalInstrumentsRegistry::ForEach(
212         [&](const GlobalInstrumentsRegistry::GlobalInstrumentDescriptor&
213                 descriptor) {
214           if (!use_disabled_by_default_metrics &&
215               !descriptor.enable_by_default) {
216             gpr_log(GPR_INFO,
217                     "FakeStatsPlugin[%p]: skipping disabled metric: %s", this,
218                     std::string(descriptor.name).c_str());
219             return;
220           }
221           switch (descriptor.instrument_type) {
222             case GlobalInstrumentsRegistry::InstrumentType::kCounter: {
223               MutexLock lock(&mu_);
224               if (descriptor.value_type ==
225                   GlobalInstrumentsRegistry::ValueType::kUInt64) {
226                 uint64_counters_.emplace(descriptor.index, descriptor);
227               } else {
228                 double_counters_.emplace(descriptor.index, descriptor);
229               }
230               break;
231             }
232             case GlobalInstrumentsRegistry::InstrumentType::kHistogram: {
233               MutexLock lock(&mu_);
234               if (descriptor.value_type ==
235                   GlobalInstrumentsRegistry::ValueType::kUInt64) {
236                 uint64_histograms_.emplace(descriptor.index, descriptor);
237               } else {
238                 double_histograms_.emplace(descriptor.index, descriptor);
239               }
240               break;
241             }
242             case GlobalInstrumentsRegistry::InstrumentType::kGauge: {
243               MutexLock lock(&mu_);
244               if (descriptor.value_type ==
245                   GlobalInstrumentsRegistry::ValueType::kInt64) {
246                 int64_gauges_.emplace(descriptor.index, descriptor);
247               } else {
248                 double_gauges_.emplace(descriptor.index, descriptor);
249               }
250               break;
251             }
252             case GlobalInstrumentsRegistry::InstrumentType::kCallbackGauge: {
253               MutexLock lock(&callback_mu_);
254               if (descriptor.value_type ==
255                   GlobalInstrumentsRegistry::ValueType::kInt64) {
256                 int64_callback_gauges_.emplace(descriptor.index, descriptor);
257               } else {
258                 double_callback_gauges_.emplace(descriptor.index, descriptor);
259               }
260               break;
261             }
262             default:
263               Crash("unknown instrument type");
264           }
265         });
266   }
267 
268   std::pair<bool, std::shared_ptr<StatsPlugin::ScopeConfig>>
IsEnabledForChannel(const experimental::StatsPluginChannelScope & scope)269   IsEnabledForChannel(
270       const experimental::StatsPluginChannelScope& scope) const override {
271     if (channel_filter_ == nullptr || channel_filter_(scope)) {
272       return {true, nullptr};
273     }
274     return {false, nullptr};
275   }
IsEnabledForServer(const ChannelArgs &)276   std::pair<bool, std::shared_ptr<StatsPlugin::ScopeConfig>> IsEnabledForServer(
277       const ChannelArgs& /*args*/) const override {
278     return {true, nullptr};
279   }
280 
AddCounter(GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,uint64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)281   void AddCounter(
282       GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
283       uint64_t value, absl::Span<const absl::string_view> label_values,
284       absl::Span<const absl::string_view> optional_values) override {
285     // The problem with this approach is that we initialize uint64_counters_ in
286     // BuildAndRegister by querying the GlobalInstrumentsRegistry at the time.
287     // If the GlobalInstrumentsRegistry has changed since then (which we
288     // currently don't allow), we might not have seen that descriptor nor have
289     // we created an instrument for it. We probably could copy the existing
290     // instruments at build time and for the handle that we haven't seen we will
291     // just ignore it here. This would also prevent us from having to lock the
292     // GlobalInstrumentsRegistry everytime a metric is recorded. But this is not
293     // a concern for now.
294     gpr_log(GPR_INFO,
295             "FakeStatsPlugin[%p]::AddCounter(index=%u, value=(uint64)%lu, "
296             "label_values={%s}, optional_label_values={%s}",
297             this, handle.index, value,
298             absl::StrJoin(label_values, ", ").c_str(),
299             absl::StrJoin(optional_values, ", ").c_str());
300     MutexLock lock(&mu_);
301     auto iter = uint64_counters_.find(handle.index);
302     if (iter == uint64_counters_.end()) return;
303     iter->second.Add(value, label_values, optional_values);
304   }
AddCounter(GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)305   void AddCounter(
306       GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle, double value,
307       absl::Span<const absl::string_view> label_values,
308       absl::Span<const absl::string_view> optional_values) override {
309     gpr_log(GPR_INFO,
310             "FakeStatsPlugin[%p]::AddCounter(index=%u, value(double)=%f, "
311             "label_values={%s}, optional_label_values={%s}",
312             this, handle.index, value,
313             absl::StrJoin(label_values, ", ").c_str(),
314             absl::StrJoin(optional_values, ", ").c_str());
315     MutexLock lock(&mu_);
316     auto iter = double_counters_.find(handle.index);
317     if (iter == double_counters_.end()) return;
318     iter->second.Add(value, label_values, optional_values);
319   }
RecordHistogram(GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,uint64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)320   void RecordHistogram(
321       GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,
322       uint64_t value, absl::Span<const absl::string_view> label_values,
323       absl::Span<const absl::string_view> optional_values) override {
324     gpr_log(GPR_INFO,
325             "FakeStatsPlugin[%p]::RecordHistogram(index=%u, value=(uint64)%lu, "
326             "label_values={%s}, optional_label_values={%s}",
327             this, handle.index, value,
328             absl::StrJoin(label_values, ", ").c_str(),
329             absl::StrJoin(optional_values, ", ").c_str());
330     MutexLock lock(&mu_);
331     auto iter = uint64_histograms_.find(handle.index);
332     if (iter == uint64_histograms_.end()) return;
333     iter->second.Record(value, label_values, optional_values);
334   }
RecordHistogram(GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)335   void RecordHistogram(
336       GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
337       double value, absl::Span<const absl::string_view> label_values,
338       absl::Span<const absl::string_view> optional_values) override {
339     gpr_log(GPR_INFO,
340             "FakeStatsPlugin[%p]::RecordHistogram(index=%u, value=(double)%f, "
341             "label_values={%s}, optional_label_values={%s}",
342             this, handle.index, value,
343             absl::StrJoin(label_values, ", ").c_str(),
344             absl::StrJoin(optional_values, ", ").c_str());
345     MutexLock lock(&mu_);
346     auto iter = double_histograms_.find(handle.index);
347     if (iter == double_histograms_.end()) return;
348     iter->second.Record(value, label_values, optional_values);
349   }
SetGauge(GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,int64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)350   void SetGauge(GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,
351                 int64_t value, absl::Span<const absl::string_view> label_values,
352                 absl::Span<const absl::string_view> optional_values) override {
353     gpr_log(GPR_INFO,
354             "FakeStatsPlugin[%p]::RecordGauge(index=%u, value=(uint64)%lu, "
355             "label_values={%s}, optional_label_values={%s}",
356             this, handle.index, value,
357             absl::StrJoin(label_values, ", ").c_str(),
358             absl::StrJoin(optional_values, ", ").c_str());
359     MutexLock lock(&mu_);
360     auto iter = int64_gauges_.find(handle.index);
361     if (iter == int64_gauges_.end()) return;
362     iter->second.Set(value, label_values, optional_values);
363   }
SetGauge(GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)364   void SetGauge(GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,
365                 double value, absl::Span<const absl::string_view> label_values,
366                 absl::Span<const absl::string_view> optional_values) override {
367     gpr_log(GPR_INFO,
368             "FakeStatsPlugin[%p]::RecordGauge(index=%u, value=(double)%f, "
369             "label_values={%s}, optional_label_values={%s}",
370             this, handle.index, value,
371             absl::StrJoin(label_values, ", ").c_str(),
372             absl::StrJoin(optional_values, ", ").c_str());
373     MutexLock lock(&mu_);
374     auto iter = double_gauges_.find(handle.index);
375     if (iter == double_gauges_.end()) return;
376     iter->second.Set(value, label_values, optional_values);
377   }
AddCallback(RegisteredMetricCallback * callback)378   void AddCallback(RegisteredMetricCallback* callback) override {
379     gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::AddCallback(%p)", this, callback);
380     callbacks_.insert(callback);
381   }
RemoveCallback(RegisteredMetricCallback * callback)382   void RemoveCallback(RegisteredMetricCallback* callback) override {
383     gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::RemoveCallback(%p)", this,
384             callback);
385     callbacks_.erase(callback);
386   }
387 
GetClientCallTracer(const Slice &,bool,std::shared_ptr<StatsPlugin::ScopeConfig>)388   ClientCallTracer* GetClientCallTracer(
389       const Slice& /*path*/, bool /*registered_method*/,
390       std::shared_ptr<StatsPlugin::ScopeConfig> /*scope_config*/) override {
391     return nullptr;
392   }
GetServerCallTracer(std::shared_ptr<StatsPlugin::ScopeConfig>)393   ServerCallTracer* GetServerCallTracer(
394       std::shared_ptr<StatsPlugin::ScopeConfig> /*scope_config*/) override {
395     return nullptr;
396   }
397 
GetCounterValue(GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)398   absl::optional<uint64_t> GetCounterValue(
399       GlobalInstrumentsRegistry::GlobalUInt64CounterHandle handle,
400       absl::Span<const absl::string_view> label_values,
401       absl::Span<const absl::string_view> optional_values) {
402     MutexLock lock(&mu_);
403     auto iter = uint64_counters_.find(handle.index);
404     if (iter == uint64_counters_.end()) {
405       return absl::nullopt;
406     }
407     return iter->second.GetValue(label_values, optional_values);
408   }
GetCounterValue(GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)409   absl::optional<double> GetCounterValue(
410       GlobalInstrumentsRegistry::GlobalDoubleCounterHandle handle,
411       absl::Span<const absl::string_view> label_values,
412       absl::Span<const absl::string_view> optional_values) {
413     MutexLock lock(&mu_);
414     auto iter = double_counters_.find(handle.index);
415     if (iter == double_counters_.end()) {
416       return absl::nullopt;
417     }
418     return iter->second.GetValue(label_values, optional_values);
419   }
GetHistogramValue(GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)420   absl::optional<std::vector<uint64_t>> GetHistogramValue(
421       GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle handle,
422       absl::Span<const absl::string_view> label_values,
423       absl::Span<const absl::string_view> optional_values) {
424     MutexLock lock(&mu_);
425     auto iter = uint64_histograms_.find(handle.index);
426     if (iter == uint64_histograms_.end()) {
427       return absl::nullopt;
428     }
429     return iter->second.GetValues(label_values, optional_values);
430   }
GetHistogramValue(GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)431   absl::optional<std::vector<double>> GetHistogramValue(
432       GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle handle,
433       absl::Span<const absl::string_view> label_values,
434       absl::Span<const absl::string_view> optional_values) {
435     MutexLock lock(&mu_);
436     auto iter = double_histograms_.find(handle.index);
437     if (iter == double_histograms_.end()) {
438       return absl::nullopt;
439     }
440     return iter->second.GetValues(label_values, optional_values);
441   }
GetGaugeValue(GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)442   absl::optional<int64_t> GetGaugeValue(
443       GlobalInstrumentsRegistry::GlobalInt64GaugeHandle handle,
444       absl::Span<const absl::string_view> label_values,
445       absl::Span<const absl::string_view> optional_values) {
446     MutexLock lock(&mu_);
447     auto iter = int64_gauges_.find(handle.index);
448     if (iter == int64_gauges_.end()) {
449       return absl::nullopt;
450     }
451     return iter->second.GetValue(label_values, optional_values);
452   }
GetGaugeValue(GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)453   absl::optional<double> GetGaugeValue(
454       GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle handle,
455       absl::Span<const absl::string_view> label_values,
456       absl::Span<const absl::string_view> optional_values) {
457     MutexLock lock(&mu_);
458     auto iter = double_gauges_.find(handle.index);
459     if (iter == double_gauges_.end()) {
460       return absl::nullopt;
461     }
462     return iter->second.GetValue(label_values, optional_values);
463   }
TriggerCallbacks()464   void TriggerCallbacks() {
465     gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::TriggerCallbacks(): START", this);
466     Reporter reporter(*this);
467     for (auto* callback : callbacks_) {
468       callback->Run(reporter);
469     }
470     gpr_log(GPR_INFO, "FakeStatsPlugin[%p]::TriggerCallbacks(): END", this);
471   }
GetCallbackGaugeValue(GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)472   absl::optional<int64_t> GetCallbackGaugeValue(
473       GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
474       absl::Span<const absl::string_view> label_values,
475       absl::Span<const absl::string_view> optional_values) {
476     MutexLock lock(&callback_mu_);
477     auto iter = int64_callback_gauges_.find(handle.index);
478     if (iter == int64_callback_gauges_.end()) {
479       return absl::nullopt;
480     }
481     return iter->second.GetValue(label_values, optional_values);
482   }
GetCallbackGaugeValue(GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)483   absl::optional<double> GetCallbackGaugeValue(
484       GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,
485       absl::Span<const absl::string_view> label_values,
486       absl::Span<const absl::string_view> optional_values) {
487     MutexLock lock(&callback_mu_);
488     auto iter = double_callback_gauges_.find(handle.index);
489     if (iter == double_callback_gauges_.end()) {
490       return absl::nullopt;
491     }
492     return iter->second.GetValue(label_values, optional_values);
493   }
494 
495  private:
496   class Reporter : public CallbackMetricReporter {
497    public:
Reporter(FakeStatsPlugin & plugin)498     explicit Reporter(FakeStatsPlugin& plugin) : plugin_(plugin) {}
499 
Report(GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,int64_t value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)500     void Report(
501         GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle handle,
502         int64_t value, absl::Span<const absl::string_view> label_values,
503         absl::Span<const absl::string_view> optional_values) override {
504       gpr_log(GPR_INFO,
505               "FakeStatsPlugin[%p]::Reporter::Report(index=%u, "
506               "value=(uint64)%ld, label_values={%s}, "
507               "optional_label_values={%s}",
508               this, handle.index, value,
509               absl::StrJoin(label_values, ", ").c_str(),
510               absl::StrJoin(optional_values, ", ").c_str());
511       MutexLock lock(&plugin_.callback_mu_);
512       auto iter = plugin_.int64_callback_gauges_.find(handle.index);
513       if (iter == plugin_.int64_callback_gauges_.end()) return;
514       iter->second.Set(value, label_values, optional_values);
515     }
516 
Report(GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,double value,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)517     void Report(
518         GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle handle,
519         double value, absl::Span<const absl::string_view> label_values,
520         absl::Span<const absl::string_view> optional_values) override {
521       gpr_log(GPR_INFO,
522               "FakeStatsPlugin[%p]::Reporter::Report(index=%u, "
523               "value=(double)%f, label_values={%s}, "
524               "optional_label_values={%s}",
525               this, handle.index, value,
526               absl::StrJoin(label_values, ", ").c_str(),
527               absl::StrJoin(optional_values, ", ").c_str());
528       MutexLock lock(&plugin_.callback_mu_);
529       auto iter = plugin_.double_callback_gauges_.find(handle.index);
530       if (iter == plugin_.double_callback_gauges_.end()) return;
531       iter->second.Set(value, label_values, optional_values);
532     }
533 
534    private:
535     FakeStatsPlugin& plugin_;
536   };
537 
538   template <class T>
539   class Counter {
540    public:
Counter(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)541     explicit Counter(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)
542         : name_(u.name),
543           description_(u.description),
544           unit_(u.unit),
545           label_keys_(std::move(u.label_keys)),
546           optional_label_keys_(std::move(u.optional_label_keys)) {}
547 
Add(T t,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)548     void Add(T t, absl::Span<const absl::string_view> label_values,
549              absl::Span<const absl::string_view> optional_values) {
550       auto iter = storage_.find(MakeLabelString(
551           label_keys_, label_values, optional_label_keys_, optional_values));
552       if (iter != storage_.end()) {
553         iter->second += t;
554       } else {
555         storage_[MakeLabelString(label_keys_, label_values,
556                                  optional_label_keys_, optional_values)] = t;
557       }
558     }
559 
GetValue(absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)560     absl::optional<T> GetValue(
561         absl::Span<const absl::string_view> label_values,
562         absl::Span<const absl::string_view> optional_values) {
563       auto iter = storage_.find(MakeLabelString(
564           label_keys_, label_values, optional_label_keys_, optional_values));
565       if (iter == storage_.end()) {
566         return absl::nullopt;
567       }
568       return iter->second;
569     }
570 
571    private:
572     absl::string_view name_;
573     absl::string_view description_;
574     absl::string_view unit_;
575     std::vector<absl::string_view> label_keys_;
576     std::vector<absl::string_view> optional_label_keys_;
577     // Aggregation of the same key attributes.
578     absl::flat_hash_map<std::string, T> storage_;
579   };
580 
581   template <class T>
582   class Histogram {
583    public:
Histogram(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)584     explicit Histogram(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)
585         : name_(u.name),
586           description_(u.description),
587           unit_(u.unit),
588           label_keys_(std::move(u.label_keys)),
589           optional_label_keys_(std::move(u.optional_label_keys)) {}
590 
Record(T t,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)591     void Record(T t, absl::Span<const absl::string_view> label_values,
592                 absl::Span<const absl::string_view> optional_values) {
593       std::string key = MakeLabelString(label_keys_, label_values,
594                                         optional_label_keys_, optional_values);
595       auto iter = storage_.find(key);
596       if (iter == storage_.end()) {
597         storage_.emplace(key, std::initializer_list<T>{t});
598       } else {
599         iter->second.push_back(t);
600       }
601     }
602 
GetValues(absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)603     absl::optional<std::vector<T>> GetValues(
604         absl::Span<const absl::string_view> label_values,
605         absl::Span<const absl::string_view> optional_values) {
606       auto iter = storage_.find(MakeLabelString(
607           label_keys_, label_values, optional_label_keys_, optional_values));
608       if (iter == storage_.end()) {
609         return absl::nullopt;
610       }
611       return iter->second;
612     }
613 
614    private:
615     absl::string_view name_;
616     absl::string_view description_;
617     absl::string_view unit_;
618     std::vector<absl::string_view> label_keys_;
619     std::vector<absl::string_view> optional_label_keys_;
620     absl::flat_hash_map<std::string, std::vector<T>> storage_;
621   };
622 
623   template <class T>
624   class Gauge {
625    public:
Gauge(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)626     explicit Gauge(GlobalInstrumentsRegistry::GlobalInstrumentDescriptor u)
627         : name_(u.name),
628           description_(u.description),
629           unit_(u.unit),
630           label_keys_(std::move(u.label_keys)),
631           optional_label_keys_(std::move(u.optional_label_keys)) {}
632 
Set(T t,absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)633     void Set(T t, absl::Span<const absl::string_view> label_values,
634              absl::Span<const absl::string_view> optional_values) {
635       storage_[MakeLabelString(label_keys_, label_values, optional_label_keys_,
636                                optional_values)] = t;
637     }
638 
GetValue(absl::Span<const absl::string_view> label_values,absl::Span<const absl::string_view> optional_values)639     absl::optional<T> GetValue(
640         absl::Span<const absl::string_view> label_values,
641         absl::Span<const absl::string_view> optional_values) {
642       auto iter = storage_.find(MakeLabelString(
643           label_keys_, label_values, optional_label_keys_, optional_values));
644       if (iter == storage_.end()) {
645         return absl::nullopt;
646       }
647       return iter->second;
648     }
649 
650    private:
651     absl::string_view name_;
652     absl::string_view description_;
653     absl::string_view unit_;
654     std::vector<absl::string_view> label_keys_;
655     std::vector<absl::string_view> optional_label_keys_;
656     absl::flat_hash_map<std::string, T> storage_;
657   };
658 
659   absl::AnyInvocable<bool(
660       const experimental::StatsPluginChannelScope& /*scope*/) const>
661       channel_filter_;
662   // Instruments.
663   Mutex mu_;
664   absl::flat_hash_map<uint32_t, Counter<uint64_t>> uint64_counters_
665       ABSL_GUARDED_BY(&mu_);
666   absl::flat_hash_map<uint32_t, Counter<double>> double_counters_
667       ABSL_GUARDED_BY(&mu_);
668   absl::flat_hash_map<uint32_t, Histogram<uint64_t>> uint64_histograms_
669       ABSL_GUARDED_BY(&mu_);
670   absl::flat_hash_map<uint32_t, Histogram<double>> double_histograms_
671       ABSL_GUARDED_BY(&mu_);
672   absl::flat_hash_map<uint32_t, Gauge<int64_t>> int64_gauges_
673       ABSL_GUARDED_BY(&mu_);
674   absl::flat_hash_map<uint32_t, Gauge<double>> double_gauges_
675       ABSL_GUARDED_BY(&mu_);
676   Mutex callback_mu_;
677   absl::flat_hash_map<uint32_t, Gauge<int64_t>> int64_callback_gauges_
678       ABSL_GUARDED_BY(&callback_mu_);
679   absl::flat_hash_map<uint32_t, Gauge<double>> double_callback_gauges_
680       ABSL_GUARDED_BY(&callback_mu_);
681   std::set<RegisteredMetricCallback*> callbacks_;
682 };
683 
684 class FakeStatsPluginBuilder {
685  public:
SetChannelFilter(absl::AnyInvocable<bool (const experimental::StatsPluginChannelScope &)const> channel_filter)686   FakeStatsPluginBuilder& SetChannelFilter(
687       absl::AnyInvocable<
688           bool(const experimental::StatsPluginChannelScope& /*scope*/) const>
689           channel_filter) {
690     channel_filter_ = std::move(channel_filter);
691     return *this;
692   }
693 
UseDisabledByDefaultMetrics(bool value)694   FakeStatsPluginBuilder& UseDisabledByDefaultMetrics(bool value) {
695     use_disabled_by_default_metrics_ = value;
696     return *this;
697   }
698 
BuildAndRegister()699   std::shared_ptr<FakeStatsPlugin> BuildAndRegister() {
700     auto f = std::make_shared<FakeStatsPlugin>(
701         std::move(channel_filter_), use_disabled_by_default_metrics_);
702     GlobalStatsPluginRegistry::RegisterStatsPlugin(f);
703     return f;
704   }
705 
706  private:
707   absl::AnyInvocable<bool(
708       const experimental::StatsPluginChannelScope& /*scope*/) const>
709       channel_filter_;
710   bool use_disabled_by_default_metrics_ = false;
711 };
712 
713 std::shared_ptr<FakeStatsPlugin> MakeStatsPluginForTarget(
714     absl::string_view target_suffix);
715 
716 class GlobalInstrumentsRegistryTestPeer {
717  public:
718   static void ResetGlobalInstrumentsRegistry();
719 
720   static absl::optional<GlobalInstrumentsRegistry::GlobalUInt64CounterHandle>
721   FindUInt64CounterHandleByName(absl::string_view name);
722   static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleCounterHandle>
723   FindDoubleCounterHandleByName(absl::string_view name);
724   static absl::optional<GlobalInstrumentsRegistry::GlobalUInt64HistogramHandle>
725   FindUInt64HistogramHandleByName(absl::string_view name);
726   static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleHistogramHandle>
727   FindDoubleHistogramHandleByName(absl::string_view name);
728   static absl::optional<GlobalInstrumentsRegistry::GlobalInt64GaugeHandle>
729   FindInt64GaugeHandleByName(absl::string_view name);
730   static absl::optional<GlobalInstrumentsRegistry::GlobalDoubleGaugeHandle>
731   FindDoubleGaugeHandleByName(absl::string_view name);
732   static absl::optional<
733       GlobalInstrumentsRegistry::GlobalCallbackInt64GaugeHandle>
734   FindCallbackInt64GaugeHandleByName(absl::string_view name);
735   static absl::optional<
736       GlobalInstrumentsRegistry::GlobalCallbackDoubleGaugeHandle>
737   FindCallbackDoubleGaugeHandleByName(absl::string_view name);
738 
739   static GlobalInstrumentsRegistry::GlobalInstrumentDescriptor*
740   FindMetricDescriptorByName(absl::string_view name);
741 };
742 
743 class GlobalStatsPluginRegistryTestPeer {
744  public:
ResetGlobalStatsPluginRegistry()745   static void ResetGlobalStatsPluginRegistry() {
746     MutexLock lock(&*GlobalStatsPluginRegistry::mutex_);
747     GlobalStatsPluginRegistry::plugins_->clear();
748   }
749 };
750 
751 }  // namespace grpc_core
752 
753 #endif  // GRPC_TEST_CORE_UTIL_FAKE_STATS_PLUGIN_H
754