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 bc9bbe59219..9a9e3b7df90 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.cc +++ b/src/core/ext/filters/client_channel/client_channel_channelz.cc @@ -47,64 +47,48 @@ void SubchannelNode::SetChildSocket(RefCountedPtr socket) { child_socket_ = std::move(socket); } -void SubchannelNode::PopulateConnectivityState(grpc_json* json) { +Json SubchannelNode::RenderJson() { + // Create and fill the data child. grpc_connectivity_state state = connectivity_state_.Load(MemoryOrder::RELAXED); - json = grpc_json_create_child(nullptr, json, "state", nullptr, - GRPC_JSON_OBJECT, false); - grpc_json_create_child(nullptr, json, "state", ConnectivityStateName(state), - GRPC_JSON_STRING, false); -} + Json::Object data = { + {"state", + Json::Object{ + {"state", ConnectivityStateName(state)}, + }}, + {"target", target_}, + }; -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_.empty()); - grpc_json_create_child(nullptr, json, "target", target_.c_str(), - 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); + // Fill in the channel trace if applicable + Json trace_json = trace_.RenderJson(); + if (trace_json.type() != Json::Type::JSON_NULL) { + data["trace"] = std::move(trace_json); } - // ask CallCountingHelper to populate trace and call count data. - call_counter_.PopulateCallCounts(json); - json = top_level_json; - // populate the child socket. + // Ask CallCountingHelper to populate call count data. + call_counter_.PopulateCallCounts(&data); + // Construct top-level object. + Json::Object object{ + {"ref", + Json::Object{ + {"subchannelId", std::to_string(uuid())}, + }}, + {"data", std::move(data)}, + }; + // Populate the child socket. RefCountedPtr child_socket; { MutexLock lock(&socket_mu_); child_socket = child_socket_; } if (child_socket != nullptr && child_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* sibling_iterator = grpc_json_add_number_string_child( - json_iterator, nullptr, "socketId", child_socket->uuid()); - grpc_json_create_child(sibling_iterator, json_iterator, "name", - child_socket->name().c_str(), GRPC_JSON_STRING, - false); + object["socketRef"] = Json::Array{ + Json::Object{ + {"socketId", std::to_string(child_socket->uuid())}, + {"name", child_socket->name()}, + }, + }; } - return top_level_json; + return object; } } // 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 270aa543dfc..c29569a939b 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.h +++ b/src/core/ext/filters/client_channel/client_channel_channelz.h @@ -47,7 +47,7 @@ class SubchannelNode : public BaseNode { // subchannel unrefs the transport. void SetChildSocket(RefCountedPtr socket); - grpc_json* RenderJson() override; + Json RenderJson() override; // proxy methods to composed classes. void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { @@ -64,8 +64,6 @@ class SubchannelNode : public BaseNode { void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } private: - void PopulateConnectivityState(grpc_json* json); - Atomic connectivity_state_{GRPC_CHANNEL_IDLE}; Mutex socket_mu_; RefCountedPtr child_socket_; diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index b6fcd0f87bf..a26533f7f9f 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -144,59 +144,50 @@ const char* severity_string(ChannelTrace::Severity severity) { } // anonymous namespace -void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { - grpc_json* json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, "description", - grpc_slice_to_c_string(data_), - GRPC_JSON_STRING, true); - json_iterator = grpc_json_create_child(json_iterator, json, "severity", - severity_string(severity_), - GRPC_JSON_STRING, false); - json_iterator = grpc_json_create_child(json_iterator, json, "timestamp", - gpr_format_timespec(timestamp_), - GRPC_JSON_STRING, true); +Json ChannelTrace::TraceEvent::RenderTraceEvent() const { + char* description = grpc_slice_to_c_string(data_); + char* ts_str = gpr_format_timespec(timestamp_); + Json::Object object = { + {"description", description}, + {"severity", severity_string(severity_)}, + {"timestamp", ts_str}, + }; + gpr_free(description); + gpr_free(ts_str); if (referenced_entity_ != nullptr) { const bool is_channel = (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel || referenced_entity_->type() == BaseNode::EntityType::kInternalChannel); - char* uuid_str; - gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_entity_->uuid()); - grpc_json* child_ref = grpc_json_create_child( - json_iterator, json, is_channel ? "channelRef" : "subchannelRef", - nullptr, GRPC_JSON_OBJECT, false); - json_iterator = grpc_json_create_child( - nullptr, child_ref, is_channel ? "channelId" : "subchannelId", uuid_str, - GRPC_JSON_STRING, true); - json_iterator = child_ref; + object[is_channel ? "channelRef" : "subchannelRef"] = Json::Object{ + {(is_channel ? "channelId" : "subchannelId"), + std::to_string(referenced_entity_->uuid())}, + }; } + return object; } -grpc_json* ChannelTrace::RenderJson() const { - if (max_event_memory_ == 0) - return nullptr; // tracing is disabled if max_event_memory_ == 0 - grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json_iterator = nullptr; +Json ChannelTrace::RenderJson() const { + // Tracing is disabled if max_event_memory_ == 0. + if (max_event_memory_ == 0) { + return Json(); // JSON null + } + char* ts_str = gpr_format_timespec(time_created_); + Json::Object object = { + {"creationTimestamp", ts_str}, + }; + gpr_free(ts_str); if (num_events_logged_ > 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "numEventsLogged", num_events_logged_); + object["numEventsLogged"] = std::to_string(num_events_logged_); } - json_iterator = grpc_json_create_child( - json_iterator, json, "creationTimestamp", - gpr_format_timespec(time_created_), GRPC_JSON_STRING, true); - // only add in the event list if it is non-empty. + // Only add in the event list if it is non-empty. if (head_trace_ != nullptr) { - grpc_json* events = grpc_json_create_child(json_iterator, json, "events", - nullptr, GRPC_JSON_ARRAY, false); - json_iterator = nullptr; - TraceEvent* it = head_trace_; - while (it != nullptr) { - json_iterator = grpc_json_create_child(json_iterator, events, nullptr, - nullptr, GRPC_JSON_OBJECT, false); - it->RenderTraceEvent(json_iterator); - it = it->next(); + Json::Array array; + for (TraceEvent* it = head_trace_; it != nullptr; it = it->next()) { + array.emplace_back(it->RenderTraceEvent()); } + object["events"] = std::move(array); } - return json; + return object; } } // namespace channelz diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index f088185a423..c26e3016da7 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -75,9 +75,9 @@ class ChannelTrace { void AddTraceEventWithReference(Severity severity, const grpc_slice& data, RefCountedPtr referenced_entity); - // Creates and returns the raw grpc_json object, so a parent channelz + // Creates and returns the raw Json object, so a parent channelz // object may incorporate the json before rendering. - grpc_json* RenderJson() const; + Json RenderJson() const; private: friend size_t testing::GetSizeofTraceEvent(void); @@ -98,7 +98,7 @@ class ChannelTrace { // Renders the data inside of this TraceEvent into a json object. This is // used by the ChannelTrace, when it is rendering itself. - void RenderTraceEvent(grpc_json* json) const; + Json RenderTraceEvent() const; // set and get for the next_ pointer. TraceEvent* next() const { return next_; } diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index d66d05cf1b7..ff6b7a71789 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -94,12 +94,9 @@ BaseNode::BaseNode(EntityType type, std::string name) BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); } -char* BaseNode::RenderJsonString() { - grpc_json* json = RenderJson(); - GPR_ASSERT(json != nullptr); - char* json_str = grpc_json_dump_to_string(json, 0); - grpc_json_destroy(json); - return json_str; +std::string BaseNode::RenderJsonString() { + Json json = RenderJson(); + return json.Dump(); } // @@ -151,29 +148,23 @@ void CallCountingHelper::CollectData(CounterData* out) { } } -void CallCountingHelper::PopulateCallCounts(grpc_json* json) { - grpc_json* json_iterator = nullptr; +void CallCountingHelper::PopulateCallCounts(Json::Object* object) { CounterData data; CollectData(&data); if (data.calls_started != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsStarted", data.calls_started); + (*object)["callsStarted"] = std::to_string(data.calls_started); + gpr_timespec ts = gpr_convert_clock_type( + gpr_cycle_counter_to_time(data.last_call_started_cycle), + GPR_CLOCK_REALTIME); + char* ts_str = gpr_format_timespec(ts); + (*object)["lastCallStartedTimestamp"] = ts_str; + gpr_free(ts_str); } if (data.calls_succeeded != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsSucceeded", data.calls_succeeded); + (*object)["callsSucceeded"] = std::to_string(data.calls_succeeded); } if (data.calls_failed) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "callsFailed", data.calls_failed); - } - if (data.calls_started != 0) { - gpr_timespec ts = gpr_convert_clock_type( - gpr_cycle_counter_to_time(data.last_call_started_cycle), - GPR_CLOCK_REALTIME); - json_iterator = - grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp", - gpr_format_timespec(ts), GRPC_JSON_STRING, true); + (*object)["callsFailed"] = std::to_string(data.calls_failed); } } @@ -207,82 +198,60 @@ const char* ChannelNode::GetChannelConnectivityStateChangeString( GPR_UNREACHABLE_CODE(return "UNKNOWN"); } -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; - grpc_json* json_iterator = nullptr; - // create and fill the ref child - 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, - "channelId", 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; - // connectivity state +Json ChannelNode::RenderJson() { + Json::Object data = { + {"target", target_}, + }; + // Connectivity state. // If low-order bit is on, then the field is set. int state_field = connectivity_state_.Load(MemoryOrder::RELAXED); if ((state_field & 1) != 0) { grpc_connectivity_state state = static_cast(state_field >> 1); - json = grpc_json_create_child(nullptr, json, "state", nullptr, - GRPC_JSON_OBJECT, false); - grpc_json_create_child(nullptr, json, "state", ConnectivityStateName(state), - GRPC_JSON_STRING, false); - json = data; + data["state"] = Json::Object{ + {"state", ConnectivityStateName(state)}, + }; } - // populate the target. - GPR_ASSERT(!target_.empty()); - grpc_json_create_child(nullptr, json, "target", target_.c_str(), - 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); + // Fill in the channel trace if applicable. + Json trace_json = trace_.RenderJson(); + if (trace_json.type() != Json::Type::JSON_NULL) { + data["trace"] = std::move(trace_json); } - // ask CallCountingHelper to populate trace and call count data. - call_counter_.PopulateCallCounts(json); - json = top_level_json; - // template method. Child classes may override this to add their specific + // Ask CallCountingHelper to populate call count data. + call_counter_.PopulateCallCounts(&data); + // Construct outer object. + Json::Object json = { + {"ref", + Json::Object{ + {"channelId", std::to_string(uuid())}, + }}, + {"data", std::move(data)}, + }; + // Template method. Child classes may override this to add their specific // functionality. - PopulateChildRefs(json); - return top_level_json; + PopulateChildRefs(&json); + return json; } -void ChannelNode::PopulateChildRefs(grpc_json* json) { +void ChannelNode::PopulateChildRefs(Json::Object* json) { MutexLock lock(&child_mu_); - grpc_json* json_iterator = nullptr; if (!child_subchannels_.empty()) { - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false); + Json::Array array; for (const auto& p : child_subchannels_) { - 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", - p.first); + array.emplace_back(Json::Object{ + {"subchannelId", std::to_string(p.first)}, + }); } + (*json)["subchannelRef"] = std::move(array); } if (!child_channels_.empty()) { - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false); - json_iterator = nullptr; + Json::Array array; for (const auto& p : child_channels_) { - 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", - p.first); + array.emplace_back(Json::Object{ + {"channelId", std::to_string(p.first)}, + }); } + (*json)["channelRef"] = std::move(array); } } @@ -341,87 +310,66 @@ void ServerNode::RemoveChildListenSocket(intptr_t child_uuid) { child_listen_sockets_.erase(child_uuid); } -char* ServerNode::RenderServerSockets(intptr_t start_socket_id, - intptr_t max_results) { +std::string ServerNode::RenderServerSockets(intptr_t start_socket_id, + intptr_t max_results) { // If user does not set max_results, we choose 500. size_t pagination_limit = max_results == 0 ? 500 : max_results; - grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json = top_level_json; - grpc_json* json_iterator = nullptr; - MutexLock lock(&child_mu_); - size_t sockets_rendered = 0; - if (!child_sockets_.empty()) { - // Create list of socket refs - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false); - const size_t limit = GPR_MIN(child_sockets_.size(), pagination_limit); - for (auto it = child_sockets_.lower_bound(start_socket_id); - it != child_sockets_.end() && sockets_rendered < limit; - ++it, ++sockets_rendered) { - grpc_json* socket_ref_json = grpc_json_create_child( - nullptr, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false); - json_iterator = grpc_json_add_number_string_child( - socket_ref_json, nullptr, "socketId", it->first); - grpc_json_create_child(json_iterator, socket_ref_json, "name", - it->second->name().c_str(), GRPC_JSON_STRING, - false); + Json::Object object; + { + MutexLock lock(&child_mu_); + size_t sockets_rendered = 0; + if (!child_sockets_.empty()) { + // Create list of socket refs. + Json::Array array; + const size_t limit = GPR_MIN(child_sockets_.size(), pagination_limit); + for (auto it = child_sockets_.lower_bound(start_socket_id); + it != child_sockets_.end() && sockets_rendered < limit; + ++it, ++sockets_rendered) { + array.emplace_back(Json::Object{ + {"socketId", std::to_string(it->first)}, + {"name", it->second->name()}, + }); + } + object["socketRef"] = std::move(array); } + if (sockets_rendered == child_sockets_.size()) object["end"] = true; } - if (sockets_rendered == child_sockets_.size()) { - 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; + Json json = std::move(object); + return json.Dump(); } -grpc_json* ServerNode::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; - grpc_json* json_iterator = nullptr; - // create and fill the ref child - 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, - "serverId", 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; - // 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); +Json ServerNode::RenderJson() { + Json::Object data; + // Fill in the channel trace if applicable. + Json trace_json = trace_.RenderJson(); + if (trace_json.type() != Json::Type::JSON_NULL) { + data["trace"] = std::move(trace_json); } - // ask CallCountingHelper to populate trace and call count data. - call_counter_.PopulateCallCounts(json); - json = top_level_json; - // Render listen sockets - MutexLock lock(&child_mu_); - if (!child_listen_sockets_.empty()) { - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "listenSocket", nullptr, GRPC_JSON_ARRAY, false); - for (const auto& it : child_listen_sockets_) { - json_iterator = - grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, - GRPC_JSON_OBJECT, false); - grpc_json* sibling_iterator = grpc_json_add_number_string_child( - json_iterator, nullptr, "socketId", it.first); - grpc_json_create_child(sibling_iterator, json_iterator, "name", - it.second->name().c_str(), GRPC_JSON_STRING, - false); + // Ask CallCountingHelper to populate call count data. + call_counter_.PopulateCallCounts(&data); + // Construct top-level object. + Json::Object object = { + {"ref", + Json::Object{ + {"serverId", std::to_string(uuid())}, + }}, + {"data", std::move(data)}, + }; + // Render listen sockets. + { + MutexLock lock(&child_mu_); + if (!child_listen_sockets_.empty()) { + Json::Array array; + for (const auto& it : child_listen_sockets_) { + array.emplace_back(Json::Object{ + {"socketId", std::to_string(it.first)}, + {"name", it.second->name()}, + }); + } + object["listenSocket"] = std::move(array); } } - return top_level_json; + return object; } // @@ -430,14 +378,10 @@ grpc_json* ServerNode::RenderJson() { namespace { -void PopulateSocketAddressJson(grpc_json* json, const char* name, +void PopulateSocketAddressJson(Json::Object* json, const char* name, const char* addr_str) { if (addr_str == nullptr) return; - grpc_json* json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr, - GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; + Json::Object data; grpc_uri* uri = grpc_uri_parse(addr_str, true); if ((uri != nullptr) && ((strcmp(uri->scheme, "ipv4") == 0) || (strcmp(uri->scheme, "ipv6") == 0))) { @@ -452,31 +396,22 @@ void PopulateSocketAddressJson(grpc_json* json, const char* name, } char* b64_host = grpc_base64_encode(host.get(), strlen(host.get()), false, false); - json_iterator = grpc_json_create_child(json_iterator, json, "tcpip_address", - nullptr, GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = grpc_json_add_number_string_child(json, json_iterator, - "port", port_num); - json_iterator = grpc_json_create_child(json_iterator, json, "ip_address", - b64_host, GRPC_JSON_STRING, true); + data["tcpip_address"] = Json::Object{ + {"port", port_num}, + {"ip_address", b64_host}, + }; + gpr_free(b64_host); } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) { - json_iterator = grpc_json_create_child(json_iterator, json, "uds_address", - nullptr, GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = - grpc_json_create_child(json_iterator, json, "filename", - gpr_strdup(uri->path), GRPC_JSON_STRING, true); + data["uds_address"] = Json::Object{ + {"filename", uri->path}, + }; } else { - json_iterator = grpc_json_create_child(json_iterator, json, "other_address", - nullptr, GRPC_JSON_OBJECT, false); - json = json_iterator; - json_iterator = nullptr; - json_iterator = grpc_json_create_child(json_iterator, json, "name", - addr_str, GRPC_JSON_STRING, false); + data["other_address"] = Json::Object{ + {"name", addr_str}, + }; } grpc_uri_destroy(uri); + (*json)[name] = std::move(data); } } // namespace @@ -509,45 +444,22 @@ void SocketNode::RecordMessageReceived() { MemoryOrder::RELAXED); } -grpc_json* SocketNode::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; - grpc_json* json_iterator = nullptr; - // create and fill the ref child - 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, - "socketId", uuid()); - json_iterator = grpc_json_create_child( - json_iterator, json, "name", name().c_str(), GRPC_JSON_STRING, false); - json = top_level_json; - PopulateSocketAddressJson(json, "remote", remote_.c_str()); - PopulateSocketAddressJson(json, "local", local_.c_str()); - // 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; +Json SocketNode::RenderJson() { + // Create and fill the data child. + Json::Object data; gpr_timespec ts; int64_t streams_started = streams_started_.Load(MemoryOrder::RELAXED); if (streams_started != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "streamsStarted", streams_started); + data["streamsStarted"] = std::to_string(streams_started); gpr_cycle_counter last_local_stream_created_cycle = last_local_stream_created_cycle_.Load(MemoryOrder::RELAXED); if (last_local_stream_created_cycle != 0) { ts = gpr_convert_clock_type( gpr_cycle_counter_to_time(last_local_stream_created_cycle), GPR_CLOCK_REALTIME); - json_iterator = grpc_json_create_child( - json_iterator, json, "lastLocalStreamCreatedTimestamp", - gpr_format_timespec(ts), GRPC_JSON_STRING, true); + char* ts_str = gpr_format_timespec(ts); + data["lastLocalStreamCreatedTimestamp"] = ts_str; + gpr_free(ts_str); } gpr_cycle_counter last_remote_stream_created_cycle = last_remote_stream_created_cycle_.Load(MemoryOrder::RELAXED); @@ -555,51 +467,57 @@ grpc_json* SocketNode::RenderJson() { ts = gpr_convert_clock_type( gpr_cycle_counter_to_time(last_remote_stream_created_cycle), GPR_CLOCK_REALTIME); - json_iterator = grpc_json_create_child( - json_iterator, json, "lastRemoteStreamCreatedTimestamp", - gpr_format_timespec(ts), GRPC_JSON_STRING, true); + char* ts_str = gpr_format_timespec(ts); + data["lastRemoteStreamCreatedTimestamp"] = ts_str; + gpr_free(ts_str); } } int64_t streams_succeeded = streams_succeeded_.Load(MemoryOrder::RELAXED); if (streams_succeeded != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "streamsSucceeded", streams_succeeded); + data["streamsSucceeded"] = std::to_string(streams_succeeded); } int64_t streams_failed = streams_failed_.Load(MemoryOrder::RELAXED); - if (streams_failed) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "streamsFailed", streams_failed); + if (streams_failed != 0) { + data["streamsFailed"] = std::to_string(streams_failed); } int64_t messages_sent = messages_sent_.Load(MemoryOrder::RELAXED); if (messages_sent != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "messagesSent", messages_sent); + data["messagesSent"] = std::to_string(messages_sent); ts = gpr_convert_clock_type( gpr_cycle_counter_to_time( last_message_sent_cycle_.Load(MemoryOrder::RELAXED)), GPR_CLOCK_REALTIME); - json_iterator = - grpc_json_create_child(json_iterator, json, "lastMessageSentTimestamp", - gpr_format_timespec(ts), GRPC_JSON_STRING, true); + char* ts_str = gpr_format_timespec(ts); + data["lastMessageSentTimestamp"] = ts_str; + gpr_free(ts_str); } int64_t messages_received = messages_received_.Load(MemoryOrder::RELAXED); if (messages_received != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "messagesReceived", messages_received); + data["messagesReceived"] = std::to_string(messages_received); ts = gpr_convert_clock_type( gpr_cycle_counter_to_time( last_message_received_cycle_.Load(MemoryOrder::RELAXED)), GPR_CLOCK_REALTIME); - json_iterator = grpc_json_create_child( - json_iterator, json, "lastMessageReceivedTimestamp", - gpr_format_timespec(ts), GRPC_JSON_STRING, true); + char* ts_str = gpr_format_timespec(ts); + data["lastMessageReceivedTimestamp"] = ts_str; + gpr_free(ts_str); } int64_t keepalives_sent = keepalives_sent_.Load(MemoryOrder::RELAXED); if (keepalives_sent != 0) { - json_iterator = grpc_json_add_number_string_child( - json, json_iterator, "keepAlivesSent", keepalives_sent); + data["keepAlivesSent"] = std::to_string(keepalives_sent); } - return top_level_json; + // Create and fill the parent object. + Json::Object object = { + {"ref", + Json::Object{ + {"socketId", std::to_string(uuid())}, + {"name", name()}, + }}, + {"data", std::move(data)}, + }; + PopulateSocketAddressJson(&object, "remote", remote_.c_str()); + PopulateSocketAddressJson(&object, "local", local_.c_str()); + return object; } // @@ -610,24 +528,16 @@ ListenSocketNode::ListenSocketNode(std::string local_addr, std::string name) : BaseNode(EntityType::kSocket, std::move(name)), local_addr_(std::move(local_addr)) {} -grpc_json* ListenSocketNode::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; - grpc_json* json_iterator = nullptr; - // create and fill the ref child - 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, - "socketId", uuid()); - json_iterator = grpc_json_create_child( - json_iterator, json, "name", name().c_str(), GRPC_JSON_STRING, false); - json = top_level_json; - PopulateSocketAddressJson(json, "local", local_addr_.c_str()); - - return top_level_json; +Json ListenSocketNode::RenderJson() { + Json::Object object = { + {"ref", + Json::Object{ + {"socketId", std::to_string(uuid())}, + {"name", name()}, + }}, + }; + PopulateSocketAddressJson(&object, "local", local_addr_.c_str()); + return object; } } // namespace channelz diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 3b3639e55b7..11b1c7f1cfa 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -91,11 +91,11 @@ class BaseNode : public RefCounted { virtual ~BaseNode(); // All children must implement this function. - virtual grpc_json* RenderJson() = 0; + virtual Json RenderJson() = 0; // Renders the json and returns allocated string that must be freed by the // caller. - char* RenderJsonString(); + std::string RenderJsonString(); EntityType type() const { return type_; } intptr_t uuid() const { return uuid_; } @@ -124,7 +124,7 @@ class CallCountingHelper { void RecordCallSucceeded(); // Common rendering of the call count data and last_call_started_timestamp. - void PopulateCallCounts(grpc_json* json); + void PopulateCallCounts(Json::Object* json); private: // testing peer friend. @@ -187,7 +187,7 @@ class ChannelNode : public BaseNode { intptr_t parent_uuid() const { return parent_uuid_; } - grpc_json* RenderJson() override; + Json RenderJson() override; // proxy methods to composed classes. void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { @@ -216,7 +216,7 @@ class ChannelNode : public BaseNode { void RemoveChildSubchannel(intptr_t child_uuid); private: - void PopulateChildRefs(grpc_json* json); + void PopulateChildRefs(Json::Object* json); // to allow the channel trace test to access trace_. friend class testing::ChannelNodePeer; @@ -245,9 +245,10 @@ class ServerNode : public BaseNode { ~ServerNode() override; - grpc_json* RenderJson() override; + Json RenderJson() override; - char* RenderServerSockets(intptr_t start_socket_id, intptr_t max_results); + std::string RenderServerSockets(intptr_t start_socket_id, + intptr_t max_results); void AddChildSocket(RefCountedPtr node); @@ -285,7 +286,7 @@ class SocketNode : public BaseNode { SocketNode(std::string local, std::string remote, std::string name); ~SocketNode() override {} - grpc_json* RenderJson() override; + Json RenderJson() override; void RecordStreamStartedFromLocal(); void RecordStreamStartedFromRemote(); @@ -324,7 +325,7 @@ class ListenSocketNode : public BaseNode { ListenSocketNode(std::string local_addr, std::string name); ~ListenSocketNode() override {} - grpc_json* RenderJson() override; + Json RenderJson() override; private: std::string local_addr_; diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc index e0c9c8e67f3..0964ffca2a1 100644 --- a/src/core/lib/channel/channelz_registry.cc +++ b/src/core/lib/channel/channelz_registry.cc @@ -30,6 +30,7 @@ #include #include +#include #include namespace grpc_core { @@ -79,10 +80,8 @@ RefCountedPtr ChannelzRegistry::InternalGet(intptr_t uuid) { return RefCountedPtr(node); } -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; +std::string ChannelzRegistry::InternalGetTopChannels( + intptr_t start_channel_id) { InlinedVector, 10> top_level_channels; RefCountedPtr node_after_pagination_limit; { @@ -106,29 +105,21 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) { } } } + Json::Object object; if (!top_level_channels.empty()) { - // create list of channels - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "channel", nullptr, GRPC_JSON_ARRAY, false); + // Create list of channels. + Json::Array array; 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); + array.emplace_back(top_level_channels[i]->RenderJson()); } + object["channel"] = std::move(array); } - if (node_after_pagination_limit == nullptr) { - 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; + if (node_after_pagination_limit == nullptr) object["end"] = true; + Json json(std::move(object)); + return json.Dump(); } -char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { - grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json = top_level_json; - grpc_json* json_iterator = nullptr; +std::string ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { InlinedVector, 10> servers; RefCountedPtr node_after_pagination_limit; { @@ -152,23 +143,18 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { } } } + Json::Object object; if (!servers.empty()) { - // create list of servers - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "server", nullptr, GRPC_JSON_ARRAY, false); + // Create list of servers. + Json::Array array; for (size_t i = 0; i < servers.size(); ++i) { - grpc_json* server_json = servers[i]->RenderJson(); - json_iterator = - grpc_json_link_child(array_parent, server_json, json_iterator); + array.emplace_back(servers[i]->RenderJson()); } + object["server"] = std::move(array); } - if (node_after_pagination_limit == nullptr) { - 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; + if (node_after_pagination_limit == nullptr) object["end"] = true; + Json json(std::move(object)); + return json.Dump(); } void ChannelzRegistry::InternalLogAllEntities() { @@ -183,9 +169,8 @@ void ChannelzRegistry::InternalLogAllEntities() { } } for (size_t i = 0; i < nodes.size(); ++i) { - char* json = nodes[i]->RenderJsonString(); - gpr_log(GPR_INFO, "%s", json); - gpr_free(json); + std::string json = nodes[i]->RenderJsonString(); + gpr_log(GPR_INFO, "%s", json.c_str()); } } @@ -193,12 +178,15 @@ void ChannelzRegistry::InternalLogAllEntities() { } // namespace grpc_core char* grpc_channelz_get_top_channels(intptr_t start_channel_id) { - return grpc_core::channelz::ChannelzRegistry::GetTopChannels( - start_channel_id); + return gpr_strdup( + grpc_core::channelz::ChannelzRegistry::GetTopChannels(start_channel_id) + .c_str()); } char* grpc_channelz_get_servers(intptr_t start_server_id) { - return grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id); + return gpr_strdup( + grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id) + .c_str()); } char* grpc_channelz_get_server(intptr_t server_id) { @@ -209,14 +197,10 @@ char* grpc_channelz_get_server(intptr_t server_id) { grpc_core::channelz::BaseNode::EntityType::kServer) { return nullptr; } - grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json = top_level_json; - grpc_json* channel_json = server_node->RenderJson(); - channel_json->key = "server"; - grpc_json_link_child(json, channel_json, nullptr); - char* json_str = grpc_json_dump_to_string(top_level_json, 0); - grpc_json_destroy(top_level_json); - return json_str; + grpc_core::Json json = grpc_core::Json::Object{ + {"server", server_node->RenderJson()}, + }; + return gpr_strdup(json.Dump().c_str()); } char* grpc_channelz_get_server_sockets(intptr_t server_id, @@ -229,10 +213,11 @@ char* grpc_channelz_get_server_sockets(intptr_t server_id, return nullptr; } // This cast is ok since we have just checked to make sure base_node is - // actually a server node + // actually a server node. grpc_core::channelz::ServerNode* server_node = static_cast(base_node.get()); - return server_node->RenderServerSockets(start_socket_id, max_results); + return gpr_strdup( + server_node->RenderServerSockets(start_socket_id, max_results).c_str()); } char* grpc_channelz_get_channel(intptr_t channel_id) { @@ -245,14 +230,10 @@ char* grpc_channelz_get_channel(intptr_t channel_id) { grpc_core::channelz::BaseNode::EntityType::kInternalChannel)) { return nullptr; } - grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json = top_level_json; - grpc_json* channel_json = channel_node->RenderJson(); - channel_json->key = "channel"; - grpc_json_link_child(json, channel_json, nullptr); - char* json_str = grpc_json_dump_to_string(top_level_json, 0); - grpc_json_destroy(top_level_json); - return json_str; + grpc_core::Json json = grpc_core::Json::Object{ + {"channel", channel_node->RenderJson()}, + }; + return gpr_strdup(json.Dump().c_str()); } char* grpc_channelz_get_subchannel(intptr_t subchannel_id) { @@ -263,14 +244,10 @@ char* grpc_channelz_get_subchannel(intptr_t subchannel_id) { grpc_core::channelz::BaseNode::EntityType::kSubchannel) { return nullptr; } - grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json = top_level_json; - grpc_json* subchannel_json = subchannel_node->RenderJson(); - subchannel_json->key = "subchannel"; - grpc_json_link_child(json, subchannel_json, nullptr); - char* json_str = grpc_json_dump_to_string(top_level_json, 0); - grpc_json_destroy(top_level_json); - return json_str; + grpc_core::Json json = grpc_core::Json::Object{ + {"subchannel", subchannel_node->RenderJson()}, + }; + return gpr_strdup(json.Dump().c_str()); } char* grpc_channelz_get_socket(intptr_t socket_id) { @@ -281,12 +258,8 @@ char* grpc_channelz_get_socket(intptr_t socket_id) { grpc_core::channelz::BaseNode::EntityType::kSocket) { return nullptr; } - grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); - grpc_json* json = top_level_json; - grpc_json* socket_json = socket_node->RenderJson(); - socket_json->key = "socket"; - grpc_json_link_child(json, socket_json, nullptr); - char* json_str = grpc_json_dump_to_string(top_level_json, 0); - grpc_json_destroy(top_level_json); - return json_str; + grpc_core::Json json = grpc_core::Json::Object{ + {"socket", socket_node->RenderJson()}, + }; + return gpr_strdup(json.Dump().c_str()); } diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h index c60a5554fb9..d777651c12f 100644 --- a/src/core/lib/channel/channelz_registry.h +++ b/src/core/lib/channel/channelz_registry.h @@ -51,13 +51,13 @@ class ChannelzRegistry { // Returns the allocated JSON string that represents the proto // GetTopChannelsResponse as per channelz.proto. - static char* GetTopChannels(intptr_t start_channel_id) { + static std::string GetTopChannels(intptr_t start_channel_id) { return Default()->InternalGetTopChannels(start_channel_id); } // Returns the allocated JSON string that represents the proto // GetServersResponse as per channelz.proto. - static char* GetServers(intptr_t start_server_id) { + static std::string GetServers(intptr_t start_server_id) { return Default()->InternalGetServers(start_server_id); } @@ -80,8 +80,8 @@ class ChannelzRegistry { // returns the void* associated with that uuid. Else returns nullptr. RefCountedPtr InternalGet(intptr_t uuid); - char* InternalGetTopChannels(intptr_t start_channel_id); - char* InternalGetServers(intptr_t start_server_id); + std::string InternalGetTopChannels(intptr_t start_channel_id); + std::string InternalGetServers(intptr_t start_server_id); void InternalLogAllEntities(); diff --git a/src/cpp/server/channelz/channelz_service.cc b/src/cpp/server/channelz/channelz_service.cc index 62852bfab4a..6dcf84bf40d 100644 --- a/src/cpp/server/channelz/channelz_service.cc +++ b/src/cpp/server/channelz/channelz_service.cc @@ -24,6 +24,9 @@ #include namespace grpc { + +namespace { + grpc::protobuf::util::Status ParseJson(const char* json_str, grpc::protobuf::Message* message) { grpc::protobuf::json::JsonParseOptions options; @@ -31,6 +34,8 @@ grpc::protobuf::util::Status ParseJson(const char* json_str, return grpc::protobuf::json::JsonStringToMessage(json_str, message, options); } +} // namespace + Status ChannelzService::GetTopChannels( ServerContext* /*unused*/, const channelz::v1::GetTopChannelsRequest* request, diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index a957dca0f97..4a7af6a881f 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -57,44 +57,28 @@ size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); } namespace { -grpc_json* GetJsonChild(grpc_json* parent, const char* key) { - EXPECT_NE(parent, nullptr); - for (grpc_json* child = parent->child; child != nullptr; - child = child->next) { - if (child->key != nullptr && strcmp(child->key, key) == 0) return child; +void ValidateJsonArraySize(const Json& array, size_t expected) { + if (expected == 0) { + ASSERT_EQ(array.type(), Json::Type::JSON_NULL); + } else { + ASSERT_EQ(array.type(), Json::Type::ARRAY); + EXPECT_EQ(array.array_value().size(), expected); } - return nullptr; } -void ValidateJsonArraySize(grpc_json* json, const char* key, - size_t expected_size) { - grpc_json* arr = GetJsonChild(json, key); - // the events array should not be present if there are no events. - if (expected_size == 0) { - EXPECT_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; - } - ASSERT_EQ(count, expected_size); -} - -void ValidateChannelTraceData(grpc_json* json, +void ValidateChannelTraceData(const Json& json, size_t num_events_logged_expected, size_t actual_num_events_expected) { - ASSERT_NE(json, nullptr); - grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged"); - ASSERT_NE(num_events_logged_json, nullptr); - grpc_json* start_time = GetJsonChild(json, "creationTimestamp"); - ASSERT_NE(start_time, nullptr); + ASSERT_EQ(json.type(), Json::Type::OBJECT); + Json::Object object = json.object_value(); + Json& num_events_logged_json = object["numEventsLogged"]; + ASSERT_EQ(num_events_logged_json.type(), Json::Type::STRING); size_t num_events_logged = - (size_t)strtol(num_events_logged_json->value, nullptr, 0); + (size_t)strtol(num_events_logged_json.string_value().c_str(), nullptr, 0); ASSERT_EQ(num_events_logged, num_events_logged_expected); - ValidateJsonArraySize(json, "events", actual_num_events_expected); + Json& start_time_json = object["creationTimestamp"]; + ASSERT_EQ(start_time_json.type(), Json::Type::STRING); + ValidateJsonArraySize(object["events"], actual_num_events_expected); } void AddSimpleTrace(ChannelTrace* tracer) { @@ -105,15 +89,11 @@ void AddSimpleTrace(ChannelTrace* tracer) { // checks for the existence of all the required members of the tracer. void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged, size_t num_events_expected) { - grpc_json* json = tracer->RenderJson(); - EXPECT_NE(json, nullptr); - char* json_str = grpc_json_dump_to_string(json, 0); - grpc_json_destroy(json); - grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str); - grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateChannelTraceData(parsed_json, num_events_logged, num_events_expected); - grpc_json_destroy(parsed_json); - gpr_free(json_str); + Json json = tracer->RenderJson(); + ASSERT_EQ(json.type(), Json::Type::OBJECT); + std::string json_str = json.Dump(); + grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str.c_str()); + ValidateChannelTraceData(json, num_events_logged, num_events_expected); } void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) { diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 3f42d9fc81a..ebbbc31f6dd 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -61,57 +61,60 @@ class CallCountingHelperPeer { namespace { -grpc_json* GetJsonChild(grpc_json* parent, const char* key) { - EXPECT_NE(parent, nullptr); - for (grpc_json* child = parent->child; child != nullptr; - child = child->next) { - if (child->key != nullptr && strcmp(child->key, key) == 0) return child; +std::vector GetUuidListFromArray(const Json::Array& arr) { + std::vector uuids; + for (const Json& value : arr) { + EXPECT_EQ(value.type(), Json::Type::OBJECT); + if (value.type() != Json::Type::OBJECT) continue; + const Json::Object& object = value.object_value(); + auto it = object.find("ref"); + EXPECT_NE(it, object.end()); + if (it == object.end()) continue; + EXPECT_EQ(it->second.type(), Json::Type::OBJECT); + if (it->second.type() != Json::Type::OBJECT) continue; + const Json::Object& ref_object = it->second.object_value(); + it = ref_object.find("channelId"); + EXPECT_NE(it, ref_object.end()); + if (it != ref_object.end()) { + uuids.push_back(atoi(it->second.string_value().c_str())); + } } - return nullptr; + return uuids; } -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; +void ValidateJsonArraySize(const Json& array, size_t expected) { + if (expected == 0) { + ASSERT_EQ(array.type(), Json::Type::JSON_NULL); + } else { + ASSERT_EQ(array.type(), Json::Type::ARRAY); + EXPECT_EQ(array.array_value().size(), expected); } - EXPECT_EQ(count, expected_size); } -std::vector GetUuidListFromArray(grpc_json* arr) { - EXPECT_EQ(arr->type, GRPC_JSON_ARRAY); - std::vector uuids; - for (grpc_json* child = arr->child; child != nullptr; child = child->next) { - grpc_json* it = GetJsonChild(child, "ref"); - EXPECT_NE(it, nullptr); - it = GetJsonChild(it, "channelId"); - EXPECT_NE(it, nullptr); - uuids.push_back(atoi(it->value)); +void ValidateJsonEnd(const Json& json, bool end) { + auto it = json.object_value().find("end"); + if (end) { + ASSERT_NE(it, json.object_value().end()); + EXPECT_EQ(it->second.type(), Json::Type::JSON_TRUE); + } else { + ASSERT_EQ(it, json.object_value().end()); } - return uuids; } 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); + std::string json_str = ChannelzRegistry::GetTopChannels(0); + grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation( + json_str.c_str()); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); // 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); - // also check that the core API formats this correctly + ValidateJsonArraySize((*parsed_json.mutable_object())["channel"], + expected_channels); + ValidateJsonEnd(parsed_json, true); + // Also check that the core API formats this correctly. char* core_api_json_str = grpc_channelz_get_top_channels(0); grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation( core_api_json_str); @@ -119,18 +122,19 @@ void ValidateGetTopChannels(size_t expected_channels) { } void ValidateGetServers(size_t expected_servers) { - char* json_str = ChannelzRegistry::GetServers(0); - grpc::testing::ValidateGetServersResponseProtoJsonTranslation(json_str); - grpc_json* parsed_json = grpc_json_parse_string(json_str); + std::string json_str = ChannelzRegistry::GetServers(0); + grpc::testing::ValidateGetServersResponseProtoJsonTranslation( + json_str.c_str()); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); // This check will naturally have to change when we support pagination. // tracked: https://github.com/grpc/grpc/issues/16019. - ValidateJsonArraySize(parsed_json, "server", expected_servers); - 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); - // also check that the core API formats this correctly + ValidateJsonArraySize((*parsed_json.mutable_object())["server"], + expected_servers); + ValidateJsonEnd(parsed_json, true); + // Also check that the core API formats this correctly. char* core_api_json_str = grpc_channelz_get_servers(0); grpc::testing::ValidateGetServersResponseProtoJsonTranslation( core_api_json_str); @@ -181,38 +185,46 @@ class ServerFixture { grpc_server* server_; }; -struct validate_channel_data_args { +struct ValidateChannelDataArgs { int64_t calls_started; int64_t calls_failed; int64_t calls_succeeded; }; -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); +void ValidateChildInteger(const Json::Object& object, const std::string& key, + int64_t expected) { + auto it = object.find(key); + if (expected == 0) { + ASSERT_EQ(it, object.end()); return; } - ASSERT_NE(gotten_json, nullptr); - int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0); - EXPECT_EQ(gotten_number, expect); + ASSERT_NE(it, object.end()); + ASSERT_EQ(it->second.type(), Json::Type::STRING); + int64_t gotten_number = + (int64_t)strtol(it->second.string_value().c_str(), nullptr, 0); + EXPECT_EQ(gotten_number, expected); } -void ValidateCounters(char* json_str, validate_channel_data_args args) { - grpc_json* json = grpc_json_parse_string(json_str); - ASSERT_NE(json, nullptr); - grpc_json* data = GetJsonChild(json, "data"); - ValidateChildInteger(data, args.calls_started, "callsStarted"); - ValidateChildInteger(data, args.calls_failed, "callsFailed"); - ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded"); - grpc_json_destroy(json); +void ValidateCounters(const std::string& json_str, + const ValidateChannelDataArgs& args) { + grpc_error* error = GRPC_ERROR_NONE; + Json json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(json.type(), Json::Type::OBJECT); + Json::Object* object = json.mutable_object(); + Json& data = (*object)["data"]; + ASSERT_EQ(data.type(), Json::Type::OBJECT); + ValidateChildInteger(data.object_value(), "callsStarted", args.calls_started); + ValidateChildInteger(data.object_value(), "callsFailed", args.calls_failed); + ValidateChildInteger(data.object_value(), "callsSucceeded", + args.calls_succeeded); } -void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) { - char* json_str = channel->RenderJsonString(); - grpc::testing::ValidateChannelProtoJsonTranslation(json_str); +void ValidateChannel(ChannelNode* channel, + const ValidateChannelDataArgs& args) { + std::string json_str = channel->RenderJsonString(); + grpc::testing::ValidateChannelProtoJsonTranslation(json_str.c_str()); ValidateCounters(json_str, args); - gpr_free(json_str); // also check that the core API formats this the correct way char* core_api_json_str = grpc_channelz_get_channel(channel->uuid()); grpc::testing::ValidateGetChannelResponseProtoJsonTranslation( @@ -220,11 +232,10 @@ void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) { gpr_free(core_api_json_str); } -void ValidateServer(ServerNode* server, validate_channel_data_args args) { - char* json_str = server->RenderJsonString(); - grpc::testing::ValidateServerProtoJsonTranslation(json_str); +void ValidateServer(ServerNode* server, const ValidateChannelDataArgs& args) { + std::string json_str = server->RenderJsonString(); + grpc::testing::ValidateServerProtoJsonTranslation(json_str.c_str()); ValidateCounters(json_str, args); - gpr_free(json_str); // also check that the core API formats this the correct way char* core_api_json_str = grpc_channelz_get_server(server->uuid()); grpc::testing::ValidateGetServerResponseProtoJsonTranslation( @@ -348,28 +359,29 @@ TEST_F(ChannelzRegistryBasedTest, ManyChannelsTest) { TEST_F(ChannelzRegistryBasedTest, GetTopChannelsPagination) { grpc_core::ExecCtx exec_ctx; - // this is over the pagination limit. + // This is over the pagination limit. ChannelFixture channels[150]; (void)channels; // suppress unused variable error - char* json_str = ChannelzRegistry::GetTopChannels(0); - grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str); - grpc_json* parsed_json = grpc_json_parse_string(json_str); + std::string json_str = ChannelzRegistry::GetTopChannels(0); + grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation( + json_str.c_str()); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); // 100 is the pagination limit. - ValidateJsonArraySize(parsed_json, "channel", 100); - grpc_json* end = GetJsonChild(parsed_json, "end"); - EXPECT_EQ(end, nullptr); - grpc_json_destroy(parsed_json); - gpr_free(json_str); - // Now we get the rest + ValidateJsonArraySize((*parsed_json.mutable_object())["channel"], 100); + ValidateJsonEnd(parsed_json, false); + // Now we get the rest. json_str = ChannelzRegistry::GetTopChannels(101); - grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation(json_str); - parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", 50); - 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); + grpc::testing::ValidateGetTopChannelsResponseProtoJsonTranslation( + json_str.c_str()); + error = GRPC_ERROR_NONE; + parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + ValidateJsonArraySize((*parsed_json.mutable_object())["channel"], 50); + ValidateJsonEnd(parsed_json, true); } TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidCheck) { @@ -377,16 +389,17 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidCheck) { grpc_core::ExecCtx exec_ctx; ChannelFixture channels[kNumChannels]; (void)channels; // suppress unused variable error - char* json_str = ChannelzRegistry::GetTopChannels(0); - grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", kNumChannels); - grpc_json* json_channels = GetJsonChild(parsed_json, "channel"); - std::vector uuids = GetUuidListFromArray(json_channels); + std::string json_str = ChannelzRegistry::GetTopChannels(0); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + Json& array = (*parsed_json.mutable_object())["channel"]; + ValidateJsonArraySize(array, kNumChannels); + std::vector uuids = GetUuidListFromArray(array.array_value()); for (int i = 0; i < kNumChannels; ++i) { EXPECT_EQ(i + 1, uuids[i]); } - grpc_json_destroy(parsed_json); - gpr_free(json_str); } TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMiddleUuidCheck) { @@ -395,17 +408,18 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMiddleUuidCheck) { grpc_core::ExecCtx exec_ctx; ChannelFixture channels[kNumChannels]; (void)channels; // suppress unused variable error - // only query for the end of the channels - char* json_str = ChannelzRegistry::GetTopChannels(kMidQuery); - grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", kNumChannels - kMidQuery + 1); - grpc_json* json_channels = GetJsonChild(parsed_json, "channel"); - std::vector uuids = GetUuidListFromArray(json_channels); - for (size_t i = 0; i < uuids.size(); ++i) { + // Only query for the end of the channels. + std::string json_str = ChannelzRegistry::GetTopChannels(kMidQuery); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + Json& array = (*parsed_json.mutable_object())["channel"]; + ValidateJsonArraySize(array, kNumChannels - kMidQuery + 1); + std::vector uuids = GetUuidListFromArray(array.array_value()); + for (int i = 0; i < uuids.size(); ++i) { EXPECT_EQ(static_cast(kMidQuery + i), uuids[i]); } - grpc_json_destroy(parsed_json); - gpr_free(json_str); } TEST_F(ChannelzRegistryBasedTest, GetTopChannelsNoHitUuid) { @@ -416,17 +430,18 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsNoHitUuid) { (void)servers; // suppress unused variable error ChannelFixture channels[10]; // will take uuid[51, 60] (void)channels; // suppress unused variable error - // query in the middle of the server channels - char* json_str = ChannelzRegistry::GetTopChannels(45); - grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", 10); - grpc_json* json_channels = GetJsonChild(parsed_json, "channel"); - std::vector uuids = GetUuidListFromArray(json_channels); - for (size_t i = 0; i < uuids.size(); ++i) { + // Query in the middle of the server channels. + std::string json_str = ChannelzRegistry::GetTopChannels(45); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + Json& array = (*parsed_json.mutable_object())["channel"]; + ValidateJsonArraySize(array, 10); + std::vector uuids = GetUuidListFromArray(array.array_value()); + for (int i = 0; i < uuids.size(); ++i) { EXPECT_EQ(static_cast(51 + i), uuids[i]); } - grpc_json_destroy(parsed_json); - gpr_free(json_str); } TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMoreGaps) { @@ -437,23 +452,25 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsMoreGaps) { { ServerFixture server_with_uuid4; } ChannelFixture channel_with_uuid5; // Current state of list: [1, NULL, 3, NULL, 5] - char* json_str = ChannelzRegistry::GetTopChannels(2); - grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", 2); - grpc_json* json_channels = GetJsonChild(parsed_json, "channel"); - std::vector uuids = GetUuidListFromArray(json_channels); + std::string json_str = ChannelzRegistry::GetTopChannels(2); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + Json array = (*parsed_json.mutable_object())["channel"]; + ValidateJsonArraySize(array, 2); + std::vector uuids = GetUuidListFromArray(array.array_value()); EXPECT_EQ(static_cast(3), uuids[0]); EXPECT_EQ(static_cast(5), uuids[1]); - grpc_json_destroy(parsed_json); - gpr_free(json_str); json_str = ChannelzRegistry::GetTopChannels(4); - parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", 1); - json_channels = GetJsonChild(parsed_json, "channel"); - uuids = GetUuidListFromArray(json_channels); + error = GRPC_ERROR_NONE; + parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + array = (*parsed_json.mutable_object())["channel"]; + ValidateJsonArraySize(array, 1); + uuids = GetUuidListFromArray(array.array_value()); EXPECT_EQ(static_cast(5), uuids[0]); - grpc_json_destroy(parsed_json); - gpr_free(json_str); } TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidAfterCompaction) { @@ -468,17 +485,18 @@ TEST_F(ChannelzRegistryBasedTest, GetTopChannelsUuidAfterCompaction) { even_channels.push_back(grpc_core::MakeUnique()); } } - char* json_str = ChannelzRegistry::GetTopChannels(0); - grpc_json* parsed_json = grpc_json_parse_string(json_str); - ValidateJsonArraySize(parsed_json, "channel", kLoopIterations); - grpc_json* json_channels = GetJsonChild(parsed_json, "channel"); - std::vector uuids = GetUuidListFromArray(json_channels); + std::string json_str = ChannelzRegistry::GetTopChannels(0); + grpc_error* error = GRPC_ERROR_NONE; + Json parsed_json = Json::Parse(json_str, &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), Json::Type::OBJECT); + Json& array = (*parsed_json.mutable_object())["channel"]; + ValidateJsonArraySize(array, kLoopIterations); + std::vector uuids = GetUuidListFromArray(array.array_value()); for (int i = 0; i < kLoopIterations; ++i) { // only the even uuids will still be present. EXPECT_EQ((i + 1) * 2, uuids[i]); } - grpc_json_destroy(parsed_json); - gpr_free(json_str); } TEST_F(ChannelzRegistryBasedTest, InternalChannelTest) { diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 81f97811466..fe50d9a6a5c 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -217,51 +217,42 @@ static void test_channelz(grpc_end2end_test_config config) { grpc_server_get_channelz_node(f.server); GPR_ASSERT(channelz_server != nullptr); - char* json = channelz_channel->RenderJsonString(); - GPR_ASSERT(json != nullptr); + std::string json = channelz_channel->RenderJsonString(); // 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); + GPR_ASSERT(json.find("\"callsStarted\"") == json.npos); + GPR_ASSERT(json.find("\"callsFailed\"") == json.npos); + GPR_ASSERT(json.find("\"callsSucceeded\"") == json.npos); // one successful request run_one_request(config, f, true); json = channelz_channel->RenderJsonString(); - GPR_ASSERT(json != nullptr); - GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); - gpr_free(json); + GPR_ASSERT(json.find("\"callsStarted\":\"1\"") != json.npos); + GPR_ASSERT(json.find("\"callsSucceeded\":\"1\"") != json.npos); // one failed request run_one_request(config, f, false); json = channelz_channel->RenderJsonString(); - GPR_ASSERT(json != nullptr); - GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); + GPR_ASSERT(json.find("\"callsStarted\":\"2\"") != json.npos); + GPR_ASSERT(json.find("\"callsFailed\":\"1\"") != json.npos); + GPR_ASSERT(json.find("\"callsSucceeded\":\"1\"") != json.npos); // channel tracing is not enabled, so these should not be preset. - GPR_ASSERT(nullptr == strstr(json, "\"trace\"")); - GPR_ASSERT(nullptr == strstr(json, "\"description\":\"Channel created\"")); - GPR_ASSERT(nullptr == strstr(json, "\"severity\":\"CT_INFO\"")); - gpr_free(json); + GPR_ASSERT(json.find("\"trace\"") == json.npos); + GPR_ASSERT(json.find("\"description\":\"Channel created\"") == json.npos); + GPR_ASSERT(json.find("\"severity\":\"CT_INFO\"") == json.npos); json = channelz_server->RenderJsonString(); - GPR_ASSERT(json != nullptr); - GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); + GPR_ASSERT(json.find("\"callsStarted\":\"2\"") != json.npos); + GPR_ASSERT(json.find("\"callsFailed\":\"1\"") != json.npos); + GPR_ASSERT(json.find("\"callsSucceeded\":\"1\"") != json.npos); // channel tracing is not enabled, so these should not be preset. - GPR_ASSERT(nullptr == strstr(json, "\"trace\"")); - GPR_ASSERT(nullptr == strstr(json, "\"description\":\"Channel created\"")); - GPR_ASSERT(nullptr == strstr(json, "\"severity\":\"CT_INFO\"")); - gpr_free(json); + GPR_ASSERT(json.find("\"trace\"") == json.npos); + GPR_ASSERT(json.find("\"description\":\"Channel created\"") == json.npos); + GPR_ASSERT(json.find("\"severity\":\"CT_INFO\"") == json.npos); json = channelz_server->RenderServerSockets(0, 100); - GPR_ASSERT(nullptr != strstr(json, "\"end\":true")); - gpr_free(json); + GPR_ASSERT(json.find("\"end\":true") != json.npos); end_test(&f); config.tear_down_data(&f); @@ -289,19 +280,15 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { run_one_request(config, f, true); - char* json = channelz_channel->RenderJsonString(); - GPR_ASSERT(json != nullptr); - GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); - GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Channel created\"")); - GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\"")); - gpr_free(json); + std::string json = channelz_channel->RenderJsonString(); + GPR_ASSERT(json.find("\"trace\"") != json.npos); + GPR_ASSERT(json.find("\"description\":\"Channel created\"") != json.npos); + GPR_ASSERT(json.find("\"severity\":\"CT_INFO\"") != json.npos); json = channelz_server->RenderJsonString(); - GPR_ASSERT(json != nullptr); - GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); - GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Server created\"")); - GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\"")); - gpr_free(json); + GPR_ASSERT(json.find("\"trace\"") != json.npos); + GPR_ASSERT(json.find("\"description\":\"Server created\"") != json.npos); + GPR_ASSERT(json.find("\"severity\":\"CT_INFO\"") != json.npos); end_test(&f); config.tear_down_data(&f); diff --git a/test/core/end2end/tests/retry_streaming.cc b/test/core/end2end/tests/retry_streaming.cc index 94a27faf7b2..e2171379e91 100644 --- a/test/core/end2end/tests/retry_streaming.cc +++ b/test/core/end2end/tests/retry_streaming.cc @@ -396,18 +396,16 @@ static void test_retry_streaming(grpc_end2end_test_config config) { GPR_ASSERT(was_cancelled == 1); GPR_ASSERT(channelz_channel != nullptr); - char* json = channelz_channel->RenderJsonString(); - GPR_ASSERT(json != nullptr); - gpr_log(GPR_INFO, "%s", json); - GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); - GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Channel created\"")); - GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\"")); - GPR_ASSERT(nullptr != strstr(json, "Resolution event")); - GPR_ASSERT(nullptr != strstr(json, "Created new LB policy")); - GPR_ASSERT(nullptr != strstr(json, "Service config changed")); - GPR_ASSERT(nullptr != strstr(json, "Address list became non-empty")); - GPR_ASSERT(nullptr != strstr(json, "Channel state change to CONNECTING")); - gpr_free(json); + std::string json = channelz_channel->RenderJsonString(); + gpr_log(GPR_INFO, "%s", json.c_str()); + GPR_ASSERT(json.find("\"trace\"") != json.npos); + GPR_ASSERT(json.find("\"description\":\"Channel created\"") != json.npos); + GPR_ASSERT(json.find("\"severity\":\"CT_INFO\"") != json.npos); + GPR_ASSERT(json.find("Resolution event") != json.npos); + GPR_ASSERT(json.find("Created new LB policy") != json.npos); + GPR_ASSERT(json.find("Service config changed") != json.npos); + GPR_ASSERT(json.find("Address list became non-empty") != json.npos); + GPR_ASSERT(json.find("Channel state change to CONNECTING") != json.npos); grpc_slice_unref(details); grpc_metadata_array_destroy(&initial_metadata_recv); diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc index 9137eda8e07..301bac45d07 100644 --- a/test/cpp/util/channel_trace_proto_helper.cc +++ b/test/cpp/util/channel_trace_proto_helper.cc @@ -26,6 +26,8 @@ #include #include +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/json/json.h" #include "src/proto/grpc/channelz/channelz.pb.h" namespace grpc { @@ -36,8 +38,7 @@ namespace { // then back to json. This ensures that the json string was correctly formatted // according to https://developers.google.com/protocol-buffers/docs/proto3#json template -void VaidateProtoJsonTranslation(char* json_c_str) { - grpc::string json_str(json_c_str); +void VaidateProtoJsonTranslation(const std::string& json_str) { Message msg; grpc::protobuf::json::JsonParseOptions parse_options; // If the following line is failing, then uncomment the last line of the @@ -55,6 +56,14 @@ void VaidateProtoJsonTranslation(char* json_c_str) { // print_options.always_print_primitive_fields = true; s = grpc::protobuf::json::MessageToJsonString(msg, &proto_json_str); EXPECT_TRUE(s.ok()); + // Parse JSON and re-dump to string, to make sure formatting is the + // same as what would be generated by our JSON library. + grpc_error* error = GRPC_ERROR_NONE; + grpc_core::Json parsed_json = + grpc_core::Json::Parse(proto_json_str.c_str(), &error); + ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); + ASSERT_EQ(parsed_json.type(), grpc_core::Json::Type::OBJECT); + proto_json_str = parsed_json.Dump(); // uncomment these to compare the json strings. // gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str()); // gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str()); @@ -65,38 +74,39 @@ void VaidateProtoJsonTranslation(char* json_c_str) { namespace testing { -void ValidateChannelTraceProtoJsonTranslation(char* json_c_str) { +void ValidateChannelTraceProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation(json_c_str); } -void ValidateChannelProtoJsonTranslation(char* json_c_str) { +void ValidateChannelProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation(json_c_str); } -void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str) { +void ValidateGetTopChannelsResponseProtoJsonTranslation( + const char* json_c_str) { VaidateProtoJsonTranslation( json_c_str); } -void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str) { +void ValidateGetChannelResponseProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation( json_c_str); } -void ValidateGetServerResponseProtoJsonTranslation(char* json_c_str) { +void ValidateGetServerResponseProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation( json_c_str); } -void ValidateSubchannelProtoJsonTranslation(char* json_c_str) { +void ValidateSubchannelProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation(json_c_str); } -void ValidateServerProtoJsonTranslation(char* json_c_str) { +void ValidateServerProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation(json_c_str); } -void ValidateGetServersResponseProtoJsonTranslation(char* json_c_str) { +void ValidateGetServersResponseProtoJsonTranslation(const char* json_c_str) { VaidateProtoJsonTranslation( json_c_str); } diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h index 4f74e02f100..664e899deb6 100644 --- a/test/cpp/util/channel_trace_proto_helper.h +++ b/test/cpp/util/channel_trace_proto_helper.h @@ -22,14 +22,14 @@ namespace grpc { namespace testing { -void ValidateChannelTraceProtoJsonTranslation(char* json_c_str); -void ValidateChannelProtoJsonTranslation(char* json_c_str); -void ValidateGetTopChannelsResponseProtoJsonTranslation(char* json_c_str); -void ValidateGetChannelResponseProtoJsonTranslation(char* json_c_str); -void ValidateGetServerResponseProtoJsonTranslation(char* json_c_str); -void ValidateSubchannelProtoJsonTranslation(char* json_c_str); -void ValidateServerProtoJsonTranslation(char* json_c_str); -void ValidateGetServersResponseProtoJsonTranslation(char* json_c_str); +void ValidateChannelTraceProtoJsonTranslation(const char* json_c_str); +void ValidateChannelProtoJsonTranslation(const char* json_c_str); +void ValidateGetTopChannelsResponseProtoJsonTranslation(const char* json_c_str); +void ValidateGetChannelResponseProtoJsonTranslation(const char* json_c_str); +void ValidateGetServerResponseProtoJsonTranslation(const char* json_c_str); +void ValidateSubchannelProtoJsonTranslation(const char* json_c_str); +void ValidateServerProtoJsonTranslation(const char* json_c_str); +void ValidateGetServersResponseProtoJsonTranslation(const char* json_c_str); } // namespace testing } // namespace grpc