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