Imported Upstream version 1.18.0
[platform/upstream/grpc.git] / src / core / lib / channel / channelz.cc
1 /*
2  *
3  * Copyright 2017 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 #include <grpc/impl/codegen/port_platform.h>
20
21 #include "src/core/lib/channel/channelz.h"
22
23 #include <grpc/grpc.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/string_util.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
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"
45
46 namespace grpc_core {
47 namespace channelz {
48
49 BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) {
50   // The registry will set uuid_ under its lock.
51   ChannelzRegistry::Register(this);
52 }
53
54 BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); }
55
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);
61   return json_str;
62 }
63
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_));
68 }
69
70 CallCountingHelper::~CallCountingHelper() {
71   gpr_free(per_cpu_counter_data_storage_);
72 }
73
74 void CallCountingHelper::RecordCallStarted() {
75   gpr_atm_no_barrier_fetch_add(
76       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
77            .calls_started,
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());
83 }
84
85 void CallCountingHelper::RecordCallFailed() {
86   gpr_atm_no_barrier_fetch_add(
87       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
88            .calls_failed,
89       static_cast<gpr_atm>(1));
90 }
91
92 void CallCountingHelper::RecordCallSucceeded() {
93   gpr_atm_no_barrier_fetch_add(
94       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
95            .calls_succeeded,
96       static_cast<gpr_atm>(1));
97 }
98
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;
111     }
112   }
113 }
114
115 void CallCountingHelper::PopulateCallCounts(grpc_json* json) {
116   grpc_json* json_iterator = nullptr;
117   CounterData data;
118   CollectData(&data);
119   if (data.calls_started != 0) {
120     json_iterator = grpc_json_add_number_string_child(
121         json, json_iterator, "callsStarted", data.calls_started);
122   }
123   if (data.calls_succeeded != 0) {
124     json_iterator = grpc_json_add_number_string_child(
125         json, json_iterator, "callsSucceeded", data.calls_succeeded);
126   }
127   if (data.calls_failed) {
128     json_iterator = grpc_json_add_number_string_child(
129         json, json_iterator, "callsFailed", data.calls_failed);
130   }
131   if (data.calls_started != 0) {
132     gpr_timespec ts = grpc_millis_to_timespec(data.last_call_started_millis,
133                                               GPR_CLOCK_REALTIME);
134     json_iterator =
135         grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
136                                gpr_format_timespec(ts), GRPC_JSON_STRING, true);
137   }
138 }
139
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),
144       channel_(channel),
145       target_(UniquePtr<char>(grpc_channel_get_target(channel_))),
146       trace_(channel_tracer_max_nodes) {}
147
148 ChannelNode::~ChannelNode() {}
149
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);
168   json = data;
169   json_iterator = nullptr;
170   // template method. Child classes may override this to add their specific
171   // functionality.
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);
182   }
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
187   // functionality.
188   PopulateChildRefs(json);
189   return top_level_json;
190 }
191
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);
197 }
198
199 ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
200     : BaseNode(EntityType::kServer),
201       server_(server),
202       trace_(channel_tracer_max_nodes) {}
203
204 ServerNode::~ServerNode() {}
205
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.
216   size_t i = 0;
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);
228     }
229   }
230   if (i == socket_refs.size()) {
231     json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
232                                            GRPC_JSON_TRUE, false);
233   }
234   char* json_str = grpc_json_dump_to_string(top_level_json, 0);
235   grpc_json_destroy(top_level_json);
236   return json_str;
237 }
238
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,
250                                                     "serverId", uuid());
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);
257   json = data;
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);
264   }
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) {
274       json_iterator =
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",
278                                         listen_sockets[i]);
279     }
280   }
281   return top_level_json;
282 }
283
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));
300     int port_num = -1;
301     if (port != nullptr) {
302       port_num = atoi(port);
303     }
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,
310                                                       "port", port_num);
311     json_iterator = grpc_json_create_child(json_iterator, json, "ip_address",
312                                            b64_host, GRPC_JSON_STRING, true);
313     gpr_free(host);
314     gpr_free(port);
315
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;
321     json_iterator =
322         grpc_json_create_child(json_iterator, json, "filename",
323                                gpr_strdup(uri->path), GRPC_JSON_STRING, true);
324   } else {
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);
331   }
332   grpc_uri_destroy(uri);
333 }
334
335 SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote)
336     : BaseNode(EntityType::kSocket),
337       local_(std::move(local)),
338       remote_(std::move(remote)) {}
339
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());
344 }
345
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());
350 }
351
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());
356 }
357
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());
362 }
363
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,
375                                                     "socketId", uuid());
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);
385   json = data;
386   json_iterator = nullptr;
387   gpr_timespec ts;
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_,
393                                    GPR_CLOCK_REALTIME);
394       json_iterator = grpc_json_create_child(
395           json_iterator, json, "lastLocalStreamCreatedTimestamp",
396           gpr_format_timespec(ts), GRPC_JSON_STRING, true);
397     }
398     if (last_remote_stream_created_millis_ != 0) {
399       ts = grpc_millis_to_timespec(last_remote_stream_created_millis_,
400                                    GPR_CLOCK_REALTIME);
401       json_iterator = grpc_json_create_child(
402           json_iterator, json, "lastRemoteStreamCreatedTimestamp",
403           gpr_format_timespec(ts), GRPC_JSON_STRING, true);
404     }
405   }
406   if (streams_succeeded_ != 0) {
407     json_iterator = grpc_json_add_number_string_child(
408         json, json_iterator, "streamsSucceeded", streams_succeeded_);
409   }
410   if (streams_failed_) {
411     json_iterator = grpc_json_add_number_string_child(
412         json, json_iterator, "streamsFailed", streams_failed_);
413   }
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);
418     json_iterator =
419         grpc_json_create_child(json_iterator, json, "lastMessageSentTimestamp",
420                                gpr_format_timespec(ts), GRPC_JSON_STRING, true);
421   }
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_,
426                                  GPR_CLOCK_REALTIME);
427     json_iterator = grpc_json_create_child(
428         json_iterator, json, "lastMessageReceivedTimestamp",
429         gpr_format_timespec(ts), GRPC_JSON_STRING, true);
430   }
431   if (keepalives_sent_ != 0) {
432     json_iterator = grpc_json_add_number_string_child(
433         json, json_iterator, "keepAlivesSent", keepalives_sent_);
434   }
435   return top_level_json;
436 }
437
438 ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr)
439     : BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {}
440
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,
452                                                     "socketId", uuid());
453   json = top_level_json;
454   PopulateSocketAddressJson(json, "local", local_addr_.get());
455
456   return top_level_json;
457 }
458
459 }  // namespace channelz
460 }  // namespace grpc_core