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