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