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