aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD2
-rw-r--r--CMakeLists.txt56
-rw-r--r--Makefile60
-rw-r--r--build.yaml19
-rw-r--r--config.m41
-rw-r--r--config.w321
-rw-r--r--examples/cpp/cpptutorial.md488
-rw-r--r--examples/cpp/route_guide/README.md6
-rw-r--r--gRPC-C++.podspec2
-rw-r--r--gRPC-Core.podspec4
-rw-r--r--grpc.def2
-rw-r--r--grpc.gemspec2
-rw-r--r--grpc.gyp6
-rw-r--r--include/grpc/grpc.h8
-rw-r--r--include/grpc/impl/codegen/grpc_types.h4
-rw-r--r--package.xml2
-rw-r--r--src/core/lib/channel/channel_trace.cc49
-rw-r--r--src/core/lib/channel/channel_trace.h30
-rw-r--r--src/core/lib/channel/channelz.cc185
-rw-r--r--src/core/lib/channel/channelz.h85
-rw-r--r--src/core/lib/surface/call.cc29
-rw-r--r--src/core/lib/surface/channel.cc33
-rw-r--r--src/core/lib/surface/channel.h4
-rw-r--r--src/proto/grpc/channelz/channelz.proto143
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py1
-rwxr-xr-xsrc/ruby/end2end/multiple_killed_watching_threads_driver.rb4
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c4
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h6
-rw-r--r--test/core/channel/BUILD17
-rw-r--r--test/core/channel/channel_trace_test.cc196
-rw-r--r--test/core/channel/channelz_test.cc216
-rw-r--r--test/core/end2end/end2end_nosec_tests.cc8
-rw-r--r--test/core/end2end/end2end_tests.cc8
-rw-r--r--test/core/end2end/fuzzers/api_fuzzer.cc1
-rwxr-xr-xtest/core/end2end/gen_build_yaml.py1
-rwxr-xr-xtest/core/end2end/generate_tests.bzl1
-rw-r--r--test/core/end2end/tests/channelz.cc299
-rw-r--r--test/core/surface/public_headers_must_be_c89.c2
-rw-r--r--test/cpp/util/channel_trace_proto_helper.cc41
-rw-r--r--test/cpp/util/channel_trace_proto_helper.h1
-rw-r--r--tools/doxygen/Doxyfile.c++.internal1
-rw-r--r--tools/doxygen/Doxyfile.core.internal2
-rw-r--r--tools/run_tests/generated/sources_and_headers.json26
-rw-r--r--tools/run_tests/generated/tests.json813
-rwxr-xr-xtools/run_tests/helper_scripts/run_ruby_end2end_tests.sh22
-rwxr-xr-xtools/run_tests/run_tests.py2
46 files changed, 2163 insertions, 730 deletions
diff --git a/BUILD b/BUILD
index fea71153bb..0cbf9a9884 100644
--- a/BUILD
+++ b/BUILD
@@ -676,6 +676,7 @@ grpc_cc_library(
"src/core/lib/channel/channel_stack_builder.cc",
"src/core/lib/channel/channel_trace.cc",
"src/core/lib/channel/channelz_registry.cc",
+ "src/core/lib/channel/channelz.cc",
"src/core/lib/channel/connected_channel.cc",
"src/core/lib/channel/handshaker.cc",
"src/core/lib/channel/handshaker_factory.cc",
@@ -823,6 +824,7 @@ grpc_cc_library(
"src/core/lib/channel/channel_stack_builder.h",
"src/core/lib/channel/channel_trace.h",
"src/core/lib/channel/channelz_registry.h",
+ "src/core/lib/channel/channelz.h",
"src/core/lib/channel/connected_channel.h",
"src/core/lib/channel/context.h",
"src/core/lib/channel/handshaker.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 63c670606c..aec2e1ba88 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -544,6 +544,7 @@ add_dependencies(buildtests_cxx channel_arguments_test)
add_dependencies(buildtests_cxx channel_filter_test)
add_dependencies(buildtests_cxx channel_trace_test)
add_dependencies(buildtests_cxx channelz_registry_test)
+add_dependencies(buildtests_cxx channelz_test)
add_dependencies(buildtests_cxx check_gcp_environment_linux_test)
add_dependencies(buildtests_cxx check_gcp_environment_windows_test)
add_dependencies(buildtests_cxx chttp2_settings_timeout_test)
@@ -936,6 +937,7 @@ add_library(grpc
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.cc
+ src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
@@ -1331,6 +1333,7 @@ add_library(grpc_cronet
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.cc
+ src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
@@ -1717,6 +1720,7 @@ add_library(grpc_test_util
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.cc
+ src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
@@ -2022,6 +2026,7 @@ add_library(grpc_test_util_unsecure
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.cc
+ src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
@@ -2306,6 +2311,7 @@ add_library(grpc_unsecure
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.cc
+ src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
@@ -3138,6 +3144,7 @@ add_library(grpc++_cronet
src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.cc
+ src/core/lib/channel/channelz.cc
src/core/lib/channel/channelz_registry.cc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
@@ -5319,6 +5326,7 @@ add_library(end2end_tests
test/core/end2end/tests/cancel_before_invoke.cc
test/core/end2end/tests/cancel_in_a_vacuum.cc
test/core/end2end/tests/cancel_with_status.cc
+ test/core/end2end/tests/channelz.cc
test/core/end2end/tests/compressed_payload.cc
test/core/end2end/tests/connectivity.cc
test/core/end2end/tests/default_host.cc
@@ -5439,6 +5447,7 @@ add_library(end2end_nosec_tests
test/core/end2end/tests/cancel_before_invoke.cc
test/core/end2end/tests/cancel_in_a_vacuum.cc
test/core/end2end/tests/cancel_with_status.cc
+ test/core/end2end/tests/channelz.cc
test/core/end2end/tests/compressed_payload.cc
test/core/end2end/tests/connectivity.cc
test/core/end2end/tests/default_host.cc
@@ -10801,6 +10810,53 @@ target_link_libraries(channelz_registry_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(channelz_test
+ test/core/channel/channelz_test.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.h
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+protobuf_generate_grpc_cpp(
+ src/proto/grpc/channelz/channelz.proto
+)
+
+target_include_directories(channelz_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(channelz_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+ grpc++_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(check_gcp_environment_linux_test
test/core/security/check_gcp_environment_linux_test.cc
third_party/googletest/googletest/src/gtest-all.cc
diff --git a/Makefile b/Makefile
index 5bb4fbab43..5ef8b816e0 100644
--- a/Makefile
+++ b/Makefile
@@ -1122,6 +1122,7 @@ channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
channel_filter_test: $(BINDIR)/$(CONFIG)/channel_filter_test
channel_trace_test: $(BINDIR)/$(CONFIG)/channel_trace_test
channelz_registry_test: $(BINDIR)/$(CONFIG)/channelz_registry_test
+channelz_test: $(BINDIR)/$(CONFIG)/channelz_test
check_gcp_environment_linux_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test
check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test
chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test
@@ -1619,6 +1620,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/channel_filter_test \
$(BINDIR)/$(CONFIG)/channel_trace_test \
$(BINDIR)/$(CONFIG)/channelz_registry_test \
+ $(BINDIR)/$(CONFIG)/channelz_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
@@ -1795,6 +1797,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/channel_filter_test \
$(BINDIR)/$(CONFIG)/channel_trace_test \
$(BINDIR)/$(CONFIG)/channelz_registry_test \
+ $(BINDIR)/$(CONFIG)/channelz_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
@@ -2233,6 +2236,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/channel_trace_test || ( echo test channel_trace_test failed ; exit 1 )
$(E) "[RUN] Testing channelz_registry_test"
$(Q) $(BINDIR)/$(CONFIG)/channelz_registry_test || ( echo test channelz_registry_test failed ; exit 1 )
+ $(E) "[RUN] Testing channelz_test"
+ $(Q) $(BINDIR)/$(CONFIG)/channelz_test || ( echo test channelz_test failed ; exit 1 )
$(E) "[RUN] Testing check_gcp_environment_linux_test"
$(Q) $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test || ( echo test check_gcp_environment_linux_test failed ; exit 1 )
$(E) "[RUN] Testing check_gcp_environment_windows_test"
@@ -3311,6 +3316,7 @@ LIBGRPC_SRC = \
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
@@ -3705,6 +3711,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
@@ -4089,6 +4096,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
@@ -4385,6 +4393,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
@@ -4647,6 +4656,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
@@ -5467,6 +5477,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
@@ -9974,6 +9985,7 @@ LIBEND2END_TESTS_SRC = \
test/core/end2end/tests/cancel_before_invoke.cc \
test/core/end2end/tests/cancel_in_a_vacuum.cc \
test/core/end2end/tests/cancel_with_status.cc \
+ test/core/end2end/tests/channelz.cc \
test/core/end2end/tests/compressed_payload.cc \
test/core/end2end/tests/connectivity.cc \
test/core/end2end/tests/default_host.cc \
@@ -10091,6 +10103,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \
test/core/end2end/tests/cancel_before_invoke.cc \
test/core/end2end/tests/cancel_in_a_vacuum.cc \
test/core/end2end/tests/cancel_with_status.cc \
+ test/core/end2end/tests/channelz.cc \
test/core/end2end/tests/compressed_payload.cc \
test/core/end2end/tests/connectivity.cc \
test/core/end2end/tests/default_host.cc \
@@ -16424,6 +16437,53 @@ endif
endif
+CHANNELZ_TEST_SRC = \
+ test/core/channel/channelz_test.cc \
+ $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc \
+
+CHANNELZ_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHANNELZ_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/channelz_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/channelz_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/channelz_test: $(PROTOBUF_DEP) $(CHANNELZ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(CHANNELZ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/channelz_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/channel/channelz_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/channelz/channelz.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_channelz_test: $(CHANNELZ_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CHANNELZ_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/core/channel/channelz_test.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc
+
+
CHECK_GCP_ENVIRONMENT_LINUX_TEST_SRC = \
test/core/security/check_gcp_environment_linux_test.cc \
diff --git a/build.yaml b/build.yaml
index f963f0c913..aacb99aaba 100644
--- a/build.yaml
+++ b/build.yaml
@@ -234,6 +234,7 @@ filegroups:
- src/core/lib/channel/channel_stack.cc
- src/core/lib/channel/channel_stack_builder.cc
- src/core/lib/channel/channel_trace.cc
+ - src/core/lib/channel/channelz.cc
- src/core/lib/channel/channelz_registry.cc
- src/core/lib/channel/connected_channel.cc
- src/core/lib/channel/handshaker.cc
@@ -404,6 +405,7 @@ filegroups:
- src/core/lib/channel/channel_stack.h
- src/core/lib/channel/channel_stack_builder.h
- src/core/lib/channel/channel_trace.h
+ - src/core/lib/channel/channelz.h
- src/core/lib/channel/channelz_registry.h
- src/core/lib/channel/connected_channel.h
- src/core/lib/channel/context.h
@@ -4252,6 +4254,23 @@ targets:
uses:
- grpc++_test
uses_polling: false
+- name: channelz_test
+ gtest: true
+ build: test
+ language: c++
+ src:
+ - test/core/channel/channelz_test.cc
+ deps:
+ - grpc_test_util
+ - grpc++_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
+ filegroups:
+ - grpc++_channelz_proto
+ uses:
+ - grpc++_test
- name: check_gcp_environment_linux_test
build: test
language: c++
diff --git a/config.m4 b/config.m4
index 781fd08fa1..2704c42a12 100644
--- a/config.m4
+++ b/config.m4
@@ -89,6 +89,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.cc \
+ src/core/lib/channel/channelz.cc \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
diff --git a/config.w32 b/config.w32
index b87b261772..e960c283b3 100644
--- a/config.w32
+++ b/config.w32
@@ -65,6 +65,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\channel\\channel_stack.cc " +
"src\\core\\lib\\channel\\channel_stack_builder.cc " +
"src\\core\\lib\\channel\\channel_trace.cc " +
+ "src\\core\\lib\\channel\\channelz.cc " +
"src\\core\\lib\\channel\\channelz_registry.cc " +
"src\\core\\lib\\channel\\connected_channel.cc " +
"src\\core\\lib\\channel\\handshaker.cc " +
diff --git a/examples/cpp/cpptutorial.md b/examples/cpp/cpptutorial.md
deleted file mode 100644
index 7d98367da4..0000000000
--- a/examples/cpp/cpptutorial.md
+++ /dev/null
@@ -1,488 +0,0 @@
-# gRPC Basics: C++
-
-This tutorial provides a basic C++ programmer's introduction to working with
-gRPC. By walking through this example you'll learn how to:
-
-- Define a service in a `.proto` file.
-- Generate server and client code using the protocol buffer compiler.
-- Use the C++ gRPC API to write a simple client and server for your service.
-
-It assumes that you are familiar with
-[protocol buffers](https://developers.google.com/protocol-buffers/docs/overview).
-Note that the example in this tutorial uses the proto3 version of the protocol
-buffers language, which is currently in alpha release: you can find out more in
-the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3)
-and see the [release notes](https://github.com/google/protobuf/releases) for the
-new version in the protocol buffers Github repository.
-
-## Why use gRPC?
-
-Our example is a simple route mapping application that lets clients get
-information about features on their route, create a summary of their route, and
-exchange route information such as traffic updates with the server and other
-clients.
-
-With gRPC we can define our service once in a `.proto` file and implement clients
-and servers in any of gRPC's supported languages, which in turn can be run in
-environments ranging from servers inside Google to your own tablet - all the
-complexity of communication between different languages and environments is
-handled for you by gRPC. We also get all the advantages of working with protocol
-buffers, including efficient serialization, a simple IDL, and easy interface
-updating.
-
-## Example code and setup
-
-The example code for our tutorial is in [examples/cpp/route_guide](route_guide).
-You also should have the relevant tools installed to generate the server and
-client interface code - if you don't already, follow the setup instructions in
-[INSTALL.md](../../INSTALL.md).
-
-## Defining the service
-
-Our first step is to define the gRPC *service* and the method *request* and
-*response* types using
-[protocol buffers](https://developers.google.com/protocol-buffers/docs/overview).
-You can see the complete `.proto` file in
-[`examples/protos/route_guide.proto`](../protos/route_guide.proto).
-
-To define a service, you specify a named `service` in your `.proto` file:
-
-```protobuf
-service RouteGuide {
- ...
-}
-```
-
-Then you define `rpc` methods inside your service definition, specifying their
-request and response types. gRPC lets you define four kinds of service method,
-all of which are used in the `RouteGuide` service:
-
-- A *simple RPC* where the client sends a request to the server using the stub
- and waits for a response to come back, just like a normal function call.
-
-```protobuf
- // Obtains the feature at a given position.
- rpc GetFeature(Point) returns (Feature) {}
-```
-
-- A *server-side streaming RPC* where the client sends a request to the server
- and gets a stream to read a sequence of messages back. The client reads from
- the returned stream until there are no more messages. As you can see in our
- example, you specify a server-side streaming method by placing the `stream`
- keyword before the *response* type.
-
-```protobuf
- // Obtains the Features available within the given Rectangle. Results are
- // streamed rather than returned at once (e.g. in a response message with a
- // repeated field), as the rectangle may cover a large area and contain a
- // huge number of features.
- rpc ListFeatures(Rectangle) returns (stream Feature) {}
-```
-
-- A *client-side streaming RPC* where the client writes a sequence of messages
- and sends them to the server, again using a provided stream. Once the client
- has finished writing the messages, it waits for the server to read them all
- and return its response. You specify a client-side streaming method by placing
- the `stream` keyword before the *request* type.
-
-```protobuf
- // Accepts a stream of Points on a route being traversed, returning a
- // RouteSummary when traversal is completed.
- rpc RecordRoute(stream Point) returns (RouteSummary) {}
-```
-
-- A *bidirectional streaming RPC* where both sides send a sequence of messages
- using a read-write stream. The two streams operate independently, so clients
- and servers can read and write in whatever order they like: for example, the
- server could wait to receive all the client messages before writing its
- responses, or it could alternately read a message then write a message, or
- some other combination of reads and writes. The order of messages in each
- stream is preserved. You specify this type of method by placing the `stream`
- keyword before both the request and the response.
-
-```protobuf
- // Accepts a stream of RouteNotes sent while a route is being traversed,
- // while receiving other RouteNotes (e.g. from other users).
- rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
-```
-
-Our `.proto` file also contains protocol buffer message type definitions for all
-the request and response types used in our service methods - for example, here's
-the `Point` message type:
-
-```protobuf
-// Points are represented as latitude-longitude pairs in the E7 representation
-// (degrees multiplied by 10**7 and rounded to the nearest integer).
-// Latitudes should be in the range +/- 90 degrees and longitude should be in
-// the range +/- 180 degrees (inclusive).
-message Point {
- int32 latitude = 1;
- int32 longitude = 2;
-}
-```
-
-## Generating client and server code
-
-Next we need to generate the gRPC client and server interfaces from our `.proto`
-service definition. We do this using the protocol buffer compiler `protoc` with
-a special gRPC C++ plugin.
-
-For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs
-`protoc` for you with the appropriate plugin, input, and output (if you want to
-run this yourself, make sure you've installed protoc and followed the gRPC code
-[installation instructions](../../INSTALL.md) first):
-
-```shell
-$ make route_guide.grpc.pb.cc route_guide.pb.cc
-```
-
-which actually runs:
-
-```shell
-$ protoc -I ../../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../../protos/route_guide.proto
-$ protoc -I ../../protos --cpp_out=. ../../protos/route_guide.proto
-```
-
-Running this command generates the following files in your current directory:
-- `route_guide.pb.h`, the header which declares your generated message classes
-- `route_guide.pb.cc`, which contains the implementation of your message classes
-- `route_guide.grpc.pb.h`, the header which declares your generated service
- classes
-- `route_guide.grpc.pb.cc`, which contains the implementation of your service
- classes
-
-These contain:
-- All the protocol buffer code to populate, serialize, and retrieve our request
- and response message types
-- A class called `RouteGuide` that contains
- - a remote interface type (or *stub*) for clients to call with the methods
- defined in the `RouteGuide` service.
- - two abstract interfaces for servers to implement, also with the methods
- defined in the `RouteGuide` service.
-
-
-<a name="server"></a>
-## Creating the server
-
-First let's look at how we create a `RouteGuide` server. If you're only
-interested in creating gRPC clients, you can skip this section and go straight
-to [Creating the client](#client) (though you might find it interesting
-anyway!).
-
-There are two parts to making our `RouteGuide` service do its job:
-- Implementing the service interface generated from our service definition:
- doing the actual "work" of our service.
-- Running a gRPC server to listen for requests from clients and return the
- service responses.
-
-You can find our example `RouteGuide` server in
-[route_guide/route_guide_server.cc](route_guide/route_guide_server.cc). Let's
-take a closer look at how it works.
-
-### Implementing RouteGuide
-
-As you can see, our server has a `RouteGuideImpl` class that implements the
-generated `RouteGuide::Service` interface:
-
-```cpp
-class RouteGuideImpl final : public RouteGuide::Service {
-...
-}
-```
-In this case we're implementing the *synchronous* version of `RouteGuide`, which
-provides our default gRPC server behaviour. It's also possible to implement an
-asynchronous interface, `RouteGuide::AsyncService`, which allows you to further
-customize your server's threading behaviour, though we won't look at this in
-this tutorial.
-
-`RouteGuideImpl` implements all our service methods. Let's look at the simplest
-type first, `GetFeature`, which just gets a `Point` from the client and returns
-the corresponding feature information from its database in a `Feature`.
-
-```cpp
- Status GetFeature(ServerContext* context, const Point* point,
- Feature* feature) override {
- feature->set_name(GetFeatureName(*point, feature_list_));
- feature->mutable_location()->CopyFrom(*point);
- return Status::OK;
- }
-```
-
-The method is passed a context object for the RPC, the client's `Point` protocol
-buffer request, and a `Feature` protocol buffer to fill in with the response
-information. In the method we populate the `Feature` with the appropriate
-information, and then `return` with an `OK` status to tell gRPC that we've
-finished dealing with the RPC and that the `Feature` can be returned to the
-client.
-
-Now let's look at something a bit more complicated - a streaming RPC.
-`ListFeatures` is a server-side streaming RPC, so we need to send back multiple
-`Feature`s to our client.
-
-```cpp
-Status ListFeatures(ServerContext* context, const Rectangle* rectangle,
- ServerWriter<Feature>* writer) override {
- auto lo = rectangle->lo();
- auto hi = rectangle->hi();
- long left = std::min(lo.longitude(), hi.longitude());
- long right = std::max(lo.longitude(), hi.longitude());
- long top = std::max(lo.latitude(), hi.latitude());
- long bottom = std::min(lo.latitude(), hi.latitude());
- for (const Feature& f : feature_list_) {
- if (f.location().longitude() >= left &&
- f.location().longitude() <= right &&
- f.location().latitude() >= bottom &&
- f.location().latitude() <= top) {
- writer->Write(f);
- }
- }
- return Status::OK;
-}
-```
-
-As you can see, instead of getting simple request and response objects in our
-method parameters, this time we get a request object (the `Rectangle` in which
-our client wants to find `Feature`s) and a special `ServerWriter` object. In the
-method, we populate as many `Feature` objects as we need to return, writing them
-to the `ServerWriter` using its `Write()` method. Finally, as in our simple RPC,
-we `return Status::OK` to tell gRPC that we've finished writing responses.
-
-If you look at the client-side streaming method `RecordRoute` you'll see it's
-quite similar, except this time we get a `ServerReader` instead of a request
-object and a single response. We use the `ServerReader`s `Read()` method to
-repeatedly read in our client's requests to a request object (in this case a
-`Point`) until there are no more messages: the server needs to check the return
-value of `Read()` after each call. If `true`, the stream is still good and it
-can continue reading; if `false` the message stream has ended.
-
-```cpp
-while (stream->Read(&point)) {
- ...//process client input
-}
-```
-Finally, let's look at our bidirectional streaming RPC `RouteChat()`.
-
-```cpp
- Status RouteChat(ServerContext* context,
- ServerReaderWriter<RouteNote, RouteNote>* stream) override {
- std::vector<RouteNote> received_notes;
- RouteNote note;
- while (stream->Read(&note)) {
- for (const RouteNote& n : received_notes) {
- if (n.location().latitude() == note.location().latitude() &&
- n.location().longitude() == note.location().longitude()) {
- stream->Write(n);
- }
- }
- received_notes.push_back(note);
- }
-
- return Status::OK;
- }
-```
-
-This time we get a `ServerReaderWriter` that can be used to read *and* write
-messages. The syntax for reading and writing here is exactly the same as for our
-client-streaming and server-streaming methods. Although each side will always
-get the other's messages in the order they were written, both the client and
-server can read and write in any order — the streams operate completely
-independently.
-
-### Starting the server
-
-Once we've implemented all our methods, we also need to start up a gRPC server
-so that clients can actually use our service. The following snippet shows how we
-do this for our `RouteGuide` service:
-
-```cpp
-void RunServer(const std::string& db_path) {
- std::string server_address("0.0.0.0:50051");
- RouteGuideImpl service(db_path);
-
- ServerBuilder builder;
- builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
- builder.RegisterService(&service);
- std::unique_ptr<Server> server(builder.BuildAndStart());
- std::cout << "Server listening on " << server_address << std::endl;
- server->Wait();
-}
-```
-As you can see, we build and start our server using a `ServerBuilder`. To do this, we:
-
-1. Create an instance of our service implementation class `RouteGuideImpl`.
-1. Create an instance of the factory `ServerBuilder` class.
-1. Specify the address and port we want to use to listen for client requests
- using the builder's `AddListeningPort()` method.
-1. Register our service implementation with the builder.
-1. Call `BuildAndStart()` on the builder to create and start an RPC server for
- our service.
-1. Call `Wait()` on the server to do a blocking wait until process is killed or
- `Shutdown()` is called.
-
-<a name="client"></a>
-## Creating the client
-
-In this section, we'll look at creating a C++ client for our `RouteGuide`
-service. You can see our complete example client code in
-[route_guide/route_guide_client.cc](route_guide/route_guide_client.cc).
-
-### Creating a stub
-
-To call service methods, we first need to create a *stub*.
-
-First we need to create a gRPC *channel* for our stub, specifying the server
-address and port we want to connect to without SSL:
-
-```cpp
-grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());
-```
-
-Now we can use the channel to create our stub using the `NewStub` method
-provided in the `RouteGuide` class we generated from our `.proto`.
-
-```cpp
-public:
- RouteGuideClient(std::shared_ptr<Channel> channel, const std::string& db)
- : stub_(RouteGuide::NewStub(channel)) {
- ...
- }
-```
-
-### Calling service methods
-
-Now let's look at how we call our service methods. Note that in this tutorial
-we're calling the *blocking/synchronous* versions of each method: this means
-that the RPC call waits for the server to respond, and will either return a
-response or raise an exception.
-
-#### Simple RPC
-
-Calling the simple RPC `GetFeature` is nearly as straightforward as calling a
-local method.
-
-```cpp
- Point point;
- Feature feature;
- point = MakePoint(409146138, -746188906);
- GetOneFeature(point, &feature);
-
-...
-
- bool GetOneFeature(const Point& point, Feature* feature) {
- ClientContext context;
- Status status = stub_->GetFeature(&context, point, feature);
- ...
- }
-```
-
-As you can see, we create and populate a request protocol buffer object (in our
-case `Point`), and create a response protocol buffer object for the server to
-fill in. We also create a `ClientContext` object for our call - you can
-optionally set RPC configuration values on this object, such as deadlines,
-though for now we'll use the default settings. Note that you cannot reuse this
-object between calls. Finally, we call the method on the stub, passing it the
-context, request, and response. If the method returns `OK`, then we can read the
-response information from the server from our response object.
-
-```cpp
-std::cout << "Found feature called " << feature->name() << " at "
- << feature->location().latitude()/kCoordFactor_ << ", "
- << feature->location().longitude()/kCoordFactor_ << std::endl;
-```
-
-#### Streaming RPCs
-
-Now let's look at our streaming methods. If you've already read [Creating the
-server](#server) some of this may look very familiar - streaming RPCs are
-implemented in a similar way on both sides. Here's where we call the server-side
-streaming method `ListFeatures`, which returns a stream of geographical
-`Feature`s:
-
-```cpp
-std::unique_ptr<ClientReader<Feature> > reader(
- stub_->ListFeatures(&context, rect));
-while (reader->Read(&feature)) {
- std::cout << "Found feature called "
- << feature.name() << " at "
- << feature.location().latitude()/kCoordFactor_ << ", "
- << feature.location().longitude()/kCoordFactor_ << std::endl;
-}
-Status status = reader->Finish();
-```
-
-Instead of passing the method a context, request, and response, we pass it a
-context and request and get a `ClientReader` object back. The client can use the
-`ClientReader` to read the server's responses. We use the `ClientReader`s
-`Read()` method to repeatedly read in the server's responses to a response
-protocol buffer object (in this case a `Feature`) until there are no more
-messages: the client needs to check the return value of `Read()` after each
-call. If `true`, the stream is still good and it can continue reading; if
-`false` the message stream has ended. Finally, we call `Finish()` on the stream
-to complete the call and get our RPC status.
-
-The client-side streaming method `RecordRoute` is similar, except there we pass
-the method a context and response object and get back a `ClientWriter`.
-
-```cpp
- std::unique_ptr<ClientWriter<Point> > writer(
- stub_->RecordRoute(&context, &stats));
- for (int i = 0; i < kPoints; i++) {
- const Feature& f = feature_list_[feature_distribution(generator)];
- std::cout << "Visiting point "
- << f.location().latitude()/kCoordFactor_ << ", "
- << f.location().longitude()/kCoordFactor_ << std::endl;
- if (!writer->Write(f.location())) {
- // Broken stream.
- break;
- }
- std::this_thread::sleep_for(std::chrono::milliseconds(
- delay_distribution(generator)));
- }
- writer->WritesDone();
- Status status = writer->Finish();
- if (status.IsOk()) {
- std::cout << "Finished trip with " << stats.point_count() << " points\n"
- << "Passed " << stats.feature_count() << " features\n"
- << "Travelled " << stats.distance() << " meters\n"
- << "It took " << stats.elapsed_time() << " seconds"
- << std::endl;
- } else {
- std::cout << "RecordRoute rpc failed." << std::endl;
- }
-```
-
-Once we've finished writing our client's requests to the stream using `Write()`,
-we need to call `WritesDone()` on the stream to let gRPC know that we've
-finished writing, then `Finish()` to complete the call and get our RPC status.
-If the status is `OK`, our response object that we initially passed to
-`RecordRoute()` will be populated with the server's response.
-
-Finally, let's look at our bidirectional streaming RPC `RouteChat()`. In this
-case, we just pass a context to the method and get back a `ClientReaderWriter`,
-which we can use to both write and read messages.
-
-```cpp
-std::shared_ptr<ClientReaderWriter<RouteNote, RouteNote> > stream(
- stub_->RouteChat(&context));
-```
-
-The syntax for reading and writing here is exactly the same as for our
-client-streaming and server-streaming methods. Although each side will always
-get the other's messages in the order they were written, both the client and
-server can read and write in any order — the streams operate completely
-independently.
-
-## Try it out!
-
-Build client and server:
-```shell
-$ make
-```
-Run the server, which will listen on port 50051:
-```shell
-$ ./route_guide_server
-```
-Run the client (in a different terminal):
-```shell
-$ ./route_guide_client
-```
diff --git a/examples/cpp/route_guide/README.md b/examples/cpp/route_guide/README.md
new file mode 100644
index 0000000000..1cb5a409f8
--- /dev/null
+++ b/examples/cpp/route_guide/README.md
@@ -0,0 +1,6 @@
+# gRPC Basics: C++ sample code
+
+The files in this folder are the samples used in [gRPC Basics: C++][],
+a detailed tutorial for using gRPC in C++.
+
+[gRPC Basics: C++]:https://grpc.io/docs/tutorials/basic/c.html
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 2380da9476..d7afd5a99c 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -347,6 +347,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.h',
+ 'src/core/lib/channel/channelz.h',
'src/core/lib/channel/channelz_registry.h',
'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.h',
@@ -532,6 +533,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.h',
+ 'src/core/lib/channel/channelz.h',
'src/core/lib/channel/channelz_registry.h',
'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index b7548e31d9..89ddf20efb 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -357,6 +357,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.h',
+ 'src/core/lib/channel/channelz.h',
'src/core/lib/channel/channelz_registry.h',
'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.h',
@@ -507,6 +508,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.cc',
+ 'src/core/lib/channel/channelz.cc',
'src/core/lib/channel/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
@@ -936,6 +938,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.h',
+ 'src/core/lib/channel/channelz.h',
'src/core/lib/channel/channelz_registry.h',
'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.h',
@@ -1194,6 +1197,7 @@ Pod::Spec.new do |s|
'test/core/end2end/tests/cancel_before_invoke.cc',
'test/core/end2end/tests/cancel_in_a_vacuum.cc',
'test/core/end2end/tests/cancel_with_status.cc',
+ 'test/core/end2end/tests/channelz.cc',
'test/core/end2end/tests/compressed_payload.cc',
'test/core/end2end/tests/connectivity.cc',
'test/core/end2end/tests/default_host.cc',
diff --git a/grpc.def b/grpc.def
index 6a91214e8c..e7f93396b2 100644
--- a/grpc.def
+++ b/grpc.def
@@ -45,8 +45,6 @@ EXPORTS
grpc_insecure_channel_create
grpc_lame_client_channel_create
grpc_channel_destroy
- grpc_channel_get_trace
- grpc_channel_get_uuid
grpc_call_cancel
grpc_call_cancel_with_status
grpc_call_ref
diff --git a/grpc.gemspec b/grpc.gemspec
index eb059d8514..3b48967cba 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -294,6 +294,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/channel_stack.h )
s.files += %w( src/core/lib/channel/channel_stack_builder.h )
s.files += %w( src/core/lib/channel/channel_trace.h )
+ s.files += %w( src/core/lib/channel/channelz.h )
s.files += %w( src/core/lib/channel/channelz_registry.h )
s.files += %w( src/core/lib/channel/connected_channel.h )
s.files += %w( src/core/lib/channel/context.h )
@@ -444,6 +445,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/channel_stack.cc )
s.files += %w( src/core/lib/channel/channel_stack_builder.cc )
s.files += %w( src/core/lib/channel/channel_trace.cc )
+ s.files += %w( src/core/lib/channel/channelz.cc )
s.files += %w( src/core/lib/channel/channelz_registry.cc )
s.files += %w( src/core/lib/channel/connected_channel.cc )
s.files += %w( src/core/lib/channel/handshaker.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 420cf75f57..99746033c5 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -256,6 +256,7 @@
'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.cc',
+ 'src/core/lib/channel/channelz.cc',
'src/core/lib/channel/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
@@ -606,6 +607,7 @@
'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.cc',
+ 'src/core/lib/channel/channelz.cc',
'src/core/lib/channel/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
@@ -837,6 +839,7 @@
'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.cc',
+ 'src/core/lib/channel/channelz.cc',
'src/core/lib/channel/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
@@ -1046,6 +1049,7 @@
'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.cc',
+ 'src/core/lib/channel/channelz.cc',
'src/core/lib/channel/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
@@ -2616,6 +2620,7 @@
'test/core/end2end/tests/cancel_before_invoke.cc',
'test/core/end2end/tests/cancel_in_a_vacuum.cc',
'test/core/end2end/tests/cancel_with_status.cc',
+ 'test/core/end2end/tests/channelz.cc',
'test/core/end2end/tests/compressed_payload.cc',
'test/core/end2end/tests/connectivity.cc',
'test/core/end2end/tests/default_host.cc',
@@ -2707,6 +2712,7 @@
'test/core/end2end/tests/cancel_before_invoke.cc',
'test/core/end2end/tests/cancel_in_a_vacuum.cc',
'test/core/end2end/tests/cancel_with_status.cc',
+ 'test/core/end2end/tests/channelz.cc',
'test/core/end2end/tests/compressed_payload.cc',
'test/core/end2end/tests/connectivity.cc',
'test/core/end2end/tests/default_host.cc',
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index dd8a5d7d5f..c129a66949 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -286,14 +286,6 @@ GRPCAPI grpc_channel* grpc_lame_client_channel_create(
/** Close and destroy a grpc channel */
GRPCAPI void grpc_channel_destroy(grpc_channel* channel);
-/** Returns the JSON formatted channel trace for this channel. The caller
- owns the returned string and is responsible for freeing it. */
-GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel);
-
-/** Returns the channel uuid, which can be used to look up its trace at a
- later time. */
-GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel);
-
/** Error handling for grpc_call
Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
then the operation failed due to some unsatisfied precondition.
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index a5961857c1..c32e99ed4c 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -289,6 +289,10 @@ typedef struct {
* subchannel. The default is 10. If set to 0, channel tracing is disabled. */
#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
"grpc.max_channel_trace_events_per_node"
+/** If non-zero, gRPC library will track stats and information at at per channel
+ * level. Disabling channelz naturally disables channel tracing. The default
+ * is for channelz to be disabled. */
+#define GRPC_ARG_ENABLE_CHANNELZ "grpc.enable_channelz"
/** If non-zero, Cronet transport will coalesce packets to fewer frames
* when possible. */
#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
diff --git a/package.xml b/package.xml
index 51f82e1889..29f6f0147a 100644
--- a/package.xml
+++ b/package.xml
@@ -299,6 +299,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_trace.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/channel/channelz.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
@@ -449,6 +450,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_trace.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/channel/channelz.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/connected_channel.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker.cc" role="src" />
diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc
index eb7214b355..0f655d8716 100644
--- a/src/core/lib/channel/channel_trace.cc
+++ b/src/core/lib/channel/channel_trace.cc
@@ -28,7 +28,6 @@
#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"
@@ -40,16 +39,17 @@
#include "src/core/lib/transport/error_utils.h"
namespace grpc_core {
+namespace channelz {
ChannelTrace::TraceEvent::TraceEvent(
Severity severity, grpc_slice data,
- RefCountedPtr<ChannelTrace> referenced_tracer, ReferencedType type)
+ RefCountedPtr<ChannelNode> referenced_channel, ReferencedType type)
: severity_(severity),
data_(data),
timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME)),
next_(nullptr),
- referenced_tracer_(std::move(referenced_tracer)),
+ referenced_channel_(std::move(referenced_channel)),
referenced_type_(type) {}
ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
@@ -62,15 +62,13 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
ChannelTrace::ChannelTrace(size_t max_events)
- : channel_uuid_(-1),
- num_events_logged_(0),
+ : num_events_logged_(0),
list_size_(0),
max_list_size_(max_events),
head_trace_(nullptr),
tail_trace_(nullptr) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
gpr_mu_init(&tracer_mu_);
- channel_uuid_ = ChannelzRegistry::Register(this);
time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME);
}
@@ -83,12 +81,9 @@ ChannelTrace::~ChannelTrace() {
it = it->next();
Delete<TraceEvent>(to_free);
}
- ChannelzRegistry::Unregister(channel_uuid_);
gpr_mu_destroy(&tracer_mu_);
}
-intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; }
-
void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
++num_events_logged_;
// first event case
@@ -117,20 +112,21 @@ void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) {
void ChannelTrace::AddTraceEventReferencingChannel(
Severity severity, grpc_slice data,
- RefCountedPtr<ChannelTrace> referenced_tracer) {
+ RefCountedPtr<ChannelNode> referenced_channel) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
// create and fill up the new event
- AddTraceEventHelper(
- New<TraceEvent>(severity, data, std::move(referenced_tracer), Channel));
+ AddTraceEventHelper(New<TraceEvent>(
+ severity, data, std::move(referenced_channel), ReferencedType::Channel));
}
void ChannelTrace::AddTraceEventReferencingSubchannel(
Severity severity, grpc_slice data,
- RefCountedPtr<ChannelTrace> referenced_tracer) {
+ RefCountedPtr<ChannelNode> referenced_subchannel) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
// create and fill up the new event
- AddTraceEventHelper(New<TraceEvent>(
- severity, data, std::move(referenced_tracer), Subchannel));
+ AddTraceEventHelper(New<TraceEvent>(severity, data,
+ std::move(referenced_subchannel),
+ ReferencedType::Subchannel));
}
namespace {
@@ -193,22 +189,24 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
json_iterator =
grpc_json_create_child(json_iterator, json, "timestamp",
fmt_time(timestamp_), GRPC_JSON_STRING, true);
- if (referenced_tracer_ != nullptr) {
+ if (referenced_channel_ != nullptr) {
char* uuid_str;
- gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_tracer_->channel_uuid_);
+ gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_channel_->channel_uuid());
grpc_json* child_ref = grpc_json_create_child(
json_iterator, json,
- (referenced_type_ == Channel) ? "channelRef" : "subchannelRef", nullptr,
- GRPC_JSON_OBJECT, false);
+ (referenced_type_ == ReferencedType::Channel) ? "channelRef"
+ : "subchannelRef",
+ nullptr, GRPC_JSON_OBJECT, false);
json_iterator = grpc_json_create_child(
nullptr, child_ref,
- (referenced_type_ == Channel) ? "channelId" : "subchannelId", uuid_str,
- GRPC_JSON_STRING, true);
+ (referenced_type_ == ReferencedType::Channel) ? "channelId"
+ : "subchannelId",
+ uuid_str, GRPC_JSON_STRING, true);
json_iterator = child_ref;
}
}
-char* ChannelTrace::RenderTrace() const {
+grpc_json* ChannelTrace::RenderJSON() const {
if (!max_list_size_)
return nullptr; // tracing is disabled if max_events == 0
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
@@ -219,7 +217,7 @@ char* ChannelTrace::RenderTrace() const {
grpc_json_create_child(json_iterator, json, "numEventsLogged",
num_events_logged_str, GRPC_JSON_STRING, true);
json_iterator =
- grpc_json_create_child(json_iterator, json, "creationTime",
+ grpc_json_create_child(json_iterator, json, "creationTimestamp",
fmt_time(time_created_), GRPC_JSON_STRING, true);
grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
nullptr, GRPC_JSON_ARRAY, false);
@@ -231,9 +229,8 @@ char* ChannelTrace::RenderTrace() const {
it->RenderTraceEvent(json_iterator);
it = it->next();
}
- char* json_str = grpc_json_dump_to_string(json, 0);
- grpc_json_destroy(json);
- return json_str;
+ return json;
}
+} // namespace channelz
} // namespace grpc_core
diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h
index 1df1e585f2..0dd162a777 100644
--- a/src/core/lib/channel/channel_trace.h
+++ b/src/core/lib/channel/channel_trace.h
@@ -28,18 +28,18 @@
#include "src/core/lib/json/json.h"
namespace grpc_core {
+namespace channelz {
+
+class ChannelNode;
// Object used to hold live data for a channel. This data is exposed via the
// channelz service:
// https://github.com/grpc/proposal/blob/master/A14-channelz.md
-class ChannelTrace : public RefCounted<ChannelTrace> {
+class ChannelTrace {
public:
ChannelTrace(size_t max_events);
~ChannelTrace();
- // returns the tracer's uuid
- intptr_t GetUuid() const;
-
enum Severity {
Unset = 0, // never to be used
Info, // we start at 1 to avoid using proto default values
@@ -59,34 +59,30 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
// created a new subchannel, then it would record that with a TraceEvent
// referencing the new subchannel.
//
- // TODO(ncteisen): Once channelz is implemented, the events should reference
- // the overall channelz object, not just the ChannelTrace object.
// TODO(ncteisen): as this call is used more and more throughout the gRPC
// stack, determine if it makes more sense to accept a char* instead of a
// slice.
void AddTraceEventReferencingChannel(
Severity severity, grpc_slice data,
- RefCountedPtr<ChannelTrace> referenced_tracer);
+ RefCountedPtr<ChannelNode> referenced_channel);
void AddTraceEventReferencingSubchannel(
Severity severity, grpc_slice data,
- RefCountedPtr<ChannelTrace> referenced_tracer);
+ RefCountedPtr<ChannelNode> referenced_subchannel);
- // Returns the tracing data rendered as a grpc json string.
- // The string is owned by the caller and must be freed.
- char* RenderTrace() const;
+ // Creates and returns the raw grpc_json object, so a parent channelz
+ // object may incorporate the json before rendering.
+ grpc_json* RenderJSON() const;
private:
// Types of objects that can be references by trace events.
- enum ReferencedType { Channel, Subchannel };
+ enum class ReferencedType { Channel, Subchannel };
// Private class to encapsulate all the data and bookkeeping needed for a
// a trace event.
class TraceEvent {
public:
// Constructor for a TraceEvent that references a different channel.
- // TODO(ncteisen): once channelz is implemented, this should reference the
- // overall channelz object, not just the ChannelTrace object
TraceEvent(Severity severity, grpc_slice data,
- RefCountedPtr<ChannelTrace> referenced_tracer,
+ RefCountedPtr<ChannelNode> referenced_channel,
ReferencedType type);
// Constructor for a TraceEvent that does not reverence a different
@@ -109,7 +105,7 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
gpr_timespec timestamp_;
TraceEvent* next_;
// the tracer object for the (sub)channel that this trace event refers to.
- RefCountedPtr<ChannelTrace> referenced_tracer_;
+ RefCountedPtr<ChannelNode> referenced_channel_;
// the type that the referenced tracer points to. Unused if this trace
// does not point to any channel or subchannel
ReferencedType referenced_type_;
@@ -119,7 +115,6 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
void AddTraceEventHelper(TraceEvent* new_trace_event);
gpr_mu tracer_mu_;
- intptr_t channel_uuid_;
uint64_t num_events_logged_;
size_t list_size_;
size_t max_list_size_;
@@ -128,6 +123,7 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
gpr_timespec time_created_;
};
+} // namespace channelz
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */
diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc
new file mode 100644
index 0000000000..3550fc0551
--- /dev/null
+++ b/src/core/lib/channel/channelz.cc
@@ -0,0 +1,185 @@
+/*
+ *
+ * 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"
+
+namespace grpc_core {
+namespace channelz {
+
+namespace {
+
+// TODO(ncteisen): move this function to a common helper location.
+//
+// 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,
+ int64_t num) {
+ char* num_str;
+ gpr_asprintf(&num_str, "%" PRId64, num);
+ return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING,
+ true);
+}
+
+} // namespace
+
+ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes)
+ : channel_(channel), target_(nullptr), channel_uuid_(-1) {
+ trace_.Init(channel_tracer_max_nodes);
+ target_ = UniquePtr<char>(grpc_channel_get_target(channel_));
+ channel_uuid_ = ChannelzRegistry::Register(this);
+ gpr_atm_no_barrier_store(&last_call_started_millis_,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+ChannelNode::~ChannelNode() {
+ trace_.Destroy();
+ ChannelzRegistry::Unregister(channel_uuid_);
+}
+
+void ChannelNode::RecordCallStarted() {
+ gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1);
+ gpr_atm_no_barrier_store(&last_call_started_millis_,
+ (gpr_atm)ExecCtx::Get()->Now());
+}
+
+grpc_connectivity_state ChannelNode::GetConnectivityState() {
+ if (channel_ == nullptr) {
+ return GRPC_CHANNEL_SHUTDOWN;
+ } else {
+ return grpc_channel_check_connectivity_state(channel_, false);
+ }
+}
+
+char* 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 = 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.
+ grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = data;
+ json_iterator = nullptr;
+ // create and fill the connectivity state child.
+ grpc_connectivity_state connectivity_state = GetConnectivityState();
+ json_iterator = grpc_json_create_child(json_iterator, json, "state", nullptr,
+ GRPC_JSON_OBJECT, false);
+ json = json_iterator;
+ grpc_json_create_child(nullptr, json, "state",
+ grpc_connectivity_state_name(connectivity_state),
+ GRPC_JSON_STRING, false);
+ // reset the parent to be the data object.
+ json = data;
+ json_iterator = grpc_json_create_child(
+ json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false);
+ // fill in the channel trace if applicable
+ grpc_json* trace = trace_->RenderJSON();
+ if (trace != nullptr) {
+ // we manuall link up and fill the child since it was created for us in
+ // ChannelTrace::RenderJSON
+ json_iterator = grpc_json_link_child(json, trace, json_iterator);
+ trace->parent = json;
+ trace->value = nullptr;
+ trace->key = "trace";
+ trace->owns_value = false;
+ }
+ // reset the parent to be the data object.
+ json = data;
+ json_iterator = nullptr;
+ // We use -1 as sentinel values since proto default value for integers is
+ // zero, and the confuses the parser into thinking the value weren't present
+ json_iterator =
+ 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_);
+ gpr_timespec ts =
+ grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME);
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp",
+ fmt_time(ts), GRPC_JSON_STRING, true);
+ // 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..2aad1e82f4
--- /dev/null
+++ b/src/core/lib/channel/channelz.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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/lib/channel/channel_trace.h"
+#include "src/core/lib/gprpp/manual_constructor.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/iomgr/exec_ctx.h"
+#include "src/core/lib/json/json.h"
+
+namespace grpc_core {
+namespace channelz {
+
+namespace testing {
+class ChannelNodePeer;
+}
+
+class ChannelNode : public RefCounted<ChannelNode> {
+ public:
+ ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes);
+ ~ChannelNode();
+
+ void RecordCallStarted();
+ void RecordCallFailed() {
+ gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1)));
+ }
+ void RecordCallSucceeded() {
+ gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1)));
+ }
+
+ char* RenderJSON();
+
+ ChannelTrace* trace() { return trace_.get(); }
+
+ void set_channel_destroyed() {
+ GPR_ASSERT(channel_ != nullptr);
+ channel_ = nullptr;
+ }
+
+ intptr_t channel_uuid() { return channel_uuid_; }
+
+ private:
+ // testing peer friend.
+ friend class testing::ChannelNodePeer;
+
+ // helper for getting connectivity state.
+ grpc_connectivity_state GetConnectivityState();
+
+ grpc_channel* channel_ = nullptr;
+ UniquePtr<char> target_;
+ gpr_atm calls_started_ = 0;
+ gpr_atm calls_succeeded_ = 0;
+ gpr_atm calls_failed_ = 0;
+ gpr_atm last_call_started_millis_ = 0;
+ intptr_t channel_uuid_;
+ ManualConstructor<ChannelTrace> trace_;
+};
+
+} // 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 135a128aae..556eb234b4 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -489,6 +489,12 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
&call->pollent);
}
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(call->channel);
+ if (channelz_channel != nullptr) {
+ channelz_channel->RecordCallStarted();
+ }
+
grpc_slice_unref_internal(path);
return error;
@@ -531,7 +537,6 @@ static void release_call(void* call, grpc_error* error) {
GRPC_CHANNEL_INTERNAL_UNREF(channel, "call");
}
-static void set_status_value_directly(grpc_status_code status, void* dest);
static void destroy_call(void* call, grpc_error* error) {
GPR_TIMER_SCOPE("destroy_call", 0);
size_t i;
@@ -1087,13 +1092,12 @@ 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;
+ if (status_code != GRPC_STATUS_OK) {
+ 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,
@@ -1260,6 +1264,15 @@ static void post_batch_completion(batch_control* bctl) {
get_final_status(call, set_cancelled_value,
call->final_op.server.cancelled, nullptr, nullptr);
}
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(call->channel);
+ if (channelz_channel != nullptr) {
+ if (*call->final_op.client.status != GRPC_STATUS_OK) {
+ channelz_channel->RecordCallFailed();
+ } else {
+ channelz_channel->RecordCallSucceeded();
+ }
+ }
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc
index a466b325be..d5d75fcb2a 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"
@@ -66,7 +67,7 @@ struct grpc_channel {
gpr_mu registered_call_mu;
registered_call* registered_calls;
- grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer;
+ grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
char* target;
};
@@ -103,6 +104,7 @@ grpc_channel* grpc_channel_create_with_builder(
channel->target = target;
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
size_t channel_tracer_max_nodes = 0; // default to off
+ bool channelz_enabled = false;
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = nullptr;
@@ -141,15 +143,20 @@ grpc_channel* grpc_channel_create_with_builder(
const grpc_integer_options options = {0, 0, INT_MAX};
channel_tracer_max_nodes =
(size_t)grpc_channel_arg_get_integer(&args->args[i], options);
+ } else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) {
+ channelz_enabled = grpc_channel_arg_get_bool(&args->args[i], false);
}
}
grpc_channel_args_destroy(args);
- channel->tracer = grpc_core::MakeRefCounted<grpc_core::ChannelTrace>(
- channel_tracer_max_nodes);
- channel->tracer->AddTraceEvent(
- grpc_core::ChannelTrace::Severity::Info,
- grpc_slice_from_static_string("Channel created"));
+ if (channelz_enabled) {
+ channel->channelz_channel =
+ grpc_core::MakeRefCounted<grpc_core::channelz::ChannelNode>(
+ channel, channel_tracer_max_nodes);
+ channel->channelz_channel->trace()->AddTraceEvent(
+ grpc_core::channelz::ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("Channel created"));
+ }
return channel;
}
@@ -184,12 +191,9 @@ static grpc_channel_args* build_channel_args(
return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
}
-char* grpc_channel_get_trace(grpc_channel* channel) {
- return channel->tracer->RenderTrace();
-}
-
-intptr_t grpc_channel_get_uuid(grpc_channel* channel) {
- return channel->tracer->GetUuid();
+grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
+ grpc_channel* channel) {
+ return channel->channelz_channel.get();
}
grpc_channel* grpc_channel_create(const char* target,
@@ -395,6 +399,10 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
static void destroy_channel(void* arg, grpc_error* error) {
grpc_channel* channel = static_cast<grpc_channel*>(arg);
+ if (channel->channelz_channel != nullptr) {
+ channel->channelz_channel->set_channel_destroyed();
+ channel->channelz_channel.reset();
+ }
grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
while (channel->registered_calls) {
registered_call* rc = channel->registered_calls;
@@ -403,7 +411,6 @@ static void destroy_channel(void* arg, grpc_error* error) {
GRPC_MDELEM_UNREF(rc->authority);
gpr_free(rc);
}
- channel->tracer.reset();
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
gpr_free(channel);
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 288313951e..e5ff2c3596 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,9 @@ 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::ChannelNode* grpc_channel_get_channelz_node(
+ grpc_channel* channel);
+
/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
status_code.
diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto
index 14db66a654..d930dfcfb4 100644
--- a/src/proto/grpc/channelz/channelz.proto
+++ b/src/proto/grpc/channelz/channelz.proto
@@ -1,4 +1,4 @@
-// Copyright 2018 gRPC authors.
+// Copyright 2018 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,20 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// This file defines an interface for exporting monitoring information
+// out of gRPC servers. See the full design at
+// https://github.com/grpc/proposal/blob/master/A14-channelz.md
+//
+// The canonical version of this proto can be found at
+// https://github.com/grpc/grpc-proto/blob/master/grpc/channelz/v1/channelz.proto
+
syntax = "proto3";
-package grpc.channelz;
+package grpc.channelz.v1;
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
-// See go/grpc-channelz.
+option go_package = "google.golang.org/grpc/channelz/grpc_channelz_v1";
+option java_multiple_files = true;
+option java_package = "io.grpc.channelz.v1";
+option java_outer_classname = "ChannelzProto";
// Channel is a logical grouping of channels, subchannels, and sockets.
message Channel {
- // The identifier for this channel.
+ // The identifier for this channel. This should bet set.
ChannelRef ref = 1;
// Data specific to this channel.
ChannelData data = 2;
@@ -43,7 +53,7 @@ message Channel {
repeated SubchannelRef subchannel_ref = 4;
// There are no ordering guarantees on the order of sockets.
- repeated SocketRef socket = 5;
+ repeated SocketRef socket_ref = 5;
}
// Subchannel is a logical grouping of channels, subchannels, and sockets.
@@ -67,7 +77,7 @@ message Subchannel {
repeated SubchannelRef subchannel_ref = 4;
// There are no ordering guarantees on the order of sockets.
- repeated SocketRef socket = 5;
+ repeated SocketRef socket_ref = 5;
}
// These come from the specified states in this document:
@@ -84,20 +94,23 @@ message ChannelConnectivityState {
State state = 1;
}
+// Channel data is data related to a specific Channel or Subchannel.
message ChannelData {
-
+ // The connectivity state of the channel or subchannel. Implementations
+ // should always set this.
ChannelConnectivityState state = 1;
// The target this channel originally tried to connect to. May be absent
string target = 2;
+ // A trace of recent events on the channel. May be absent.
ChannelTrace trace = 3;
// The number of calls started on the channel
int64 calls_started = 4;
// The number of calls that have completed with an OK status
int64 calls_succeeded = 5;
- // The number of calls that have a completed with a non-OK status
+ // The number of calls that have completed with a non-OK status
int64 calls_failed = 6;
// The last time a call was started on the channel.
@@ -130,26 +143,29 @@ message ChannelTraceEvent {
}
}
+// ChannelTrace represents the recent events that have occurred on the channel.
message ChannelTrace {
// Number of events ever logged in this tracing object. This can differ from
// events.size() because events can be overwritten or garbage collected by
// implementations.
int64 num_events_logged = 1;
// Time that this channel was created.
- google.protobuf.Timestamp creation_time = 2;
+ google.protobuf.Timestamp creation_timestamp = 2;
// List of events that have occurred on this channel.
repeated ChannelTraceEvent events = 3;
}
+// ChannelRef is a reference to a Channel.
message ChannelRef {
// The globally unique id for this channel. Must be a positive number.
int64 channel_id = 1;
// An optional name associated with the channel.
string name = 2;
// Intentionally don't use field numbers from other refs.
- reserved 3, 4, 5, 6;
+ reserved 3, 4, 5, 6, 7, 8;
}
+// ChannelRef is a reference to a Subchannel.
message SubchannelRef {
// The globally unique id for this subchannel. Must be a positive number.
int64 subchannel_id = 7;
@@ -159,6 +175,7 @@ message SubchannelRef {
reserved 1, 2, 3, 4, 5, 6;
}
+// SocketRef is a reference to a Socket.
message SocketRef {
int64 socket_id = 3;
// An optional name associated with the socket.
@@ -167,8 +184,9 @@ message SocketRef {
reserved 1, 2, 5, 6, 7, 8;
}
+// ServerRef is a reference to a Server.
message ServerRef {
- // A globally unique identifier for this server. Must be a positive number.
+ // A globally unique identifier for this server. Must be a positive number.
int64 server_id = 5;
// An optional name associated with the server.
string name = 6;
@@ -176,16 +194,22 @@ message ServerRef {
reserved 1, 2, 3, 4, 7, 8;
}
+// Server represents a single server. There may be multiple servers in a single
+// program.
message Server {
+ // The identifier for a Server. This should be set.
ServerRef ref = 1;
+ // The associated data of the Server.
ServerData data = 2;
// The sockets that the server is listening on. There are no ordering
- // guarantees.
+ // guarantees. This may be absent.
repeated SocketRef listen_socket = 3;
}
+// ServerData is data for a specific Server.
message ServerData {
+ // A trace of recent events on the server. May be absent.
ChannelTrace trace = 1;
// The number of incoming calls started on the server
@@ -201,13 +225,17 @@ message ServerData {
// Information about an actual connection. Pronounced "sock-ay".
message Socket {
+ // The identifier for the Socket.
SocketRef ref = 1;
+ // Data specific to this Socket.
SocketData data = 2;
// The locally bound address.
Address local = 3;
// The remote bound address. May be absent.
Address remote = 4;
+ // Security details for this socket. May be absent if not available, or
+ // there is no security on the socket.
Security security = 5;
// Optional, represents the name of the remote endpoint, if different than
@@ -215,17 +243,23 @@ message Socket {
string remote_name = 6;
}
+// SocketData is data associated for a specific Socket. The fields present
+// are specific to the implementation, so there may be minor differences in
+// the semantics. (e.g. flow control windows)
message SocketData {
// The number of streams that have been started.
int64 streams_started = 1;
- // The number of streams that have ended successfully with the EoS bit set for
- // both end points
+ // The number of streams that have ended successfully:
+ // On client side, received frame with eos bit set;
+ // On server side, sent frame with eos bit set.
int64 streams_succeeded = 2;
- // The number of incoming streams that have a completed with a non-OK status
+ // The number of streams that have ended unsuccessfully:
+ // On client side, ended without receiving frame with eos bit set;
+ // On server side, ended without sending frame with eos bit set.
int64 streams_failed = 3;
-
- // The number of messages successfully sent on this socket.
+ // The number of grpc messages successfully sent on this socket.
int64 messages_sent = 4;
+ // The number of grpc messages received on this socket.
int64 messages_received = 5;
// The number of keep alives sent. This is typically implemented with HTTP/2
@@ -254,12 +288,14 @@ message SocketData {
// include stream level or TCP level flow control info.
google.protobuf.Int64Value remote_flow_control_window = 12;
+ // Socket options set on this socket. May be absent.
repeated SocketOption option = 13;
}
+// Address represents the address used to create the socket.
message Address {
message TcpIpAddress {
- // Either the IPv4 or IPv6 address in bytes. Will either be 4 bytes or 16
+ // Either the IPv4 or IPv6 address in bytes. Will be either 4 bytes or 16
// bytes in length.
bytes ip_address = 1;
// 0-64k, or -1 if not appropriate.
@@ -271,7 +307,7 @@ message Address {
}
// An address type not included above.
message OtherAddress {
- // The human readable version of the value.
+ // The human readable version of the value. This value should be set.
string name = 1;
// The actual address message.
google.protobuf.Any value = 2;
@@ -284,12 +320,17 @@ message Address {
}
}
+// Security represents details about how secure the socket is.
message Security {
message Tls {
- // The key exchange used. e.g. X25519
- string key_exchange = 1;
- // The cipher used. e.g. AES_128_GCM.
- string cipher = 2;
+ oneof cipher_suite {
+ // The cipher suite name in the RFC 4346 format:
+ // https://tools.ietf.org/html/rfc4346#appendix-C
+ string standard_name = 1;
+ // Some other way to describe the cipher suite if
+ // the RFC 4346 name is not available.
+ string other_name = 2;
+ }
// the certificate used by this endpoint.
bytes local_certificate = 3;
// the certificate used by the remote endpoint.
@@ -307,7 +348,11 @@ message Security {
}
}
+// SocketOption represents socket options for a socket. Specifically, these
+// are the options returned by getsockopt().
message SocketOption {
+ // The full name of the socket option. Typically this will be the upper case
+ // name, such as "SO_REUSEPORT".
string name = 1;
// The human readable value of this socket option. At least one of value or
// additional will be set.
@@ -323,12 +368,17 @@ message SocketOptionTimeout {
google.protobuf.Duration duration = 1;
}
+// For use with SocketOption's additional field. This is primarily used for
+// SO_LINGER.
message SocketOptionLinger {
+ // active maps to `struct linger.l_onoff`
bool active = 1;
+ // duration maps to `struct linger.l_linger`
google.protobuf.Duration duration = 2;
}
-// Tcp info for SOL_TCP, TCP_INFO
+// For use with SocketOption's additional field. Tcp info for
+// SOL_TCP and TCP_INFO.
message SocketOptionTcpInfo {
uint32 tcpi_state = 1;
@@ -366,8 +416,10 @@ message SocketOptionTcpInfo {
uint32 tcpi_reordering = 29;
}
+// Channelz is a service exposed by gRPC servers that provides detailed debug
+// information.
service Channelz {
- // Gets all root channels (e.g. channels the application has directly
+ // Gets all root channels (i.e. channels the application has directly
// created). This does not include subchannels nor non-top level channels.
rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse);
// Gets all servers that exist in the process.
@@ -382,6 +434,22 @@ service Channelz {
rpc GetSocket(GetSocketRequest) returns (GetSocketResponse);
}
+message GetTopChannelsRequest {
+ // start_channel_id indicates that only channels at or above this id should be
+ // included in the results.
+ int64 start_channel_id = 1;
+}
+
+message GetTopChannelsResponse {
+ // list of channels that the connection detail service knows about. Sorted in
+ // ascending channel_id order.
+ repeated Channel channel = 1;
+ // If set, indicates that the list of channels is the final list. Requesting
+ // more channels can only return more if they are created after this RPC
+ // completes.
+ bool end = 2;
+}
+
message GetServersRequest {
// start_server_id indicates that only servers at or above this id should be
// included in the results.
@@ -415,42 +483,35 @@ message GetServerSocketsResponse {
bool end = 2;
}
-message GetTopChannelsRequest {
- // start_channel_id indicates that only channels at or above this id should be
- // included in the results.
- int64 start_channel_id = 1;
-}
-
-message GetTopChannelsResponse {
- // list of channels that the connection detail service knows about. Sorted in
- // ascending channel_id order.
- repeated Channel channel = 1;
- // If set, indicates that the list of channels is the final list. Requesting
- // more channels can only return more if they are created after this RPC
- // completes.
- bool end = 2;
-}
-
message GetChannelRequest {
+ // channel_id is the identifier of the specific channel to get.
int64 channel_id = 1;
}
message GetChannelResponse {
+ // The Channel that corresponds to the requested channel_id. This field
+ // should be set.
Channel channel = 1;
}
message GetSubchannelRequest {
+ // subchannel_id is the identifier of the specific subchannel to get.
int64 subchannel_id = 1;
}
message GetSubchannelResponse {
+ // The Subchannel that corresponds to the requested subchannel_id. This
+ // field should be set.
Subchannel subchannel = 1;
}
message GetSocketRequest {
+ // socket_id is the identifier of the specific socket to get.
int64 socket_id = 1;
}
message GetSocketResponse {
+ // The Socket that corresponds to the requested socket_id. This field
+ // should be set.
Socket socket = 1;
}
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index f53a6c9be2..b20b8155a0 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -64,6 +64,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.cc',
+ 'src/core/lib/channel/channelz.cc',
'src/core/lib/channel/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
index 8ec2073d98..7b39f5a347 100755
--- a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
+++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
@@ -58,10 +58,6 @@ def main
run_multiple_killed_watches(10, 0.1)
STDERR.puts '1000 iterations, sleep 0.001 before killing thread'
run_multiple_killed_watches(1000, 0.001)
- STDERR.puts '10000 iterations, sleep 0.00001 before killing thread'
- run_multiple_killed_watches(10_000, 0.00001)
- STDERR.puts '20000 iterations, sleep 0.00001 before killing thread'
- run_multiple_killed_watches(20_000, 0.00001)
end
main
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 02f84c0b96..031699ce8e 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -68,8 +68,6 @@ grpc_channel_get_info_type grpc_channel_get_info_import;
grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
grpc_channel_destroy_type grpc_channel_destroy_import;
-grpc_channel_get_trace_type grpc_channel_get_trace_import;
-grpc_channel_get_uuid_type grpc_channel_get_uuid_import;
grpc_call_cancel_type grpc_call_cancel_import;
grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
grpc_call_ref_type grpc_call_ref_import;
@@ -316,8 +314,6 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create");
grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create");
grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy");
- grpc_channel_get_trace_import = (grpc_channel_get_trace_type) GetProcAddress(library, "grpc_channel_get_trace");
- grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid");
grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel");
grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status");
grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 46d3bf5a33..474405ae3f 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -179,12 +179,6 @@ extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_impo
typedef void(*grpc_channel_destroy_type)(grpc_channel* channel);
extern grpc_channel_destroy_type grpc_channel_destroy_import;
#define grpc_channel_destroy grpc_channel_destroy_import
-typedef char*(*grpc_channel_get_trace_type)(grpc_channel* channel);
-extern grpc_channel_get_trace_type grpc_channel_get_trace_import;
-#define grpc_channel_get_trace grpc_channel_get_trace_import
-typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel);
-extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import;
-#define grpc_channel_get_uuid grpc_channel_get_uuid_import
typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved);
extern grpc_call_cancel_type grpc_call_cancel_import;
#define grpc_call_cancel grpc_call_cancel_import
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD
index e5a9e36457..da419f00cf 100644
--- a/test/core/channel/BUILD
+++ b/test/core/channel/BUILD
@@ -84,6 +84,23 @@ grpc_cc_test(
)
grpc_cc_test(
+ name = "channelz_test",
+ srcs = ["channelz_test.cc"],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:channel_trace_proto_helper",
+ ],
+ external_deps = [
+ "gtest",
+ ],
+)
+
+grpc_cc_test(
name = "channelz_registry_test",
srcs = ["channelz_registry_test.cc"],
language = "C++",
diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc
index d99a32d91d..bbddee3f14 100644
--- a/test/core/channel/channel_trace_test.cc
+++ b/test/core/channel/channel_trace_test.cc
@@ -25,6 +25,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@@ -39,6 +40,7 @@
#include <string.h>
namespace grpc_core {
+namespace channelz {
namespace testing {
namespace {
@@ -69,7 +71,7 @@ void ValidateChannelTraceData(grpc_json* json,
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, "creationTime");
+ grpc_json* start_time = GetJsonChild(json, "creationTimestamp");
ASSERT_NE(start_time, nullptr);
size_t num_events_logged =
(size_t)strtol(num_events_logged_json->value, nullptr, 0);
@@ -77,35 +79,47 @@ void ValidateChannelTraceData(grpc_json* json,
ValidateJsonArraySize(json, "events", actual_num_events_expected);
}
-void AddSimpleTrace(const RefCountedPtr<ChannelTrace>& tracer) {
+void AddSimpleTrace(ChannelTrace* tracer) {
tracer->AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("simple trace"));
}
// checks for the existence of all the required members of the tracer.
-void ValidateChannelTrace(const RefCountedPtr<ChannelTrace>& tracer,
+void ValidateChannelTrace(ChannelTrace* tracer,
size_t expected_num_event_logged, size_t max_nodes) {
if (!max_nodes) return;
- char* json_str = tracer->RenderTrace();
+ 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* json = grpc_json_parse_string(json_str);
- ValidateChannelTraceData(json, expected_num_event_logged,
+ grpc_json* parsed_json = grpc_json_parse_string(json_str);
+ ValidateChannelTraceData(parsed_json, expected_num_event_logged,
GPR_MIN(expected_num_event_logged, max_nodes));
- grpc_json_destroy(json);
+ grpc_json_destroy(parsed_json);
gpr_free(json_str);
}
-void ValidateTraceDataMatchedUuidLookup(
- const RefCountedPtr<ChannelTrace>& tracer) {
- intptr_t uuid = tracer->GetUuid();
- if (uuid == -1) return; // Doesn't make sense to lookup if tracing disabled
- char* tracer_json_str = tracer->RenderTrace();
- ChannelTrace* uuid_lookup = ChannelzRegistry::Get<ChannelTrace>(uuid);
- char* uuid_lookup_json_str = uuid_lookup->RenderTrace();
- EXPECT_EQ(strcmp(tracer_json_str, uuid_lookup_json_str), 0);
- gpr_free(tracer_json_str);
- gpr_free(uuid_lookup_json_str);
-}
+class ChannelFixture {
+ public:
+ ChannelFixture(int max_trace_nodes) {
+ grpc_arg client_a;
+ client_a.type = GRPC_ARG_INTEGER;
+ client_a.key =
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
+ client_a.value.integer = max_trace_nodes;
+ grpc_channel_args client_args = {1, &client_a};
+ channel_ =
+ grpc_insecure_channel_create("fake_target", &client_args, nullptr);
+ }
+
+ ~ChannelFixture() { grpc_channel_destroy(channel_); }
+
+ grpc_channel* channel() { return channel_; }
+
+ private:
+ grpc_channel* channel_;
+};
} // anonymous namespace
@@ -115,25 +129,22 @@ class ChannelTracerTest : public ::testing::TestWithParam<size_t> {};
// lookups by uuid.
TEST_P(ChannelTracerTest, BasicTest) {
grpc_core::ExecCtx exec_ctx;
- RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateTraceDataMatchedUuidLookup(tracer);
- tracer->AddTraceEvent(ChannelTrace::Severity::Info,
- grpc_slice_from_static_string("trace three"));
- tracer->AddTraceEvent(ChannelTrace::Severity::Error,
- grpc_slice_from_static_string("trace four error"));
- ValidateChannelTrace(tracer, 4, GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateChannelTrace(tracer, 6, GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateChannelTrace(tracer, 10, GetParam());
- ValidateTraceDataMatchedUuidLookup(tracer);
- tracer.reset(nullptr);
+ ChannelTrace tracer(GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ tracer.AddTraceEvent(ChannelTrace::Severity::Info,
+ grpc_slice_from_static_string("trace three"));
+ tracer.AddTraceEvent(ChannelTrace::Severity::Error,
+ grpc_slice_from_static_string("trace four error"));
+ ValidateChannelTrace(&tracer, 4, GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, 6, GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, 10, GetParam());
}
// Tests more complex functionality, like a parent channel tracking
@@ -141,42 +152,43 @@ TEST_P(ChannelTracerTest, BasicTest) {
// and this function will both hold refs to the subchannel.
TEST_P(ChannelTracerTest, ComplexTest) {
grpc_core::ExecCtx exec_ctx;
- RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam());
- tracer->AddTraceEventReferencingSubchannel(
+ ChannelTrace tracer(GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ChannelFixture channel1(GetParam());
+ RefCountedPtr<ChannelNode> sc1 =
+ MakeRefCounted<ChannelNode>(channel1.channel(), GetParam());
+ tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
- ValidateChannelTrace(tracer, 3, GetParam());
- AddSimpleTrace(sc1);
- AddSimpleTrace(sc1);
- AddSimpleTrace(sc1);
- ValidateChannelTrace(sc1, 3, GetParam());
- AddSimpleTrace(sc1);
- AddSimpleTrace(sc1);
- AddSimpleTrace(sc1);
- ValidateChannelTrace(sc1, 6, GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateChannelTrace(tracer, 5, GetParam());
- ValidateTraceDataMatchedUuidLookup(tracer);
- RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam());
- tracer->AddTraceEventReferencingChannel(
+ ValidateChannelTrace(&tracer, 3, GetParam());
+ AddSimpleTrace(sc1->trace());
+ AddSimpleTrace(sc1->trace());
+ AddSimpleTrace(sc1->trace());
+ ValidateChannelTrace(sc1->trace(), 3, GetParam());
+ AddSimpleTrace(sc1->trace());
+ AddSimpleTrace(sc1->trace());
+ AddSimpleTrace(sc1->trace());
+ ValidateChannelTrace(sc1->trace(), 6, GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, 5, GetParam());
+ ChannelFixture channel2(GetParam());
+ RefCountedPtr<ChannelNode> sc2 =
+ MakeRefCounted<ChannelNode>(channel2.channel(), GetParam());
+ tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("LB channel two created"), sc2);
- tracer->AddTraceEventReferencingSubchannel(
+ tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
- ValidateChannelTrace(tracer, 7, GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateTraceDataMatchedUuidLookup(tracer);
- tracer.reset(nullptr);
+ ValidateChannelTrace(&tracer, 7, GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
sc1.reset(nullptr);
sc2.reset(nullptr);
}
@@ -186,39 +198,44 @@ TEST_P(ChannelTracerTest, ComplexTest) {
// gets deleted.
TEST_P(ChannelTracerTest, TestNesting) {
grpc_core::ExecCtx exec_ctx;
- RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam());
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateChannelTrace(tracer, 2, GetParam());
- RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam());
- tracer->AddTraceEventReferencingChannel(
+ ChannelTrace tracer(GetParam());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, 2, GetParam());
+ ChannelFixture channel1(GetParam());
+ RefCountedPtr<ChannelNode> sc1 =
+ MakeRefCounted<ChannelNode>(channel1.channel(), GetParam());
+ tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1);
- ValidateChannelTrace(tracer, 3, GetParam());
- AddSimpleTrace(sc1);
- RefCountedPtr<ChannelTrace> conn1 = MakeRefCounted<ChannelTrace>(GetParam());
+ ValidateChannelTrace(&tracer, 3, GetParam());
+ AddSimpleTrace(sc1->trace());
+ ChannelFixture channel2(GetParam());
+ RefCountedPtr<ChannelNode> conn1 =
+ MakeRefCounted<ChannelNode>(channel2.channel(), GetParam());
// nesting one level deeper.
- sc1->AddTraceEventReferencingSubchannel(
+ sc1->trace()->AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("connection one created"), conn1);
- ValidateChannelTrace(tracer, 3, GetParam());
- AddSimpleTrace(conn1);
- AddSimpleTrace(tracer);
- AddSimpleTrace(tracer);
- ValidateChannelTrace(tracer, 5, GetParam());
- ValidateChannelTrace(conn1, 1, GetParam());
- RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam());
- tracer->AddTraceEventReferencingSubchannel(
+ ValidateChannelTrace(&tracer, 3, GetParam());
+ AddSimpleTrace(conn1->trace());
+ AddSimpleTrace(&tracer);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, 5, GetParam());
+ ValidateChannelTrace(conn1->trace(), 1, GetParam());
+ ChannelFixture channel3(GetParam());
+ RefCountedPtr<ChannelNode> sc2 =
+ MakeRefCounted<ChannelNode>(channel3.channel(), GetParam());
+ tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel two created"), sc2);
// this trace should not get added to the parents children since it is already
// present in the tracer.
- tracer->AddTraceEventReferencingChannel(
+ tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1);
- AddSimpleTrace(tracer);
- ValidateChannelTrace(tracer, 8, GetParam());
- tracer.reset(nullptr);
+ AddSimpleTrace(&tracer);
+ ValidateChannelTrace(&tracer, 8, GetParam());
sc1.reset(nullptr);
sc2.reset(nullptr);
conn1.reset(nullptr);
@@ -228,6 +245,7 @@ INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest,
::testing::Values(0, 1, 2, 6, 10, 15));
} // namespace testing
+} // namespace channelz
} // namespace grpc_core
int main(int argc, char** argv) {
diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc
new file mode 100644
index 0000000000..058eea914c
--- /dev/null
+++ b/test/core/channel/channelz_test.cc
@@ -0,0 +1,216 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_trace.h"
+#include "src/core/lib/channel/channelz.h"
+#include "src/core/lib/channel/channelz_registry.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/surface/channel.h"
+
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/channel_trace_proto_helper.h"
+
+#include <grpc/support/string_util.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace grpc_core {
+namespace channelz {
+namespace testing {
+
+// testing peer to access channel internals
+class ChannelNodePeer {
+ public:
+ ChannelNodePeer(ChannelNode* channel) : channel_(channel) {}
+ grpc_millis last_call_started_millis() {
+ return (grpc_millis)gpr_atm_no_barrier_load(
+ &channel_->last_call_started_millis_);
+ }
+
+ private:
+ ChannelNode* channel_;
+};
+
+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;
+ }
+ return nullptr;
+}
+
+class ChannelFixture {
+ public:
+ ChannelFixture(int max_trace_nodes) {
+ grpc_arg client_a[2];
+ client_a[0].type = GRPC_ARG_INTEGER;
+ client_a[0].key =
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
+ client_a[0].value.integer = max_trace_nodes;
+ client_a[1].type = GRPC_ARG_INTEGER;
+ client_a[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
+ client_a[1].value.integer = true;
+ grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
+ channel_ =
+ grpc_insecure_channel_create("fake_target", &client_args, nullptr);
+ }
+
+ ~ChannelFixture() { grpc_channel_destroy(channel_); }
+
+ grpc_channel* channel() { return channel_; }
+
+ private:
+ grpc_channel* channel_;
+};
+
+struct validate_channel_data_args {
+ 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);
+ ASSERT_NE(gotten_json, nullptr);
+ int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0);
+ EXPECT_EQ(gotten_number, expect);
+}
+
+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 ValidateChannel(ChannelNode* channel, validate_channel_data_args args) {
+ char* json_str = channel->RenderJSON();
+ grpc::testing::ValidateChannelProtoJsonTranslation(json_str);
+ ValidateCounters(json_str, args);
+ gpr_free(json_str);
+}
+
+grpc_millis GetLastCallStartedMillis(ChannelNode* channel) {
+ ChannelNodePeer peer(channel);
+ return peer.last_call_started_millis();
+}
+
+void ChannelzSleep(int64_t sleep_us) {
+ gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_micros(sleep_us, GPR_TIMESPAN)));
+ grpc_core::ExecCtx::Get()->InvalidateNow();
+}
+
+} // anonymous namespace
+
+class ChannelzChannelTest : public ::testing::TestWithParam<size_t> {};
+
+TEST_P(ChannelzChannelTest, BasicChannel) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channel(GetParam());
+ ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(channel.channel());
+ char* json_str = channelz_channel->RenderJSON();
+ ValidateCounters(json_str, {0, 0, 0});
+ gpr_free(json_str);
+}
+
+TEST(ChannelzChannelTest, ChannelzDisabled) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_channel* channel =
+ grpc_insecure_channel_create("fake_target", nullptr, nullptr);
+ ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel);
+ ASSERT_EQ(channelz_channel, nullptr);
+ grpc_channel_destroy(channel);
+}
+
+TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channel(GetParam());
+ ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(channel.channel());
+ channelz_channel->RecordCallStarted();
+ channelz_channel->RecordCallFailed();
+ channelz_channel->RecordCallSucceeded();
+ ValidateChannel(channelz_channel, {1, 1, 1});
+ channelz_channel->RecordCallStarted();
+ channelz_channel->RecordCallFailed();
+ channelz_channel->RecordCallSucceeded();
+ channelz_channel->RecordCallStarted();
+ channelz_channel->RecordCallFailed();
+ channelz_channel->RecordCallSucceeded();
+ ValidateChannel(channelz_channel, {3, 3, 3});
+}
+
+TEST_P(ChannelzChannelTest, LastCallStartedMillis) {
+ grpc_core::ExecCtx exec_ctx;
+ ChannelFixture channel(GetParam());
+ ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(channel.channel());
+ // start a call to set the last call started timestamp
+ channelz_channel->RecordCallStarted();
+ grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel);
+ // time gone by should not affect the timestamp
+ ChannelzSleep(100);
+ grpc_millis millis2 = GetLastCallStartedMillis(channelz_channel);
+ EXPECT_EQ(millis1, millis2);
+ // calls succeeded or failed should not affect the timestamp
+ ChannelzSleep(100);
+ channelz_channel->RecordCallFailed();
+ channelz_channel->RecordCallSucceeded();
+ grpc_millis millis3 = GetLastCallStartedMillis(channelz_channel);
+ EXPECT_EQ(millis1, millis3);
+ // another call started should affect the timestamp
+ // sleep for extra long to avoid flakes (since we cache Now())
+ ChannelzSleep(5000);
+ channelz_channel->RecordCallStarted();
+ grpc_millis millis4 = GetLastCallStartedMillis(channelz_channel);
+ EXPECT_NE(millis1, millis4);
+}
+
+INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest,
+ ::testing::Values(0, 1, 2, 6, 10, 15));
+
+} // namespace testing
+} // namespace channelz
+} // namespace grpc_core
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ grpc_init();
+ ::testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ grpc_shutdown();
+ return ret;
+}
diff --git a/test/core/end2end/end2end_nosec_tests.cc b/test/core/end2end/end2end_nosec_tests.cc
index a70128254a..061b23b5d6 100644
--- a/test/core/end2end/end2end_nosec_tests.cc
+++ b/test/core/end2end/end2end_nosec_tests.cc
@@ -54,6 +54,8 @@ extern void cancel_in_a_vacuum(grpc_end2end_test_config config);
extern void cancel_in_a_vacuum_pre_init(void);
extern void cancel_with_status(grpc_end2end_test_config config);
extern void cancel_with_status_pre_init(void);
+extern void channelz(grpc_end2end_test_config config);
+extern void channelz_pre_init(void);
extern void compressed_payload(grpc_end2end_test_config config);
extern void compressed_payload_pre_init(void);
extern void connectivity(grpc_end2end_test_config config);
@@ -201,6 +203,7 @@ void grpc_end2end_tests_pre_init(void) {
cancel_before_invoke_pre_init();
cancel_in_a_vacuum_pre_init();
cancel_with_status_pre_init();
+ channelz_pre_init();
compressed_payload_pre_init();
connectivity_pre_init();
default_host_pre_init();
@@ -287,6 +290,7 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_before_invoke(config);
cancel_in_a_vacuum(config);
cancel_with_status(config);
+ channelz(config);
compressed_payload(config);
connectivity(config);
default_host(config);
@@ -404,6 +408,10 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_with_status(config);
continue;
}
+ if (0 == strcmp("channelz", argv[i])) {
+ channelz(config);
+ continue;
+ }
if (0 == strcmp("compressed_payload", argv[i])) {
compressed_payload(config);
continue;
diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc
index bf75dd4579..7ae475cdef 100644
--- a/test/core/end2end/end2end_tests.cc
+++ b/test/core/end2end/end2end_tests.cc
@@ -56,6 +56,8 @@ extern void cancel_in_a_vacuum(grpc_end2end_test_config config);
extern void cancel_in_a_vacuum_pre_init(void);
extern void cancel_with_status(grpc_end2end_test_config config);
extern void cancel_with_status_pre_init(void);
+extern void channelz(grpc_end2end_test_config config);
+extern void channelz_pre_init(void);
extern void compressed_payload(grpc_end2end_test_config config);
extern void compressed_payload_pre_init(void);
extern void connectivity(grpc_end2end_test_config config);
@@ -204,6 +206,7 @@ void grpc_end2end_tests_pre_init(void) {
cancel_before_invoke_pre_init();
cancel_in_a_vacuum_pre_init();
cancel_with_status_pre_init();
+ channelz_pre_init();
compressed_payload_pre_init();
connectivity_pre_init();
default_host_pre_init();
@@ -291,6 +294,7 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_before_invoke(config);
cancel_in_a_vacuum(config);
cancel_with_status(config);
+ channelz(config);
compressed_payload(config);
connectivity(config);
default_host(config);
@@ -412,6 +416,10 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_with_status(config);
continue;
}
+ if (0 == strcmp("channelz", argv[i])) {
+ channelz(config);
+ continue;
+ }
if (0 == strcmp("compressed_payload", argv[i])) {
compressed_payload(config);
continue;
diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc
index 6c226818b9..eacfd4a8c3 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.cc
+++ b/test/core/end2end/fuzzers/api_fuzzer.cc
@@ -1046,6 +1046,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
op->reserved = nullptr;
op->flags = grpc_fuzzer_get_next_uint32(&inp);
}
+ if (g_channel == nullptr) ok = false;
if (ok) {
validator* v = make_finished_batch_validator(g_active_call, has_ops);
g_active_call->pending_ops++;
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 1851214191..04dc2a8785 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -106,6 +106,7 @@ END2END_TESTS = {
needs_compression=True),
'connectivity': connectivity_test_options._replace(needs_names=True,
proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
+ 'channelz': default_test_options,
'default_host': default_test_options._replace(
needs_fullstack=True, needs_dns=True, needs_names=True),
'call_host_override': default_test_options._replace(
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 706f4fa86d..67769a8cb1 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -113,6 +113,7 @@ END2END_TESTS = {
'compressed_payload': test_options(proxyable=False, exclude_inproc=True),
'connectivity': test_options(needs_fullstack=True, needs_names=True,
proxyable=False),
+ 'channelz': test_options(),
'default_host': test_options(needs_fullstack=True, needs_dns=True,
needs_names=True),
'disappearing_server': test_options(needs_fullstack=True,needs_names=True),
diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc
new file mode 100644
index 0000000000..eb052119ca
--- /dev/null
+++ b/test/core/end2end/tests/channelz.cc
@@ -0,0 +1,299 @@
+/*
+ *
+ * Copyright 2015 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/lib/surface/channel.h"
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/gpr/string.h"
+#include "test/core/end2end/cq_verifier.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+ const char* test_name,
+ grpc_channel_args* client_args,
+ grpc_channel_args* server_args) {
+ grpc_end2end_test_fixture f;
+ gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+ f = config.create_fixture(client_args, server_args);
+ config.init_server(&f, server_args);
+ config.init_client(&f, client_args);
+ return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+ return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+ return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+ grpc_event ev;
+ do {
+ ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+ } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+ if (!f->server) return;
+ grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+ GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+ grpc_timeout_seconds_to_deadline(5),
+ nullptr)
+ .type == GRPC_OP_COMPLETE);
+ grpc_server_destroy(f->server);
+ f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+ if (!f->client) return;
+ grpc_channel_destroy(f->client);
+ f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+ shutdown_server(f);
+ shutdown_client(f);
+
+ grpc_completion_queue_shutdown(f->cq);
+ drain_cq(f->cq);
+ grpc_completion_queue_destroy(f->cq);
+ grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+static void run_one_request(grpc_end2end_test_config config,
+ grpc_end2end_test_fixture f,
+ bool request_is_success) {
+ grpc_call* c;
+ grpc_call* s;
+ cq_verifier* cqv = cq_verifier_create(f.cq);
+ grpc_op ops[6];
+ grpc_op* op;
+ grpc_metadata_array initial_metadata_recv;
+ grpc_metadata_array trailing_metadata_recv;
+ grpc_metadata_array request_metadata_recv;
+ grpc_call_details call_details;
+ grpc_status_code status;
+ grpc_call_error error;
+ grpc_slice details;
+ int was_cancelled = 2;
+
+ gpr_timespec deadline = five_seconds_from_now();
+ c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+ grpc_slice_from_static_string("/foo"), nullptr,
+ deadline, nullptr);
+ GPR_ASSERT(c);
+
+ grpc_metadata_array_init(&initial_metadata_recv);
+ grpc_metadata_array_init(&trailing_metadata_recv);
+ grpc_metadata_array_init(&request_metadata_recv);
+ grpc_call_details_init(&call_details);
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+ op->data.recv_status_on_client.status = &status;
+ op->data.recv_status_on_client.status_details = &details;
+ op->data.recv_status_on_client.error_string = nullptr;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+ nullptr);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ error =
+ grpc_server_request_call(f.server, &s, &call_details,
+ &request_metadata_recv, f.cq, f.cq, tag(101));
+ GPR_ASSERT(GRPC_CALL_OK == error);
+ CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+ cq_verify(cqv);
+
+ memset(ops, 0, sizeof(ops));
+ op = ops;
+ op->op = GRPC_OP_SEND_INITIAL_METADATA;
+ op->data.send_initial_metadata.count = 0;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op->data.send_status_from_server.trailing_metadata_count = 0;
+ op->data.send_status_from_server.status =
+ request_is_success ? GRPC_STATUS_OK : GRPC_STATUS_UNIMPLEMENTED;
+ grpc_slice status_details = grpc_slice_from_static_string("xyz");
+ op->data.send_status_from_server.status_details = &status_details;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ op->data.recv_close_on_server.cancelled = &was_cancelled;
+ op->flags = 0;
+ op->reserved = nullptr;
+ op++;
+ error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+ nullptr);
+ GPR_ASSERT(GRPC_CALL_OK == error);
+
+ CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+ CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+ cq_verify(cqv);
+
+ GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+ GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+ GPR_ASSERT(0 == call_details.flags);
+
+ grpc_slice_unref(details);
+ grpc_metadata_array_destroy(&initial_metadata_recv);
+ grpc_metadata_array_destroy(&trailing_metadata_recv);
+ grpc_metadata_array_destroy(&request_metadata_recv);
+ grpc_call_details_destroy(&call_details);
+
+ grpc_call_unref(c);
+ grpc_call_unref(s);
+
+ cq_verifier_destroy(cqv);
+}
+
+static void test_channelz(grpc_end2end_test_config config) {
+ grpc_end2end_test_fixture f;
+
+ grpc_arg client_a;
+ client_a.type = GRPC_ARG_INTEGER;
+ client_a.key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
+ client_a.value.integer = true;
+ grpc_channel_args client_args = {1, &client_a};
+
+ f = begin_test(config, "test_channelz", &client_args, nullptr);
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(f.client);
+
+ GPR_ASSERT(channelz_channel != nullptr);
+ char* json = channelz_channel->RenderJSON();
+ GPR_ASSERT(json != nullptr);
+ GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\""));
+ gpr_free(json);
+
+ // one successful request
+ run_one_request(config, f, true);
+
+ json = channelz_channel->RenderJSON();
+ GPR_ASSERT(json != nullptr);
+ GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\""));
+ gpr_free(json);
+
+ // one failed request
+ run_one_request(config, f, false);
+
+ json = channelz_channel->RenderJSON();
+ GPR_ASSERT(json != nullptr);
+ gpr_log(GPR_INFO, "%s", json);
+ GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\""));
+ GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\""));
+ // channel tracing is not enables, 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);
+
+ end_test(&f);
+ config.tear_down_data(&f);
+}
+
+static void test_channelz_with_channel_trace(grpc_end2end_test_config config) {
+ grpc_end2end_test_fixture f;
+
+ grpc_arg client_a[2];
+ client_a[0].type = GRPC_ARG_INTEGER;
+ client_a[0].key =
+ const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
+ client_a[0].value.integer = 5;
+ client_a[1].type = GRPC_ARG_INTEGER;
+ client_a[1].key = const_cast<char*>(GRPC_ARG_ENABLE_CHANNELZ);
+ client_a[1].value.integer = true;
+ grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
+
+ f = begin_test(config, "test_channelz_with_channel_trace", &client_args,
+ nullptr);
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(f.client);
+
+ GPR_ASSERT(channelz_channel != nullptr);
+ char* json = channelz_channel->RenderJSON();
+ 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_free(json);
+
+ end_test(&f);
+ config.tear_down_data(&f);
+}
+
+static void test_channelz_disabled(grpc_end2end_test_config config) {
+ grpc_end2end_test_fixture f;
+
+ f = begin_test(config, "test_channelz_disabled", nullptr, nullptr);
+ grpc_core::channelz::ChannelNode* channelz_channel =
+ grpc_channel_get_channelz_node(f.client);
+ GPR_ASSERT(channelz_channel == nullptr);
+ // one successful request
+ run_one_request(config, f, true);
+ GPR_ASSERT(channelz_channel == nullptr);
+ end_test(&f);
+ config.tear_down_data(&f);
+}
+
+void channelz(grpc_end2end_test_config config) {
+ test_channelz(config);
+ test_channelz_with_channel_trace(config);
+ test_channelz_disabled(config);
+}
+
+void channelz_pre_init(void) {}
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 52a1b03998..29083061bb 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -106,8 +106,6 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_insecure_channel_create);
printf("%lx", (unsigned long) grpc_lame_client_channel_create);
printf("%lx", (unsigned long) grpc_channel_destroy);
- printf("%lx", (unsigned long) grpc_channel_get_trace);
- printf("%lx", (unsigned long) grpc_channel_get_uuid);
printf("%lx", (unsigned long) grpc_call_cancel);
printf("%lx", (unsigned long) grpc_call_cancel_with_status);
printf("%lx", (unsigned long) grpc_call_ref);
diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc
index fbc9f1501c..ee310784c2 100644
--- a/test/cpp/util/channel_trace_proto_helper.cc
+++ b/test/cpp/util/channel_trace_proto_helper.cc
@@ -30,26 +30,47 @@
namespace grpc {
namespace testing {
-void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) {
- std::string tracer_json_str(tracer_json_c_str);
- grpc::channelz::ChannelTrace channel_trace;
+namespace {
+
+// Generic helper that takes in a json string, converts it to a proto, and
+// 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 <typename Message>
+void VaidateProtoJsonTranslation(char* json_c_str) {
+ std::string json_str(json_c_str);
+ Message msg;
google::protobuf::util::JsonParseOptions parse_options;
// If the following line is failing, then uncomment the last line of the
// comment, and uncomment the lines that print the two strings. You can
// then compare the output, and determine what fields are missing.
//
- // options.ignore_unknown_fields = true;
- ASSERT_EQ(google::protobuf::util::JsonStringToMessage(
- tracer_json_str, &channel_trace, parse_options),
+ // parse_options.ignore_unknown_fields = true;
+ EXPECT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg,
+ parse_options),
google::protobuf::util::Status::OK);
std::string proto_json_str;
- ASSERT_EQ(google::protobuf::util::MessageToJsonString(channel_trace,
- &proto_json_str),
+ google::protobuf::util::JsonPrintOptions print_options;
+ // We usually do not want this to be true, however it can be helpful to
+ // uncomment and see the output produced then all fields are printed.
+ // print_options.always_print_primitive_fields = true;
+ EXPECT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str,
+ print_options),
google::protobuf::util::Status::OK);
// uncomment these to compare the the json strings.
- // gpr_log(GPR_ERROR, "tracer json: %s", tracer_json_str.c_str());
+ // gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str());
// gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str());
- ASSERT_EQ(tracer_json_str, proto_json_str);
+ EXPECT_EQ(json_str, proto_json_str);
+}
+
+} // namespace
+
+void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(
+ tracer_json_c_str);
+}
+
+void ValidateChannelProtoJsonTranslation(char* channel_json_c_str) {
+ VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(channel_json_c_str);
}
} // namespace testing
diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h
index d7043d9f06..d1a3603372 100644
--- a/test/cpp/util/channel_trace_proto_helper.h
+++ b/test/cpp/util/channel_trace_proto_helper.h
@@ -23,6 +23,7 @@ namespace grpc {
namespace testing {
void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str);
+void ValidateChannelProtoJsonTranslation(char* channel_json_c_str);
} // namespace testing
} // namespace grpc
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index e552b4ed56..c230d987f9 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1012,6 +1012,7 @@ src/core/lib/channel/channel_args.h \
src/core/lib/channel/channel_stack.h \
src/core/lib/channel/channel_stack_builder.h \
src/core/lib/channel/channel_trace.h \
+src/core/lib/channel/channelz.h \
src/core/lib/channel/channelz_registry.h \
src/core/lib/channel/connected_channel.h \
src/core/lib/channel/context.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 0a3f7fbdc2..c84dd1c86c 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1038,6 +1038,8 @@ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_stack_builder.h \
src/core/lib/channel/channel_trace.cc \
src/core/lib/channel/channel_trace.h \
+src/core/lib/channel/channelz.cc \
+src/core/lib/channel/channelz.h \
src/core/lib/channel/channelz_registry.cc \
src/core/lib/channel/channelz_registry.h \
src/core/lib/channel/connected_channel.cc \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 66191656ff..df1819f46d 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -3123,6 +3123,27 @@
{
"deps": [
"gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_channelz_proto",
+ "grpc++_test",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "channelz_test",
+ "src": [
+ "test/core/channel/channelz_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
"grpc"
],
"headers": [],
@@ -8760,6 +8781,7 @@
"test/core/end2end/tests/cancel_in_a_vacuum.cc",
"test/core/end2end/tests/cancel_test_helpers.h",
"test/core/end2end/tests/cancel_with_status.cc",
+ "test/core/end2end/tests/channelz.cc",
"test/core/end2end/tests/compressed_payload.cc",
"test/core/end2end/tests/connectivity.cc",
"test/core/end2end/tests/default_host.cc",
@@ -8860,6 +8882,7 @@
"test/core/end2end/tests/cancel_in_a_vacuum.cc",
"test/core/end2end/tests/cancel_test_helpers.h",
"test/core/end2end/tests/cancel_with_status.cc",
+ "test/core/end2end/tests/channelz.cc",
"test/core/end2end/tests/compressed_payload.cc",
"test/core/end2end/tests/connectivity.cc",
"test/core/end2end/tests/default_host.cc",
@@ -9332,6 +9355,7 @@
"src/core/lib/channel/channel_stack.cc",
"src/core/lib/channel/channel_stack_builder.cc",
"src/core/lib/channel/channel_trace.cc",
+ "src/core/lib/channel/channelz.cc",
"src/core/lib/channel/channelz_registry.cc",
"src/core/lib/channel/connected_channel.cc",
"src/core/lib/channel/handshaker.cc",
@@ -9503,6 +9527,7 @@
"src/core/lib/channel/channel_stack.h",
"src/core/lib/channel/channel_stack_builder.h",
"src/core/lib/channel/channel_trace.h",
+ "src/core/lib/channel/channelz.h",
"src/core/lib/channel/channelz_registry.h",
"src/core/lib/channel/connected_channel.h",
"src/core/lib/channel/context.h",
@@ -9652,6 +9677,7 @@
"src/core/lib/channel/channel_stack.h",
"src/core/lib/channel/channel_stack_builder.h",
"src/core/lib/channel/channel_trace.h",
+ "src/core/lib/channel/channelz.h",
"src/core/lib/channel/channelz_registry.h",
"src/core/lib/channel/connected_channel.h",
"src/core/lib/channel/context.h",
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 498edbb35d..afa2e8bda5 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -3726,6 +3726,30 @@
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "channelz_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
"gtest": false,
"language": "c++",
"name": "check_gcp_environment_linux_test",
@@ -7307,6 +7331,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_census_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -9082,6 +9129,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_compress_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -10821,6 +10891,28 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fakesec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -12486,6 +12578,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fd_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -13751,6 +13866,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -15474,6 +15612,25 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+pipe_test",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -16989,6 +17146,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+trace_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -18718,6 +18898,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+workarounds_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -20506,6 +20709,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_http_proxy_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -22365,6 +22592,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_load_reporting_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -24153,6 +24403,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_oauth2_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -25977,6 +26251,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_proxy_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"default_host"
],
"ci_platforms": [
@@ -27129,6 +27427,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -28401,6 +28723,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair+trace_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -29623,6 +29969,32 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [
+ "msan"
+ ],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair_1byte_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -30988,6 +31360,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_ssl_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -32752,6 +33147,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_ssl_proxy_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"default_host"
],
"ci_platforms": [
@@ -33916,6 +34335,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_uds_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -35595,6 +36037,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "inproc_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"empty_batch"
],
"ci_platforms": [
@@ -36607,6 +37072,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_census_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -38359,6 +38847,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_compress_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -40042,6 +40553,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_fd_nosec_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -41284,6 +41818,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -42988,6 +43545,25 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "linux"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+pipe_nosec_test",
+ "platforms": [
+ "linux"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -44480,6 +45056,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+trace_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -46186,6 +46785,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_full+workarounds_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -47950,6 +48572,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_http_proxy_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -49786,6 +50432,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_load_reporting_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -51526,6 +52195,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_proxy_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"default_host"
],
"ci_platforms": [
@@ -52654,6 +53347,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -53902,6 +54619,30 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair+trace_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -55098,6 +55839,32 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [
+ "msan"
+ ],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_sockpair_1byte_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -56417,6 +57184,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "language": "c",
+ "name": "h2_uds_nosec_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"compressed_payload"
],
"ci_platforms": [
@@ -58073,6 +58863,29 @@
},
{
"args": [
+ "channelz"
+ ],
+ "ci_platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "language": "c",
+ "name": "inproc_nosec_test",
+ "platforms": [
+ "windows",
+ "linux",
+ "mac",
+ "posix"
+ ]
+ },
+ {
+ "args": [
"empty_batch"
],
"ci_platforms": [
diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
index a480091c58..7ff877e830 100755
--- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
+++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
@@ -19,15 +19,15 @@ set -ex
cd "$(dirname "$0")/../../.."
EXIT_CODE=0
-ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/load_grpc_with_gc_stress_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/client_memory_usage_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/package_with_underscore_checker.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/load_grpc_with_gc_stress_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/client_memory_usage_driver.rb || EXIT_CODE=1
+time ruby src/ruby/end2end/package_with_underscore_checker.rb || EXIT_CODE=1
exit $EXIT_CODE
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 67aa641e2d..e04b13b24c 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -883,7 +883,7 @@ class RubyLanguage(object):
tests.append(
self.config.job_spec(
['tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh'],
- timeout_seconds=10 * 60,
+ timeout_seconds=20 * 60,
environ=_FORCE_ENVIRON_FOR_WRAPPERS))
return tests