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