• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/channel_trace.h"
22 #include "src/core/lib/channel/channelz.h"
23 #include "src/core/lib/channel/channelz_registry.h"
24 #include "src/core/lib/gpr/useful.h"
25 #include "src/core/lib/gprpp/memory.h"
26 #include "src/core/lib/gprpp/mutex_lock.h"
27 
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30 #include <grpc/support/sync.h>
31 
32 #include <cstring>
33 
34 namespace grpc_core {
35 namespace channelz {
36 namespace {
37 
38 // singleton instance of the registry.
39 ChannelzRegistry* g_channelz_registry = nullptr;
40 
41 }  // anonymous namespace
42 
Init()43 void ChannelzRegistry::Init() { g_channelz_registry = New<ChannelzRegistry>(); }
44 
Shutdown()45 void ChannelzRegistry::Shutdown() { Delete(g_channelz_registry); }
46 
Default()47 ChannelzRegistry* ChannelzRegistry::Default() {
48   GPR_DEBUG_ASSERT(g_channelz_registry != nullptr);
49   return g_channelz_registry;
50 }
51 
ChannelzRegistry()52 ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); }
53 
~ChannelzRegistry()54 ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }
55 
InternalRegister(BaseNode * node)56 intptr_t ChannelzRegistry::InternalRegister(BaseNode* node) {
57   MutexLock lock(&mu_);
58   entities_.push_back(node);
59   intptr_t uuid = entities_.size();
60   return uuid;
61 }
62 
InternalUnregister(intptr_t uuid)63 void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
64   GPR_ASSERT(uuid >= 1);
65   MutexLock lock(&mu_);
66   GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size());
67   entities_[uuid - 1] = nullptr;
68 }
69 
InternalGet(intptr_t uuid)70 BaseNode* ChannelzRegistry::InternalGet(intptr_t uuid) {
71   MutexLock lock(&mu_);
72   if (uuid < 1 || uuid > static_cast<intptr_t>(entities_.size())) {
73     return nullptr;
74   }
75   return entities_[uuid - 1];
76 }
77 
InternalGetTopChannels(intptr_t start_channel_id)78 char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
79   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
80   grpc_json* json = top_level_json;
81   grpc_json* json_iterator = nullptr;
82   InlinedVector<BaseNode*, 10> top_level_channels;
83   // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
84   // reserved). However, we want to support requests coming in with
85   // start_channel_id=0, which signifies "give me everything." Hence this
86   // funky looking line below.
87   size_t start_idx = start_channel_id == 0 ? 0 : start_channel_id - 1;
88   for (size_t i = start_idx; i < entities_.size(); ++i) {
89     if (entities_[i] != nullptr &&
90         entities_[i]->type() ==
91             grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel) {
92       top_level_channels.push_back(entities_[i]);
93     }
94   }
95   if (!top_level_channels.empty()) {
96     // create list of channels
97     grpc_json* array_parent = grpc_json_create_child(
98         nullptr, json, "channel", nullptr, GRPC_JSON_ARRAY, false);
99     for (size_t i = 0; i < top_level_channels.size(); ++i) {
100       grpc_json* channel_json = top_level_channels[i]->RenderJson();
101       json_iterator =
102           grpc_json_link_child(array_parent, channel_json, json_iterator);
103     }
104   }
105   // For now we do not have any pagination rules. In the future we could
106   // pick a constant for max_channels_sent for a GetTopChannels request.
107   // Tracking: https://github.com/grpc/grpc/issues/16019.
108   json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
109                                          GRPC_JSON_TRUE, false);
110   char* json_str = grpc_json_dump_to_string(top_level_json, 0);
111   grpc_json_destroy(top_level_json);
112   return json_str;
113 }
114 
InternalGetServers(intptr_t start_server_id)115 char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
116   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
117   grpc_json* json = top_level_json;
118   grpc_json* json_iterator = nullptr;
119   InlinedVector<BaseNode*, 10> servers;
120   // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
121   // reserved). However, we want to support requests coming in with
122   // start_server_id=0, which signifies "give me everything."
123   size_t start_idx = start_server_id == 0 ? 0 : start_server_id - 1;
124   for (size_t i = start_idx; i < entities_.size(); ++i) {
125     if (entities_[i] != nullptr &&
126         entities_[i]->type() ==
127             grpc_core::channelz::BaseNode::EntityType::kServer) {
128       servers.push_back(entities_[i]);
129     }
130   }
131   if (!servers.empty()) {
132     // create list of servers
133     grpc_json* array_parent = grpc_json_create_child(
134         nullptr, json, "server", nullptr, GRPC_JSON_ARRAY, false);
135     for (size_t i = 0; i < servers.size(); ++i) {
136       grpc_json* server_json = servers[i]->RenderJson();
137       json_iterator =
138           grpc_json_link_child(array_parent, server_json, json_iterator);
139     }
140   }
141   // For now we do not have any pagination rules. In the future we could
142   // pick a constant for max_channels_sent for a GetServers request.
143   // Tracking: https://github.com/grpc/grpc/issues/16019.
144   json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
145                                          GRPC_JSON_TRUE, false);
146   char* json_str = grpc_json_dump_to_string(top_level_json, 0);
147   grpc_json_destroy(top_level_json);
148   return json_str;
149 }
150 
151 }  // namespace channelz
152 }  // namespace grpc_core
153 
grpc_channelz_get_top_channels(intptr_t start_channel_id)154 char* grpc_channelz_get_top_channels(intptr_t start_channel_id) {
155   return grpc_core::channelz::ChannelzRegistry::GetTopChannels(
156       start_channel_id);
157 }
158 
grpc_channelz_get_servers(intptr_t start_server_id)159 char* grpc_channelz_get_servers(intptr_t start_server_id) {
160   return grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id);
161 }
162 
grpc_channelz_get_channel(intptr_t channel_id)163 char* grpc_channelz_get_channel(intptr_t channel_id) {
164   grpc_core::channelz::BaseNode* channel_node =
165       grpc_core::channelz::ChannelzRegistry::Get(channel_id);
166   if (channel_node == nullptr ||
167       (channel_node->type() !=
168            grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel &&
169        channel_node->type() !=
170            grpc_core::channelz::BaseNode::EntityType::kInternalChannel)) {
171     return nullptr;
172   }
173   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
174   grpc_json* json = top_level_json;
175   grpc_json* channel_json = channel_node->RenderJson();
176   channel_json->key = "channel";
177   grpc_json_link_child(json, channel_json, nullptr);
178   char* json_str = grpc_json_dump_to_string(top_level_json, 0);
179   grpc_json_destroy(top_level_json);
180   return json_str;
181 }
182 
grpc_channelz_get_subchannel(intptr_t subchannel_id)183 char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
184   grpc_core::channelz::BaseNode* subchannel_node =
185       grpc_core::channelz::ChannelzRegistry::Get(subchannel_id);
186   if (subchannel_node == nullptr ||
187       subchannel_node->type() !=
188           grpc_core::channelz::BaseNode::EntityType::kSubchannel) {
189     return nullptr;
190   }
191   grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
192   grpc_json* json = top_level_json;
193   grpc_json* subchannel_json = subchannel_node->RenderJson();
194   subchannel_json->key = "subchannel";
195   grpc_json_link_child(json, subchannel_json, nullptr);
196   char* json_str = grpc_json_dump_to_string(top_level_json, 0);
197   grpc_json_destroy(top_level_json);
198   return json_str;
199 }
200