diff options
46 files changed, 2163 insertions, 730 deletions
@@ -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 @@ -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++ @@ -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(¬e)) { - 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', @@ -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 ) @@ -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 |