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