• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2018 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #ifndef GRPC_SRC_CORE_CHANNELZ_CHANNELZ_H
20 #define GRPC_SRC_CORE_CHANNELZ_CHANNELZ_H
21 
22 #include <grpc/grpc.h>
23 #include <grpc/impl/connectivity_state.h>
24 #include <grpc/slice.h>
25 #include <grpc/support/port_platform.h>
26 #include <stddef.h>
27 
28 #include <atomic>
29 #include <cstdint>
30 #include <map>
31 #include <set>
32 #include <string>
33 #include <utility>
34 
35 #include "absl/base/thread_annotations.h"
36 #include "absl/strings/string_view.h"
37 #include "absl/types/optional.h"
38 #include "src/core/channelz/channel_trace.h"
39 #include "src/core/util/json/json.h"
40 #include "src/core/util/per_cpu.h"
41 #include "src/core/util/ref_counted.h"
42 #include "src/core/util/ref_counted_ptr.h"
43 #include "src/core/util/sync.h"
44 #include "src/core/util/time_precise.h"
45 #include "src/core/util/useful.h"
46 
47 // Channel arg key for channelz node.
48 #define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.internal.channelz_channel_node"
49 
50 // Channel arg key for indicating an internal channel.
51 #define GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL \
52   "grpc.channelz_is_internal_channel"
53 
54 /// This is the default value for whether or not to enable channelz. If
55 /// GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value.
56 #define GRPC_ENABLE_CHANNELZ_DEFAULT true
57 
58 /// This is the default value for the maximum amount of memory used by trace
59 /// events per channel trace node. If
60 /// GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE is set, it will override
61 /// this default value.
62 #define GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT (1024 * 4)
63 
64 namespace grpc_core {
65 
66 namespace channelz {
67 
68 class SocketNode;
69 class ListenSocketNode;
70 
71 namespace testing {
72 class CallCountingHelperPeer;
73 class SubchannelNodePeer;
74 }  // namespace testing
75 
76 // base class for all channelz entities
77 class BaseNode : public RefCounted<BaseNode> {
78  public:
79   // There are only four high level channelz entities. However, to support
80   // GetTopChannelsRequest, we split the Channel entity into two different
81   // types. All children of BaseNode must be one of these types.
82   enum class EntityType {
83     kTopLevelChannel,
84     kInternalChannel,
85     kSubchannel,
86     kServer,
87     kSocket,
88   };
89 
90  protected:
91   BaseNode(EntityType type, std::string name);
92 
93  public:
94   ~BaseNode() override;
95 
96   // All children must implement this function.
97   virtual Json RenderJson() = 0;
98 
99   // Renders the json and returns allocated string that must be freed by the
100   // caller.
101   std::string RenderJsonString();
102 
type()103   EntityType type() const { return type_; }
uuid()104   intptr_t uuid() const { return uuid_; }
name()105   const std::string& name() const { return name_; }
106 
107  private:
108   // to allow the ChannelzRegistry to set uuid_ under its lock.
109   friend class ChannelzRegistry;
110   const EntityType type_;
111   intptr_t uuid_;
112   std::string name_;
113 };
114 
115 // This class is a helper class for channelz entities that deal with Channels,
116 // Subchannels, and Servers, since those have similar proto definitions.
117 // This class has the ability to:
118 //   - track calls_{started,succeeded,failed}
119 //   - track last_call_started_timestamp
120 //   - perform rendering of the above items
121 class CallCountingHelper final {
122  public:
123   void RecordCallStarted();
124   void RecordCallFailed();
125   void RecordCallSucceeded();
126 
127   // Common rendering of the call count data and last_call_started_timestamp.
128   void PopulateCallCounts(Json::Object* json);
129 
130  private:
131   // testing peer friend.
132   friend class testing::CallCountingHelperPeer;
133 
134   std::atomic<int64_t> calls_started_{0};
135   std::atomic<int64_t> calls_succeeded_{0};
136   std::atomic<int64_t> calls_failed_{0};
137   std::atomic<gpr_cycle_counter> last_call_started_cycle_{0};
138 };
139 
140 class PerCpuCallCountingHelper final {
141  public:
142   void RecordCallStarted();
143   void RecordCallFailed();
144   void RecordCallSucceeded();
145 
146   // Common rendering of the call count data and last_call_started_timestamp.
147   void PopulateCallCounts(Json::Object* json);
148 
149  private:
150   // testing peer friend.
151   friend class testing::CallCountingHelperPeer;
152 
153   // We want to ensure that this per-cpu data structure lands on different
154   // cachelines per cpu.
155   // With C++17 we can do so explicitly with an `alignas` specifier.
156   // Prior versions we can at best approximate it by padding the structure.
157   // It'll probably work out ok, but it's not guaranteed across allocators.
158   // (in the bad case where this gets split across cachelines we'll just have
159   // two cpus fighting over the same cacheline with a slight performance
160   // degregation).
161   // TODO(ctiller): When we move to C++17 delete the duplicate definition.
162 #if __cplusplus >= 201703L
163   struct alignas(GPR_CACHELINE_SIZE) PerCpuData {
164     std::atomic<int64_t> calls_started{0};
165     std::atomic<int64_t> calls_succeeded{0};
166     std::atomic<int64_t> calls_failed{0};
167     std::atomic<gpr_cycle_counter> last_call_started_cycle{0};
168   };
169 #else
170   struct PerCpuDataHeader {
171     std::atomic<int64_t> calls_started{0};
172     std::atomic<int64_t> calls_succeeded{0};
173     std::atomic<int64_t> calls_failed{0};
174     std::atomic<gpr_cycle_counter> last_call_started_cycle{0};
175   };
176   struct PerCpuData : public PerCpuDataHeader {
177     uint8_t padding[GPR_CACHELINE_SIZE - sizeof(PerCpuDataHeader)];
178   };
179 #endif
180   PerCpu<PerCpuData> per_cpu_data_{PerCpuOptions().SetCpusPerShard(4)};
181 };
182 
183 // Handles channelz bookkeeping for channels
184 class ChannelNode final : public BaseNode {
185  public:
186   ChannelNode(std::string target, size_t channel_tracer_max_nodes,
187               bool is_internal_channel);
188 
ChannelArgName()189   static absl::string_view ChannelArgName() {
190     return GRPC_ARG_CHANNELZ_CHANNEL_NODE;
191   }
ChannelArgsCompare(const ChannelNode * a,const ChannelNode * b)192   static int ChannelArgsCompare(const ChannelNode* a, const ChannelNode* b) {
193     return QsortCompare(a, b);
194   }
195 
196   // Returns the string description of the given connectivity state.
197   static const char* GetChannelConnectivityStateChangeString(
198       grpc_connectivity_state state);
199 
200   Json RenderJson() override;
201 
202   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)203   void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
204     trace_.AddTraceEvent(severity, data);
205   }
AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)206   void AddTraceEventWithReference(ChannelTrace::Severity severity,
207                                   const grpc_slice& data,
208                                   RefCountedPtr<BaseNode> referenced_channel) {
209     trace_.AddTraceEventWithReference(severity, data,
210                                       std::move(referenced_channel));
211   }
RecordCallStarted()212   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()213   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()214   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
215 
216   void SetConnectivityState(grpc_connectivity_state state);
217 
218   // TODO(roth): take in a RefCountedPtr to the child channel so we can retrieve
219   // the human-readable name.
220   void AddChildChannel(intptr_t child_uuid);
221   void RemoveChildChannel(intptr_t child_uuid);
222 
223   // TODO(roth): take in a RefCountedPtr to the child subchannel so we can
224   // retrieve the human-readable name.
225   void AddChildSubchannel(intptr_t child_uuid);
226   void RemoveChildSubchannel(intptr_t child_uuid);
227 
228  private:
229   void PopulateChildRefs(Json::Object* json);
230 
231   std::string target_;
232   CallCountingHelper call_counter_;
233   ChannelTrace trace_;
234 
235   // Least significant bit indicates whether the value is set.  Remaining
236   // bits are a grpc_connectivity_state value.
237   std::atomic<int> connectivity_state_{0};
238 
239   Mutex child_mu_;  // Guards sets below.
240   std::set<intptr_t> child_channels_;
241   std::set<intptr_t> child_subchannels_;
242 };
243 
244 // Handles channelz bookkeeping for subchannels
245 class SubchannelNode final : public BaseNode {
246  public:
247   SubchannelNode(std::string target_address, size_t channel_tracer_max_nodes);
248   ~SubchannelNode() override;
249 
250   // Sets the subchannel's connectivity state without health checking.
251   void UpdateConnectivityState(grpc_connectivity_state state);
252 
253   // Used when the subchannel's child socket changes. This should be set when
254   // the subchannel's transport is created and set to nullptr when the
255   // subchannel unrefs the transport.
256   void SetChildSocket(RefCountedPtr<SocketNode> socket);
257 
258   Json RenderJson() override;
259 
260   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)261   void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
262     trace_.AddTraceEvent(severity, data);
263   }
AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)264   void AddTraceEventWithReference(ChannelTrace::Severity severity,
265                                   const grpc_slice& data,
266                                   RefCountedPtr<BaseNode> referenced_channel) {
267     trace_.AddTraceEventWithReference(severity, data,
268                                       std::move(referenced_channel));
269   }
RecordCallStarted()270   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()271   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()272   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
273 
274  private:
275   // Allows the channel trace test to access trace_.
276   friend class testing::SubchannelNodePeer;
277 
278   std::atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE};
279   Mutex socket_mu_;
280   RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_);
281   std::string target_;
282   CallCountingHelper call_counter_;
283   ChannelTrace trace_;
284 };
285 
286 // Handles channelz bookkeeping for servers
287 class ServerNode final : public BaseNode {
288  public:
289   explicit ServerNode(size_t channel_tracer_max_nodes);
290 
291   ~ServerNode() override;
292 
293   Json RenderJson() override;
294 
295   std::string RenderServerSockets(intptr_t start_socket_id,
296                                   intptr_t max_results);
297 
298   void AddChildSocket(RefCountedPtr<SocketNode> node);
299 
300   void RemoveChildSocket(intptr_t child_uuid);
301 
302   void AddChildListenSocket(RefCountedPtr<ListenSocketNode> node);
303 
304   void RemoveChildListenSocket(intptr_t child_uuid);
305 
306   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)307   void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
308     trace_.AddTraceEvent(severity, data);
309   }
AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)310   void AddTraceEventWithReference(ChannelTrace::Severity severity,
311                                   const grpc_slice& data,
312                                   RefCountedPtr<BaseNode> referenced_channel) {
313     trace_.AddTraceEventWithReference(severity, data,
314                                       std::move(referenced_channel));
315   }
RecordCallStarted()316   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()317   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()318   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
319 
320  private:
321   PerCpuCallCountingHelper call_counter_;
322   ChannelTrace trace_;
323   Mutex child_mu_;  // Guards child maps below.
324   std::map<intptr_t, RefCountedPtr<SocketNode>> child_sockets_;
325   std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets_;
326 };
327 
328 #define GRPC_ARG_CHANNELZ_SECURITY "grpc.internal.channelz_security"
329 
330 // Handles channelz bookkeeping for sockets
331 class SocketNode final : public BaseNode {
332  public:
333   struct Security : public RefCounted<Security> {
334     struct Tls {
335       // This is a workaround for https://bugs.llvm.org/show_bug.cgi?id=50346
TlsSecurity::Tls336       Tls() {}
337 
338       enum class NameType { kUnset = 0, kStandardName = 1, kOtherName = 2 };
339       NameType type = NameType::kUnset;
340       // Holds the value of standard_name or other_names if type is not kUnset.
341       std::string name;
342       std::string local_certificate;
343       std::string remote_certificate;
344 
345       Json RenderJson();
346     };
347     enum class ModelType { kUnset = 0, kTls = 1, kOther = 2 };
348     ModelType type = ModelType::kUnset;
349     absl::optional<Tls> tls;
350     absl::optional<Json> other;
351 
352     Json RenderJson();
353 
ChannelArgNameSecurity354     static absl::string_view ChannelArgName() {
355       return GRPC_ARG_CHANNELZ_SECURITY;
356     }
357 
ChannelArgsCompareSecurity358     static int ChannelArgsCompare(const Security* a, const Security* b) {
359       return QsortCompare(a, b);
360     }
361 
362     grpc_arg MakeChannelArg() const;
363 
364     static RefCountedPtr<Security> GetFromChannelArgs(
365         const grpc_channel_args* args);
366   };
367 
368   SocketNode(std::string local, std::string remote, std::string name,
369              RefCountedPtr<Security> security);
~SocketNode()370   ~SocketNode() override {}
371 
372   Json RenderJson() override;
373 
374   void RecordStreamStartedFromLocal();
375   void RecordStreamStartedFromRemote();
RecordStreamSucceeded()376   void RecordStreamSucceeded() {
377     streams_succeeded_.fetch_add(1, std::memory_order_relaxed);
378   }
RecordStreamFailed()379   void RecordStreamFailed() {
380     streams_failed_.fetch_add(1, std::memory_order_relaxed);
381   }
382   void RecordMessagesSent(uint32_t num_sent);
383   void RecordMessageReceived();
RecordKeepaliveSent()384   void RecordKeepaliveSent() {
385     keepalives_sent_.fetch_add(1, std::memory_order_relaxed);
386   }
387 
remote()388   const std::string& remote() { return remote_; }
389 
390  private:
391   std::atomic<int64_t> streams_started_{0};
392   std::atomic<int64_t> streams_succeeded_{0};
393   std::atomic<int64_t> streams_failed_{0};
394   std::atomic<int64_t> messages_sent_{0};
395   std::atomic<int64_t> messages_received_{0};
396   std::atomic<int64_t> keepalives_sent_{0};
397   std::atomic<gpr_cycle_counter> last_local_stream_created_cycle_{0};
398   std::atomic<gpr_cycle_counter> last_remote_stream_created_cycle_{0};
399   std::atomic<gpr_cycle_counter> last_message_sent_cycle_{0};
400   std::atomic<gpr_cycle_counter> last_message_received_cycle_{0};
401   std::string local_;
402   std::string remote_;
403   RefCountedPtr<Security> const security_;
404 };
405 
406 // Handles channelz bookkeeping for listen sockets
407 class ListenSocketNode final : public BaseNode {
408  public:
409   ListenSocketNode(std::string local_addr, std::string name);
~ListenSocketNode()410   ~ListenSocketNode() override {}
411 
412   Json RenderJson() override;
413 
414  private:
415   std::string local_addr_;
416 };
417 
418 }  // namespace channelz
419 }  // namespace grpc_core
420 
421 #endif  // GRPC_SRC_CORE_CHANNELZ_CHANNELZ_H
422