aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/channel/channelz.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib/channel/channelz.cc')
-rw-r--r--src/core/lib/channel/channelz.cc164
1 files changed, 164 insertions, 0 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