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"
22 #include "src/core/lib/iomgr/resolve_address.h"
23 #include "src/core/lib/iomgr/sockaddr_utils.h"
25 #include "absl/strings/escaping.h"
26 #include "absl/strings/strip.h"
28 #include <grpc/grpc.h>
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
31 #include <grpc/support/string_util.h>
36 #include "src/core/lib/channel/channelz_registry.h"
37 #include "src/core/lib/channel/status_util.h"
38 #include "src/core/lib/gpr/string.h"
39 #include "src/core/lib/gpr/useful.h"
40 #include "src/core/lib/gprpp/atomic.h"
41 #include "src/core/lib/gprpp/host_port.h"
42 #include "src/core/lib/gprpp/memory.h"
43 #include "src/core/lib/iomgr/error.h"
44 #include "src/core/lib/iomgr/exec_ctx.h"
45 #include "src/core/lib/slice/b64.h"
46 #include "src/core/lib/slice/slice_internal.h"
47 #include "src/core/lib/surface/channel.h"
48 #include "src/core/lib/surface/server.h"
49 #include "src/core/lib/transport/connectivity_state.h"
50 #include "src/core/lib/transport/error_utils.h"
51 #include "src/core/lib/uri/uri_parser.h"
60 BaseNode::BaseNode(EntityType type, std::string name)
61 : type_(type), uuid_(-1), name_(std::move(name)) {
62 // The registry will set uuid_ under its lock.
63 ChannelzRegistry::Register(this);
66 BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); }
68 std::string BaseNode::RenderJsonString() {
69 Json json = RenderJson();
77 CallCountingHelper::CallCountingHelper() {
78 num_cores_ = GPR_MAX(1, gpr_cpu_num_cores());
79 per_cpu_counter_data_storage_.reserve(num_cores_);
80 for (size_t i = 0; i < num_cores_; ++i) {
81 per_cpu_counter_data_storage_.emplace_back();
85 void CallCountingHelper::RecordCallStarted() {
86 AtomicCounterData& data =
87 per_cpu_counter_data_storage_[ExecCtx::Get()->starting_cpu()];
88 data.calls_started.FetchAdd(1, MemoryOrder::RELAXED);
89 data.last_call_started_cycle.Store(gpr_get_cycle_counter(),
90 MemoryOrder::RELAXED);
93 void CallCountingHelper::RecordCallFailed() {
94 per_cpu_counter_data_storage_[ExecCtx::Get()->starting_cpu()]
95 .calls_failed.FetchAdd(1, MemoryOrder::RELAXED);
98 void CallCountingHelper::RecordCallSucceeded() {
99 per_cpu_counter_data_storage_[ExecCtx::Get()->starting_cpu()]
100 .calls_succeeded.FetchAdd(1, MemoryOrder::RELAXED);
103 void CallCountingHelper::CollectData(CounterData* out) {
104 for (size_t core = 0; core < num_cores_; ++core) {
105 AtomicCounterData& data = per_cpu_counter_data_storage_[core];
107 out->calls_started += data.calls_started.Load(MemoryOrder::RELAXED);
108 out->calls_succeeded +=
109 per_cpu_counter_data_storage_[core].calls_succeeded.Load(
110 MemoryOrder::RELAXED);
111 out->calls_failed += per_cpu_counter_data_storage_[core].calls_failed.Load(
112 MemoryOrder::RELAXED);
113 const gpr_cycle_counter last_call =
114 per_cpu_counter_data_storage_[core].last_call_started_cycle.Load(
115 MemoryOrder::RELAXED);
116 if (last_call > out->last_call_started_cycle) {
117 out->last_call_started_cycle = last_call;
122 void CallCountingHelper::PopulateCallCounts(Json::Object* json) {
125 if (data.calls_started != 0) {
126 (*json)["callsStarted"] = std::to_string(data.calls_started);
127 gpr_timespec ts = gpr_convert_clock_type(
128 gpr_cycle_counter_to_time(data.last_call_started_cycle),
130 (*json)["lastCallStartedTimestamp"] = gpr_format_timespec(ts);
132 if (data.calls_succeeded != 0) {
133 (*json)["callsSucceeded"] = std::to_string(data.calls_succeeded);
135 if (data.calls_failed) {
136 (*json)["callsFailed"] = std::to_string(data.calls_failed);
144 ChannelNode::ChannelNode(std::string target, size_t channel_tracer_max_nodes,
145 bool is_internal_channel)
146 : BaseNode(is_internal_channel ? EntityType::kInternalChannel
147 : EntityType::kTopLevelChannel,
149 target_(std::move(target)),
150 trace_(channel_tracer_max_nodes) {}
152 const char* ChannelNode::GetChannelConnectivityStateChangeString(
153 grpc_connectivity_state state) {
155 case GRPC_CHANNEL_IDLE:
156 return "Channel state change to IDLE";
157 case GRPC_CHANNEL_CONNECTING:
158 return "Channel state change to CONNECTING";
159 case GRPC_CHANNEL_READY:
160 return "Channel state change to READY";
161 case GRPC_CHANNEL_TRANSIENT_FAILURE:
162 return "Channel state change to TRANSIENT_FAILURE";
163 case GRPC_CHANNEL_SHUTDOWN:
164 return "Channel state change to SHUTDOWN";
166 GPR_UNREACHABLE_CODE(return "UNKNOWN");
169 Json ChannelNode::RenderJson() {
170 Json::Object data = {
173 // Connectivity state.
174 // If low-order bit is on, then the field is set.
175 int state_field = connectivity_state_.Load(MemoryOrder::RELAXED);
176 if ((state_field & 1) != 0) {
177 grpc_connectivity_state state =
178 static_cast<grpc_connectivity_state>(state_field >> 1);
179 data["state"] = Json::Object{
180 {"state", ConnectivityStateName(state)},
183 // Fill in the channel trace if applicable.
184 Json trace_json = trace_.RenderJson();
185 if (trace_json.type() != Json::Type::JSON_NULL) {
186 data["trace"] = std::move(trace_json);
188 // Ask CallCountingHelper to populate call count data.
189 call_counter_.PopulateCallCounts(&data);
190 // Construct outer object.
191 Json::Object json = {
194 {"channelId", std::to_string(uuid())},
196 {"data", std::move(data)},
198 // Template method. Child classes may override this to add their specific
200 PopulateChildRefs(&json);
204 void ChannelNode::PopulateChildRefs(Json::Object* json) {
205 MutexLock lock(&child_mu_);
206 if (!child_subchannels_.empty()) {
208 for (intptr_t subchannel_uuid : child_subchannels_) {
209 array.emplace_back(Json::Object{
210 {"subchannelId", std::to_string(subchannel_uuid)},
213 (*json)["subchannelRef"] = std::move(array);
215 if (!child_channels_.empty()) {
217 for (intptr_t channel_uuid : child_channels_) {
218 array.emplace_back(Json::Object{
219 {"channelId", std::to_string(channel_uuid)},
222 (*json)["channelRef"] = std::move(array);
226 void ChannelNode::SetConnectivityState(grpc_connectivity_state state) {
227 // Store with low-order bit set to indicate that the field is set.
228 int state_field = (state << 1) + 1;
229 connectivity_state_.Store(state_field, MemoryOrder::RELAXED);
232 void ChannelNode::AddChildChannel(intptr_t child_uuid) {
233 MutexLock lock(&child_mu_);
234 child_channels_.insert(child_uuid);
237 void ChannelNode::RemoveChildChannel(intptr_t child_uuid) {
238 MutexLock lock(&child_mu_);
239 child_channels_.erase(child_uuid);
242 void ChannelNode::AddChildSubchannel(intptr_t child_uuid) {
243 MutexLock lock(&child_mu_);
244 child_subchannels_.insert(child_uuid);
247 void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
248 MutexLock lock(&child_mu_);
249 child_subchannels_.erase(child_uuid);
256 ServerNode::ServerNode(size_t channel_tracer_max_nodes)
257 : BaseNode(EntityType::kServer, ""), trace_(channel_tracer_max_nodes) {}
259 ServerNode::~ServerNode() {}
261 void ServerNode::AddChildSocket(RefCountedPtr<SocketNode> node) {
262 MutexLock lock(&child_mu_);
263 child_sockets_.insert(std::make_pair(node->uuid(), std::move(node)));
266 void ServerNode::RemoveChildSocket(intptr_t child_uuid) {
267 MutexLock lock(&child_mu_);
268 child_sockets_.erase(child_uuid);
271 void ServerNode::AddChildListenSocket(RefCountedPtr<ListenSocketNode> node) {
272 MutexLock lock(&child_mu_);
273 child_listen_sockets_.insert(std::make_pair(node->uuid(), std::move(node)));
276 void ServerNode::RemoveChildListenSocket(intptr_t child_uuid) {
277 MutexLock lock(&child_mu_);
278 child_listen_sockets_.erase(child_uuid);
281 std::string ServerNode::RenderServerSockets(intptr_t start_socket_id,
282 intptr_t max_results) {
283 GPR_ASSERT(start_socket_id >= 0);
284 GPR_ASSERT(max_results >= 0);
285 // If user does not set max_results, we choose 500.
286 size_t pagination_limit = max_results == 0 ? 500 : max_results;
289 MutexLock lock(&child_mu_);
290 size_t sockets_rendered = 0;
291 // Create list of socket refs.
293 auto it = child_sockets_.lower_bound(start_socket_id);
294 for (; it != child_sockets_.end() && sockets_rendered < pagination_limit;
295 ++it, ++sockets_rendered) {
296 array.emplace_back(Json::Object{
297 {"socketId", std::to_string(it->first)},
298 {"name", it->second->name()},
301 object["socketRef"] = std::move(array);
302 if (it == child_sockets_.end()) object["end"] = true;
304 Json json = std::move(object);
308 Json ServerNode::RenderJson() {
310 // Fill in the channel trace if applicable.
311 Json trace_json = trace_.RenderJson();
312 if (trace_json.type() != Json::Type::JSON_NULL) {
313 data["trace"] = std::move(trace_json);
315 // Ask CallCountingHelper to populate call count data.
316 call_counter_.PopulateCallCounts(&data);
317 // Construct top-level object.
318 Json::Object object = {
321 {"serverId", std::to_string(uuid())},
323 {"data", std::move(data)},
325 // Render listen sockets.
327 MutexLock lock(&child_mu_);
328 if (!child_listen_sockets_.empty()) {
330 for (const auto& it : child_listen_sockets_) {
331 array.emplace_back(Json::Object{
332 {"socketId", std::to_string(it.first)},
333 {"name", it.second->name()},
336 object["listenSocket"] = std::move(array);
343 // SocketNode::Security::Tls
346 Json SocketNode::Security::Tls::RenderJson() {
348 if (type == NameType::kStandardName) {
349 data["standard_name"] = name;
350 } else if (type == NameType::kOtherName) {
351 data["other_name"] = name;
353 if (!local_certificate.empty()) {
354 data["local_certificate"] = absl::Base64Escape(local_certificate);
356 if (!remote_certificate.empty()) {
357 data["remote_certificate"] = absl::Base64Escape(remote_certificate);
363 // SocketNode::Security
366 Json SocketNode::Security::RenderJson() {
369 case ModelType::kUnset:
371 case ModelType::kTls:
373 data["tls"] = tls->RenderJson();
376 case ModelType::kOther:
378 data["other"] = *other;
387 void* SecurityArgCopy(void* p) {
388 SocketNode::Security* xds_certificate_provider =
389 static_cast<SocketNode::Security*>(p);
390 return xds_certificate_provider->Ref().release();
393 void SecurityArgDestroy(void* p) {
394 SocketNode::Security* xds_certificate_provider =
395 static_cast<SocketNode::Security*>(p);
396 xds_certificate_provider->Unref();
399 int SecurityArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
401 const grpc_arg_pointer_vtable kChannelArgVtable = {
402 SecurityArgCopy, SecurityArgDestroy, SecurityArgCmp};
406 grpc_arg SocketNode::Security::MakeChannelArg() const {
407 return grpc_channel_arg_pointer_create(
408 const_cast<char*>(GRPC_ARG_CHANNELZ_SECURITY),
409 const_cast<SocketNode::Security*>(this), &kChannelArgVtable);
412 RefCountedPtr<SocketNode::Security> SocketNode::Security::GetFromChannelArgs(
413 const grpc_channel_args* args) {
414 Security* security = grpc_channel_args_find_pointer<Security>(
415 args, GRPC_ARG_CHANNELZ_SECURITY);
416 return security != nullptr ? security->Ref() : nullptr;
425 void PopulateSocketAddressJson(Json::Object* json, const char* name,
426 const char* addr_str) {
427 if (addr_str == nullptr) return;
429 absl::StatusOr<URI> uri = URI::Parse(addr_str);
430 if (uri.ok() && (uri->scheme() == "ipv4" || uri->scheme() == "ipv6")) {
434 SplitHostPort(absl::StripPrefix(uri->path(), "/"), &host, &port));
437 port_num = atoi(port.data());
439 grpc_resolved_address resolved_host;
440 grpc_string_to_sockaddr(&resolved_host, host.c_str(), port_num);
441 std::string packed_host = grpc_sockaddr_get_packed_host(&resolved_host);
442 std::string b64_host = absl::Base64Escape(packed_host);
443 data["tcpip_address"] = Json::Object{
445 {"ip_address", b64_host},
447 } else if (uri.ok() && uri->scheme() == "unix") {
448 data["uds_address"] = Json::Object{
449 {"filename", uri->path()},
452 data["other_address"] = Json::Object{
456 (*json)[name] = std::move(data);
461 SocketNode::SocketNode(std::string local, std::string remote, std::string name,
462 RefCountedPtr<Security> security)
463 : BaseNode(EntityType::kSocket, std::move(name)),
464 local_(std::move(local)),
465 remote_(std::move(remote)),
466 security_(std::move(security)) {}
468 void SocketNode::RecordStreamStartedFromLocal() {
469 streams_started_.FetchAdd(1, MemoryOrder::RELAXED);
470 last_local_stream_created_cycle_.Store(gpr_get_cycle_counter(),
471 MemoryOrder::RELAXED);
474 void SocketNode::RecordStreamStartedFromRemote() {
475 streams_started_.FetchAdd(1, MemoryOrder::RELAXED);
476 last_remote_stream_created_cycle_.Store(gpr_get_cycle_counter(),
477 MemoryOrder::RELAXED);
480 void SocketNode::RecordMessagesSent(uint32_t num_sent) {
481 messages_sent_.FetchAdd(num_sent, MemoryOrder::RELAXED);
482 last_message_sent_cycle_.Store(gpr_get_cycle_counter(), MemoryOrder::RELAXED);
485 void SocketNode::RecordMessageReceived() {
486 messages_received_.FetchAdd(1, MemoryOrder::RELAXED);
487 last_message_received_cycle_.Store(gpr_get_cycle_counter(),
488 MemoryOrder::RELAXED);
491 Json SocketNode::RenderJson() {
492 // Create and fill the data child.
495 int64_t streams_started = streams_started_.Load(MemoryOrder::RELAXED);
496 if (streams_started != 0) {
497 data["streamsStarted"] = std::to_string(streams_started);
498 gpr_cycle_counter last_local_stream_created_cycle =
499 last_local_stream_created_cycle_.Load(MemoryOrder::RELAXED);
500 if (last_local_stream_created_cycle != 0) {
501 ts = gpr_convert_clock_type(
502 gpr_cycle_counter_to_time(last_local_stream_created_cycle),
504 data["lastLocalStreamCreatedTimestamp"] = gpr_format_timespec(ts);
506 gpr_cycle_counter last_remote_stream_created_cycle =
507 last_remote_stream_created_cycle_.Load(MemoryOrder::RELAXED);
508 if (last_remote_stream_created_cycle != 0) {
509 ts = gpr_convert_clock_type(
510 gpr_cycle_counter_to_time(last_remote_stream_created_cycle),
512 data["lastRemoteStreamCreatedTimestamp"] = gpr_format_timespec(ts);
515 int64_t streams_succeeded = streams_succeeded_.Load(MemoryOrder::RELAXED);
516 if (streams_succeeded != 0) {
517 data["streamsSucceeded"] = std::to_string(streams_succeeded);
519 int64_t streams_failed = streams_failed_.Load(MemoryOrder::RELAXED);
520 if (streams_failed != 0) {
521 data["streamsFailed"] = std::to_string(streams_failed);
523 int64_t messages_sent = messages_sent_.Load(MemoryOrder::RELAXED);
524 if (messages_sent != 0) {
525 data["messagesSent"] = std::to_string(messages_sent);
526 ts = gpr_convert_clock_type(
527 gpr_cycle_counter_to_time(
528 last_message_sent_cycle_.Load(MemoryOrder::RELAXED)),
530 data["lastMessageSentTimestamp"] = gpr_format_timespec(ts);
532 int64_t messages_received = messages_received_.Load(MemoryOrder::RELAXED);
533 if (messages_received != 0) {
534 data["messagesReceived"] = std::to_string(messages_received);
535 ts = gpr_convert_clock_type(
536 gpr_cycle_counter_to_time(
537 last_message_received_cycle_.Load(MemoryOrder::RELAXED)),
539 data["lastMessageReceivedTimestamp"] = gpr_format_timespec(ts);
541 int64_t keepalives_sent = keepalives_sent_.Load(MemoryOrder::RELAXED);
542 if (keepalives_sent != 0) {
543 data["keepAlivesSent"] = std::to_string(keepalives_sent);
545 // Create and fill the parent object.
546 Json::Object object = {
549 {"socketId", std::to_string(uuid())},
552 {"data", std::move(data)},
554 if (security_ != nullptr &&
555 security_->type != SocketNode::Security::ModelType::kUnset) {
556 object["security"] = security_->RenderJson();
558 PopulateSocketAddressJson(&object, "remote", remote_.c_str());
559 PopulateSocketAddressJson(&object, "local", local_.c_str());
567 ListenSocketNode::ListenSocketNode(std::string local_addr, std::string name)
568 : BaseNode(EntityType::kSocket, std::move(name)),
569 local_addr_(std::move(local_addr)) {}
571 Json ListenSocketNode::RenderJson() {
572 Json::Object object = {
575 {"socketId", std::to_string(uuid())},
579 PopulateSocketAddressJson(&object, "local", local_addr_.c_str());
583 } // namespace channelz
584 } // namespace grpc_core