/* * * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/connectivity_state.h" #include namespace grpc_core { namespace channelz { namespace { void* client_channel_channelz_copy(void* p) { return p; } void client_channel_channelz_destroy(void* p) {} int client_channel_channelz_cmp(void* a, void* b) { return GPR_ICMP(a, b); } } // namespace static const grpc_arg_pointer_vtable client_channel_channelz_vtable = { client_channel_channelz_copy, client_channel_channelz_destroy, client_channel_channelz_cmp}; ClientChannelNode::ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, bool is_top_level_channel) : ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) { client_channel_ = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); grpc_client_channel_set_channelz_node(client_channel_, this); GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter); } void ClientChannelNode::PopulateConnectivityState(grpc_json* json) { grpc_connectivity_state state; if (ChannelIsDestroyed()) { state = GRPC_CHANNEL_SHUTDOWN; } else { state = grpc_client_channel_check_connectivity_state(client_channel_, false); } json = grpc_json_create_child(nullptr, json, "state", nullptr, GRPC_JSON_OBJECT, false); grpc_json_create_child(nullptr, json, "state", grpc_connectivity_state_name(state), GRPC_JSON_STRING, false); } void ClientChannelNode::PopulateChildRefs(grpc_json* json) { ChildRefsList child_subchannels; ChildRefsList child_channels; grpc_json* json_iterator = nullptr; grpc_client_channel_populate_child_refs(client_channel_, &child_subchannels, &child_channels); if (!child_subchannels.empty()) { grpc_json* array_parent = grpc_json_create_child( nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false); for (size_t i = 0; i < child_subchannels.size(); ++i) { json_iterator = grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId", child_subchannels[i]); } } if (!child_channels.empty()) { grpc_json* array_parent = grpc_json_create_child( nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false); json_iterator = nullptr; for (size_t i = 0; i < child_channels.size(); ++i) { json_iterator = grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); grpc_json_add_number_string_child(json_iterator, nullptr, "channelId", child_channels[i]); } } } grpc_arg ClientChannelNode::CreateChannelArg() { return grpc_channel_arg_pointer_create( const_cast(GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC), reinterpret_cast(MakeClientChannelNode), &client_channel_channelz_vtable); } RefCountedPtr ClientChannelNode::MakeClientChannelNode( grpc_channel* channel, size_t channel_tracer_max_nodes, bool is_top_level_channel) { return MakeRefCounted(channel, channel_tracer_max_nodes, is_top_level_channel); } SubchannelNode::SubchannelNode(grpc_subchannel* subchannel, size_t channel_tracer_max_nodes) : BaseNode(EntityType::kSubchannel), subchannel_(subchannel), target_( UniquePtr(gpr_strdup(grpc_subchannel_get_target(subchannel_)))), trace_(channel_tracer_max_nodes) {} SubchannelNode::~SubchannelNode() {} void SubchannelNode::PopulateConnectivityState(grpc_json* json) { grpc_connectivity_state state; if (subchannel_ == nullptr) { state = GRPC_CHANNEL_SHUTDOWN; } else { state = grpc_subchannel_check_connectivity( subchannel_, nullptr, true /* inhibit_health_checking */); } json = grpc_json_create_child(nullptr, json, "state", nullptr, GRPC_JSON_OBJECT, false); grpc_json_create_child(nullptr, json, "state", grpc_connectivity_state_name(state), GRPC_JSON_STRING, false); } grpc_json* SubchannelNode::RenderJson() { grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, GRPC_JSON_OBJECT, false); json = json_iterator; json_iterator = nullptr; json_iterator = grpc_json_add_number_string_child(json, json_iterator, "subchannelId", uuid()); // reset json iterators to top level object json = top_level_json; json_iterator = nullptr; // create and fill the data child. grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr, GRPC_JSON_OBJECT, false); json = data; json_iterator = nullptr; PopulateConnectivityState(json); GPR_ASSERT(target_.get() != nullptr); grpc_json_create_child(nullptr, json, "target", target_.get(), GRPC_JSON_STRING, false); // fill in the channel trace if applicable grpc_json* trace_json = trace_.RenderJson(); if (trace_json != nullptr) { trace_json->key = "trace"; // this object is named trace in channelz.proto grpc_json_link_child(json, trace_json, nullptr); } // ask CallCountingHelper to populate trace and call count data. call_counter_.PopulateCallCounts(json); json = top_level_json; // populate the child socket. intptr_t socket_uuid = grpc_subchannel_get_child_socket_uuid(subchannel_); if (socket_uuid != 0) { grpc_json* array_parent = grpc_json_create_child( nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); json_iterator = grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); grpc_json_add_number_string_child(json_iterator, nullptr, "socketId", socket_uuid); } return top_level_json; } } // namespace channelz } // namespace grpc_core