• 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_CORE_LIB_CHANNEL_CHANNELZ_H
20 #define GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
21 
22 #include <grpc/impl/codegen/port_platform.h>
23 
24 #include <grpc/grpc.h>
25 
26 #include <set>
27 #include <string>
28 
29 #include "absl/container/inlined_vector.h"
30 
31 #include "src/core/lib/channel/channel_trace.h"
32 #include "src/core/lib/gpr/time_precise.h"
33 #include "src/core/lib/gprpp/atomic.h"
34 #include "src/core/lib/gprpp/manual_constructor.h"
35 #include "src/core/lib/gprpp/ref_counted.h"
36 #include "src/core/lib/gprpp/ref_counted_ptr.h"
37 #include "src/core/lib/gprpp/sync.h"
38 #include "src/core/lib/iomgr/error.h"
39 #include "src/core/lib/iomgr/exec_ctx.h"
40 #include "src/core/lib/json/json.h"
41 
42 // Channel arg key for channelz node.
43 #define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.channelz_channel_node"
44 
45 // Channel arg key for indicating an internal channel.
46 #define GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL \
47   "grpc.channelz_is_internal_channel"
48 
49 /** This is the default value for whether or not to enable channelz. If
50  * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */
51 #define GRPC_ENABLE_CHANNELZ_DEFAULT true
52 
53 /** This is the default value for the maximum amount of memory used by trace
54  * events per channel trace node. If
55  * GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE is set, it will override
56  * this default value. */
57 #define GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT (1024 * 4)
58 
59 namespace grpc_core {
60 
61 namespace channelz {
62 
63 class SocketNode;
64 class ListenSocketNode;
65 
66 namespace testing {
67 class CallCountingHelperPeer;
68 class ChannelNodePeer;
69 }  // namespace testing
70 
71 // base class for all channelz entities
72 class BaseNode : public RefCounted<BaseNode> {
73  public:
74   // There are only four high level channelz entities. However, to support
75   // GetTopChannelsRequest, we split the Channel entity into two different
76   // types. All children of BaseNode must be one of these types.
77   enum class EntityType {
78     kTopLevelChannel,
79     kInternalChannel,
80     kSubchannel,
81     kServer,
82     kSocket,
83   };
84 
85  protected:
86   BaseNode(EntityType type, std::string name);
87 
88  public:
89   ~BaseNode() override;
90 
91   // All children must implement this function.
92   virtual Json RenderJson() = 0;
93 
94   // Renders the json and returns allocated string that must be freed by the
95   // caller.
96   std::string RenderJsonString();
97 
type()98   EntityType type() const { return type_; }
uuid()99   intptr_t uuid() const { return uuid_; }
name()100   const std::string& name() const { return name_; }
101 
102  private:
103   // to allow the ChannelzRegistry to set uuid_ under its lock.
104   friend class ChannelzRegistry;
105   const EntityType type_;
106   intptr_t uuid_;
107   std::string name_;
108 };
109 
110 // This class is a helper class for channelz entities that deal with Channels,
111 // Subchannels, and Servers, since those have similar proto definitions.
112 // This class has the ability to:
113 //   - track calls_{started,succeeded,failed}
114 //   - track last_call_started_timestamp
115 //   - perform rendering of the above items
116 class CallCountingHelper {
117  public:
118   CallCountingHelper();
119 
120   void RecordCallStarted();
121   void RecordCallFailed();
122   void RecordCallSucceeded();
123 
124   // Common rendering of the call count data and last_call_started_timestamp.
125   void PopulateCallCounts(Json::Object* json);
126 
127  private:
128   // testing peer friend.
129   friend class testing::CallCountingHelperPeer;
130 
131   // TODO(soheil): add a proper PerCPU helper and use it here.
132   struct AtomicCounterData {
133     // Define the ctors so that we can use this structure in InlinedVector.
134     AtomicCounterData() = default;
AtomicCounterDataAtomicCounterData135     AtomicCounterData(const AtomicCounterData& that)
136         : calls_started(that.calls_started.Load(MemoryOrder::RELAXED)),
137           calls_succeeded(that.calls_succeeded.Load(MemoryOrder::RELAXED)),
138           calls_failed(that.calls_failed.Load(MemoryOrder::RELAXED)),
139           last_call_started_cycle(
140               that.last_call_started_cycle.Load(MemoryOrder::RELAXED)) {}
141 
142     Atomic<int64_t> calls_started{0};
143     Atomic<int64_t> calls_succeeded{0};
144     Atomic<int64_t> calls_failed{0};
145     Atomic<gpr_cycle_counter> last_call_started_cycle{0};
146     // Make sure the size is exactly one cache line.
147     uint8_t padding[GPR_CACHELINE_SIZE - 3 * sizeof(Atomic<intptr_t>) -
148                     sizeof(Atomic<gpr_cycle_counter>)];
149   };
150   // TODO(soheilhy,veblush): Revist this after abseil integration.
151   // This has a problem when using abseil inlined_vector because it
152   // carries an alignment attribute properly but our allocator doesn't
153   // respect this. To avoid UBSAN errors, this should be removed with
154   // abseil inlined_vector.
155   // GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE);
156 
157   struct CounterData {
158     int64_t calls_started = 0;
159     int64_t calls_succeeded = 0;
160     int64_t calls_failed = 0;
161     gpr_cycle_counter last_call_started_cycle = 0;
162   };
163 
164   // collects the sharded data into one CounterData struct.
165   void CollectData(CounterData* out);
166 
167   // Really zero-sized, but 0-sized arrays are illegal on MSVC.
168   absl::InlinedVector<AtomicCounterData, 1> per_cpu_counter_data_storage_;
169   size_t num_cores_ = 0;
170 };
171 
172 // Handles channelz bookkeeping for channels
173 class ChannelNode : public BaseNode {
174  public:
175   ChannelNode(std::string target, size_t channel_tracer_max_nodes,
176               bool is_internal_channel);
177 
178   // Returns the string description of the given connectivity state.
179   static const char* GetChannelConnectivityStateChangeString(
180       grpc_connectivity_state state);
181 
182   Json RenderJson() override;
183 
184   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)185   void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
186     trace_.AddTraceEvent(severity, data);
187   }
AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)188   void AddTraceEventWithReference(ChannelTrace::Severity severity,
189                                   const grpc_slice& data,
190                                   RefCountedPtr<BaseNode> referenced_channel) {
191     trace_.AddTraceEventWithReference(severity, data,
192                                       std::move(referenced_channel));
193   }
RecordCallStarted()194   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()195   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()196   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
197 
198   void SetConnectivityState(grpc_connectivity_state state);
199 
200   // TODO(roth): take in a RefCountedPtr to the child channel so we can retrieve
201   // the human-readable name.
202   void AddChildChannel(intptr_t child_uuid);
203   void RemoveChildChannel(intptr_t child_uuid);
204 
205   // TODO(roth): take in a RefCountedPtr to the child subchannel so we can
206   // retrieve the human-readable name.
207   void AddChildSubchannel(intptr_t child_uuid);
208   void RemoveChildSubchannel(intptr_t child_uuid);
209 
210  private:
211   // Allows the channel trace test to access trace_.
212   friend class testing::ChannelNodePeer;
213 
214   void PopulateChildRefs(Json::Object* json);
215 
216   std::string target_;
217   CallCountingHelper call_counter_;
218   ChannelTrace trace_;
219 
220   // Least significant bit indicates whether the value is set.  Remaining
221   // bits are a grpc_connectivity_state value.
222   Atomic<int> connectivity_state_{0};
223 
224   Mutex child_mu_;  // Guards sets below.
225   std::set<intptr_t> child_channels_;
226   std::set<intptr_t> child_subchannels_;
227 };
228 
229 // Handles channelz bookkeeping for servers
230 class ServerNode : public BaseNode {
231  public:
232   explicit ServerNode(size_t channel_tracer_max_nodes);
233 
234   ~ServerNode() override;
235 
236   Json RenderJson() override;
237 
238   std::string RenderServerSockets(intptr_t start_socket_id,
239                                   intptr_t max_results);
240 
241   void AddChildSocket(RefCountedPtr<SocketNode> node);
242 
243   void RemoveChildSocket(intptr_t child_uuid);
244 
245   void AddChildListenSocket(RefCountedPtr<ListenSocketNode> node);
246 
247   void RemoveChildListenSocket(intptr_t child_uuid);
248 
249   // proxy methods to composed classes.
AddTraceEvent(ChannelTrace::Severity severity,const grpc_slice & data)250   void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
251     trace_.AddTraceEvent(severity, data);
252   }
AddTraceEventWithReference(ChannelTrace::Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_channel)253   void AddTraceEventWithReference(ChannelTrace::Severity severity,
254                                   const grpc_slice& data,
255                                   RefCountedPtr<BaseNode> referenced_channel) {
256     trace_.AddTraceEventWithReference(severity, data,
257                                       std::move(referenced_channel));
258   }
RecordCallStarted()259   void RecordCallStarted() { call_counter_.RecordCallStarted(); }
RecordCallFailed()260   void RecordCallFailed() { call_counter_.RecordCallFailed(); }
RecordCallSucceeded()261   void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
262 
263  private:
264   CallCountingHelper call_counter_;
265   ChannelTrace trace_;
266   Mutex child_mu_;  // Guards child maps below.
267   std::map<intptr_t, RefCountedPtr<SocketNode>> child_sockets_;
268   std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets_;
269 };
270 
271 // Handles channelz bookkeeping for sockets
272 class SocketNode : public BaseNode {
273  public:
274   SocketNode(std::string local, std::string remote, std::string name);
~SocketNode()275   ~SocketNode() override {}
276 
277   Json RenderJson() override;
278 
279   void RecordStreamStartedFromLocal();
280   void RecordStreamStartedFromRemote();
RecordStreamSucceeded()281   void RecordStreamSucceeded() {
282     streams_succeeded_.FetchAdd(1, MemoryOrder::RELAXED);
283   }
RecordStreamFailed()284   void RecordStreamFailed() {
285     streams_failed_.FetchAdd(1, MemoryOrder::RELAXED);
286   }
287   void RecordMessagesSent(uint32_t num_sent);
288   void RecordMessageReceived();
RecordKeepaliveSent()289   void RecordKeepaliveSent() {
290     keepalives_sent_.FetchAdd(1, MemoryOrder::RELAXED);
291   }
292 
remote()293   const std::string& remote() { return remote_; }
294 
295  private:
296   Atomic<int64_t> streams_started_{0};
297   Atomic<int64_t> streams_succeeded_{0};
298   Atomic<int64_t> streams_failed_{0};
299   Atomic<int64_t> messages_sent_{0};
300   Atomic<int64_t> messages_received_{0};
301   Atomic<int64_t> keepalives_sent_{0};
302   Atomic<gpr_cycle_counter> last_local_stream_created_cycle_{0};
303   Atomic<gpr_cycle_counter> last_remote_stream_created_cycle_{0};
304   Atomic<gpr_cycle_counter> last_message_sent_cycle_{0};
305   Atomic<gpr_cycle_counter> last_message_received_cycle_{0};
306   std::string local_;
307   std::string remote_;
308 };
309 
310 // Handles channelz bookkeeping for listen sockets
311 class ListenSocketNode : public BaseNode {
312  public:
313   ListenSocketNode(std::string local_addr, std::string name);
~ListenSocketNode()314   ~ListenSocketNode() override {}
315 
316   Json RenderJson() override;
317 
318  private:
319   std::string local_addr_;
320 };
321 
322 }  // namespace channelz
323 }  // namespace grpc_core
324 
325 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */
326