Imported Upstream version 1.23.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/string.h"
34 #include "src/core/lib/gpr/useful.h"
35 #include "src/core/lib/gprpp/host_port.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/connectivity_state.h"
44 #include "src/core/lib/transport/error_utils.h"
45 #include "src/core/lib/uri/uri_parser.h"
46
47 namespace grpc_core {
48 namespace channelz {
49
50 //
51 // channel arg code
52 //
53
54 namespace {
55
56 void* parent_uuid_copy(void* p) { return p; }
57 void parent_uuid_destroy(void* p) {}
58 int parent_uuid_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
59 const grpc_arg_pointer_vtable parent_uuid_vtable = {
60     parent_uuid_copy, parent_uuid_destroy, parent_uuid_cmp};
61
62 }  // namespace
63
64 grpc_arg MakeParentUuidArg(intptr_t parent_uuid) {
65   // We would ideally like to store the uuid in an integer argument.
66   // Unfortunately, that won't work, because intptr_t (the type used for
67   // uuids) doesn't fit in an int (the type used for integer args).
68   // So instead, we use a hack to store it as a pointer, because
69   // intptr_t should be the same size as void*.
70   static_assert(sizeof(intptr_t) <= sizeof(void*),
71                 "can't fit intptr_t inside of void*");
72   return grpc_channel_arg_pointer_create(
73       const_cast<char*>(GRPC_ARG_CHANNELZ_PARENT_UUID),
74       reinterpret_cast<void*>(parent_uuid), &parent_uuid_vtable);
75 }
76
77 intptr_t GetParentUuidFromArgs(const grpc_channel_args& args) {
78   const grpc_arg* arg =
79       grpc_channel_args_find(&args, GRPC_ARG_CHANNELZ_PARENT_UUID);
80   if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return 0;
81   return reinterpret_cast<intptr_t>(arg->value.pointer.p);
82 }
83
84 //
85 // BaseNode
86 //
87
88 BaseNode::BaseNode(EntityType type, UniquePtr<char> name)
89     : type_(type), uuid_(-1), name_(std::move(name)) {
90   // The registry will set uuid_ under its lock.
91   ChannelzRegistry::Register(this);
92 }
93
94 BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); }
95
96 char* BaseNode::RenderJsonString() {
97   grpc_json* json = RenderJson();
98   GPR_ASSERT(json != nullptr);
99   char* json_str = grpc_json_dump_to_string(json, 0);
100   grpc_json_destroy(json);
101   return json_str;
102 }
103
104 //
105 // CallCountingHelper
106 //
107
108 CallCountingHelper::CallCountingHelper() {
109   num_cores_ = GPR_MAX(1, gpr_cpu_num_cores());
110   per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>(
111       gpr_zalloc(sizeof(AtomicCounterData) * num_cores_));
112 }
113
114 CallCountingHelper::~CallCountingHelper() {
115   gpr_free(per_cpu_counter_data_storage_);
116 }
117
118 void CallCountingHelper::RecordCallStarted() {
119   gpr_atm_no_barrier_fetch_add(
120       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
121            .calls_started,
122       static_cast<gpr_atm>(1));
123   gpr_atm_no_barrier_store(
124       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
125            .last_call_started_millis,
126       (gpr_atm)ExecCtx::Get()->Now());
127 }
128
129 void CallCountingHelper::RecordCallFailed() {
130   gpr_atm_no_barrier_fetch_add(
131       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
132            .calls_failed,
133       static_cast<gpr_atm>(1));
134 }
135
136 void CallCountingHelper::RecordCallSucceeded() {
137   gpr_atm_no_barrier_fetch_add(
138       &per_cpu_counter_data_storage_[grpc_core::ExecCtx::Get()->starting_cpu()]
139            .calls_succeeded,
140       static_cast<gpr_atm>(1));
141 }
142
143 void CallCountingHelper::CollectData(CounterData* out) {
144   for (size_t core = 0; core < num_cores_; ++core) {
145     out->calls_started += gpr_atm_no_barrier_load(
146         &per_cpu_counter_data_storage_[core].calls_started);
147     out->calls_succeeded += gpr_atm_no_barrier_load(
148         &per_cpu_counter_data_storage_[core].calls_succeeded);
149     out->calls_failed += gpr_atm_no_barrier_load(
150         &per_cpu_counter_data_storage_[core].calls_failed);
151     gpr_atm last_call = gpr_atm_no_barrier_load(
152         &per_cpu_counter_data_storage_[core].last_call_started_millis);
153     if (last_call > out->last_call_started_millis) {
154       out->last_call_started_millis = last_call;
155     }
156   }
157 }
158
159 void CallCountingHelper::PopulateCallCounts(grpc_json* json) {
160   grpc_json* json_iterator = nullptr;
161   CounterData data;
162   CollectData(&data);
163   if (data.calls_started != 0) {
164     json_iterator = grpc_json_add_number_string_child(
165         json, json_iterator, "callsStarted", data.calls_started);
166   }
167   if (data.calls_succeeded != 0) {
168     json_iterator = grpc_json_add_number_string_child(
169         json, json_iterator, "callsSucceeded", data.calls_succeeded);
170   }
171   if (data.calls_failed) {
172     json_iterator = grpc_json_add_number_string_child(
173         json, json_iterator, "callsFailed", data.calls_failed);
174   }
175   if (data.calls_started != 0) {
176     gpr_timespec ts = grpc_millis_to_timespec(data.last_call_started_millis,
177                                               GPR_CLOCK_REALTIME);
178     json_iterator =
179         grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
180                                gpr_format_timespec(ts), GRPC_JSON_STRING, true);
181   }
182 }
183
184 //
185 // ChannelNode
186 //
187
188 ChannelNode::ChannelNode(UniquePtr<char> target,
189                          size_t channel_tracer_max_nodes, intptr_t parent_uuid)
190     : BaseNode(parent_uuid == 0 ? EntityType::kTopLevelChannel
191                                 : EntityType::kInternalChannel,
192                UniquePtr<char>(gpr_strdup(target.get()))),
193       target_(std::move(target)),
194       trace_(channel_tracer_max_nodes),
195       parent_uuid_(parent_uuid) {}
196
197 const char* ChannelNode::GetChannelConnectivityStateChangeString(
198     grpc_connectivity_state state) {
199   switch (state) {
200     case GRPC_CHANNEL_IDLE:
201       return "Channel state change to IDLE";
202     case GRPC_CHANNEL_CONNECTING:
203       return "Channel state change to CONNECTING";
204     case GRPC_CHANNEL_READY:
205       return "Channel state change to READY";
206     case GRPC_CHANNEL_TRANSIENT_FAILURE:
207       return "Channel state change to TRANSIENT_FAILURE";
208     case GRPC_CHANNEL_SHUTDOWN:
209       return "Channel state change to SHUTDOWN";
210   }
211   GPR_UNREACHABLE_CODE(return "UNKNOWN");
212 }
213
214 grpc_json* ChannelNode::RenderJson() {
215   // We need to track these three json objects to build our object
216   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
217   grpc_json* json = top_level_json;
218   grpc_json* json_iterator = nullptr;
219   // create and fill the ref child
220   json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
221                                          GRPC_JSON_OBJECT, false);
222   json = json_iterator;
223   json_iterator = nullptr;
224   json_iterator = grpc_json_add_number_string_child(json, json_iterator,
225                                                     "channelId", uuid());
226   // reset json iterators to top level object
227   json = top_level_json;
228   json_iterator = nullptr;
229   // create and fill the data child.
230   grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
231                                            GRPC_JSON_OBJECT, false);
232   json = data;
233   json_iterator = nullptr;
234   // connectivity state
235   // If low-order bit is on, then the field is set.
236   int state_field = connectivity_state_.Load(MemoryOrder::RELAXED);
237   if ((state_field & 1) != 0) {
238     grpc_connectivity_state state =
239         static_cast<grpc_connectivity_state>(state_field >> 1);
240     json = grpc_json_create_child(nullptr, json, "state", nullptr,
241                                   GRPC_JSON_OBJECT, false);
242     grpc_json_create_child(nullptr, json, "state",
243                            grpc_connectivity_state_name(state),
244                            GRPC_JSON_STRING, false);
245     json = data;
246   }
247   // populate the target.
248   GPR_ASSERT(target_.get() != nullptr);
249   grpc_json_create_child(nullptr, json, "target", target_.get(),
250                          GRPC_JSON_STRING, false);
251   // fill in the channel trace if applicable
252   grpc_json* trace_json = trace_.RenderJson();
253   if (trace_json != nullptr) {
254     trace_json->key = "trace";  // this object is named trace in channelz.proto
255     grpc_json_link_child(json, trace_json, nullptr);
256   }
257   // ask CallCountingHelper to populate trace and call count data.
258   call_counter_.PopulateCallCounts(json);
259   json = top_level_json;
260   // template method. Child classes may override this to add their specific
261   // functionality.
262   PopulateChildRefs(json);
263   return top_level_json;
264 }
265
266 void ChannelNode::PopulateChildRefs(grpc_json* json) {
267   MutexLock lock(&child_mu_);
268   grpc_json* json_iterator = nullptr;
269   if (!child_subchannels_.empty()) {
270     grpc_json* array_parent = grpc_json_create_child(
271         nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false);
272     for (const auto& p : child_subchannels_) {
273       json_iterator =
274           grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
275                                  GRPC_JSON_OBJECT, false);
276       grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId",
277                                         p.first);
278     }
279   }
280   if (!child_channels_.empty()) {
281     grpc_json* array_parent = grpc_json_create_child(
282         nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false);
283     json_iterator = nullptr;
284     for (const auto& p : child_channels_) {
285       json_iterator =
286           grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
287                                  GRPC_JSON_OBJECT, false);
288       grpc_json_add_number_string_child(json_iterator, nullptr, "channelId",
289                                         p.first);
290     }
291   }
292 }
293
294 void ChannelNode::SetConnectivityState(grpc_connectivity_state state) {
295   // Store with low-order bit set to indicate that the field is set.
296   int state_field = (state << 1) + 1;
297   connectivity_state_.Store(state_field, MemoryOrder::RELAXED);
298 }
299
300 void ChannelNode::AddChildChannel(intptr_t child_uuid) {
301   MutexLock lock(&child_mu_);
302   child_channels_.insert(MakePair(child_uuid, true));
303 }
304
305 void ChannelNode::RemoveChildChannel(intptr_t child_uuid) {
306   MutexLock lock(&child_mu_);
307   child_channels_.erase(child_uuid);
308 }
309
310 void ChannelNode::AddChildSubchannel(intptr_t child_uuid) {
311   MutexLock lock(&child_mu_);
312   child_subchannels_.insert(MakePair(child_uuid, true));
313 }
314
315 void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
316   MutexLock lock(&child_mu_);
317   child_subchannels_.erase(child_uuid);
318 }
319
320 //
321 // ServerNode
322 //
323
324 ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
325     : BaseNode(EntityType::kServer, /* name */ nullptr),
326       trace_(channel_tracer_max_nodes) {}
327
328 ServerNode::~ServerNode() {}
329
330 void ServerNode::AddChildSocket(RefCountedPtr<SocketNode> node) {
331   MutexLock lock(&child_mu_);
332   child_sockets_.insert(MakePair(node->uuid(), std::move(node)));
333 }
334
335 void ServerNode::RemoveChildSocket(intptr_t child_uuid) {
336   MutexLock lock(&child_mu_);
337   child_sockets_.erase(child_uuid);
338 }
339
340 void ServerNode::AddChildListenSocket(RefCountedPtr<ListenSocketNode> node) {
341   MutexLock lock(&child_mu_);
342   child_listen_sockets_.insert(MakePair(node->uuid(), std::move(node)));
343 }
344
345 void ServerNode::RemoveChildListenSocket(intptr_t child_uuid) {
346   MutexLock lock(&child_mu_);
347   child_listen_sockets_.erase(child_uuid);
348 }
349
350 char* ServerNode::RenderServerSockets(intptr_t start_socket_id,
351                                       intptr_t max_results) {
352   // If user does not set max_results, we choose 500.
353   size_t pagination_limit = max_results == 0 ? 500 : max_results;
354   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
355   grpc_json* json = top_level_json;
356   grpc_json* json_iterator = nullptr;
357   MutexLock lock(&child_mu_);
358   size_t sockets_rendered = 0;
359   if (!child_sockets_.empty()) {
360     // Create list of socket refs
361     grpc_json* array_parent = grpc_json_create_child(
362         nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false);
363     const size_t limit = GPR_MIN(child_sockets_.size(), pagination_limit);
364     for (auto it = child_sockets_.lower_bound(start_socket_id);
365          it != child_sockets_.end() && sockets_rendered < limit;
366          ++it, ++sockets_rendered) {
367       grpc_json* socket_ref_json = grpc_json_create_child(
368           nullptr, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false);
369       json_iterator = grpc_json_add_number_string_child(
370           socket_ref_json, nullptr, "socketId", it->first);
371       grpc_json_create_child(json_iterator, socket_ref_json, "name",
372                              it->second->name(), GRPC_JSON_STRING, false);
373     }
374   }
375   if (sockets_rendered == child_sockets_.size()) {
376     json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
377                                            GRPC_JSON_TRUE, false);
378   }
379   char* json_str = grpc_json_dump_to_string(top_level_json, 0);
380   grpc_json_destroy(top_level_json);
381   return json_str;
382 }
383
384 grpc_json* ServerNode::RenderJson() {
385   // We need to track these three json objects to build our object
386   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
387   grpc_json* json = top_level_json;
388   grpc_json* json_iterator = nullptr;
389   // create and fill the ref child
390   json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
391                                          GRPC_JSON_OBJECT, false);
392   json = json_iterator;
393   json_iterator = nullptr;
394   json_iterator = grpc_json_add_number_string_child(json, json_iterator,
395                                                     "serverId", uuid());
396   // reset json iterators to top level object
397   json = top_level_json;
398   json_iterator = nullptr;
399   // create and fill the data child.
400   grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
401                                            GRPC_JSON_OBJECT, false);
402   json = data;
403   json_iterator = nullptr;
404   // fill in the channel trace if applicable
405   grpc_json* trace_json = trace_.RenderJson();
406   if (trace_json != nullptr) {
407     trace_json->key = "trace";  // this object is named trace in channelz.proto
408     grpc_json_link_child(json, trace_json, nullptr);
409   }
410   // ask CallCountingHelper to populate trace and call count data.
411   call_counter_.PopulateCallCounts(json);
412   json = top_level_json;
413   // Render listen sockets
414   MutexLock lock(&child_mu_);
415   if (!child_listen_sockets_.empty()) {
416     grpc_json* array_parent = grpc_json_create_child(
417         nullptr, json, "listenSocket", nullptr, GRPC_JSON_ARRAY, false);
418     for (const auto& it : child_listen_sockets_) {
419       json_iterator =
420           grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
421                                  GRPC_JSON_OBJECT, false);
422       grpc_json* sibling_iterator = grpc_json_add_number_string_child(
423           json_iterator, nullptr, "socketId", it.first);
424       grpc_json_create_child(sibling_iterator, json_iterator, "name",
425                              it.second->name(), GRPC_JSON_STRING, false);
426     }
427   }
428   return top_level_json;
429 }
430
431 //
432 // SocketNode
433 //
434
435 namespace {
436
437 void PopulateSocketAddressJson(grpc_json* json, const char* name,
438                                const char* addr_str) {
439   if (addr_str == nullptr) return;
440   grpc_json* json_iterator = nullptr;
441   json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr,
442                                          GRPC_JSON_OBJECT, false);
443   json = json_iterator;
444   json_iterator = nullptr;
445   grpc_uri* uri = grpc_uri_parse(addr_str, true);
446   if ((uri != nullptr) && ((strcmp(uri->scheme, "ipv4") == 0) ||
447                            (strcmp(uri->scheme, "ipv6") == 0))) {
448     const char* host_port = uri->path;
449     if (*host_port == '/') ++host_port;
450     UniquePtr<char> host;
451     UniquePtr<char> port;
452     GPR_ASSERT(SplitHostPort(host_port, &host, &port));
453     int port_num = -1;
454     if (port != nullptr) {
455       port_num = atoi(port.get());
456     }
457     char* b64_host =
458         grpc_base64_encode(host.get(), strlen(host.get()), false, false);
459     json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address",
460                                            nullptr, GRPC_JSON_OBJECT, false);
461     json = json_iterator;
462     json_iterator = nullptr;
463     json_iterator = grpc_json_add_number_string_child(json, json_iterator,
464                                                       "port", port_num);
465     json_iterator = grpc_json_create_child(json_iterator, json, "ip_address",
466                                            b64_host, GRPC_JSON_STRING, true);
467   } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) {
468     json_iterator = grpc_json_create_child(json_iterator, json, "uds_address",
469                                            nullptr, GRPC_JSON_OBJECT, false);
470     json = json_iterator;
471     json_iterator = nullptr;
472     json_iterator =
473         grpc_json_create_child(json_iterator, json, "filename",
474                                gpr_strdup(uri->path), GRPC_JSON_STRING, true);
475   } else {
476     json_iterator = grpc_json_create_child(json_iterator, json, "other_address",
477                                            nullptr, GRPC_JSON_OBJECT, false);
478     json = json_iterator;
479     json_iterator = nullptr;
480     json_iterator = grpc_json_create_child(json_iterator, json, "name",
481                                            addr_str, GRPC_JSON_STRING, false);
482   }
483   grpc_uri_destroy(uri);
484 }
485
486 }  // namespace
487
488 SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote,
489                        UniquePtr<char> name)
490     : BaseNode(EntityType::kSocket, std::move(name)),
491       local_(std::move(local)),
492       remote_(std::move(remote)) {}
493
494 void SocketNode::RecordStreamStartedFromLocal() {
495   gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1));
496   gpr_atm_no_barrier_store(&last_local_stream_created_millis_,
497                            (gpr_atm)ExecCtx::Get()->Now());
498 }
499
500 void SocketNode::RecordStreamStartedFromRemote() {
501   gpr_atm_no_barrier_fetch_add(&streams_started_, static_cast<gpr_atm>(1));
502   gpr_atm_no_barrier_store(&last_remote_stream_created_millis_,
503                            (gpr_atm)ExecCtx::Get()->Now());
504 }
505
506 void SocketNode::RecordMessagesSent(uint32_t num_sent) {
507   gpr_atm_no_barrier_fetch_add(&messages_sent_, static_cast<gpr_atm>(num_sent));
508   gpr_atm_no_barrier_store(&last_message_sent_millis_,
509                            (gpr_atm)ExecCtx::Get()->Now());
510 }
511
512 void SocketNode::RecordMessageReceived() {
513   gpr_atm_no_barrier_fetch_add(&messages_received_, static_cast<gpr_atm>(1));
514   gpr_atm_no_barrier_store(&last_message_received_millis_,
515                            (gpr_atm)ExecCtx::Get()->Now());
516 }
517
518 grpc_json* SocketNode::RenderJson() {
519   // We need to track these three json objects to build our object
520   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
521   grpc_json* json = top_level_json;
522   grpc_json* json_iterator = nullptr;
523   // create and fill the ref child
524   json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
525                                          GRPC_JSON_OBJECT, false);
526   json = json_iterator;
527   json_iterator = nullptr;
528   json_iterator = grpc_json_add_number_string_child(json, json_iterator,
529                                                     "socketId", uuid());
530   json_iterator = grpc_json_create_child(json_iterator, json, "name", name(),
531                                          GRPC_JSON_STRING, false);
532   json = top_level_json;
533   PopulateSocketAddressJson(json, "remote", remote_.get());
534   PopulateSocketAddressJson(json, "local", local_.get());
535   // reset json iterators to top level object
536   json = top_level_json;
537   json_iterator = nullptr;
538   // create and fill the data child.
539   grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
540                                            GRPC_JSON_OBJECT, false);
541   json = data;
542   json_iterator = nullptr;
543   gpr_timespec ts;
544   gpr_atm streams_started = gpr_atm_no_barrier_load(&streams_started_);
545   if (streams_started != 0) {
546     json_iterator = grpc_json_add_number_string_child(
547         json, json_iterator, "streamsStarted", streams_started);
548     gpr_atm last_local_stream_created_millis =
549         gpr_atm_no_barrier_load(&last_local_stream_created_millis_);
550     if (last_local_stream_created_millis != 0) {
551       ts = grpc_millis_to_timespec(last_local_stream_created_millis,
552                                    GPR_CLOCK_REALTIME);
553       json_iterator = grpc_json_create_child(
554           json_iterator, json, "lastLocalStreamCreatedTimestamp",
555           gpr_format_timespec(ts), GRPC_JSON_STRING, true);
556     }
557     gpr_atm last_remote_stream_created_millis =
558         gpr_atm_no_barrier_load(&last_remote_stream_created_millis_);
559     if (last_remote_stream_created_millis != 0) {
560       ts = grpc_millis_to_timespec(last_remote_stream_created_millis,
561                                    GPR_CLOCK_REALTIME);
562       json_iterator = grpc_json_create_child(
563           json_iterator, json, "lastRemoteStreamCreatedTimestamp",
564           gpr_format_timespec(ts), GRPC_JSON_STRING, true);
565     }
566   }
567   gpr_atm streams_succeeded = gpr_atm_no_barrier_load(&streams_succeeded_);
568   if (streams_succeeded != 0) {
569     json_iterator = grpc_json_add_number_string_child(
570         json, json_iterator, "streamsSucceeded", streams_succeeded);
571   }
572   gpr_atm streams_failed = gpr_atm_no_barrier_load(&streams_failed_);
573   if (streams_failed) {
574     json_iterator = grpc_json_add_number_string_child(
575         json, json_iterator, "streamsFailed", streams_failed);
576   }
577   gpr_atm messages_sent = gpr_atm_no_barrier_load(&messages_sent_);
578   if (messages_sent != 0) {
579     json_iterator = grpc_json_add_number_string_child(
580         json, json_iterator, "messagesSent", messages_sent);
581     ts = grpc_millis_to_timespec(
582         gpr_atm_no_barrier_load(&last_message_sent_millis_),
583         GPR_CLOCK_REALTIME);
584     json_iterator =
585         grpc_json_create_child(json_iterator, json, "lastMessageSentTimestamp",
586                                gpr_format_timespec(ts), GRPC_JSON_STRING, true);
587   }
588   gpr_atm messages_received = gpr_atm_no_barrier_load(&messages_received_);
589   if (messages_received != 0) {
590     json_iterator = grpc_json_add_number_string_child(
591         json, json_iterator, "messagesReceived", messages_received);
592     ts = grpc_millis_to_timespec(
593         gpr_atm_no_barrier_load(&last_message_received_millis_),
594         GPR_CLOCK_REALTIME);
595     json_iterator = grpc_json_create_child(
596         json_iterator, json, "lastMessageReceivedTimestamp",
597         gpr_format_timespec(ts), GRPC_JSON_STRING, true);
598   }
599   gpr_atm keepalives_sent = gpr_atm_no_barrier_load(&keepalives_sent_);
600   if (keepalives_sent != 0) {
601     json_iterator = grpc_json_add_number_string_child(
602         json, json_iterator, "keepAlivesSent", keepalives_sent);
603   }
604   return top_level_json;
605 }
606
607 //
608 // ListenSocketNode
609 //
610
611 ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr,
612                                    UniquePtr<char> name)
613     : BaseNode(EntityType::kSocket, std::move(name)),
614       local_addr_(std::move(local_addr)) {}
615
616 grpc_json* ListenSocketNode::RenderJson() {
617   // We need to track these three json objects to build our object
618   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
619   grpc_json* json = top_level_json;
620   grpc_json* json_iterator = nullptr;
621   // create and fill the ref child
622   json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr,
623                                          GRPC_JSON_OBJECT, false);
624   json = json_iterator;
625   json_iterator = nullptr;
626   json_iterator = grpc_json_add_number_string_child(json, json_iterator,
627                                                     "socketId", uuid());
628   json_iterator = grpc_json_create_child(json_iterator, json, "name", name(),
629                                          GRPC_JSON_STRING, false);
630   json = top_level_json;
631   PopulateSocketAddressJson(json, "local", local_addr_.get());
632
633   return top_level_json;
634 }
635
636 }  // namespace channelz
637 }  // namespace grpc_core