blob: 7ca3fc5836870cb9883d8818d699ef82ebf953b5 [file] [log] [blame]
ncteisen3b42f832018-03-19 13:22:35 -07001/*
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
ncteisen3b42f832018-03-19 13:22:35 -070021#include "src/core/lib/channel/channel_trace.h"
ncteisen97066fd2018-07-13 14:05:27 -070022#include "src/core/lib/channel/channelz.h"
ncteisenbba88402018-05-11 11:54:41 -040023#include "src/core/lib/channel/channelz_registry.h"
ncteisen3b42f832018-03-19 13:22:35 -070024#include "src/core/lib/gpr/useful.h"
ncteisen3be52f92018-05-11 12:34:02 -040025#include "src/core/lib/gprpp/memory.h"
ncteisen3b42f832018-03-19 13:22:35 -070026
27#include <grpc/support/alloc.h>
28#include <grpc/support/log.h>
ncteisen9a6c7222018-07-13 12:09:55 -070029#include <grpc/support/sync.h>
ncteisen3b42f832018-03-19 13:22:35 -070030
ncteisenaca50432018-07-10 18:50:45 -070031#include <cstring>
32
ncteisen3be52f92018-05-11 12:34:02 -040033namespace grpc_core {
ncteisen9a6c7222018-07-13 12:09:55 -070034namespace channelz {
ncteisen3be52f92018-05-11 12:34:02 -040035namespace {
ncteisen3b42f832018-03-19 13:22:35 -070036
ncteisen3be52f92018-05-11 12:34:02 -040037// singleton instance of the registry.
38ChannelzRegistry* g_channelz_registry = nullptr;
39
ncteisen3be52f92018-05-11 12:34:02 -040040} // anonymous namespace
41
42void ChannelzRegistry::Init() { g_channelz_registry = New<ChannelzRegistry>(); }
43
44void ChannelzRegistry::Shutdown() { Delete(g_channelz_registry); }
45
46ChannelzRegistry* ChannelzRegistry::Default() {
47 GPR_DEBUG_ASSERT(g_channelz_registry != nullptr);
48 return g_channelz_registry;
ncteisen3b42f832018-03-19 13:22:35 -070049}
50
ncteisen2fe49382018-07-11 08:11:40 -070051ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); }
ncteisen3b42f832018-03-19 13:22:35 -070052
ncteisen2fe49382018-07-11 08:11:40 -070053ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }
ncteisen3be52f92018-05-11 12:34:02 -040054
ncteisen9a6c7222018-07-13 12:09:55 -070055intptr_t ChannelzRegistry::InternalRegisterEntry(const RegistryEntry& entry) {
56 mu_guard guard(&mu_);
57 entities_.push_back(entry);
58 intptr_t uuid = entities_.size();
59 return uuid;
ncteisen3b42f832018-03-19 13:22:35 -070060}
61
ncteisen9a6c7222018-07-13 12:09:55 -070062void ChannelzRegistry::InternalUnregisterEntry(intptr_t uuid, EntityType type) {
63 GPR_ASSERT(uuid >= 1);
64 mu_guard guard(&mu_);
65 GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size());
66 GPR_ASSERT(entities_[uuid - 1].type == type);
67 entities_[uuid - 1].object = nullptr;
ncteisen97066fd2018-07-13 14:05:27 -070068 entities_[uuid - 1].type = EntityType::kUnset;
ncteisen9a6c7222018-07-13 12:09:55 -070069}
70
71void* ChannelzRegistry::InternalGetEntry(intptr_t uuid, EntityType type) {
72 mu_guard guard(&mu_);
73 if (uuid < 1 || uuid > static_cast<intptr_t>(entities_.size())) {
74 return nullptr;
75 }
76 if (entities_[uuid - 1].type == type) {
77 return entities_[uuid - 1].object;
78 } else {
79 return nullptr;
80 }
81}
82
ncteisen97066fd2018-07-13 14:05:27 -070083char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
84 grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
85 grpc_json* json = top_level_json;
86 grpc_json* json_iterator = nullptr;
87 InlinedVector<ChannelNode*, 10> top_level_channels;
88 // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
ncteisen5d373c42018-07-17 11:57:31 -070089 // reserved). However, we want to support requests coming in this
ncteisen97066fd2018-07-13 14:05:27 -070090 // start_channel_id=0, which signifies "give me everything." Hence this
91 // funky looking line below.
92 size_t start_idx = start_channel_id == 0 ? 0 : start_channel_id - 1;
93 for (size_t i = start_idx; i < entities_.size(); ++i) {
94 if (entities_[i].type == EntityType::kChannelNode) {
95 ChannelNode* channel_node =
96 static_cast<ChannelNode*>(entities_[i].object);
97 if (channel_node->is_top_level_channel()) {
98 top_level_channels.push_back(channel_node);
99 }
100 }
101 }
102 if (top_level_channels.size() > 0) {
103 // create list of channels
104 grpc_json* array_parent = grpc_json_create_child(
105 nullptr, json, "channel", nullptr, GRPC_JSON_ARRAY, false);
106 for (size_t i = 0; i < top_level_channels.size(); ++i) {
107 grpc_json* channel_json = top_level_channels[i]->RenderJson();
108 json_iterator =
109 grpc_json_link_child(array_parent, channel_json, json_iterator);
110 channel_json->parent = array_parent;
ncteisen97066fd2018-07-13 14:05:27 -0700111 }
112 }
113 // For now we do not have any pagination rules. In the future we could
114 // pick a constant for max_channels_sent for a GetTopChannels request.
115 // Tracking: https://github.com/grpc/grpc/issues/16019.
116 json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
117 GRPC_JSON_TRUE, false);
118 char* json_str = grpc_json_dump_to_string(top_level_json, 0);
119 grpc_json_destroy(top_level_json);
120 return json_str;
121}
122
ncteisen9a6c7222018-07-13 12:09:55 -0700123} // namespace channelz
ncteisen3be52f92018-05-11 12:34:02 -0400124} // namespace grpc_core