• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 #include "src/core/telemetry/metrics.h"
16 
17 #include <grpc/support/port_platform.h>
18 
19 #include <memory>
20 
21 #include "absl/log/check.h"
22 #include "absl/types/optional.h"
23 #include "src/core/util/crash.h"
24 
25 namespace grpc_core {
26 
27 // Uses the Construct-on-First-Use idiom to avoid the static initialization
28 // order fiasco.
29 std::vector<GlobalInstrumentsRegistry::GlobalInstrumentDescriptor>&
GetInstrumentList()30 GlobalInstrumentsRegistry::GetInstrumentList() {
31   static NoDestruct<
32       std::vector<GlobalInstrumentsRegistry::GlobalInstrumentDescriptor>>
33       instruments;
34   return *instruments;
35 }
36 
37 GlobalInstrumentsRegistry::InstrumentID
RegisterInstrument(GlobalInstrumentsRegistry::ValueType value_type,GlobalInstrumentsRegistry::InstrumentType instrument_type,absl::string_view name,absl::string_view description,absl::string_view unit,bool enable_by_default,absl::Span<const absl::string_view> label_keys,absl::Span<const absl::string_view> optional_label_keys)38 GlobalInstrumentsRegistry::RegisterInstrument(
39     GlobalInstrumentsRegistry::ValueType value_type,
40     GlobalInstrumentsRegistry::InstrumentType instrument_type,
41     absl::string_view name, absl::string_view description,
42     absl::string_view unit, bool enable_by_default,
43     absl::Span<const absl::string_view> label_keys,
44     absl::Span<const absl::string_view> optional_label_keys) {
45   auto& instruments = GetInstrumentList();
46   for (const auto& descriptor : instruments) {
47     if (descriptor.name == name) {
48       Crash(
49           absl::StrFormat("Metric name %s has already been registered.", name));
50     }
51   }
52   InstrumentID index = instruments.size();
53   CHECK_LT(index, std::numeric_limits<uint32_t>::max());
54   GlobalInstrumentDescriptor descriptor;
55   descriptor.value_type = value_type;
56   descriptor.instrument_type = instrument_type;
57   descriptor.index = index;
58   descriptor.enable_by_default = enable_by_default;
59   descriptor.name = name;
60   descriptor.description = description;
61   descriptor.unit = unit;
62   descriptor.label_keys = {label_keys.begin(), label_keys.end()};
63   descriptor.optional_label_keys = {optional_label_keys.begin(),
64                                     optional_label_keys.end()};
65   instruments.push_back(std::move(descriptor));
66   return index;
67 }
68 
ForEach(absl::FunctionRef<void (const GlobalInstrumentDescriptor &)> f)69 void GlobalInstrumentsRegistry::ForEach(
70     absl::FunctionRef<void(const GlobalInstrumentDescriptor&)> f) {
71   for (const auto& instrument : GetInstrumentList()) {
72     f(instrument);
73   }
74 }
75 
76 const GlobalInstrumentsRegistry::GlobalInstrumentDescriptor&
GetInstrumentDescriptor(GlobalInstrumentHandle handle)77 GlobalInstrumentsRegistry::GetInstrumentDescriptor(
78     GlobalInstrumentHandle handle) {
79   return GetInstrumentList().at(handle.index);
80 }
81 
RegisteredMetricCallback(GlobalStatsPluginRegistry::StatsPluginGroup & stats_plugin_group,absl::AnyInvocable<void (CallbackMetricReporter &)> callback,std::vector<GlobalInstrumentsRegistry::GlobalInstrumentHandle> metrics,Duration min_interval)82 RegisteredMetricCallback::RegisteredMetricCallback(
83     GlobalStatsPluginRegistry::StatsPluginGroup& stats_plugin_group,
84     absl::AnyInvocable<void(CallbackMetricReporter&)> callback,
85     std::vector<GlobalInstrumentsRegistry::GlobalInstrumentHandle> metrics,
86     Duration min_interval)
87     : stats_plugin_group_(stats_plugin_group),
88       callback_(std::move(callback)),
89       metrics_(std::move(metrics)),
90       min_interval_(min_interval) {
91   for (auto& state : stats_plugin_group_.plugins_state_) {
92     state.plugin->AddCallback(this);
93   }
94 }
95 
~RegisteredMetricCallback()96 RegisteredMetricCallback::~RegisteredMetricCallback() {
97   for (auto& state : stats_plugin_group_.plugins_state_) {
98     state.plugin->RemoveCallback(this);
99   }
100 }
101 
AddClientCallTracers(const Slice & path,bool registered_method,Arena * arena)102 void GlobalStatsPluginRegistry::StatsPluginGroup::AddClientCallTracers(
103     const Slice& path, bool registered_method, Arena* arena) {
104   for (auto& state : plugins_state_) {
105     auto* call_tracer = state.plugin->GetClientCallTracer(
106         path, registered_method, state.scope_config);
107     if (call_tracer != nullptr) {
108       AddClientCallTracerToContext(arena, call_tracer);
109     }
110   }
111 }
112 
AddServerCallTracers(Arena * arena)113 void GlobalStatsPluginRegistry::StatsPluginGroup::AddServerCallTracers(
114     Arena* arena) {
115   for (auto& state : plugins_state_) {
116     auto* call_tracer = state.plugin->GetServerCallTracer(state.scope_config);
117     if (call_tracer != nullptr) {
118       AddServerCallTracerToContext(arena, call_tracer);
119     }
120   }
121 }
122 
123 std::atomic<GlobalStatsPluginRegistry::GlobalStatsPluginNode*>
124     GlobalStatsPluginRegistry::plugins_;
125 
RegisterStatsPlugin(std::shared_ptr<StatsPlugin> plugin)126 void GlobalStatsPluginRegistry::RegisterStatsPlugin(
127     std::shared_ptr<StatsPlugin> plugin) {
128   GlobalStatsPluginNode* node = new GlobalStatsPluginNode();
129   node->plugin = std::move(plugin);
130   node->next = plugins_.load(std::memory_order_relaxed);
131   while (!plugins_.compare_exchange_weak(
132       node->next, node, std::memory_order_acq_rel, std::memory_order_relaxed)) {
133   }
134 }
135 
136 GlobalStatsPluginRegistry::StatsPluginGroup
GetStatsPluginsForChannel(const experimental::StatsPluginChannelScope & scope)137 GlobalStatsPluginRegistry::GetStatsPluginsForChannel(
138     const experimental::StatsPluginChannelScope& scope) {
139   StatsPluginGroup group;
140   for (GlobalStatsPluginNode* node = plugins_.load(std::memory_order_acquire);
141        node != nullptr; node = node->next) {
142     bool is_enabled = false;
143     std::shared_ptr<StatsPlugin::ScopeConfig> config;
144     std::tie(is_enabled, config) = node->plugin->IsEnabledForChannel(scope);
145     if (is_enabled) {
146       group.AddStatsPlugin(node->plugin, std::move(config));
147     }
148   }
149   return group;
150 }
151 
152 GlobalStatsPluginRegistry::StatsPluginGroup
GetStatsPluginsForServer(const ChannelArgs & args)153 GlobalStatsPluginRegistry::GetStatsPluginsForServer(const ChannelArgs& args) {
154   StatsPluginGroup group;
155   for (GlobalStatsPluginNode* node = plugins_.load(std::memory_order_acquire);
156        node != nullptr; node = node->next) {
157     bool is_enabled = false;
158     std::shared_ptr<StatsPlugin::ScopeConfig> config;
159     std::tie(is_enabled, config) = node->plugin->IsEnabledForServer(args);
160     if (is_enabled) {
161       group.AddStatsPlugin(node->plugin, std::move(config));
162     }
163   }
164   return group;
165 }
166 
167 absl::optional<GlobalInstrumentsRegistry::GlobalInstrumentHandle>
FindInstrumentByName(absl::string_view name)168 GlobalInstrumentsRegistry::FindInstrumentByName(absl::string_view name) {
169   const auto& instruments = GetInstrumentList();
170   for (const auto& descriptor : instruments) {
171     if (descriptor.name == name) {
172       GlobalInstrumentsRegistry::GlobalInstrumentHandle handle;
173       handle.index = descriptor.index;
174       return handle;
175     }
176   }
177   return absl::nullopt;
178 }
179 
180 }  // namespace grpc_core
181