aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar ncteisen <ncteisen@gmail.com>2018-05-09 11:10:21 -0700
committerGravatar ncteisen <ncteisen@gmail.com>2018-06-05 16:59:25 -0700
commitc3c6e064b33ab8b7a2d3cf5a56171029d0bb1edc (patch)
tree3dce184ad675ba2ff3adbaf034209a0076c03754 /src/core
parentb69f1f6aacad86bdc72e25085d74e64f17f32195 (diff)
Add basic support for GetChannel
Diffstat (limited to 'src/core')
-rw-r--r--src/core/lib/channel/channelz.cc164
-rw-r--r--src/core/lib/channel/channelz.h68
-rw-r--r--src/core/lib/surface/call.cc27
-rw-r--r--src/core/lib/surface/channel.cc13
-rw-r--r--src/core/lib/surface/channel.h5
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.