3 * Copyright 2017 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 #include <grpc/impl/codegen/port_platform.h>
21 #include "src/core/lib/channel/channelz.h"
23 #include <grpc/grpc.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/string_util.h>
31 #include "src/core/lib/channel/channelz_registry.h"
32 #include "src/core/lib/channel/status_util.h"
33 #include "src/core/lib/gpr/host_port.h"
34 #include "src/core/lib/gpr/string.h"
35 #include "src/core/lib/gpr/useful.h"
36 #include "src/core/lib/gprpp/memory.h"
37 #include "src/core/lib/iomgr/error.h"
38 #include "src/core/lib/iomgr/exec_ctx.h"
39 #include "src/core/lib/slice/b64.h"
40 #include "src/core/lib/slice/slice_internal.h"
41 #include "src/core/lib/surface/channel.h"
42 #include "src/core/lib/surface/server.h"
43 #include "src/core/lib/transport/error_utils.h"
44 #include "src/core/lib/uri/uri_parser.h"
49 BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) {
50 // The registry will set uuid_ under its lock.
51 ChannelzRegistry::Register(this);
54 BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); }
56 char* BaseNode::RenderJsonString() {
57 grpc_json* json = RenderJson();
58 GPR_ASSERT(json != nullptr);
59 char* json_str = grpc_json_dump_to_string(json, 0);
60 grpc_json_destroy(json);
64 CallCountingHelper::CallCountingHelper() {
65 num_cores_ = GPR_MAX(1, gpr_cpu_num_cores());
66 per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>(
67 gpr_zalloc(sizeof(AtomicCounterData) * num_cores_));
70 CallCountingHelper::~CallCountingHelper() {
71 gpr_free(per_cpu_counter_data_storage_);
74 void CallCountingHelper::RecordCallStarted() {
75 gpr_atm_no_barrier_fetch_add(
76 &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
78 static_cast<gpr_atm>(1));
79 gpr_atm_no_barrier_store(
80 &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
81 .last_call_started_millis,
82 (gpr_atm)ExecCtx::Get()->Now());
85 void CallCountingHelper::RecordCallFailed() {
86 gpr_atm_no_barrier_fetch_add(
87 &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
89 static_cast<gpr_atm>(1));
92 void CallCountingHelper::RecordCallSucceeded() {
93 gpr_atm_no_barrier_fetch_add(
94 &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
96 static_cast<gpr_atm>(1));
99 void CallCountingHelper::CollectData(CounterData* out) {
100 for (size_t core = 0; core < num_cores_; ++core) {
101 out->calls_started += gpr_atm_no_barrier_load(
102 &per_cpu_counter_data_storage_[core].calls_started);
103 out->calls_succeeded += gpr_atm_no_barrier_load(
104 &per_cpu_counter_data_storage_[core].calls_succeeded);
105 out->calls_failed += gpr_atm_no_barrier_load(
106 &per_cpu_counter_data_storage_[core].calls_failed);
107 gpr_atm last_call = gpr_atm_no_barrier_load(
108 &per_cpu_counter_data_storage_[core].last_call_started_millis);
109 if (last_call > out->last_call_started_millis) {
110 out->last_call_started_millis = last_call;
115 void CallCountingHelper::PopulateCallCounts(grpc_json* json) {
116 grpc_json* json_iterator = nullptr;
119 if (data.calls_started != 0) {
120 json_iterator = grpc_json_add_number_string_child(
121 json, json_iterator, "callsStarted", data.calls_started);
123 if (data.calls_succeeded != 0) {
124 json_iterator = grpc_json_add_number_string_child(
125 json, json_iterator, "callsSucceeded", data.calls_succeeded);
127 if (data.calls_failed) {
128 json_iterator = grpc_json_add_number_string_child(
129 json, json_iterator, "callsFailed", data.calls_failed);
131 if (data.calls_started != 0) {
132 gpr_timespec ts = grpc_millis_to_timespec(data.last_call_started_millis,
135 grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
136 gpr_format_timespec(ts), GRPC_JSON_STRING, true);
140 ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
141 bool is_top_level_channel)
142 : BaseNode(is_top_level_channel ? EntityType::kTopLevelChannel
143 : EntityType::kInternalChannel),
145 target_(UniquePtr<char>(grpc_channel_get_target(channel_))),
146 trace_(channel_tracer_max_nodes) {}
148 ChannelNode::~ChannelNode() {}
150 grpc_json* ChannelNode::RenderJson() {
151 // We need to track these three json objects to build our object
152 grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
153 grpc_json* json = top_level_json;
154 grpc_json* json_iterator = nullptr;
155 // create and fill the ref child
156 json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
157 GRPC_JSON_OBJECT, false);
158 json = json_iterator;
159 json_iterator = nullptr;
160 json_iterator = grpc_json_add_number_string_child(json, json_iterator,
161 "channelId", uuid());
162 // reset json iterators to top level object
163 json = top_level_json;
164 json_iterator = nullptr;
165 // create and fill the data child.
166 grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
167 GRPC_JSON_OBJECT, false);
169 json_iterator = nullptr;
170 // template method. Child classes may override this to add their specific
172 PopulateConnectivityState(json);
173 // populate the target.
174 GPR_ASSERT(target_.get() != nullptr);
175 grpc_json_create_child(nullptr, json, "target", target_.get(),
176 GRPC_JSON_STRING, false);
177 // fill in the channel trace if applicable
178 grpc_json* trace_json = trace_.RenderJson();
179 if (trace_json != nullptr) {
180 trace_json->key = "trace"; // this object is named trace in channelz.proto
181 grpc_json_link_child(json, trace_json, nullptr);
183 // ask CallCountingHelper to populate trace and call count data.
184 call_counter_.PopulateCallCounts(json);
185 json = top_level_json;
186 // template method. Child classes may override this to add their specific
188 PopulateChildRefs(json);
189 return top_level_json;
192 RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode(
193 grpc_channel* channel, size_t channel_tracer_max_nodes,
194 bool is_top_level_channel) {
195 return MakeRefCounted<grpc_core::channelz::ChannelNode>(
196 channel, channel_tracer_max_nodes, is_top_level_channel);
199 ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
200 : BaseNode(EntityType::kServer),
202 trace_(channel_tracer_max_nodes) {}
204 ServerNode::~ServerNode() {}
206 char* ServerNode::RenderServerSockets(intptr_t start_socket_id,
207 intptr_t max_results) {
208 // if user does not set max_results, we choose 500.
209 size_t pagination_limit = max_results == 0 ? 500 : max_results;
210 grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
211 grpc_json* json = top_level_json;
212 grpc_json* json_iterator = nullptr;
213 ChildSocketsList socket_refs;
214 grpc_server_populate_server_sockets(server_, &socket_refs, start_socket_id);
215 // declared early so it can be used outside of the loop.
217 if (!socket_refs.empty()) {
218 // create list of socket refs
219 grpc_json* array_parent = grpc_json_create_child(
220 nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false);
221 for (i = 0; i < GPR_MIN(socket_refs.size(), pagination_limit); ++i) {
222 grpc_json* socket_ref_json = grpc_json_create_child(
223 nullptr, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false);
224 json_iterator = grpc_json_add_number_string_child(
225 socket_ref_json, nullptr, "socketId", socket_refs[i]->uuid());
226 grpc_json_create_child(json_iterator, socket_ref_json, "name",
227 socket_refs[i]->remote(), GRPC_JSON_STRING, false);
230 if (i == socket_refs.size()) {
231 json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
232 GRPC_JSON_TRUE, false);
234 char* json_str = grpc_json_dump_to_string(top_level_json, 0);
235 grpc_json_destroy(top_level_json);
239 grpc_json* ServerNode::RenderJson() {
240 // We need to track these three json objects to build our object
241 grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
242 grpc_json* json = top_level_json;
243 grpc_json* json_iterator = nullptr;
244 // create and fill the ref child
245 json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
246 GRPC_JSON_OBJECT, false);
247 json = json_iterator;
248 json_iterator = nullptr;
249 json_iterator = grpc_json_add_number_string_child(json, json_iterator,
251 // reset json iterators to top level object
252 json = top_level_json;
253 json_iterator = nullptr;
254 // create and fill the data child.
255 grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
256 GRPC_JSON_OBJECT, false);
258 json_iterator = nullptr;
259 // fill in the channel trace if applicable
260 grpc_json* trace_json = trace_.RenderJson();
261 if (trace_json != nullptr) {
262 trace_json->key = "trace"; // this object is named trace in channelz.proto
263 grpc_json_link_child(json, trace_json, nullptr);
265 // ask CallCountingHelper to populate trace and call count data.
266 call_counter_.PopulateCallCounts(json);
267 json = top_level_json;
268 ChildRefsList listen_sockets;
269 grpc_server_populate_listen_sockets(server_, &listen_sockets);
270 if (!listen_sockets.empty()) {
271 grpc_json* array_parent = grpc_json_create_child(
272 nullptr, json, "listenSocket", nullptr, GRPC_JSON_ARRAY, false);
273 for (size_t i = 0; i < listen_sockets.size(); ++i) {
275 grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
276 GRPC_JSON_OBJECT, false);
277 grpc_json_add_number_string_child(json_iterator, nullptr, "socketId",
281 return top_level_json;
284 static void PopulateSocketAddressJson(grpc_json* json, const char* name,
285 const char* addr_str) {
286 if (addr_str == nullptr) return;
287 grpc_json* json_iterator = nullptr;
288 json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr,
289 GRPC_JSON_OBJECT, false);
290 json = json_iterator;
291 json_iterator = nullptr;
292 grpc_uri* uri = grpc_uri_parse(addr_str, true);
293 if ((uri != nullptr) && ((strcmp(uri->scheme, "ipv4") == 0) ||
294 (strcmp(uri->scheme, "ipv6") == 0))) {
295 const char* host_port = uri->path;
296 if (*host_port == '/') ++host_port;
297 char* host = nullptr;
298 char* port = nullptr;
299 GPR_ASSERT(gpr_split_host_port(host_port, &host, &port));
301 if (port != nullptr) {
302 port_num = atoi(port);
304 char* b64_host = grpc_base64_encode(host, strlen(host), false, false);
305 json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address",
306 nullptr, GRPC_JSON_OBJECT, false);
307 json = json_iterator;
308 json_iterator = nullptr;
309 json_iterator = grpc_json_add_number_string_child(json, json_iterator,
311 json_iterator = grpc_json_create_child(json_iterator, json, "ip_address",
312 b64_host, GRPC_JSON_STRING, true);
316 } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) {
317 json_iterator = grpc_json_create_child(json_iterator, json, "uds_address",
318 nullptr, GRPC_JSON_OBJECT, false);
319 json = json_iterator;
320 json_iterator = nullptr;
322 grpc_json_create_child(json_iterator, json, "filename",
323 gpr_strdup(uri->path), GRPC_JSON_STRING, true);
325 json_iterator = grpc_json_create_child(json_iterator, json, "other_address",
326 nullptr, GRPC_JSON_OBJECT, false);
327 json = json_iterator;
328 json_iterator = nullptr;
329 json_iterator = grpc_json_create_child(json_iterator, json, "name",
330 addr_str, GRPC_JSON_STRING, false);
332 grpc_uri_destroy(uri);
335 SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote)
336 : BaseNode(EntityType::kSocket),
337 local_(std::move(local)),
338 remote_(std::move(remote)) {}
340 void SocketNode::RecordStreamStartedFromLocal() {
341 gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1));
342 gpr_atm_no_barrier_store(&last_local_stream_created_millis_,
343 (gpr_atm)ExecCtx::Get()->Now());
346 void SocketNode::RecordStreamStartedFromRemote() {
347 gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1));
348 gpr_atm_no_barrier_store(&last_remote_stream_created_millis_,
349 (gpr_atm)ExecCtx::Get()->Now());
352 void SocketNode::RecordMessagesSent(uint32_t num_sent) {
353 gpr_atm_no_barrier_fetch_add(&messages_sent_, static_cast<gpr_atm>(num_sent));
354 gpr_atm_no_barrier_store(&last_message_sent_millis_,
355 (gpr_atm)ExecCtx::Get()->Now());
358 void SocketNode::RecordMessageReceived() {
359 gpr_atm_no_barrier_fetch_add(&messages_received_, static_cast<gpr_atm>(1));
360 gpr_atm_no_barrier_store(&last_message_received_millis_,
361 (gpr_atm)ExecCtx::Get()->Now());
364 grpc_json* SocketNode::RenderJson() {
365 // We need to track these three json objects to build our object
366 grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
367 grpc_json* json = top_level_json;
368 grpc_json* json_iterator = nullptr;
369 // create and fill the ref child
370 json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
371 GRPC_JSON_OBJECT, false);
372 json = json_iterator;
373 json_iterator = nullptr;
374 json_iterator = grpc_json_add_number_string_child(json, json_iterator,
376 json = top_level_json;
377 PopulateSocketAddressJson(json, "remote", remote_.get());
378 PopulateSocketAddressJson(json, "local", local_.get());
379 // reset json iterators to top level object
380 json = top_level_json;
381 json_iterator = nullptr;
382 // create and fill the data child.
383 grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
384 GRPC_JSON_OBJECT, false);
386 json_iterator = nullptr;
388 if (streams_started_ != 0) {
389 json_iterator = grpc_json_add_number_string_child(
390 json, json_iterator, "streamsStarted", streams_started_);
391 if (last_local_stream_created_millis_ != 0) {
392 ts = grpc_millis_to_timespec(last_local_stream_created_millis_,
394 json_iterator = grpc_json_create_child(
395 json_iterator, json, "lastLocalStreamCreatedTimestamp",
396 gpr_format_timespec(ts), GRPC_JSON_STRING, true);
398 if (last_remote_stream_created_millis_ != 0) {
399 ts = grpc_millis_to_timespec(last_remote_stream_created_millis_,
401 json_iterator = grpc_json_create_child(
402 json_iterator, json, "lastRemoteStreamCreatedTimestamp",
403 gpr_format_timespec(ts), GRPC_JSON_STRING, true);
406 if (streams_succeeded_ != 0) {
407 json_iterator = grpc_json_add_number_string_child(
408 json, json_iterator, "streamsSucceeded", streams_succeeded_);
410 if (streams_failed_) {
411 json_iterator = grpc_json_add_number_string_child(
412 json, json_iterator, "streamsFailed", streams_failed_);
414 if (messages_sent_ != 0) {
415 json_iterator = grpc_json_add_number_string_child(
416 json, json_iterator, "messagesSent", messages_sent_);
417 ts = grpc_millis_to_timespec(last_message_sent_millis_, GPR_CLOCK_REALTIME);
419 grpc_json_create_child(json_iterator, json, "lastMessageSentTimestamp",
420 gpr_format_timespec(ts), GRPC_JSON_STRING, true);
422 if (messages_received_ != 0) {
423 json_iterator = grpc_json_add_number_string_child(
424 json, json_iterator, "messagesReceived", messages_received_);
425 ts = grpc_millis_to_timespec(last_message_received_millis_,
427 json_iterator = grpc_json_create_child(
428 json_iterator, json, "lastMessageReceivedTimestamp",
429 gpr_format_timespec(ts), GRPC_JSON_STRING, true);
431 if (keepalives_sent_ != 0) {
432 json_iterator = grpc_json_add_number_string_child(
433 json, json_iterator, "keepAlivesSent", keepalives_sent_);
435 return top_level_json;
438 ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr)
439 : BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {}
441 grpc_json* ListenSocketNode::RenderJson() {
442 // We need to track these three json objects to build our object
443 grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
444 grpc_json* json = top_level_json;
445 grpc_json* json_iterator = nullptr;
446 // create and fill the ref child
447 json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
448 GRPC_JSON_OBJECT, false);
449 json = json_iterator;
450 json_iterator = nullptr;
451 json_iterator = grpc_json_add_number_string_child(json, json_iterator,
453 json = top_level_json;
454 PopulateSocketAddressJson(json, "local", local_addr_.get());
456 return top_level_json;
459 } // namespace channelz
460 } // namespace grpc_core