Merge branch 'master' of https://github.com/grpc/grpc into channelz-get-top-channels
diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.cc b/src/core/ext/filters/client_channel/client_channel_channelz.cc
index 235b8f3..c1c204a 100644
--- a/src/core/ext/filters/client_channel/client_channel_channelz.cc
+++ b/src/core/ext/filters/client_channel/client_channel_channelz.cc
@@ -41,8 +41,9 @@
client_channel_channelz_cmp};
ClientChannelNode::ClientChannelNode(grpc_channel* channel,
- size_t channel_tracer_max_nodes)
- : ChannelNode(channel, channel_tracer_max_nodes) {
+ 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));
GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter);
@@ -102,9 +103,10 @@
}
RefCountedPtr<ChannelNode> ClientChannelNode::MakeClientChannelNode(
- grpc_channel* channel, size_t channel_tracer_max_nodes) {
+ grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel) {
return MakePolymorphicRefCounted<ChannelNode, ClientChannelNode>(
- channel, channel_tracer_max_nodes);
+ channel, channel_tracer_max_nodes, is_top_level_channel);
}
} // namespace channelz
diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.h b/src/core/ext/filters/client_channel/client_channel_channelz.h
index 0547109..6f27b5c 100644
--- a/src/core/ext/filters/client_channel/client_channel_channelz.h
+++ b/src/core/ext/filters/client_channel/client_channel_channelz.h
@@ -40,7 +40,8 @@
class ClientChannelNode : public ChannelNode {
public:
static RefCountedPtr<ChannelNode> MakeClientChannelNode(
- grpc_channel* channel, size_t channel_tracer_max_nodes);
+ grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
// Override this functionality since client_channels have a notion of
// channel connectivity.
@@ -56,7 +57,8 @@
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
- ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes);
+ ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
virtual ~ClientChannelNode() {}
private:
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index f757d60..8553441 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -1007,6 +1007,10 @@
// A channel arg indicating the target is a grpclb load balancer.
grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1),
+ // A channel arg indicating this is an internal channels, aka it is
+ // owned by components in Core, not by the user application.
+ grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1),
};
// Construct channel args.
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc
index c17885a..b344331 100644
--- a/src/core/lib/channel/channel_trace.cc
+++ b/src/core/lib/channel/channel_trace.cc
@@ -174,7 +174,7 @@
}
}
-grpc_json* ChannelTrace::RenderJSON() const {
+grpc_json* ChannelTrace::RenderJson() const {
if (!max_list_size_)
return nullptr; // tracing is disabled if max_events == 0
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h
index 0dd162a..596af74 100644
--- a/src/core/lib/channel/channel_trace.h
+++ b/src/core/lib/channel/channel_trace.h
@@ -71,7 +71,7 @@
// Creates and returns the raw grpc_json object, so a parent channelz
// object may incorporate the json before rendering.
- grpc_json* RenderJSON() const;
+ grpc_json* RenderJson() const;
private:
// Types of objects that can be references by trace events.
diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc
index 79a9220..df85b89 100644
--- a/src/core/lib/channel/channelz.cc
+++ b/src/core/lib/channel/channelz.cc
@@ -41,18 +41,22 @@
namespace grpc_core {
namespace channelz {
-ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes)
- : channel_(channel), target_(nullptr), channel_uuid_(-1) {
+ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel)
+ : channel_(channel),
+ target_(nullptr),
+ channel_uuid_(-1),
+ is_top_level_channel_(is_top_level_channel) {
trace_.Init(channel_tracer_max_nodes);
target_ = UniquePtr<char>(grpc_channel_get_target(channel_));
- channel_uuid_ = ChannelzRegistry::Register(this);
+ channel_uuid_ = ChannelzRegistry::RegisterChannelNode(this);
gpr_atm_no_barrier_store(&last_call_started_millis_,
(gpr_atm)ExecCtx::Get()->Now());
}
ChannelNode::~ChannelNode() {
trace_.Destroy();
- ChannelzRegistry::Unregister(channel_uuid_);
+ ChannelzRegistry::UnregisterChannelNode(channel_uuid_);
}
void ChannelNode::RecordCallStarted() {
@@ -65,7 +69,7 @@
void ChannelNode::PopulateChildRefs(grpc_json* json) {}
-char* ChannelNode::RenderJSON() {
+grpc_json* ChannelNode::RenderJson() {
// We need to track these three json objects to build our object
grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
grpc_json* json = top_level_json;
@@ -86,13 +90,14 @@
json = data;
json_iterator = nullptr;
PopulateConnectivityState(json);
+ GPR_ASSERT(target_.get() != nullptr);
json_iterator = grpc_json_create_child(
json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false);
// fill in the channel trace if applicable
- grpc_json* trace = trace_->RenderJSON();
+ grpc_json* trace = trace_->RenderJson();
if (trace != nullptr) {
- // we manuall link up and fill the child since it was created for us in
- // ChannelTrace::RenderJSON
+ // we manually link up and fill the child since it was created for us in
+ // ChannelTrace::RenderJson
json_iterator = grpc_json_link_child(json, trace, json_iterator);
trace->parent = json;
trace->value = nullptr;
@@ -102,14 +107,18 @@
// reset the parent to be the data object.
json = data;
json_iterator = nullptr;
- // We use -1 as sentinel values since proto default value for integers is
- // zero, and the confuses the parser into thinking the value weren't present
- json_iterator = grpc_json_add_number_string_child(
- json, json_iterator, "callsStarted", calls_started_);
- json_iterator = grpc_json_add_number_string_child(
- json, json_iterator, "callsSucceeded", calls_succeeded_);
- json_iterator = grpc_json_add_number_string_child(
- json, json_iterator, "callsFailed", calls_failed_);
+ if (calls_started_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "callsStarted", calls_started_);
+ }
+ if (calls_succeeded_ != 0) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "callsSucceeded", calls_succeeded_);
+ }
+ if (calls_failed_) {
+ json_iterator = grpc_json_add_number_string_child(
+ json, json_iterator, "callsFailed", calls_failed_);
+ }
gpr_timespec ts =
grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME);
json_iterator =
@@ -118,25 +127,29 @@
json = top_level_json;
json_iterator = nullptr;
PopulateChildRefs(json);
+ return top_level_json;
+}
- // render and return the over json object
- char* json_str = grpc_json_dump_to_string(top_level_json, 0);
- grpc_json_destroy(top_level_json);
+char* ChannelNode::RenderJsonString() {
+ grpc_json* json = RenderJson();
+ char* json_str = grpc_json_dump_to_string(json, 0);
+ grpc_json_destroy(json);
return json_str;
}
RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode(
- grpc_channel* channel, size_t channel_tracer_max_nodes) {
+ grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel) {
return MakeRefCounted<grpc_core::channelz::ChannelNode>(
- channel, channel_tracer_max_nodes);
+ channel, channel_tracer_max_nodes, is_top_level_channel);
}
SubchannelNode::SubchannelNode() {
- subchannel_uuid_ = ChannelzRegistry::Register(this);
+ subchannel_uuid_ = ChannelzRegistry::RegisterSubchannelNode(this);
}
SubchannelNode::~SubchannelNode() {
- ChannelzRegistry::Unregister(subchannel_uuid_);
+ ChannelzRegistry::UnregisterSubchannelNode(subchannel_uuid_);
}
} // namespace channelz
diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h
index 7184af9..07eb73d 100644
--- a/src/core/lib/channel/channelz.h
+++ b/src/core/lib/channel/channelz.h
@@ -35,6 +35,10 @@
#define GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC \
"grpc.channelz_channel_node_creation_func"
+// Channel arg key to signal that the channel is an internal channel.
+#define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \
+ "grpc.channelz_channel_is_internal_channel"
+
namespace grpc_core {
namespace channelz {
@@ -45,7 +49,8 @@
class ChannelNode : public RefCounted<ChannelNode> {
public:
static RefCountedPtr<ChannelNode> MakeChannelNode(
- grpc_channel* channel, size_t channel_tracer_max_nodes);
+ grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
void RecordCallStarted();
void RecordCallFailed() {
@@ -55,7 +60,8 @@
gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1)));
}
- char* RenderJSON();
+ grpc_json* RenderJson();
+ char* RenderJsonString();
// helper for getting and populating connectivity state. It is virtual
// because it allows the client_channel specific code to live in ext/
@@ -74,11 +80,13 @@
bool ChannelIsDestroyed() { return channel_ == nullptr; }
intptr_t channel_uuid() { return channel_uuid_; }
+ bool is_top_level_channel() { return is_top_level_channel_; }
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
- ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes);
+ ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
+ bool is_top_level_channel);
virtual ~ChannelNode();
private:
@@ -92,6 +100,7 @@
gpr_atm calls_failed_ = 0;
gpr_atm last_call_started_millis_ = 0;
intptr_t channel_uuid_;
+ bool is_top_level_channel_ = true;
ManualConstructor<ChannelTrace> trace_;
};
@@ -116,7 +125,7 @@
// Creation functions
typedef RefCountedPtr<ChannelNode> (*ChannelNodeCreationFunc)(grpc_channel*,
- size_t);
+ size_t, bool);
} // namespace channelz
} // namespace grpc_core
diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc
index 023ede5..7ca3fc5 100644
--- a/src/core/lib/channel/channelz_registry.cc
+++ b/src/core/lib/channel/channelz_registry.cc
@@ -19,16 +19,19 @@
#include <grpc/impl/codegen/port_platform.h>
#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
#include <cstring>
namespace grpc_core {
+namespace channelz {
namespace {
// singleton instance of the registry.
@@ -49,12 +52,73 @@
ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }
-void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
- GPR_ASSERT(uuid >= 1);
- gpr_mu_lock(&mu_);
- GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size());
- entities_[uuid - 1] = nullptr;
- gpr_mu_unlock(&mu_);
+intptr_t ChannelzRegistry::InternalRegisterEntry(const RegistryEntry& entry) {
+ mu_guard guard(&mu_);
+ entities_.push_back(entry);
+ intptr_t uuid = entities_.size();
+ return uuid;
}
+void ChannelzRegistry::InternalUnregisterEntry(intptr_t uuid, EntityType type) {
+ GPR_ASSERT(uuid >= 1);
+ mu_guard guard(&mu_);
+ GPR_ASSERT(static_cast<size_t>(uuid) <= entities_.size());
+ GPR_ASSERT(entities_[uuid - 1].type == type);
+ entities_[uuid - 1].object = nullptr;
+ entities_[uuid - 1].type = EntityType::kUnset;
+}
+
+void* ChannelzRegistry::InternalGetEntry(intptr_t uuid, EntityType type) {
+ mu_guard guard(&mu_);
+ if (uuid < 1 || uuid > static_cast<intptr_t>(entities_.size())) {
+ return nullptr;
+ }
+ if (entities_[uuid - 1].type == type) {
+ return entities_[uuid - 1].object;
+ } else {
+ return nullptr;
+ }
+}
+
+char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
+ grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
+ grpc_json* json = top_level_json;
+ grpc_json* json_iterator = nullptr;
+ InlinedVector<ChannelNode*, 10> top_level_channels;
+ // uuids index into entities one-off (idx 0 is really uuid 1, since 0 is
+ // reserved). However, we want to support requests coming in this
+ // start_channel_id=0, which signifies "give me everything." Hence this
+ // funky looking line below.
+ size_t start_idx = start_channel_id == 0 ? 0 : start_channel_id - 1;
+ for (size_t i = start_idx; i < entities_.size(); ++i) {
+ if (entities_[i].type == EntityType::kChannelNode) {
+ ChannelNode* channel_node =
+ static_cast<ChannelNode*>(entities_[i].object);
+ if (channel_node->is_top_level_channel()) {
+ top_level_channels.push_back(channel_node);
+ }
+ }
+ }
+ if (top_level_channels.size() > 0) {
+ // create list of channels
+ grpc_json* array_parent = grpc_json_create_child(
+ nullptr, json, "channel", nullptr, GRPC_JSON_ARRAY, false);
+ for (size_t i = 0; i < top_level_channels.size(); ++i) {
+ grpc_json* channel_json = top_level_channels[i]->RenderJson();
+ json_iterator =
+ grpc_json_link_child(array_parent, channel_json, json_iterator);
+ channel_json->parent = array_parent;
+ }
+ }
+ // For now we do not have any pagination rules. In the future we could
+ // pick a constant for max_channels_sent for a GetTopChannels request.
+ // Tracking: https://github.com/grpc/grpc/issues/16019.
+ json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
+ GRPC_JSON_TRUE, false);
+ char* json_str = grpc_json_dump_to_string(top_level_json, 0);
+ grpc_json_destroy(top_level_json);
+ return json_str;
+}
+
+} // namespace channelz
} // namespace grpc_core
diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h
index a5a187a..5d7c936 100644
--- a/src/core/lib/channel/channelz_registry.h
+++ b/src/core/lib/channel/channelz_registry.h
@@ -22,11 +22,13 @@
#include <grpc/impl/codegen/port_platform.h>
#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include <stdint.h>
namespace grpc_core {
+namespace channelz {
// singleton registry object to track all objects that are needed to support
// channelz bookkeeping. All objects share globally distributed uuids.
@@ -35,26 +37,56 @@
// To be called in grpc_init()
static void Init();
- // To be callen in grpc_shutdown();
+ // To be called in grpc_shutdown();
static void Shutdown();
- // globally registers a channelz Object. Returns its unique uuid
- template <typename Object>
- static intptr_t Register(Object* object) {
- return Default()->InternalRegister(object);
+ // Register/Unregister/Get for ChannelNode
+ static intptr_t RegisterChannelNode(ChannelNode* channel_node) {
+ RegistryEntry entry(channel_node, EntityType::kChannelNode);
+ return Default()->InternalRegisterEntry(entry);
+ }
+ static void UnregisterChannelNode(intptr_t uuid) {
+ Default()->InternalUnregisterEntry(uuid, EntityType::kChannelNode);
+ }
+ static ChannelNode* GetChannelNode(intptr_t uuid) {
+ void* gotten = Default()->InternalGetEntry(uuid, EntityType::kChannelNode);
+ return gotten == nullptr ? nullptr : static_cast<ChannelNode*>(gotten);
}
- // globally unregisters the object that is associated to uuid.
- static void Unregister(intptr_t uuid) { Default()->InternalUnregister(uuid); }
+ // Register/Unregister/Get for SubchannelNode
+ static intptr_t RegisterSubchannelNode(SubchannelNode* channel_node) {
+ RegistryEntry entry(channel_node, EntityType::kSubchannelNode);
+ return Default()->InternalRegisterEntry(entry);
+ }
+ static void UnregisterSubchannelNode(intptr_t uuid) {
+ Default()->InternalUnregisterEntry(uuid, EntityType::kSubchannelNode);
+ }
+ static SubchannelNode* GetSubchannelNode(intptr_t uuid) {
+ void* gotten =
+ Default()->InternalGetEntry(uuid, EntityType::kSubchannelNode);
+ return gotten == nullptr ? nullptr : static_cast<SubchannelNode*>(gotten);
+ }
- // if object with uuid has previously been registered, returns the
- // Object associated with that uuid. Else returns nullptr.
- template <typename Object>
- static Object* Get(intptr_t uuid) {
- return Default()->InternalGet<Object>(uuid);
+ // Returns the allocated JSON string that represents the proto
+ // GetTopChannelsResponse as per channelz.proto.
+ static char* GetTopChannels(intptr_t start_channel_id) {
+ return Default()->InternalGetTopChannels(start_channel_id);
}
private:
+ enum class EntityType {
+ kChannelNode,
+ kSubchannelNode,
+ kUnset,
+ };
+
+ struct RegistryEntry {
+ RegistryEntry(void* object_in, EntityType type_in)
+ : object(object_in), type(type_in) {}
+ void* object;
+ EntityType type;
+ };
+
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
@@ -64,40 +96,25 @@
// Returned the singleton instance of ChannelzRegistry;
static ChannelzRegistry* Default();
- // globally registers a channelz Object. Returns its unique uuid
- template <typename Object>
- intptr_t InternalRegister(Object* object) {
- gpr_mu_lock(&mu_);
- entities_.push_back(static_cast<void*>(object));
- intptr_t uuid = entities_.size();
- gpr_mu_unlock(&mu_);
- return uuid;
- }
+ // globally registers an Entry. Returns its unique uuid
+ intptr_t InternalRegisterEntry(const RegistryEntry& entry);
- // globally unregisters the object that is associated to uuid.
- void InternalUnregister(intptr_t uuid);
+ // globally unregisters the object that is associated to uuid. Also does
+ // sanity check that an object doesn't try to unregister the wrong type.
+ void InternalUnregisterEntry(intptr_t uuid, EntityType type);
- // if object with uuid has previously been registered, returns the
- // Object associated with that uuid. Else returns nullptr.
- template <typename Object>
- Object* InternalGet(intptr_t uuid) {
- gpr_mu_lock(&mu_);
- if (uuid < 1 || uuid > static_cast<intptr_t>(entities_.size())) {
- gpr_mu_unlock(&mu_);
- return nullptr;
- }
- Object* ret = static_cast<Object*>(entities_[uuid - 1]);
- gpr_mu_unlock(&mu_);
- return ret;
- }
+ // if object with uuid has previously been registered as the correct type,
+ // returns the void* associated with that uuid. Else returns nullptr.
+ void* InternalGetEntry(intptr_t uuid, EntityType type);
- // private members
+ char* InternalGetTopChannels(intptr_t start_channel_id);
// protects entities_ and uuid_
gpr_mu mu_;
- InlinedVector<void*, 20> entities_;
+ InlinedVector<RegistryEntry, 20> entities_;
};
+} // namespace channelz
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_REGISTRY_H */
diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc
index 8f3ad6c..7cbd61a 100644
--- a/src/core/lib/surface/channel.cc
+++ b/src/core/lib/surface/channel.cc
@@ -105,6 +105,7 @@
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
size_t channel_tracer_max_nodes = 0; // default to off
bool channelz_enabled = false;
+ bool internal_channel = false;
// this creates the default ChannelNode. Different types of channels may
// override this to ensure a correct ChannelNode is created.
grpc_core::channelz::ChannelNodeCreationFunc channel_node_create_func =
@@ -158,13 +159,17 @@
channel_node_create_func =
reinterpret_cast<grpc_core::channelz::ChannelNodeCreationFunc>(
args->args[i].value.pointer.p);
+ } else if (0 == strcmp(args->args[i].key,
+ GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL)) {
+ internal_channel = grpc_channel_arg_get_bool(&args->args[i], false);
}
}
grpc_channel_args_destroy(args);
if (channelz_enabled) {
- channel->channelz_channel =
- channel_node_create_func(channel, channel_tracer_max_nodes);
+ bool is_top_level_channel = channel->is_client && !internal_channel;
+ channel->channelz_channel = channel_node_create_func(
+ channel, channel_tracer_max_nodes, is_top_level_channel);
channel->channelz_channel->trace()->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("Channel created"));
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index 16be81e..0ad82fe 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -127,7 +127,7 @@
grpc_slice_intern_init();
grpc_mdctx_global_init();
grpc_channel_init_init();
- grpc_core::ChannelzRegistry::Init();
+ grpc_core::channelz::ChannelzRegistry::Init();
grpc_security_pre_init();
grpc_core::ExecCtx::GlobalInit();
grpc_iomgr_init();
@@ -176,7 +176,7 @@
grpc_mdctx_global_shutdown();
grpc_handshaker_factory_registry_shutdown();
grpc_slice_intern_shutdown();
- grpc_core::ChannelzRegistry::Shutdown();
+ grpc_core::channelz::ChannelzRegistry::Shutdown();
grpc_stats_shutdown();
grpc_core::Fork::GlobalShutdown();
}
diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc
index bbddee3..99d9a48 100644
--- a/test/core/channel/channel_trace_test.cc
+++ b/test/core/channel/channel_trace_test.cc
@@ -34,8 +34,6 @@
#include "test/core/util/test_config.h"
#include "test/cpp/util/channel_trace_proto_helper.h"
-// remove me
-#include <grpc/support/string_util.h>
#include <stdlib.h>
#include <string.h>
@@ -88,7 +86,7 @@
void ValidateChannelTrace(ChannelTrace* tracer,
size_t expected_num_event_logged, size_t max_nodes) {
if (!max_nodes) return;
- grpc_json* json = tracer->RenderJSON();
+ grpc_json* json = tracer->RenderJson();
EXPECT_NE(json, nullptr);
char* json_str = grpc_json_dump_to_string(json, 0);
grpc_json_destroy(json);
@@ -157,7 +155,7 @@
AddSimpleTrace(&tracer);
ChannelFixture channel1(GetParam());
RefCountedPtr<ChannelNode> sc1 =
- MakeRefCounted<ChannelNode>(channel1.channel(), GetParam());
+ MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true);
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
@@ -175,7 +173,7 @@
ValidateChannelTrace(&tracer, 5, GetParam());
ChannelFixture channel2(GetParam());
RefCountedPtr<ChannelNode> sc2 =
- MakeRefCounted<ChannelNode>(channel2.channel(), GetParam());
+ MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true);
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("LB channel two created"), sc2);
@@ -204,7 +202,7 @@
ValidateChannelTrace(&tracer, 2, GetParam());
ChannelFixture channel1(GetParam());
RefCountedPtr<ChannelNode> sc1 =
- MakeRefCounted<ChannelNode>(channel1.channel(), GetParam());
+ MakeRefCounted<ChannelNode>(channel1.channel(), GetParam(), true);
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
@@ -212,7 +210,7 @@
AddSimpleTrace(sc1->trace());
ChannelFixture channel2(GetParam());
RefCountedPtr<ChannelNode> conn1 =
- MakeRefCounted<ChannelNode>(channel2.channel(), GetParam());
+ MakeRefCounted<ChannelNode>(channel2.channel(), GetParam(), true);
// nesting one level deeper.
sc1->trace()->AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
@@ -225,7 +223,7 @@
ValidateChannelTrace(conn1->trace(), 1, GetParam());
ChannelFixture channel3(GetParam());
RefCountedPtr<ChannelNode> sc2 =
- MakeRefCounted<ChannelNode>(channel3.channel(), GetParam());
+ MakeRefCounted<ChannelNode>(channel3.channel(), GetParam(), true);
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel two created"), sc2);
diff --git a/test/core/channel/channelz_registry_test.cc b/test/core/channel/channelz_registry_test.cc
index 24e5093..990cd3d 100644
--- a/test/core/channel/channelz_registry_test.cc
+++ b/test/core/channel/channelz_registry_test.cc
@@ -19,17 +19,20 @@
#include <stdlib.h>
#include <string.h>
+#include <grpc/grpc.h>
#include <gtest/gtest.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
+#include "src/core/lib/surface/channel.h"
#include "test/core/util/test_config.h"
@@ -37,27 +40,26 @@
#include <string.h>
namespace grpc_core {
+namespace channelz {
namespace testing {
-// Tests basic ChannelTrace functionality like construction, adding trace, and
-// lookups by uuid.
TEST(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
- int object_to_register;
- intptr_t uuid = ChannelzRegistry::Register(&object_to_register);
+ ChannelNode* channelz_channel = nullptr;
+ intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
EXPECT_GT(uuid, 0) << "First uuid chose must be greater than zero. Zero if "
"reserved according to "
"https://github.com/grpc/proposal/blob/master/"
"A14-channelz.md";
- ChannelzRegistry::Unregister(uuid);
+ ChannelzRegistry::UnregisterChannelNode(uuid);
}
TEST(ChannelzRegistryTest, UuidsAreIncreasing) {
- int object_to_register;
+ ChannelNode* channelz_channel = nullptr;
std::vector<intptr_t> uuids;
uuids.reserve(10);
for (int i = 0; i < 10; ++i) {
// reregister the same object. It's ok since we are just testing uuids
- uuids.push_back(ChannelzRegistry::Register(&object_to_register));
+ uuids.push_back(ChannelzRegistry::RegisterChannelNode(channelz_channel));
}
for (size_t i = 1; i < uuids.size(); ++i) {
EXPECT_LT(uuids[i - 1], uuids[i]) << "Uuids must always be increasing";
@@ -65,60 +67,33 @@
}
TEST(ChannelzRegistryTest, RegisterGetTest) {
- int object_to_register = 42;
- intptr_t uuid = ChannelzRegistry::Register(&object_to_register);
- int* retrieved = ChannelzRegistry::Get<int>(uuid);
- EXPECT_EQ(&object_to_register, retrieved);
-}
-
-TEST(ChannelzRegistryTest, MultipleTypeTest) {
- int int_to_register = 42;
- intptr_t int_uuid = ChannelzRegistry::Register(&int_to_register);
- std::string str_to_register = "hello world";
- intptr_t str_uuid = ChannelzRegistry::Register(&str_to_register);
- int* retrieved_int = ChannelzRegistry::Get<int>(int_uuid);
- std::string* retrieved_str = ChannelzRegistry::Get<std::string>(str_uuid);
- EXPECT_EQ(&int_to_register, retrieved_int);
- EXPECT_EQ(&str_to_register, retrieved_str);
+ ChannelNode* channelz_channel = nullptr;
+ intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
+ ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
+ EXPECT_EQ(channelz_channel, retrieved);
}
TEST(ChannelzRegistryTest, RegisterManyItems) {
- int object_to_register = 42;
+ ChannelNode* channelz_channel = nullptr;
for (int i = 0; i < 100; i++) {
- intptr_t uuid = ChannelzRegistry::Register(&object_to_register);
- int* retrieved = ChannelzRegistry::Get<int>(uuid);
- EXPECT_EQ(&object_to_register, retrieved);
+ intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
+ ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
+ EXPECT_EQ(channelz_channel, retrieved);
}
}
-namespace {
-class Foo {
- public:
- int bar;
-};
-} // namespace
-
-TEST(ChannelzRegistryTest, CustomObjectTest) {
- Foo* foo = New<Foo>();
- foo->bar = 1024;
- intptr_t uuid = ChannelzRegistry::Register(foo);
- Foo* retrieved = ChannelzRegistry::Get<Foo>(uuid);
- EXPECT_EQ(foo, retrieved);
- Delete(foo);
-}
-
TEST(ChannelzRegistryTest, NullIfNotPresentTest) {
- int object_to_register = 42;
- intptr_t uuid = ChannelzRegistry::Register(&object_to_register);
+ ChannelNode* channelz_channel = nullptr;
+ intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
// try to pull out a uuid that does not exist.
- int* nonexistant = ChannelzRegistry::Get<int>(uuid + 1);
+ ChannelNode* nonexistant = ChannelzRegistry::GetChannelNode(uuid + 1);
EXPECT_EQ(nonexistant, nullptr);
- int* retrieved = ChannelzRegistry::Get<int>(uuid);
- EXPECT_EQ(object_to_register, *retrieved);
- EXPECT_EQ(&object_to_register, retrieved);
+ ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
+ EXPECT_EQ(channelz_channel, retrieved);
}
} // namespace testing
+} // namespace channelz
} // namespace grpc_core
int main(int argc, char** argv) {
diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc
index 058eea9..d12f529 100644
--- a/test/core/channel/channelz_test.cc
+++ b/test/core/channel/channelz_test.cc
@@ -67,17 +67,45 @@
return nullptr;
}
+void ValidateJsonArraySize(grpc_json* json, const char* key,
+ size_t expected_size) {
+ grpc_json* arr = GetJsonChild(json, key);
+ if (expected_size == 0) {
+ ASSERT_EQ(arr, nullptr);
+ return;
+ }
+ ASSERT_NE(arr, nullptr);
+ ASSERT_EQ(arr->type, GRPC_JSON_ARRAY);
+ size_t count = 0;
+ for (grpc_json* child = arr->child; child != nullptr; child = child->next) {
+ ++count;
+ }
+ EXPECT_EQ(count, expected_size);
+}
+
+void ValidateGetTopChannels(size_t expected_channels) {
+ char* json_str = ChannelzRegistry::GetTopChannels(0);
+ grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str);
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ // This check will naturally have to change when we support pagination.
+ // tracked: https://github.com/grpc/grpc/issues/16019.
+ ValidateJsonArraySize(parsed_json, "channel", expected_channels);
+ grpc_json* end = GetJsonChild(parsed_json, "end");
+ ASSERT_NE(end, nullptr);
+ EXPECT_EQ(end->type, GRPC_JSON_TRUE);
+ grpc_json_destroy(parsed_json);
+ gpr_free(json_str);
+}
+
class ChannelFixture {
public:
- ChannelFixture(int max_trace_nodes) {
+ ChannelFixture(int max_trace_nodes = 0) {
grpc_arg client_a[2];
- client_a[0].type = GRPC_ARG_INTEGER;
- client_a[0].key =
- const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
- client_a[0].value.integer = max_trace_nodes;
- client_a[1].type = GRPC_ARG_INTEGER;
- client_a[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
- client_a[1].value.integer = true;
+ client_a[0] = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE),
+ max_trace_nodes);
+ client_a[1] = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
channel_ =
grpc_insecure_channel_create("fake_target", &client_args, nullptr);
@@ -99,6 +127,10 @@
void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) {
grpc_json* gotten_json = GetJsonChild(json, key);
+ if (expect == 0) {
+ ASSERT_EQ(gotten_json, nullptr);
+ return;
+ }
ASSERT_NE(gotten_json, nullptr);
int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0);
EXPECT_EQ(gotten_number, expect);
@@ -115,7 +147,7 @@
}
void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) {
- char* json_str = channel->RenderJSON();
+ char* json_str = channel->RenderJsonString();
grpc::testing::ValidateChannelProtoJsonTranslation(json_str);
ValidateCounters(json_str, args);
gpr_free(json_str);
@@ -141,9 +173,7 @@
ChannelFixture channel(GetParam());
ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(channel.channel());
- char* json_str = channelz_channel->RenderJSON();
- ValidateCounters(json_str, {0, 0, 0});
- gpr_free(json_str);
+ ValidateChannel(channelz_channel, {0, 0, 0});
}
TEST(ChannelzChannelTest, ChannelzDisabled) {
@@ -199,6 +229,42 @@
EXPECT_NE(millis1, millis4);
}
+TEST(ChannelzGetTopChannelsTest, BasicTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channel;
+ ValidateGetTopChannels(1);
+}
+
+TEST(ChannelzGetTopChannelsTest, NoChannelsTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ValidateGetTopChannels(0);
+}
+
+TEST(ChannelzGetTopChannelsTest, ManyChannelsTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channels[10];
+ (void)channels; // suppress unused variable error
+ ValidateGetTopChannels(10);
+}
+
+TEST(ChannelzGetTopChannelsTest, InternalChannelTest) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channels[10];
+ (void)channels; // suppress unused variable error
+ // create an internal channel
+ grpc_arg client_a[2];
+ client_a[0] = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true);
+ client_a[1] = grpc_channel_arg_integer_create(
+ const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ), true);
+ grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
+ grpc_channel* internal_channel =
+ grpc_insecure_channel_create("fake_target", &client_args, nullptr);
+ // The internal channel should not be returned from the request
+ ValidateGetTopChannels(10);
+ grpc_channel_destroy(internal_channel);
+}
+
INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
::testing::Values(0, 1, 2, 6, 10, 15));
diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc
index eb05211..533703a 100644
--- a/test/core/end2end/tests/channelz.cc
+++ b/test/core/end2end/tests/channelz.cc
@@ -209,27 +209,27 @@
grpc_channel_get_channelz_node(f.client);
GPR_ASSERT(channelz_channel != nullptr);
- char* json = channelz_channel->RenderJSON();
+ char* json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
- GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\""));
- GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\""));
- GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\""));
+ // nothing is present yet
+ GPR_ASSERT(nullptr == strstr(json, "\"callsStarted\""));
+ GPR_ASSERT(nullptr == strstr(json, "\"callsFailed\""));
+ GPR_ASSERT(nullptr == strstr(json, "\"callsSucceeded\""));
gpr_free(json);
// one successful request
run_one_request(config, f, true);
- json = channelz_channel->RenderJSON();
+ json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\""));
- GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\""));
GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\""));
gpr_free(json);
// one failed request
run_one_request(config, f, false);
- json = channelz_channel->RenderJSON();
+ json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
gpr_log(GPR_INFO, "%s", json);
GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\""));
@@ -264,7 +264,7 @@
grpc_channel_get_channelz_node(f.client);
GPR_ASSERT(channelz_channel != nullptr);
- char* json = channelz_channel->RenderJSON();
+ char* json = channelz_channel->RenderJsonString();
GPR_ASSERT(json != nullptr);
gpr_log(GPR_INFO, "%s", json);
GPR_ASSERT(nullptr != strstr(json, "\"trace\""));
diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc
index ee31078..137f278 100644
--- a/test/cpp/util/channel_trace_proto_helper.cc
+++ b/test/cpp/util/channel_trace_proto_helper.cc
@@ -64,13 +64,17 @@
} // namespace
-void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) {
- VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(
- tracer_json_c_str);
+void ValidateChannelTraceProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(json_c_str);
}
-void ValidateChannelProtoJsonTranslation(char* channel_json_c_str) {
- VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(channel_json_c_str);
+void ValidateChannelProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(json_c_str);
+}
+
+void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::GetTopChannelsResponse>(
+ json_c_str);
}
} // namespace testing
diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h
index d1a3603..74c15f0 100644
--- a/test/cpp/util/channel_trace_proto_helper.h
+++ b/test/cpp/util/channel_trace_proto_helper.h
@@ -22,8 +22,9 @@
namespace grpc {
namespace testing {
-void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str);
-void ValidateChannelProtoJsonTranslation(char* channel_json_c_str);
+void ValidateChannelTraceProtoJsonTranslation(char* json_c_str);
+void ValidateChannelProtoJsonTranslation(char* json_c_str);
+void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str);
} // namespace testing
} // namespace grpc