From 7d9b6358b507aef4188739c46db1ad3f39a5bf98 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 28 Dec 2017 15:04:48 -0800 Subject: [PATCH] Initial commit Picks up work from https://github.com/grpc/grpc/pull/10259. A merge was impossible due to the many sweeping changed that have occured since I last touched that PR (c++-ization, exec_ctx, reorganitation of filters, etc). --- CMakeLists.txt | 39 +++ Makefile | 45 +++ build.yaml | 17 + config.m4 | 2 + config.w32 | 2 + gRPC-Core.podspec | 8 + grpc.gemspec | 4 + grpc.gyp | 7 + include/grpc/impl/codegen/grpc_types.h | 3 + package.xml | 4 + .../ext/filters/client_channel/subchannel.cc | 17 + .../ext/filters/client_channel/subchannel.h | 4 + src/core/lib/channel/channel_tracer.cc | 326 ++++++++++++++++++ src/core/lib/channel/channel_tracer.h | 78 +++++ src/core/lib/json/json.cc | 36 ++ src/core/lib/json/json.h | 21 +- src/core/lib/support/object_registry.cc | 100 ++++++ src/core/lib/support/object_registry.h | 39 +++ src/core/lib/surface/channel.cc | 33 +- src/core/lib/surface/channel.h | 3 + src/core/lib/surface/init.cc | 3 + src/python/grpcio/grpc_core_dependencies.py | 2 + test/core/channel/channel_tracer_test.cc | 210 +++++++++++ test/core/util/channel_tracing_utils.cc | 60 ++++ test/core/util/channel_tracing_utils.h | 30 ++ tools/doxygen/Doxyfile.c++.internal | 2 + tools/doxygen/Doxyfile.core.internal | 4 + .../generated/sources_and_headers.json | 26 ++ tools/run_tests/generated/tests.json | 24 ++ 29 files changed, 1146 insertions(+), 3 deletions(-) create mode 100644 src/core/lib/channel/channel_tracer.cc create mode 100644 src/core/lib/channel/channel_tracer.h create mode 100644 src/core/lib/support/object_registry.cc create mode 100644 src/core/lib/support/object_registry.h create mode 100644 test/core/channel/channel_tracer_test.cc create mode 100644 test/core/util/channel_tracing_utils.cc create mode 100644 test/core/util/channel_tracing_utils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8eff902f6b0..c819a09e60d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,6 +274,7 @@ add_dependencies(buildtests_c grpc_byte_buffer_reader_test) add_dependencies(buildtests_c grpc_channel_args_test) add_dependencies(buildtests_c grpc_channel_stack_builder_test) add_dependencies(buildtests_c grpc_channel_stack_test) +add_dependencies(buildtests_c grpc_channel_tracer_test) add_dependencies(buildtests_c grpc_completion_queue_test) add_dependencies(buildtests_c grpc_completion_queue_threading_test) add_dependencies(buildtests_c grpc_credentials_test) @@ -639,6 +640,7 @@ add_library(gpr src/core/lib/support/log_windows.cc src/core/lib/support/mpscq.cc src/core/lib/support/murmur_hash.cc + src/core/lib/support/object_registry.cc src/core/lib/support/string.cc src/core/lib/support/string_posix.cc src/core/lib/support/string_util_windows.cc @@ -793,6 +795,7 @@ add_library(grpc src/core/lib/channel/channel_args.cc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc + src/core/lib/channel/channel_tracer.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker_factory.cc @@ -1136,6 +1139,7 @@ add_library(grpc_cronet src/core/lib/channel/channel_args.cc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc + src/core/lib/channel/channel_tracer.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker_factory.cc @@ -1445,6 +1449,7 @@ add_library(grpc_test_util test/core/end2end/fixtures/http_proxy_fixture.cc test/core/end2end/fixtures/proxy.cc test/core/iomgr/endpoint_tests.cc + test/core/util/channel_tracing_utils.cc test/core/util/debugger_macros.cc test/core/util/grpc_profiler.cc test/core/util/histogram.cc @@ -1462,6 +1467,7 @@ add_library(grpc_test_util src/core/lib/channel/channel_args.cc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc + src/core/lib/channel/channel_tracer.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker_factory.cc @@ -1715,6 +1721,7 @@ add_library(grpc_test_util_unsecure test/core/end2end/fixtures/http_proxy_fixture.cc test/core/end2end/fixtures/proxy.cc test/core/iomgr/endpoint_tests.cc + test/core/util/channel_tracing_utils.cc test/core/util/debugger_macros.cc test/core/util/grpc_profiler.cc test/core/util/histogram.cc @@ -1732,6 +1739,7 @@ add_library(grpc_test_util_unsecure src/core/lib/channel/channel_args.cc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc + src/core/lib/channel/channel_tracer.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker_factory.cc @@ -1985,6 +1993,7 @@ add_library(grpc_unsecure src/core/lib/channel/channel_args.cc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc + src/core/lib/channel/channel_tracer.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker_factory.cc @@ -2735,6 +2744,7 @@ add_library(grpc++_cronet src/core/lib/channel/channel_args.cc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc + src/core/lib/channel/channel_tracer.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker_factory.cc @@ -6348,6 +6358,35 @@ target_link_libraries(grpc_channel_stack_test endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) +add_executable(grpc_channel_tracer_test + test/core/channel/channel_tracer_test.cc +) + + +target_include_directories(grpc_channel_tracer_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${PROTOBUF_ROOT_DIR}/src + PRIVATE ${BENCHMARK_ROOT_DIR}/include + PRIVATE ${ZLIB_ROOT_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib + PRIVATE ${CARES_INCLUDE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include +) + +target_link_libraries(grpc_channel_tracer_test + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc + gpr_test_util + gpr +) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_executable(grpc_completion_queue_test test/core/surface/completion_queue_test.cc ) diff --git a/Makefile b/Makefile index e51882c3640..d12e3ade3e0 100644 --- a/Makefile +++ b/Makefile @@ -1001,6 +1001,7 @@ grpc_byte_buffer_reader_test: $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test grpc_channel_args_test: $(BINDIR)/$(CONFIG)/grpc_channel_args_test grpc_channel_stack_builder_test: $(BINDIR)/$(CONFIG)/grpc_channel_stack_builder_test grpc_channel_stack_test: $(BINDIR)/$(CONFIG)/grpc_channel_stack_test +grpc_channel_tracer_test: $(BINDIR)/$(CONFIG)/grpc_channel_tracer_test grpc_completion_queue_test: $(BINDIR)/$(CONFIG)/grpc_completion_queue_test grpc_completion_queue_threading_test: $(BINDIR)/$(CONFIG)/grpc_completion_queue_threading_test grpc_create_jwt: $(BINDIR)/$(CONFIG)/grpc_create_jwt @@ -1400,6 +1401,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/grpc_channel_args_test \ $(BINDIR)/$(CONFIG)/grpc_channel_stack_builder_test \ $(BINDIR)/$(CONFIG)/grpc_channel_stack_test \ + $(BINDIR)/$(CONFIG)/grpc_channel_tracer_test \ $(BINDIR)/$(CONFIG)/grpc_completion_queue_test \ $(BINDIR)/$(CONFIG)/grpc_completion_queue_threading_test \ $(BINDIR)/$(CONFIG)/grpc_credentials_test \ @@ -1865,6 +1867,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/grpc_channel_stack_builder_test || ( echo test grpc_channel_stack_builder_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_channel_stack_test" $(Q) $(BINDIR)/$(CONFIG)/grpc_channel_stack_test || ( echo test grpc_channel_stack_test failed ; exit 1 ) + $(E) "[RUN] Testing grpc_channel_tracer_test" + $(Q) $(BINDIR)/$(CONFIG)/grpc_channel_tracer_test || ( echo test grpc_channel_tracer_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_completion_queue_test" $(Q) $(BINDIR)/$(CONFIG)/grpc_completion_queue_test || ( echo test grpc_completion_queue_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_completion_queue_threading_test" @@ -2843,6 +2847,7 @@ LIBGPR_SRC = \ src/core/lib/support/log_windows.cc \ src/core/lib/support/mpscq.cc \ src/core/lib/support/murmur_hash.cc \ + src/core/lib/support/object_registry.cc \ src/core/lib/support/string.cc \ src/core/lib/support/string_posix.cc \ src/core/lib/support/string_util_windows.cc \ @@ -2974,6 +2979,7 @@ LIBGRPC_SRC = \ src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ @@ -3317,6 +3323,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ @@ -3625,6 +3632,7 @@ LIBGRPC_TEST_UTIL_SRC = \ test/core/end2end/fixtures/http_proxy_fixture.cc \ test/core/end2end/fixtures/proxy.cc \ test/core/iomgr/endpoint_tests.cc \ + test/core/util/channel_tracing_utils.cc \ test/core/util/debugger_macros.cc \ test/core/util/grpc_profiler.cc \ test/core/util/histogram.cc \ @@ -3642,6 +3650,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ @@ -3886,6 +3895,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ test/core/end2end/fixtures/http_proxy_fixture.cc \ test/core/end2end/fixtures/proxy.cc \ test/core/iomgr/endpoint_tests.cc \ + test/core/util/channel_tracing_utils.cc \ test/core/util/debugger_macros.cc \ test/core/util/grpc_profiler.cc \ test/core/util/histogram.cc \ @@ -3903,6 +3913,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ @@ -4134,6 +4145,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ @@ -4867,6 +4879,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ @@ -10516,6 +10529,38 @@ endif endif +GRPC_CHANNEL_TRACER_TEST_SRC = \ + test/core/channel/channel_tracer_test.cc \ + +GRPC_CHANNEL_TRACER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CHANNEL_TRACER_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/grpc_channel_tracer_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/grpc_channel_tracer_test: $(GRPC_CHANNEL_TRACER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(GRPC_CHANNEL_TRACER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/grpc_channel_tracer_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/channel/channel_tracer_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_grpc_channel_tracer_test: $(GRPC_CHANNEL_TRACER_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GRPC_CHANNEL_TRACER_TEST_OBJS:.o=.dep) +endif +endif + + GRPC_COMPLETION_QUEUE_TEST_SRC = \ test/core/surface/completion_queue_test.cc \ diff --git a/build.yaml b/build.yaml index 42d72459811..67513d84453 100644 --- a/build.yaml +++ b/build.yaml @@ -49,6 +49,7 @@ filegroups: - src/core/lib/support/log_windows.cc - src/core/lib/support/mpscq.cc - src/core/lib/support/murmur_hash.cc + - src/core/lib/support/object_registry.cc - src/core/lib/support/string.cc - src/core/lib/support/string_posix.cc - src/core/lib/support/string_util_windows.cc @@ -113,6 +114,7 @@ filegroups: - src/core/lib/support/memory.h - src/core/lib/support/mpscq.h - src/core/lib/support/murmur_hash.h + - src/core/lib/support/object_registry.h - src/core/lib/support/spinlock.h - src/core/lib/support/string.h - src/core/lib/support/string_windows.h @@ -154,6 +156,7 @@ filegroups: - src/core/lib/channel/channel_args.cc - src/core/lib/channel/channel_stack.cc - src/core/lib/channel/channel_stack_builder.cc + - src/core/lib/channel/channel_tracer.cc - src/core/lib/channel/connected_channel.cc - src/core/lib/channel/handshaker.cc - src/core/lib/channel/handshaker_factory.cc @@ -309,6 +312,7 @@ filegroups: - 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_tracer.h - src/core/lib/channel/connected_channel.h - src/core/lib/channel/context.h - src/core/lib/channel/handshaker.h @@ -710,6 +714,7 @@ filegroups: - test/core/end2end/fixtures/http_proxy_fixture.h - test/core/end2end/fixtures/proxy.h - test/core/iomgr/endpoint_tests.h + - test/core/util/channel_tracing_utils.h - test/core/util/debugger_macros.h - test/core/util/grpc_profiler.h - test/core/util/histogram.h @@ -728,6 +733,7 @@ filegroups: - test/core/end2end/fixtures/http_proxy_fixture.cc - test/core/end2end/fixtures/proxy.cc - test/core/iomgr/endpoint_tests.cc + - test/core/util/channel_tracing_utils.cc - test/core/util/debugger_macros.cc - test/core/util/grpc_profiler.cc - test/core/util/histogram.cc @@ -2333,6 +2339,17 @@ targets: - gpr_test_util - gpr uses_polling: false +- name: grpc_channel_tracer_test + build: test + language: c + src: + - test/core/channel/channel_tracer_test.cc + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr + uses_polling: false - name: grpc_completion_queue_test build: test language: c diff --git a/config.m4 b/config.m4 index c026b83f359..e0de29807d2 100644 --- a/config.m4 +++ b/config.m4 @@ -62,6 +62,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/support/log_windows.cc \ src/core/lib/support/mpscq.cc \ src/core/lib/support/murmur_hash.cc \ + src/core/lib/support/object_registry.cc \ src/core/lib/support/string.cc \ src/core/lib/support/string_posix.cc \ src/core/lib/support/string_util_windows.cc \ @@ -88,6 +89,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/channel/channel_args.cc \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ + src/core/lib/channel/channel_tracer.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker_factory.cc \ diff --git a/config.w32 b/config.w32 index cd3a16a4653..8815331c6ad 100644 --- a/config.w32 +++ b/config.w32 @@ -39,6 +39,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\support\\log_windows.cc " + "src\\core\\lib\\support\\mpscq.cc " + "src\\core\\lib\\support\\murmur_hash.cc " + + "src\\core\\lib\\support\\object_registry.cc " + "src\\core\\lib\\support\\string.cc " + "src\\core\\lib\\support\\string_posix.cc " + "src\\core\\lib\\support\\string_util_windows.cc " + @@ -65,6 +66,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\channel\\channel_args.cc " + "src\\core\\lib\\channel\\channel_stack.cc " + "src\\core\\lib\\channel\\channel_stack_builder.cc " + + "src\\core\\lib\\channel\\channel_tracer.cc " + "src\\core\\lib\\channel\\connected_channel.cc " + "src\\core\\lib\\channel\\handshaker.cc " + "src\\core\\lib\\channel\\handshaker_factory.cc " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 708c3436abd..1cae08d0882 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -205,6 +205,7 @@ Pod::Spec.new do |s| 'src/core/lib/support/memory.h', 'src/core/lib/support/mpscq.h', 'src/core/lib/support/murmur_hash.h', + 'src/core/lib/support/object_registry.h', 'src/core/lib/support/spinlock.h', 'src/core/lib/support/string.h', 'src/core/lib/support/string_windows.h', @@ -234,6 +235,7 @@ Pod::Spec.new do |s| 'src/core/lib/support/log_windows.cc', 'src/core/lib/support/mpscq.cc', 'src/core/lib/support/murmur_hash.cc', + 'src/core/lib/support/object_registry.cc', 'src/core/lib/support/string.cc', 'src/core/lib/support/string_posix.cc', 'src/core/lib/support/string_util_windows.cc', @@ -333,6 +335,7 @@ Pod::Spec.new do |s| '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_tracer.h', 'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/context.h', 'src/core/lib/channel/handshaker.h', @@ -473,6 +476,7 @@ Pod::Spec.new do |s| 'src/core/lib/channel/channel_args.cc', 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_tracer.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker_factory.cc', @@ -729,6 +733,7 @@ Pod::Spec.new do |s| 'src/core/lib/support/memory.h', 'src/core/lib/support/mpscq.h', 'src/core/lib/support/murmur_hash.h', + 'src/core/lib/support/object_registry.h', 'src/core/lib/support/spinlock.h', 'src/core/lib/support/string.h', 'src/core/lib/support/string_windows.h', @@ -813,6 +818,7 @@ Pod::Spec.new do |s| '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_tracer.h', 'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/context.h', 'src/core/lib/channel/handshaker.h', @@ -985,6 +991,7 @@ Pod::Spec.new do |s| 'test/core/end2end/fixtures/http_proxy_fixture.cc', 'test/core/end2end/fixtures/proxy.cc', 'test/core/iomgr/endpoint_tests.cc', + 'test/core/util/channel_tracing_utils.cc', 'test/core/util/debugger_macros.cc', 'test/core/util/grpc_profiler.cc', 'test/core/util/histogram.cc', @@ -1004,6 +1011,7 @@ Pod::Spec.new do |s| 'test/core/end2end/fixtures/http_proxy_fixture.h', 'test/core/end2end/fixtures/proxy.h', 'test/core/iomgr/endpoint_tests.h', + 'test/core/util/channel_tracing_utils.h', 'test/core/util/debugger_macros.h', 'test/core/util/grpc_profiler.h', 'test/core/util/histogram.h', diff --git a/grpc.gemspec b/grpc.gemspec index d1859952619..ea11b6a94c8 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -95,6 +95,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/support/memory.h ) s.files += %w( src/core/lib/support/mpscq.h ) s.files += %w( src/core/lib/support/murmur_hash.h ) + s.files += %w( src/core/lib/support/object_registry.h ) s.files += %w( src/core/lib/support/spinlock.h ) s.files += %w( src/core/lib/support/string.h ) s.files += %w( src/core/lib/support/string_windows.h ) @@ -124,6 +125,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/support/log_windows.cc ) s.files += %w( src/core/lib/support/mpscq.cc ) s.files += %w( src/core/lib/support/murmur_hash.cc ) + s.files += %w( src/core/lib/support/object_registry.cc ) s.files += %w( src/core/lib/support/string.cc ) s.files += %w( src/core/lib/support/string_posix.cc ) s.files += %w( src/core/lib/support/string_util_windows.cc ) @@ -259,6 +261,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/channel/channel_args.h ) 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_tracer.h ) s.files += %w( src/core/lib/channel/connected_channel.h ) s.files += %w( src/core/lib/channel/context.h ) s.files += %w( src/core/lib/channel/handshaker.h ) @@ -403,6 +406,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/channel/channel_args.cc ) 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_tracer.cc ) s.files += %w( src/core/lib/channel/connected_channel.cc ) s.files += %w( src/core/lib/channel/handshaker.cc ) s.files += %w( src/core/lib/channel/handshaker_factory.cc ) diff --git a/grpc.gyp b/grpc.gyp index c34206b1a5d..8f7ba225512 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -181,6 +181,7 @@ 'src/core/lib/support/log_windows.cc', 'src/core/lib/support/mpscq.cc', 'src/core/lib/support/murmur_hash.cc', + 'src/core/lib/support/object_registry.cc', 'src/core/lib/support/string.cc', 'src/core/lib/support/string_posix.cc', 'src/core/lib/support/string_util_windows.cc', @@ -226,6 +227,7 @@ 'src/core/lib/channel/channel_args.cc', 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_tracer.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker_factory.cc', @@ -503,6 +505,7 @@ 'test/core/end2end/fixtures/http_proxy_fixture.cc', 'test/core/end2end/fixtures/proxy.cc', 'test/core/iomgr/endpoint_tests.cc', + 'test/core/util/channel_tracing_utils.cc', 'test/core/util/debugger_macros.cc', 'test/core/util/grpc_profiler.cc', 'test/core/util/histogram.cc', @@ -520,6 +523,7 @@ 'src/core/lib/channel/channel_args.cc', 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_tracer.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker_factory.cc', @@ -715,6 +719,7 @@ 'test/core/end2end/fixtures/http_proxy_fixture.cc', 'test/core/end2end/fixtures/proxy.cc', 'test/core/iomgr/endpoint_tests.cc', + 'test/core/util/channel_tracing_utils.cc', 'test/core/util/debugger_macros.cc', 'test/core/util/grpc_profiler.cc', 'test/core/util/histogram.cc', @@ -732,6 +737,7 @@ 'src/core/lib/channel/channel_args.cc', 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_tracer.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker_factory.cc', @@ -926,6 +932,7 @@ 'src/core/lib/channel/channel_args.cc', 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_tracer.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker_factory.cc', diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index fcbc8ac5a1e..b4cbff8649b 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -274,6 +274,9 @@ typedef struct { #define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator" /** The grpc_socket_factory instance to create and bind sockets. A pointer. */ #define GRPC_ARG_SOCKET_FACTORY "grpc.socket_factory" +/** The maximum number of trace nodes to keep in the tracer for each channel or + * subchannel. The default is 10. If set to 0, channel tracing is disabled. */ +#define GRPC_ARG_CHANNEL_TRACING_MAX_NODES "grpc.channel_tracing_max_nodes" /** If non-zero, Cronet transport will coalesce packets to fewer frames * when possible. */ #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \ diff --git a/package.xml b/package.xml index b4d8c886930..5f70dbc3fab 100644 --- a/package.xml +++ b/package.xml @@ -107,6 +107,7 @@ + @@ -136,6 +137,7 @@ + @@ -271,6 +273,7 @@ + @@ -415,6 +418,7 @@ + diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index f07394d29b2..8b8e468f16f 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -35,6 +35,7 @@ #include "src/core/ext/filters/client_channel/uri_parser.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_tracer.h" #include "src/core/lib/channel/connected_channel.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/iomgr/sockaddr_utils.h" @@ -42,6 +43,7 @@ #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/manual_constructor.h" +#include "src/core/lib/support/object_registry.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel_init.h" #include "src/core/lib/transport/connectivity_state.h" @@ -75,6 +77,7 @@ typedef struct external_state_watcher { } external_state_watcher; struct grpc_subchannel { + intptr_t uuid; grpc_connector* connector; /** refcount @@ -131,6 +134,8 @@ struct grpc_subchannel { bool backoff_begun; /** our alarm */ grpc_timer alarm; + + grpc_channel_tracer* tracer; }; struct grpc_subchannel_call { @@ -183,6 +188,7 @@ void grpc_connected_subchannel_unref( static void subchannel_destroy(void* arg, grpc_error* error) { grpc_subchannel* c = (grpc_subchannel*)arg; + grpc_object_registry_unregister_object(c->uuid); gpr_free((void*)c->filters); grpc_channel_args_destroy(c->args); grpc_connectivity_state_destroy(&c->state_tracker); @@ -337,6 +343,8 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector, GRPC_STATS_INC_CLIENT_SUBCHANNELS_CREATED(); c = (grpc_subchannel*)gpr_zalloc(sizeof(*c)); + c->uuid = + grpc_object_registry_register_object(c, GPRC_OBJECT_REGISTRY_SUBCHANNEL); c->key = key; gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS); c->connector = connector; @@ -385,6 +393,15 @@ grpc_subchannel* grpc_subchannel_create(grpc_connector* connector, return grpc_subchannel_index_register(key, c); } +char* grpc_subchannel_get_trace(grpc_subchannel* subchannel, bool recursive) { + return subchannel->tracer != NULL + ? grpc_channel_tracer_render_trace(subchannel->tracer, recursive) + : NULL; +} +intptr_t grpc_subchannel_get_uuid(grpc_subchannel* subchannel) { + return subchannel->uuid; +} + static void continue_connect_locked(grpc_subchannel* c) { grpc_connect_in_args args; args.interested_parties = c->pollset_set; diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 9d34fff07a8..3584d3928a1 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -165,6 +165,10 @@ struct grpc_subchannel_args { grpc_subchannel* grpc_subchannel_create(grpc_connector* connector, const grpc_subchannel_args* args); +/// retrieves the trace for this subchannel in JSON form. +char* grpc_subchannel_get_trace(grpc_subchannel* subchannel, bool recursive); +intptr_t grpc_subchannel_get_uuid(grpc_subchannel* subchannel); + /// Sets \a addr from \a args. void grpc_get_subchannel_address_arg(const grpc_channel_args* args, grpc_resolved_address* addr); diff --git a/src/core/lib/channel/channel_tracer.cc b/src/core/lib/channel/channel_tracer.cc new file mode 100644 index 00000000000..0d77f33c7f2 --- /dev/null +++ b/src/core/lib/channel/channel_tracer.cc @@ -0,0 +1,326 @@ +/* + * + * 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 "src/core/lib/channel/channel_tracer.h" +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/support/object_registry.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/connectivity_state.h" + +// One node of tracing data +typedef struct grpc_trace_node { + grpc_slice data; + grpc_error* error; + gpr_timespec time_created; + grpc_connectivity_state connectivity_state; + struct grpc_trace_node* next; + + // the tracer object for the (sub)channel that this trace node refers to. + grpc_channel_tracer* referenced_tracer; +} grpc_trace_node; + +/* the channel tracing object */ +struct grpc_channel_tracer { + gpr_refcount refs; + gpr_mu tracer_mu; + intptr_t channel_uuid; + uint64_t num_nodes_logged; + size_t list_size; + size_t max_list_size; + grpc_trace_node* head_trace; + grpc_trace_node* tail_trace; + gpr_timespec time_created; +}; + +#ifdef GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG +grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes, intptr_t uuid, + const char* file, int line, + const char* func) { +#else +grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes, + intptr_t uuid) { +#endif + grpc_channel_tracer* tracer = static_cast( + gpr_zalloc(sizeof(grpc_channel_tracer))); + gpr_mu_init(&tracer->tracer_mu); + gpr_ref_init(&tracer->refs, 1); +#ifdef GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG + gpr_log(GPR_DEBUG, "%p create [%s:%d %s]", tracer, file, line, func); +#endif + tracer->channel_uuid = uuid; + tracer->max_list_size = max_nodes; + tracer->time_created = gpr_now(GPR_CLOCK_REALTIME); + return tracer; +} + +#ifdef GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG +grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer, + const char* file, int line, + const char* func) { + if (!tracer) return tracer; + gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", tracer, + gpr_atm_no_barrier_load(&tracer->refs.count), + gpr_atm_no_barrier_load(&tracer->refs.count) + 1, file, line, func); + gpr_ref(&tracer->refs); + return tracer; +} +#else +grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer) { + if (!tracer) return tracer; + gpr_ref(&tracer->refs); + return tracer; +} +#endif + +static void free_node(grpc_trace_node* node) { + GRPC_ERROR_UNREF(node->error); + GRPC_CHANNEL_TRACER_UNREF(node->referenced_tracer); + grpc_slice_unref_internal(node->data); + gpr_free(node); +} + +static void grpc_channel_tracer_destroy(grpc_channel_tracer* tracer) { + grpc_trace_node* it = tracer->head_trace; + while (it != NULL) { + grpc_trace_node* to_free = it; + it = it->next; + free_node(to_free); + } + gpr_mu_destroy(&tracer->tracer_mu); + gpr_free(tracer); +} + +#ifdef GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG +void grpc_channel_tracer_unref(grpc_channel_tracer* tracer, const char* file, + int line, const char* func) { + if (!tracer) return; + gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", tracer, + gpr_atm_no_barrier_load(&tracer->refs.count), + gpr_atm_no_barrier_load(&tracer->refs.count) - 1, file, line, func); + if (gpr_unref(&tracer->refs)) { + grpc_channel_tracer_destroy(tracer); + } +} +#else +void grpc_channel_tracer_unref(grpc_channel_tracer* tracer) { + if (!tracer) return; + if (gpr_unref(&tracer->refs)) { + grpc_channel_tracer_destroy(tracer); + } +} +#endif + +void grpc_channel_tracer_add_trace(grpc_channel_tracer* tracer, grpc_slice data, + grpc_error* error, + grpc_connectivity_state connectivity_state, + grpc_channel_tracer* referenced_tracer) { + if (!tracer) return; + ++tracer->num_nodes_logged; + // create and fill up the new node + grpc_trace_node* new_trace_node = + static_cast(gpr_malloc(sizeof(grpc_trace_node))); + new_trace_node->data = data; + new_trace_node->error = error; + new_trace_node->time_created = gpr_now(GPR_CLOCK_REALTIME); + new_trace_node->connectivity_state = connectivity_state; + new_trace_node->next = NULL; + new_trace_node->referenced_tracer = + GRPC_CHANNEL_TRACER_REF(referenced_tracer); + // first node case + if (tracer->head_trace == NULL) { + tracer->head_trace = tracer->tail_trace = new_trace_node; + } + // regular node add case + else { + tracer->tail_trace->next = new_trace_node; + tracer->tail_trace = tracer->tail_trace->next; + } + ++tracer->list_size; + // maybe garbage collect the end + if (tracer->list_size > tracer->max_list_size) { + grpc_trace_node* to_free = tracer->head_trace; + tracer->head_trace = tracer->head_trace->next; + free_node(to_free); + --tracer->list_size; + } +} + +// returns an allocated string that represents tm according to RFC-3339. +static char* fmt_time(gpr_timespec tm) { + char buffer[35]; + struct tm* tm_info = localtime((const time_t*)&tm.tv_sec); + strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S", tm_info); + char* full_time_str; + gpr_asprintf(&full_time_str, "%s.%09dZ", buffer, tm.tv_nsec); + return full_time_str; +} + +typedef struct seen_tracers { + grpc_channel_tracer** tracers; + size_t size; + size_t cap; +} seen_tracers; + +static void seen_tracers_add(seen_tracers* tracker, + grpc_channel_tracer* tracer) { + if (tracker->size >= tracker->cap) { + tracker->cap = GPR_MAX(5 * sizeof(tracer), 3 * tracker->cap / 2); + tracker->tracers = + (grpc_channel_tracer**)gpr_realloc(tracker->tracers, tracker->cap); + } + tracker->tracers[tracker->size++] = tracer; +} + +static bool seen_tracers_check(seen_tracers* tracker, + grpc_channel_tracer* tracer) { + for (size_t i = 0; i < tracker->size; ++i) { + if (tracker->tracers[i] == tracer) return true; + } + return false; +} + +static void recursively_populate_json(grpc_channel_tracer* tracer, + seen_tracers* tracker, grpc_json* json, + bool recursive); + +static void populate_node_data(grpc_trace_node* node, seen_tracers* tracker, + grpc_json* json, grpc_json* children) { + grpc_json* child = NULL; + child = grpc_json_create_child(child, json, "data", + grpc_slice_to_c_string(node->data), + GRPC_JSON_STRING, true); + if (node->error != GRPC_ERROR_NONE) { + child = grpc_json_create_child(child, json, "error", + gpr_strdup(grpc_error_string(node->error)), + GRPC_JSON_STRING, true); + } + child = + grpc_json_create_child(child, json, "time", fmt_time(node->time_created), + GRPC_JSON_STRING, true); + child = grpc_json_create_child( + child, json, "state", + grpc_connectivity_state_name(node->connectivity_state), GRPC_JSON_STRING, + false); + if (node->referenced_tracer != NULL) { + char* uuid_str; + gpr_asprintf(&uuid_str, "%ld", node->referenced_tracer->channel_uuid); + child = grpc_json_create_child(child, json, "uuid", uuid_str, + GRPC_JSON_NUMBER, true); + if (children && !seen_tracers_check(tracker, node->referenced_tracer)) { + grpc_json* referenced_tracer = grpc_json_create_child( + NULL, children, NULL, NULL, GRPC_JSON_OBJECT, false); + recursively_populate_json(node->referenced_tracer, tracker, + referenced_tracer, true); + } + } +} + +static void populate_node_list_data(grpc_channel_tracer* tracer, + seen_tracers* tracker, grpc_json* nodes, + grpc_json* children) { + grpc_json* child = NULL; + grpc_trace_node* it = tracer->head_trace; + while (it != NULL) { + child = grpc_json_create_child(child, nodes, NULL, NULL, GRPC_JSON_OBJECT, + false); + populate_node_data(it, tracker, child, children); + it = it->next; + } +} + +static void populate_tracer_data(grpc_channel_tracer* tracer, + seen_tracers* tracker, grpc_json* channel_data, + grpc_json* children) { + grpc_json* child = NULL; + + char* uuid_str; + gpr_asprintf(&uuid_str, "%ld", tracer->channel_uuid); + child = grpc_json_create_child(child, channel_data, "uuid", uuid_str, + GRPC_JSON_NUMBER, true); + char* num_nodes_logged_str; + gpr_asprintf(&num_nodes_logged_str, "%" PRId64, tracer->num_nodes_logged); + child = grpc_json_create_child(child, channel_data, "numNodesLogged", + num_nodes_logged_str, GRPC_JSON_NUMBER, true); + child = grpc_json_create_child(child, channel_data, "startTime", + fmt_time(tracer->time_created), + GRPC_JSON_STRING, true); + child = grpc_json_create_child(child, channel_data, "nodes", NULL, + GRPC_JSON_ARRAY, false); + populate_node_list_data(tracer, tracker, child, children); +} + +static void recursively_populate_json(grpc_channel_tracer* tracer, + seen_tracers* tracker, grpc_json* json, + bool recursive) { + grpc_json* channel_data = grpc_json_create_child( + NULL, json, "channelData", NULL, GRPC_JSON_OBJECT, false); + grpc_json* children = NULL; + if (recursive) { + children = grpc_json_create_child(channel_data, json, "children", NULL, + GRPC_JSON_ARRAY, false); + } + seen_tracers_add(tracker, tracer); + populate_tracer_data(tracer, tracker, channel_data, children); +} + +char* grpc_channel_tracer_render_trace(grpc_channel_tracer* tracer, + bool recursive) { + grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); + + seen_tracers tracker; + memset(&tracker, 0, sizeof(tracker)); + + recursively_populate_json(tracer, &tracker, json, recursive); + + gpr_free(tracker.tracers); + + char* json_str = grpc_json_dump_to_string(json, 1); + grpc_json_destroy(json); + return json_str; +} + +char* grpc_channel_tracer_get_trace(intptr_t uuid, bool recursive) { + void* object; + grpc_object_registry_type type = + grpc_object_registry_get_object(uuid, &object); + GPR_ASSERT(type == GRPC_OBJECT_REGISTRY_CHANNEL || + type == GPRC_OBJECT_REGISTRY_SUBCHANNEL); + switch (type) { + case GRPC_OBJECT_REGISTRY_CHANNEL: + return grpc_channel_get_trace(static_cast(object), + recursive); + break; + case GPRC_OBJECT_REGISTRY_SUBCHANNEL: + return grpc_subchannel_get_trace(static_cast(object), + recursive); + break; + default: + abort(); + } +} diff --git a/src/core/lib/channel/channel_tracer.h b/src/core/lib/channel/channel_tracer.h new file mode 100644 index 00000000000..1f151ba8991 --- /dev/null +++ b/src/core/lib/channel/channel_tracer.h @@ -0,0 +1,78 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACER_H +#define GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACER_H + +#include +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/json/json.h" + +/* Forward declaration */ +typedef struct grpc_channel_tracer grpc_channel_tracer; + +// #define GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG + +/* Creates a new tracer. The caller owns a reference to the returned tracer. */ +#ifdef GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG +grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes, intptr_t uuid, + const char* file, int line, + const char* func); +#define GRPC_CHANNEL_TRACER_CREATE(max_nodes, id) \ + grpc_channel_tracer_create(max_nodes, id, __FILE__, __LINE__, __func__) +#else +grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes, + intptr_t uuid); +#define GRPC_CHANNEL_TRACER_CREATE(max_nodes, id) \ + grpc_channel_tracer_create(max_nodes, id) +#endif + +#ifdef GRPC_CHANNEL_TRACER_REFCOUNT_DEBUG +grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer, + const char* file, int line, + const char* func); +void grpc_channel_tracer_unref(grpc_channel_tracer* tracer, const char* file, + int line, const char* func); +#define GRPC_CHANNEL_TRACER_REF(tracer) \ + grpc_channel_tracer_ref(tracer, __FILE__, __LINE__, __func__) +#define GRPC_CHANNEL_TRACER_UNREF(tracer) \ + grpc_channel_tracer_unref(tracer, __FILE__, __LINE__, __func__) +#else +grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer); +void grpc_channel_tracer_unref(grpc_channel_tracer* tracer); +#define GRPC_CHANNEL_TRACER_REF(tracer) grpc_channel_tracer_ref(tracer) +#define GRPC_CHANNEL_TRACER_UNREF(tracer) grpc_channel_tracer_unref(tracer) +#endif + +/* Adds a new trace node to the tracing object */ +void grpc_channel_tracer_add_trace(grpc_channel_tracer* tracer, grpc_slice data, + grpc_error* error, + grpc_connectivity_state connectivity_state, + grpc_channel_tracer* subchannel); + +/* Returns the tracing data rendered as a grpc json string. + The string is owned by the caller and must be freed. If recursive + is true, then the string will include the recursive trace for all + subtracing objects. */ +char* grpc_channel_tracer_render_trace(grpc_channel_tracer* tracer, + bool recursive); +/* util functions that perform the uuid -> tracer step for you, and then + returns the trace for the uuid given. */ +char* grpc_channel_tracer_get_trace(intptr_t uuid, bool recursive); + +#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACER_H */ diff --git a/src/core/lib/json/json.cc b/src/core/lib/json/json.cc index 4ad51f662a7..2171e694555 100644 --- a/src/core/lib/json/json.cc +++ b/src/core/lib/json/json.cc @@ -19,6 +19,7 @@ #include #include +#include #include "src/core/lib/json/json.h" @@ -44,5 +45,40 @@ void grpc_json_destroy(grpc_json* json) { json->parent->child = json->next; } + if (json->owns_value) { + gpr_free((void*)json->value); + } + gpr_free(json); } + +grpc_json* grpc_json_link_child(grpc_json* parent, grpc_json* child, + grpc_json* sibling) { + // first child case. + if (parent->child == NULL) { + GPR_ASSERT(sibling == NULL); + parent->child = child; + return child; + } + if (sibling == NULL) { + sibling = parent->child; + } + // always find the right most sibling. + while (sibling->next != NULL) { + sibling = sibling->next; + } + sibling->next = child; + return child; +} + +grpc_json* grpc_json_create_child(grpc_json* sibling, grpc_json* parent, + const char* key, const char* value, + grpc_json_type type, bool owns_value) { + grpc_json* child = grpc_json_create(type); + grpc_json_link_child(parent, child, sibling); + child->owns_value = owns_value; + child->parent = parent; + child->value = value; + child->key = key; + return child; +} diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h index bbd43025eb8..d88a79271fd 100644 --- a/src/core/lib/json/json.h +++ b/src/core/lib/json/json.h @@ -19,6 +19,7 @@ #ifndef GRPC_CORE_LIB_JSON_JSON_H #define GRPC_CORE_LIB_JSON_JSON_H +#include #include #include "src/core/lib/json/json_common.h" @@ -35,6 +36,9 @@ typedef struct grpc_json { grpc_json_type type; const char* key; const char* value; + + /* if set, destructor will free value */ + bool owns_value; } grpc_json; /* The next two functions are going to parse the input string, and @@ -65,9 +69,24 @@ char* grpc_json_dump_to_string(grpc_json* json, int indent); /* Use these to create or delete a grpc_json object. * Deletion is recursive. We will not attempt to free any of the strings - * in any of the objects of that tree. + * in any of the objects of that tree, unless the boolean, owns_value, + * is true. */ grpc_json* grpc_json_create(grpc_json_type type); void grpc_json_destroy(grpc_json* json); +/* Links the child json object into the parent's json tree. If the parent + * already has children, then passing in the most recently added child as the + * sibling parameter is an optimization. For if sibling is NULL, this function + * will manually traverse the tree in order to find the right most sibling. + */ +grpc_json* grpc_json_link_child(grpc_json* parent, grpc_json* child, + grpc_json* sibling); + +/* Creates a child json object into the parent's json tree then links it in + * as described above. */ +grpc_json* grpc_json_create_child(grpc_json* sibling, grpc_json* parent, + const char* key, const char* value, + grpc_json_type type, bool owns_value); + #endif /* GRPC_CORE_LIB_JSON_JSON_H */ diff --git a/src/core/lib/support/object_registry.cc b/src/core/lib/support/object_registry.cc new file mode 100644 index 00000000000..596711804fa --- /dev/null +++ b/src/core/lib/support/object_registry.cc @@ -0,0 +1,100 @@ +/* + * + * 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 "src/core/lib/support/object_registry.h" + +#include +#include +#include + +// file global lock and avl. +static gpr_mu g_mu; +static gpr_avl g_avl; +static intptr_t g_uuid = 0; + +typedef struct { + void* object; + grpc_object_registry_type type; +} object_tracker; + +// avl vtable for uuid (intptr_t) -> object_tracker +// this table is only looking, it does not own anything. +static void destroy_intptr(void* not_used, void* user_data) {} +static void* copy_intptr(void* key, void* user_data) { return key; } +static long compare_intptr(void* key1, void* key2, void* user_data) { + return key1 > key2; +} + +static void destroy_tracker(void* tracker, void* user_data) { + gpr_free((object_tracker*)tracker); +} + +static void* copy_tracker(void* value, void* user_data) { + object_tracker* old = static_cast(value); + object_tracker* new_obj = + static_cast(gpr_malloc(sizeof(object_tracker))); + new_obj->object = old->object; + new_obj->type = old->type; + return new_obj; +} +static const gpr_avl_vtable avl_vtable = { + destroy_intptr, copy_intptr, compare_intptr, destroy_tracker, copy_tracker}; + +void grpc_object_registry_init() { + gpr_mu_init(&g_mu); + g_avl = gpr_avl_create(&avl_vtable); +} + +void grpc_object_registry_shutdown() { + gpr_avl_unref(g_avl, nullptr); + gpr_mu_destroy(&g_mu); +} + +intptr_t grpc_object_registry_register_object(void* object, + grpc_object_registry_type type) { + object_tracker* tracker = + static_cast(gpr_malloc(sizeof(object_tracker))); + tracker->object = object; + tracker->type = type; + intptr_t prior = gpr_atm_no_barrier_fetch_add(&g_uuid, 1); + gpr_mu_lock(&g_mu); + g_avl = gpr_avl_add(g_avl, (void*)prior, tracker, NULL); + gpr_mu_unlock(&g_mu); + return prior; +} + +void grpc_object_registry_unregister_object(intptr_t uuid) { + gpr_mu_lock(&g_mu); + g_avl = gpr_avl_remove(g_avl, (void*)uuid, nullptr); + gpr_mu_unlock(&g_mu); +} + +grpc_object_registry_type grpc_object_registry_get_object(intptr_t uuid, + void** object) { + GPR_ASSERT(object); + gpr_mu_lock(&g_mu); + object_tracker* tracker = + static_cast(gpr_avl_get(g_avl, (void*)uuid, nullptr)); + gpr_mu_unlock(&g_mu); + if (tracker == NULL) { + *object = NULL; + return GRPC_OBJECT_REGISTRY_UNKNOWN; + } + *object = tracker->object; + return tracker->type; +} diff --git a/src/core/lib/support/object_registry.h b/src/core/lib/support/object_registry.h new file mode 100644 index 00000000000..3a0d056e2ad --- /dev/null +++ b/src/core/lib/support/object_registry.h @@ -0,0 +1,39 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_OBJECT_REGISTRY_H +#define GRPC_CORE_LIB_SUPPORT_OBJECT_REGISTRY_H + +#include + +typedef enum { + GRPC_OBJECT_REGISTRY_CHANNEL, + GPRC_OBJECT_REGISTRY_SUBCHANNEL, + GRPC_OBJECT_REGISTRY_UNKNOWN, +} grpc_object_registry_type; + +void grpc_object_registry_init(); +void grpc_object_registry_shutdown(); + +intptr_t grpc_object_registry_register_object(void* object, + grpc_object_registry_type type); +void grpc_object_registry_unregister_object(intptr_t uuid); +grpc_object_registry_type grpc_object_registry_get_object(intptr_t uuid, + void** object); + +#endif /* GRPC_CORE_LIB_SUPPORT_OBJECT_REGISTRY_H */ diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index cf5e8c2150d..e94413e3bcb 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -28,9 +28,11 @@ #include #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_tracer.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/support/object_registry.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" @@ -51,6 +53,7 @@ typedef struct registered_call { } registered_call; struct grpc_channel { + intptr_t uuid; int is_client; grpc_compression_options compression_options; grpc_mdelem default_authority; @@ -60,6 +63,8 @@ struct grpc_channel { gpr_mu registered_call_mu; registered_call* registered_calls; + grpc_channel_tracer* tracer; + char* target; }; @@ -91,12 +96,16 @@ grpc_channel* grpc_channel_create_with_builder( grpc_error_string(error)); GRPC_ERROR_UNREF(error); gpr_free(target); - goto done; + grpc_channel_args_destroy(args); + return channel; } memset(channel, 0, sizeof(*channel)); + channel->uuid = grpc_object_registry_register_object( + channel, GRPC_OBJECT_REGISTRY_CHANNEL); channel->target = target; channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); + channel->tracer = NULL; gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = nullptr; @@ -186,14 +195,34 @@ grpc_channel* grpc_channel_create_with_builder( .enabled_stream_compression_algorithms_bitset = (uint32_t)args->args[i].value.integer | 0x1; /* always support no compression */ + } else if (0 == + strcmp(args->args[i].key, GRPC_ARG_CHANNEL_TRACING_MAX_NODES)) { + GPR_ASSERT(channel->tracer == NULL); + // max_nodes defaults to 10, clamped between 0 and 100. + const grpc_integer_options options = {10, 0, 100}; + size_t max_nodes = + (size_t)grpc_channel_arg_get_integer(&args->args[i], options); + if (max_nodes > 0) { + channel->tracer = GRPC_CHANNEL_TRACER_CREATE(max_nodes, channel->uuid); + } } } -done: grpc_channel_args_destroy(args); + grpc_channel_tracer_add_trace( + channel->tracer, grpc_slice_from_static_string("Channel created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, NULL); return channel; } +char* grpc_channel_get_trace(grpc_channel* channel, bool recursive) { + return channel->tracer + ? grpc_channel_tracer_render_trace(channel->tracer, recursive) + : NULL; +} + +intptr_t grpc_channel_get_uuid(grpc_channel* channel) { return channel->uuid; } + grpc_channel* grpc_channel_create(const char* target, const grpc_channel_args* input_args, grpc_channel_stack_type channel_stack_type, diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 26d8fceb2f8..507013f4529 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -58,6 +58,9 @@ grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel, size_t grpc_channel_get_call_size_estimate(grpc_channel* channel); void grpc_channel_update_call_size_estimate(grpc_channel* channel, size_t size); +char* grpc_channel_get_trace(grpc_channel* channel, bool recursive); +intptr_t grpc_channel_get_uuid(grpc_channel* channel); + #ifndef NDEBUG void grpc_channel_internal_ref(grpc_channel* channel, const char* reason); void grpc_channel_internal_unref(grpc_channel* channel, const char* reason); diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index 0f40965f16c..a33b6de8b7e 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -41,6 +41,7 @@ #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/fork.h" +#include "src/core/lib/support/object_registry.h" #include "src/core/lib/support/thd_internal.h" #include "src/core/lib/surface/alarm_internal.h" #include "src/core/lib/surface/api_trace.h" @@ -129,6 +130,7 @@ void grpc_init(void) { grpc_slice_intern_init(); grpc_mdctx_global_init(); grpc_channel_init_init(); + grpc_object_registry_init(); grpc_security_pre_init(); grpc_core::ExecCtx::GlobalInit(); grpc_iomgr_init(); @@ -177,6 +179,7 @@ void grpc_shutdown(void) { grpc_mdctx_global_shutdown(); grpc_handshaker_factory_registry_shutdown(); grpc_slice_intern_shutdown(); + grpc_object_registry_shutdown(); grpc_stats_shutdown(); } grpc_core::ExecCtx::GlobalShutdown(); diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index aea0786890b..1e964cebce7 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -38,6 +38,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/support/log_windows.cc', 'src/core/lib/support/mpscq.cc', 'src/core/lib/support/murmur_hash.cc', + 'src/core/lib/support/object_registry.cc', 'src/core/lib/support/string.cc', 'src/core/lib/support/string_posix.cc', 'src/core/lib/support/string_util_windows.cc', @@ -64,6 +65,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/channel/channel_args.cc', 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_tracer.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker_factory.cc', diff --git a/test/core/channel/channel_tracer_test.cc b/test/core/channel/channel_tracer_test.cc new file mode 100644 index 00000000000..a5264774fb5 --- /dev/null +++ b/test/core/channel/channel_tracer_test.cc @@ -0,0 +1,210 @@ +/* + * + * 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 +#include + +#include +#include +#include + +#include "src/core/lib/channel/channel_tracer.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +#include "test/core/util/channel_tracing_utils.h" +#include "test/core/util/test_config.h" + +static void add_simple_trace(grpc_channel_tracer* tracer) { + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("simple trace"), + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), GRPC_CHANNEL_READY, NULL); +} + +// checks for the existence of all the required members of the tracer. +static void validate_tracer(grpc_channel_tracer* tracer, + size_t expected_num_nodes_logged, + size_t max_nodes) { + char* json_str = grpc_channel_tracer_render_trace(tracer, true); + grpc_json* json = grpc_json_parse_string(json_str); + validate_channel_data(json, expected_num_nodes_logged, + GPR_MIN(expected_num_nodes_logged, max_nodes)); + grpc_json_destroy(json); + gpr_free(json_str); +} + +// ensures the tracer has the correct number of children tracers. +static void validate_children(grpc_channel_tracer* tracer, + size_t expected_num_children) { + char* json_str = grpc_channel_tracer_render_trace(tracer, true); + grpc_json* json = grpc_json_parse_string(json_str); + validate_json_array_size(json, "children", expected_num_children); + grpc_json_destroy(json); + gpr_free(json_str); +} + +static intptr_t uuid = 0; + +static void test_basic_channel_tracing(size_t max_nodes) { + grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(max_nodes, uuid++); + grpc_core::ExecCtx exec_ctx; + add_simple_trace(tracer); + add_simple_trace(tracer); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("trace three"), + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), + GRPC_ERROR_INT_HTTP2_ERROR, 2), + GRPC_CHANNEL_IDLE, NULL); + grpc_channel_tracer_add_trace(tracer, + grpc_slice_from_static_string("trace four"), + GRPC_ERROR_NONE, GRPC_CHANNEL_SHUTDOWN, NULL); + validate_tracer(tracer, 4, max_nodes); + add_simple_trace(tracer); + add_simple_trace(tracer); + validate_tracer(tracer, 6, max_nodes); + add_simple_trace(tracer); + add_simple_trace(tracer); + add_simple_trace(tracer); + add_simple_trace(tracer); + validate_tracer(tracer, 10, max_nodes); + GRPC_CHANNEL_TRACER_UNREF(tracer); +} + +static void test_basic_channel_sizing() { + test_basic_channel_tracing(0); + test_basic_channel_tracing(1); + test_basic_channel_tracing(2); + test_basic_channel_tracing(6); + test_basic_channel_tracing(10); + test_basic_channel_tracing(15); +} + +static void test_complex_channel_tracing(size_t max_nodes) { + grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(max_nodes, uuid++); + grpc_core::ExecCtx exec_ctx; + add_simple_trace(tracer); + add_simple_trace(tracer); + grpc_channel_tracer* sc1 = GRPC_CHANNEL_TRACER_CREATE(max_nodes, uuid++); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel one created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); + validate_tracer(tracer, 3, max_nodes); + add_simple_trace(sc1); + add_simple_trace(sc1); + add_simple_trace(sc1); + validate_tracer(sc1, 3, max_nodes); + add_simple_trace(sc1); + add_simple_trace(sc1); + add_simple_trace(sc1); + validate_tracer(sc1, 6, max_nodes); + add_simple_trace(tracer); + add_simple_trace(tracer); + validate_tracer(tracer, 5, max_nodes); + grpc_channel_tracer* sc2 = GRPC_CHANNEL_TRACER_CREATE(max_nodes, uuid++); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel two created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc2); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel one inactive"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); + validate_tracer(tracer, 7, max_nodes); + add_simple_trace(tracer); + add_simple_trace(tracer); + add_simple_trace(tracer); + add_simple_trace(tracer); + add_simple_trace(tracer); + add_simple_trace(tracer); + GRPC_CHANNEL_TRACER_UNREF(sc1); + GRPC_CHANNEL_TRACER_UNREF(sc2); + GRPC_CHANNEL_TRACER_UNREF(tracer); +} + +static void test_complex_channel_sizing() { + test_complex_channel_tracing(0); + test_complex_channel_tracing(1); + test_complex_channel_tracing(2); + test_complex_channel_tracing(6); + test_complex_channel_tracing(10); + test_complex_channel_tracing(15); +} + +static void test_delete_parent_first() { + grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(3, uuid++); + grpc_core::ExecCtx exec_ctx; + add_simple_trace(tracer); + add_simple_trace(tracer); + grpc_channel_tracer* sc1 = GRPC_CHANNEL_TRACER_CREATE(3, uuid++); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel one created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); + // this will cause the tracer destructor to run. + GRPC_CHANNEL_TRACER_UNREF(tracer); + GRPC_CHANNEL_TRACER_UNREF(sc1); +} + +static void test_nesting() { + grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(10, uuid++); + grpc_core::ExecCtx exec_ctx; + add_simple_trace(tracer); + add_simple_trace(tracer); + grpc_channel_tracer* sc1 = GRPC_CHANNEL_TRACER_CREATE(5, uuid++); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel one created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); + // channel has only one subchannel right here. + validate_children(tracer, 1); + add_simple_trace(sc1); + grpc_channel_tracer* conn1 = GRPC_CHANNEL_TRACER_CREATE(5, uuid++); + // nesting one level deeper. + grpc_channel_tracer_add_trace( + sc1, grpc_slice_from_static_string("connection one created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, conn1); + validate_children(sc1, 1); + add_simple_trace(conn1); + add_simple_trace(tracer); + add_simple_trace(tracer); + grpc_channel_tracer* sc2 = GRPC_CHANNEL_TRACER_CREATE(5, uuid++); + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel two created"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc2); + validate_children(tracer, 2); + // this trace should not get added to the parents children since it is already + // present in the tracer. + grpc_channel_tracer_add_trace( + tracer, grpc_slice_from_static_string("subchannel one inactive"), + GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); + validate_children(tracer, 2); + add_simple_trace(tracer); + + GRPC_CHANNEL_TRACER_UNREF(conn1); + GRPC_CHANNEL_TRACER_UNREF(sc1); + GRPC_CHANNEL_TRACER_UNREF(sc2); + GRPC_CHANNEL_TRACER_UNREF(tracer); +} + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + grpc_init(); + test_basic_channel_tracing(5); + test_basic_channel_sizing(); + test_complex_channel_tracing(5); + test_complex_channel_sizing(); + test_delete_parent_first(); + test_nesting(); + grpc_shutdown(); + return 0; +} diff --git a/test/core/util/channel_tracing_utils.cc b/test/core/util/channel_tracing_utils.cc new file mode 100644 index 00000000000..805726ff166 --- /dev/null +++ b/test/core/util/channel_tracing_utils.cc @@ -0,0 +1,60 @@ +/* + * + * 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 +#include + +#include +#include +#include "src/core/lib/channel/channel_tracer.h" +#include "src/core/lib/json/json.h" + +static grpc_json* get_json_child(grpc_json* parent, const char* key) { + GPR_ASSERT(parent != NULL); + for (grpc_json* child = parent->child; child != NULL; child = child->next) { + if (child->key != NULL && strcmp(child->key, key) == 0) return child; + } + return NULL; +} + +void validate_json_array_size(grpc_json* json, const char* key, + size_t expected_size) { + grpc_json* arr = get_json_child(json, key); + GPR_ASSERT(arr); + GPR_ASSERT(arr->type == GRPC_JSON_ARRAY); + size_t count = 0; + for (grpc_json* child = arr->child; child != NULL; child = child->next) { + ++count; + } + GPR_ASSERT(count == expected_size); +} + +void validate_channel_data(grpc_json* json, size_t num_nodes_logged_expected, + size_t actual_num_nodes_expected) { + GPR_ASSERT(json); + grpc_json* channel_data = get_json_child(json, "channelData"); + grpc_json* num_nodes_logged_json = + get_json_child(channel_data, "numNodesLogged"); + GPR_ASSERT(num_nodes_logged_json); + grpc_json* start_time = get_json_child(channel_data, "startTime"); + GPR_ASSERT(start_time); + size_t num_nodes_logged = + (size_t)strtol(num_nodes_logged_json->value, NULL, 0); + GPR_ASSERT(num_nodes_logged == num_nodes_logged_expected); + validate_json_array_size(channel_data, "nodes", actual_num_nodes_expected); +} diff --git a/test/core/util/channel_tracing_utils.h b/test/core/util/channel_tracing_utils.h new file mode 100644 index 00000000000..6a3eac98a91 --- /dev/null +++ b/test/core/util/channel_tracing_utils.h @@ -0,0 +1,30 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_TEST_CORE_UTIL_CHANNEL_TRACING_UTILS_H +#define GRPC_TEST_CORE_UTIL_CHANNEL_TRACING_UTILS_H + +#include "src/core/lib/channel/channel_tracer.h" + +void validate_json_array_size(grpc_json* json, const char* key, + size_t expected_size); + +void validate_channel_data(grpc_json* json, size_t num_nodes_logged_expected, + size_t actual_num_nodes_expected); + +#endif /* GRPC_TEST_CORE_UTIL_CHANNEL_TRACING_UTILS_H */ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index d09b325c97a..65bc771cf01 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -938,6 +938,7 @@ src/core/lib/backoff/backoff.h \ 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_tracer.h \ src/core/lib/channel/connected_channel.h \ src/core/lib/channel/context.h \ src/core/lib/channel/handshaker.h \ @@ -1039,6 +1040,7 @@ src/core/lib/support/manual_constructor.h \ src/core/lib/support/memory.h \ src/core/lib/support/mpscq.h \ src/core/lib/support/murmur_hash.h \ +src/core/lib/support/object_registry.h \ src/core/lib/support/ref_counted.h \ src/core/lib/support/ref_counted_ptr.h \ src/core/lib/support/spinlock.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 1aff0075a6a..4caa299a175 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1040,6 +1040,8 @@ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.h \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.h \ +src/core/lib/channel/channel_tracer.cc \ +src/core/lib/channel/channel_tracer.h \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.h \ src/core/lib/channel/context.h \ @@ -1305,6 +1307,8 @@ src/core/lib/support/mpscq.cc \ src/core/lib/support/mpscq.h \ src/core/lib/support/murmur_hash.cc \ src/core/lib/support/murmur_hash.h \ +src/core/lib/support/object_registry.cc \ +src/core/lib/support/object_registry.h \ src/core/lib/support/ref_counted.h \ src/core/lib/support/ref_counted_ptr.h \ src/core/lib/support/spinlock.h \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 0fc5a25afd3..067bf438341 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -914,6 +914,23 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "grpc_channel_tracer_test", + "src": [ + "test/core/channel/channel_tracer_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", @@ -7791,6 +7808,7 @@ "src/core/lib/support/log_windows.cc", "src/core/lib/support/mpscq.cc", "src/core/lib/support/murmur_hash.cc", + "src/core/lib/support/object_registry.cc", "src/core/lib/support/string.cc", "src/core/lib/support/string_posix.cc", "src/core/lib/support/string_util_windows.cc", @@ -7859,6 +7877,7 @@ "src/core/lib/support/memory.h", "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/object_registry.h", "src/core/lib/support/spinlock.h", "src/core/lib/support/string.h", "src/core/lib/support/string_windows.h", @@ -7908,6 +7927,7 @@ "src/core/lib/support/memory.h", "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/object_registry.h", "src/core/lib/support/spinlock.h", "src/core/lib/support/string.h", "src/core/lib/support/string_windows.h", @@ -8002,6 +8022,7 @@ "src/core/lib/channel/channel_args.cc", "src/core/lib/channel/channel_stack.cc", "src/core/lib/channel/channel_stack_builder.cc", + "src/core/lib/channel/channel_tracer.cc", "src/core/lib/channel/connected_channel.cc", "src/core/lib/channel/handshaker.cc", "src/core/lib/channel/handshaker_factory.cc", @@ -8158,6 +8179,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_tracer.h", "src/core/lib/channel/connected_channel.h", "src/core/lib/channel/context.h", "src/core/lib/channel/handshaker.h", @@ -8297,6 +8319,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_tracer.h", "src/core/lib/channel/connected_channel.h", "src/core/lib/channel/context.h", "src/core/lib/channel/handshaker.h", @@ -8940,6 +8963,7 @@ "test/core/end2end/fixtures/http_proxy_fixture.h", "test/core/end2end/fixtures/proxy.h", "test/core/iomgr/endpoint_tests.h", + "test/core/util/channel_tracing_utils.h", "test/core/util/debugger_macros.h", "test/core/util/grpc_profiler.h", "test/core/util/histogram.h", @@ -8967,6 +8991,8 @@ "test/core/end2end/fixtures/proxy.h", "test/core/iomgr/endpoint_tests.cc", "test/core/iomgr/endpoint_tests.h", + "test/core/util/channel_tracing_utils.cc", + "test/core/util/channel_tracing_utils.h", "test/core/util/debugger_macros.cc", "test/core/util/debugger_macros.h", "test/core/util/grpc_profiler.cc", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 5cf371190c9..82157d095bc 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1223,6 +1223,30 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "grpc_channel_tracer_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false,