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