3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #ifndef GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
20 #define GRPC_CORE_LIB_CHANNEL_CHANNELZ_H
22 #include <grpc/impl/codegen/port_platform.h>
24 #include <grpc/grpc.h>
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"
41 // Channel arg key for channelz node.
42 #define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.channelz_channel_node"
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"
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
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
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);
66 class ListenSocketNode;
69 class CallCountingHelperPeer;
70 class ChannelNodePeer;
71 } // namespace testing
73 // base class for all channelz entities
74 class BaseNode : public RefCounted<BaseNode> {
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 {
88 BaseNode(EntityType type, std::string name);
93 // All children must implement this function.
94 virtual grpc_json* RenderJson() = 0;
96 // Renders the json and returns allocated string that must be freed by the
98 char* RenderJsonString();
100 EntityType type() const { return type_; }
101 intptr_t uuid() const { return uuid_; }
102 const std::string& name() const { return name_; }
105 // to allow the ChannelzRegistry to set uuid_ under its lock.
106 friend class ChannelzRegistry;
107 const EntityType type_;
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 {
120 CallCountingHelper();
122 void RecordCallStarted();
123 void RecordCallFailed();
124 void RecordCallSucceeded();
126 // Common rendering of the call count data and last_call_started_timestamp.
127 void PopulateCallCounts(grpc_json* json);
130 // testing peer friend.
131 friend class testing::CallCountingHelperPeer;
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)) {}
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>)];
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.
160 GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE);
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;
170 // collects the sharded data into one CounterData struct.
171 void CollectData(CounterData* out);
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;
178 // Handles channelz bookkeeping for channels
179 class ChannelNode : public BaseNode {
181 ChannelNode(std::string target, size_t channel_tracer_max_nodes,
182 intptr_t parent_uuid);
184 // Returns the string description of the given connectivity state.
185 static const char* GetChannelConnectivityStateChangeString(
186 grpc_connectivity_state state);
188 intptr_t parent_uuid() const { return parent_uuid_; }
190 grpc_json* RenderJson() override;
192 // proxy methods to composed classes.
193 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
194 trace_.AddTraceEvent(severity, data);
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));
202 void RecordCallStarted() { call_counter_.RecordCallStarted(); }
203 void RecordCallFailed() { call_counter_.RecordCallFailed(); }
204 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
206 void SetConnectivityState(grpc_connectivity_state state);
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);
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);
219 void PopulateChildRefs(grpc_json* json);
221 // to allow the channel trace test to access trace_.
222 friend class testing::ChannelNodePeer;
225 CallCountingHelper call_counter_;
227 const intptr_t parent_uuid_;
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};
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_;
241 // Handles channelz bookkeeping for servers
242 class ServerNode : public BaseNode {
244 ServerNode(grpc_server* server, size_t channel_tracer_max_nodes);
246 ~ServerNode() override;
248 grpc_json* RenderJson() override;
250 char* RenderServerSockets(intptr_t start_socket_id, intptr_t max_results);
252 void AddChildSocket(RefCountedPtr<SocketNode> node);
254 void RemoveChildSocket(intptr_t child_uuid);
256 void AddChildListenSocket(RefCountedPtr<ListenSocketNode> node);
258 void RemoveChildListenSocket(intptr_t child_uuid);
260 // proxy methods to composed classes.
261 void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
262 trace_.AddTraceEvent(severity, data);
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));
270 void RecordCallStarted() { call_counter_.RecordCallStarted(); }
271 void RecordCallFailed() { call_counter_.RecordCallFailed(); }
272 void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
275 CallCountingHelper call_counter_;
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_;
282 // Handles channelz bookkeeping for sockets
283 class SocketNode : public BaseNode {
285 SocketNode(std::string local, std::string remote, std::string name);
286 ~SocketNode() override {}
288 grpc_json* RenderJson() override;
290 void RecordStreamStartedFromLocal();
291 void RecordStreamStartedFromRemote();
292 void RecordStreamSucceeded() {
293 streams_succeeded_.FetchAdd(1, MemoryOrder::RELAXED);
295 void RecordStreamFailed() {
296 streams_failed_.FetchAdd(1, MemoryOrder::RELAXED);
298 void RecordMessagesSent(uint32_t num_sent);
299 void RecordMessageReceived();
300 void RecordKeepaliveSent() {
301 keepalives_sent_.FetchAdd(1, MemoryOrder::RELAXED);
304 const std::string& remote() { return remote_; }
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};
321 // Handles channelz bookkeeping for listen sockets
322 class ListenSocketNode : public BaseNode {
324 ListenSocketNode(std::string local_addr, std::string name);
325 ~ListenSocketNode() override {}
327 grpc_json* RenderJson() override;
330 std::string local_addr_;
333 } // namespace channelz
334 } // namespace grpc_core
336 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */