diff options
author | 2018-05-09 11:10:21 -0700 | |
---|---|---|
committer | 2018-06-05 16:59:25 -0700 | |
commit | c3c6e064b33ab8b7a2d3cf5a56171029d0bb1edc (patch) | |
tree | 3dce184ad675ba2ff3adbaf034209a0076c03754 /src/core | |
parent | b69f1f6aacad86bdc72e25085d74e64f17f32195 (diff) |
Add basic support for GetChannel
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/lib/channel/channelz.cc | 164 | ||||
-rw-r--r-- | src/core/lib/channel/channelz.h | 68 | ||||
-rw-r--r-- | src/core/lib/surface/call.cc | 27 | ||||
-rw-r--r-- | src/core/lib/surface/channel.cc | 13 | ||||
-rw-r--r-- | src/core/lib/surface/channel.h | 5 |
5 files changed, 270 insertions, 7 deletions
diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc new file mode 100644 index 0000000000..aabc941dcd --- /dev/null +++ b/src/core/lib/channel/channelz.cc @@ -0,0 +1,164 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <grpc/impl/codegen/port_platform.h> + +#include "src/core/lib/channel/channelz.h" + +#include <grpc/grpc.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "src/core/lib/channel/channelz_registry.h" +#include "src/core/lib/channel/status_util.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/error_utils.h" + +// TODO(ncteisen): actually implement this +char* grpc_channelz_get_channel(intptr_t channel_id) { return nullptr; } + +namespace grpc_core { +namespace channelz { + +// TODO(ncteisen): more this functions to a loc where it can be used +namespace { + +// returns an allocated string that represents tm according to RFC-3339, and, +// more specifically, follows: +// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// "Uses RFC 3339, where generated output will always be Z-normalized and uses +// 0, 3, 6 or 9 fractional digits." +char* fmt_time(gpr_timespec tm) { + char time_buffer[35]; + char ns_buffer[11]; // '.' + 9 digits of precision + struct tm* tm_info = localtime((const time_t*)&tm.tv_sec); + strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", tm_info); + snprintf(ns_buffer, 11, ".%09d", tm.tv_nsec); + // This loop trims off trailing zeros by inserting a null character that the + // right point. We iterate in chunks of three because we want 0, 3, 6, or 9 + // fractional digits. + for (int i = 7; i >= 1; i -= 3) { + if (ns_buffer[i] == '0' && ns_buffer[i + 1] == '0' && + ns_buffer[i + 2] == '0') { + ns_buffer[i] = '\0'; + // Edge case in which all fractional digits were 0. + if (i == 1) { + ns_buffer[0] = '\0'; + } + } else { + break; + } + } + char* full_time_str; + gpr_asprintf(&full_time_str, "%s%sZ", time_buffer, ns_buffer); + return full_time_str; +} + +// TODO(ncteisen); move this to json library +grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, + uint64_t num) { + char* num_str; + gpr_asprintf(&num_str, "%" PRIu64, num); + return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING, + true); +} + +} // namespace + +Channel::Channel(grpc_channel* channel) : channel_(channel) { + target_ = grpc_channel_get_target(channel_); + channel_uuid_ = ChannelzRegistry::Register(this); +} + +Channel::~Channel() { + gpr_free(const_cast<char*>(target_)); + ChannelzRegistry::Unregister(channel_uuid_); +} + +void Channel::CallStarted() { + calls_started_++; + last_call_started_timestamp_ = grpc_millis_to_timespec( + grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); +} + +grpc_connectivity_state Channel::GetConnectivityState() { + if (channel_destroyed_) { + return GRPC_CHANNEL_SHUTDOWN; + } else { + return grpc_channel_check_connectivity_state(channel_, false); + } +} + +char* Channel::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, true); + json = json_iterator; + json_iterator = nullptr; + json_iterator = add_num_str(json, json_iterator, "channelId", channel_uuid_); + + // reset json iterators to top level object + json = top_level_json; + json_iterator = nullptr; + + // create and fill the data child + json_iterator = grpc_json_create_child(json_iterator, json, "data", nullptr, + GRPC_JSON_OBJECT, true); + json = json_iterator; + json_iterator = nullptr; + json_iterator = + add_num_str(json, json_iterator, "callsStarted", calls_started_); + json_iterator = + add_num_str(json, json_iterator, "callsSucceeded", calls_succeeded_); + json_iterator = + add_num_str(json, json_iterator, "callsFailed", calls_failed_); + json_iterator = grpc_json_create_child( + json_iterator, json, "lastCallStartedTimestamp", + fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true); + json_iterator = grpc_json_create_child(json_iterator, json, "target", target_, + GRPC_JSON_STRING, false); + grpc_connectivity_state connectivity_state = GetConnectivityState(); + json_iterator = + grpc_json_create_child(json_iterator, json, "state", + grpc_connectivity_state_name(connectivity_state), + GRPC_JSON_STRING, false); + + // 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); + return json_str; +} + +} // namespace channelz +} // namespace grpc_core diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h new file mode 100644 index 0000000000..661228cf44 --- /dev/null +++ b/src/core/lib/channel/channelz.h @@ -0,0 +1,68 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_CHANNEL_CHANNELZ_H +#define GRPC_CORE_LIB_CHANNEL_CHANNELZ_H + +#include <grpc/impl/codegen/port_platform.h> + +#include <grpc/grpc.h> + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/json/json.h" + +namespace grpc_core { +namespace channelz { + +// owned by the client_channel that it points to and tracks +class Channel : public RefCounted<Channel> { + public: + Channel(grpc_channel* channel); + ~Channel(); + + void CallStarted(); + void CallFailed() { calls_failed_++; } + void CallSucceeded() { calls_succeeded_++; } + + char* RenderJSON(); + + void set_channel_destroyed() { + GPR_ASSERT(!channel_destroyed_); + channel_destroyed_ = true; + } + + private: + bool channel_destroyed_ = false; + grpc_channel* channel_; + const char* target_; + uint64_t calls_started_ = 0; + uint64_t calls_succeeded_ = 0; + uint64_t calls_failed_ = 0; + gpr_timespec last_call_started_timestamp_; + intptr_t channel_uuid_; + + grpc_connectivity_state GetConnectivityState(); +}; + +} // namespace channelz +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */ diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 86e0afa6ee..924d633cb2 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -1077,13 +1077,23 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) { if (b->idx.named.grpc_status != nullptr) { grpc_status_code status_code = grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md); - grpc_error* error = - status_code == GRPC_STATUS_OK - ? GRPC_ERROR_NONE - : grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Error received from peer"), - GRPC_ERROR_INT_GRPC_STATUS, - static_cast<intptr_t>(status_code)); + grpc_error* error = GRPC_ERROR_NONE; + grpc_core::channelz::Channel* channelz_channel = + call->channel != nullptr + ? grpc_channel_get_channelz_channel(call->channel) + : nullptr; + if (status_code == GRPC_STATUS_OK) { + if (channelz_channel != nullptr) { + channelz_channel->CallSucceeded(); + } + } else { + if (channelz_channel != nullptr) { + channelz_channel->CallFailed(); + } + error = grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error received from peer"), + GRPC_ERROR_INT_GRPC_STATUS, static_cast<intptr_t>(status_code)); + } if (b->idx.named.grpc_message != nullptr) { error = grpc_error_set_str( error, GRPC_ERROR_STR_GRPC_MESSAGE, @@ -1665,6 +1675,9 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, stream_op_payload->send_initial_metadata.peer_string = &call->peer_string; } + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_channel(call->channel); + channelz_channel->CallStarted(); break; } case GRPC_OP_SEND_MESSAGE: { diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index a466b325be..da66a120d5 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -32,6 +32,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_trace.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" @@ -67,6 +68,7 @@ struct grpc_channel { registered_call* registered_calls; grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer; + grpc_core::RefCountedPtr<grpc_core::channelz::Channel> channelz_channel; char* target; }; @@ -150,6 +152,8 @@ grpc_channel* grpc_channel_create_with_builder( channel->tracer->AddTraceEvent( grpc_core::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel created")); + channel->channelz_channel = + grpc_core::MakeRefCounted<grpc_core::channelz::Channel>(channel); return channel; } @@ -188,6 +192,15 @@ char* grpc_channel_get_trace(grpc_channel* channel) { return channel->tracer->RenderTrace(); } +char* grpc_channel_render_channelz(grpc_channel* channel) { + return channel->channelz_channel->RenderJSON(); +} + +grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( + grpc_channel* channel) { + return channel->channelz_channel.get(); +} + intptr_t grpc_channel_get_uuid(grpc_channel* channel) { return channel->tracer->GetUuid(); } diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 288313951e..52290f05f7 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -23,6 +23,7 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/surface/channel_stack_type.h" grpc_channel* grpc_channel_create(const char* target, @@ -50,6 +51,10 @@ grpc_call* grpc_channel_create_pollset_set_call( /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); +grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( + grpc_channel* channel); +char* grpc_channel_render_channelz(grpc_channel* channel); + /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of status_code. |