Merge pull request #15343 from ncteisen/channelz

Channelz Part 1: Support for GetChannel
pull/15802/head
Noah Eisen 7 years ago committed by GitHub
commit e121fef19e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      BUILD
  2. 56
      CMakeLists.txt
  3. 60
      Makefile
  4. 19
      build.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 2
      gRPC-C++.podspec
  8. 4
      gRPC-Core.podspec
  9. 2
      grpc.def
  10. 2
      grpc.gemspec
  11. 6
      grpc.gyp
  12. 8
      include/grpc/grpc.h
  13. 4
      include/grpc/impl/codegen/grpc_types.h
  14. 2
      package.xml
  15. 49
      src/core/lib/channel/channel_trace.cc
  16. 30
      src/core/lib/channel/channel_trace.h
  17. 185
      src/core/lib/channel/channelz.cc
  18. 85
      src/core/lib/channel/channelz.h
  19. 29
      src/core/lib/surface/call.cc
  20. 33
      src/core/lib/surface/channel.cc
  21. 4
      src/core/lib/surface/channel.h
  22. 143
      src/proto/grpc/channelz/channelz.proto
  23. 1
      src/python/grpcio/grpc_core_dependencies.py
  24. 4
      src/ruby/end2end/multiple_killed_watching_threads_driver.rb
  25. 4
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  26. 6
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  27. 17
      test/core/channel/BUILD
  28. 196
      test/core/channel/channel_trace_test.cc
  29. 216
      test/core/channel/channelz_test.cc
  30. 8
      test/core/end2end/end2end_nosec_tests.cc
  31. 8
      test/core/end2end/end2end_tests.cc
  32. 1
      test/core/end2end/fuzzers/api_fuzzer.cc
  33. 1
      test/core/end2end/gen_build_yaml.py
  34. 1
      test/core/end2end/generate_tests.bzl
  35. 299
      test/core/end2end/tests/channelz.cc
  36. 2
      test/core/surface/public_headers_must_be_c89.c
  37. 41
      test/cpp/util/channel_trace_proto_helper.cc
  38. 1
      test/cpp/util/channel_trace_proto_helper.h
  39. 1
      tools/doxygen/Doxyfile.c++.internal
  40. 2
      tools/doxygen/Doxyfile.core.internal
  41. 26
      tools/run_tests/generated/sources_and_headers.json
  42. 927
      tools/run_tests/generated/tests.json
  43. 22
      tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
  44. 2
      tools/run_tests/run_tests.py

@ -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",

@ -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 \

@ -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 \

@ -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 " +

@ -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',

@ -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

@ -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',

@ -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.

@ -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 \

@ -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" />

@ -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

@ -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 */

@ -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

@ -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 */

@ -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;
}

@ -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);

@ -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.

@ -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;
}

@ -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',

@ -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

@ -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");

@ -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

@ -83,6 +83,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"],

@ -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) {

@ -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;
}

@ -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;

@ -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;

@ -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++;

@ -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(

@ -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),

@ -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) {}

@ -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);

@ -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

@ -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

@ -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 \

@ -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 \

@ -3120,6 +3120,27 @@
"third_party": false,
"type": "target"
},
{
"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",
@ -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",

File diff suppressed because it is too large Load Diff

@ -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

@ -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

Loading…
Cancel
Save