aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD4
-rw-r--r--CMakeLists.txt42
-rw-r--r--Makefile50
-rw-r--r--build.yaml17
-rw-r--r--config.m42
-rw-r--r--config.w322
-rw-r--r--gRPC-C++.podspec4
-rw-r--r--gRPC-Core.podspec8
-rw-r--r--grpc.def2
-rw-r--r--grpc.gemspec4
-rw-r--r--grpc.gyp10
-rw-r--r--include/grpc/grpc.h7
-rw-r--r--include/grpc/impl/codegen/grpc_types.h4
-rw-r--r--package.xml4
-rw-r--r--src/core/ext/filters/client_channel/subchannel.cc5
-rw-r--r--src/core/lib/channel/channel_tracer.cc181
-rw-r--r--src/core/lib/channel/channel_tracer.h129
-rw-r--r--src/core/lib/channel/object_registry.cc103
-rw-r--r--src/core/lib/channel/object_registry.h52
-rw-r--r--src/core/lib/json/json.cc36
-rw-r--r--src/core/lib/json/json.h21
-rw-r--r--src/core/lib/surface/channel.cc33
-rw-r--r--src/core/lib/surface/init.cc3
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c4
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h6
-rw-r--r--test/core/channel/BUILD12
-rw-r--r--test/core/channel/channel_tracer_test.cc208
-rw-r--r--test/core/surface/public_headers_must_be_c89.c2
-rw-r--r--test/core/util/BUILD4
-rw-r--r--test/core/util/channel_tracing_utils.cc60
-rw-r--r--test/core/util/channel_tracing_utils.h31
-rw-r--r--tools/doxygen/Doxyfile.c++.internal2
-rw-r--r--tools/doxygen/Doxyfile.core.internal4
-rw-r--r--tools/run_tests/generated/sources_and_headers.json26
-rw-r--r--tools/run_tests/generated/tests.json24
36 files changed, 1105 insertions, 3 deletions
diff --git a/BUILD b/BUILD
index 4fe3dc660e..0baf89ff57 100644
--- a/BUILD
+++ b/BUILD
@@ -676,7 +676,9 @@ grpc_cc_library(
"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/object_registry.cc",
"src/core/lib/channel/handshaker.cc",
"src/core/lib/channel/handshaker_factory.cc",
"src/core/lib/channel/handshaker_registry.cc",
@@ -811,8 +813,10 @@ grpc_cc_library(
"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/object_registry.h",
"src/core/lib/channel/handshaker.h",
"src/core/lib/channel/handshaker_factory.h",
"src/core/lib/channel/handshaker_registry.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab4fa8a253..c80744d827 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -283,6 +283,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)
@@ -799,10 +800,12 @@ 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
src/core/lib/channel/handshaker_registry.cc
+ src/core/lib/channel/object_registry.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
@@ -1141,10 +1144,12 @@ 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
src/core/lib/channel/handshaker_registry.cc
+ src/core/lib/channel/object_registry.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
@@ -1448,6 +1453,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
@@ -1469,10 +1475,12 @@ 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
src/core/lib/channel/handshaker_registry.cc
+ src/core/lib/channel/object_registry.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
@@ -1737,6 +1745,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
@@ -1758,10 +1767,12 @@ 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
src/core/lib/channel/handshaker_registry.cc
+ src/core/lib/channel/object_registry.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
@@ -2027,10 +2038,12 @@ 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
src/core/lib/channel/handshaker_registry.cc
+ src/core/lib/channel/object_registry.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
@@ -2830,10 +2843,12 @@ 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
src/core/lib/channel/handshaker_registry.cc
+ src/core/lib/channel/object_registry.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
@@ -6544,6 +6559,33 @@ 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 ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+)
+
+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 b090b9fb94..02a72910ff 100644
--- a/Makefile
+++ b/Makefile
@@ -1006,6 +1006,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
@@ -1424,6 +1425,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 \
@@ -1916,6 +1918,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"
@@ -3035,10 +3039,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
@@ -3379,10 +3385,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
@@ -3687,6 +3695,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 \
@@ -3708,10 +3717,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
@@ -3969,6 +3980,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 \
@@ -3990,10 +4002,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
@@ -4239,10 +4253,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
@@ -5041,10 +5057,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
@@ -11396,6 +11414,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 e2d194041a..d03b7a113c 100644
--- a/build.yaml
+++ b/build.yaml
@@ -154,10 +154,12 @@ 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
- src/core/lib/channel/handshaker_registry.cc
+ - src/core/lib/channel/object_registry.cc
- src/core/lib/compression/compression.cc
- src/core/lib/compression/compression_internal.cc
- src/core/lib/compression/message_compress.cc
@@ -310,11 +312,13 @@ 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
- src/core/lib/channel/handshaker_factory.h
- src/core/lib/channel/handshaker_registry.h
+ - src/core/lib/channel/object_registry.h
- src/core/lib/compression/algorithm_metadata.h
- src/core/lib/compression/compression_internal.h
- src/core/lib/compression/message_compress.h
@@ -715,6 +719,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
@@ -734,6 +739,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
@@ -2426,6 +2432,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 1a055845eb..5f79cbcb6a 100644
--- a/config.m4
+++ b/config.m4
@@ -84,10 +84,12 @@ 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 \
src/core/lib/channel/handshaker_registry.cc \
+ src/core/lib/channel/object_registry.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
diff --git a/config.w32 b/config.w32
index 5e41295cbf..5471d5cc56 100644
--- a/config.w32
+++ b/config.w32
@@ -61,10 +61,12 @@ 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 " +
"src\\core\\lib\\channel\\handshaker_registry.cc " +
+ "src\\core\\lib\\channel\\object_registry.cc " +
"src\\core\\lib\\compression\\compression.cc " +
"src\\core\\lib\\compression\\compression_internal.cc " +
"src\\core\\lib\\compression\\message_compress.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 821c16da45..d9237752c5 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -316,11 +316,13 @@ 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',
'src/core/lib/channel/handshaker_factory.h',
'src/core/lib/channel/handshaker_registry.h',
+ 'src/core/lib/channel/object_registry.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
@@ -495,11 +497,13 @@ 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',
'src/core/lib/channel/handshaker_factory.h',
'src/core/lib/channel/handshaker_registry.h',
+ 'src/core/lib/channel/object_registry.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 6c6c76991c..6546fe8af2 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -327,11 +327,13 @@ 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',
'src/core/lib/channel/handshaker_factory.h',
'src/core/lib/channel/handshaker_registry.h',
+ 'src/core/lib/channel/object_registry.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
@@ -471,10 +473,12 @@ 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',
'src/core/lib/channel/handshaker_registry.cc',
+ 'src/core/lib/channel/object_registry.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
@@ -821,11 +825,13 @@ 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',
'src/core/lib/channel/handshaker_factory.h',
'src/core/lib/channel/handshaker_registry.h',
+ 'src/core/lib/channel/object_registry.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
@@ -996,6 +1002,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',
@@ -1018,6 +1025,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.def b/grpc.def
index 2bafebbbd4..5ff3a1efe8 100644
--- a/grpc.def
+++ b/grpc.def
@@ -45,6 +45,8 @@ EXPORTS
grpc_insecure_channel_create
grpc_lame_client_channel_create
grpc_channel_destroy
+ grpc_channel_get_trace
+ grpc_channel_get_uuid
grpc_call_cancel
grpc_call_cancel_with_status
grpc_call_ref
diff --git a/grpc.gemspec b/grpc.gemspec
index fbe70aa795..d33333ace9 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -253,11 +253,13 @@ 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 )
s.files += %w( src/core/lib/channel/handshaker_factory.h )
s.files += %w( src/core/lib/channel/handshaker_registry.h )
+ s.files += %w( src/core/lib/channel/object_registry.h )
s.files += %w( src/core/lib/compression/algorithm_metadata.h )
s.files += %w( src/core/lib/compression/compression_internal.h )
s.files += %w( src/core/lib/compression/message_compress.h )
@@ -401,10 +403,12 @@ 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 )
s.files += %w( src/core/lib/channel/handshaker_registry.cc )
+ s.files += %w( src/core/lib/channel/object_registry.cc )
s.files += %w( src/core/lib/compression/compression.cc )
s.files += %w( src/core/lib/compression/compression_internal.cc )
s.files += %w( src/core/lib/compression/message_compress.cc )
diff --git a/grpc.gyp b/grpc.gyp
index cd3deddb0e..9b5ae58ee4 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -225,10 +225,12 @@
'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',
'src/core/lib/channel/handshaker_registry.cc',
+ 'src/core/lib/channel/object_registry.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.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',
@@ -524,10 +527,12 @@
'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',
'src/core/lib/channel/handshaker_registry.cc',
+ 'src/core/lib/channel/object_registry.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
@@ -720,6 +725,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',
@@ -741,10 +747,12 @@
'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',
'src/core/lib/channel/handshaker_registry.cc',
+ 'src/core/lib/channel/object_registry.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
@@ -937,10 +945,12 @@
'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',
'src/core/lib/channel/handshaker_registry.cc',
+ 'src/core/lib/channel/object_registry.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index c129a66949..5c6cabb380 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -286,6 +286,13 @@ 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. */
+GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel);
+
+/** Returns the channel uuid, which can be used to look up its trace at a
+ later time. */
+GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel);
+
/** Error handling for grpc_call
Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
then the operation failed due to some unsatisfied precondition.
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index dcce2e7f9a..b671ad653e 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -281,6 +281,10 @@ 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 events 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_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
+ "grpc.max_channel_trace_events_per_node"
/** 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 db03230eba..1cf10540ee 100644
--- a/package.xml
+++ b/package.xml
@@ -260,11 +260,13 @@
<file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
<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_tracer.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" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/channel/object_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
@@ -408,10 +410,12 @@
<file baseinstalldir="/" name="src/core/lib/channel/channel_args.cc" role="src" />
<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_tracer.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" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/channel/object_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression_internal.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/message_compress.cc" role="src" />
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index cae7cc35e3..77c0fe2c43 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -36,10 +36,13 @@
#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/channel/object_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
@@ -132,6 +135,8 @@ struct grpc_subchannel {
bool backoff_begun;
/** our alarm */
grpc_timer alarm;
+
+ grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer;
};
struct grpc_subchannel_call {
diff --git a/src/core/lib/channel/channel_tracer.cc b/src/core/lib/channel/channel_tracer.cc
new file mode 100644
index 0000000000..86b7a6cce9
--- /dev/null
+++ b/src/core/lib/channel/channel_tracer.cc
@@ -0,0 +1,181 @@
+/*
+ *
+ * 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/channel_tracer.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/lib/channel/object_registry.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"
+
+namespace grpc_core {
+
+ChannelTrace::TraceEvent::~TraceEvent() {
+ GRPC_ERROR_UNREF(error_);
+ referenced_tracer_.reset();
+ grpc_slice_unref_internal(data_);
+}
+
+ChannelTrace::ChannelTrace(size_t max_events)
+ : channel_uuid_(-1),
+ num_events_logged_(0),
+ num_children_seen_(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_ = grpc_object_registry_register_object(
+ this, GRPC_OBJECT_REGISTRY_CHANNEL_TRACER);
+ time_created_ = gpr_now(GPR_CLOCK_REALTIME);
+}
+
+ChannelTrace::~ChannelTrace() {
+ if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
+ TraceEvent* it = head_trace_;
+ while (it != nullptr) {
+ TraceEvent* to_free = it;
+ it = it->next();
+ Delete<TraceEvent>(to_free);
+ }
+ gpr_mu_destroy(&tracer_mu_);
+}
+
+intptr_t ChannelTrace::GetUuid() { return channel_uuid_; }
+
+void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
+ ++num_events_logged_;
+ // first event case
+ if (head_trace_ == nullptr) {
+ head_trace_ = tail_trace_ = new_trace_event;
+ }
+ // regular event add case
+ else {
+ tail_trace_->set_next(new_trace_event);
+ tail_trace_ = tail_trace_->next();
+ }
+ ++list_size_;
+ // maybe garbage collect the end
+ if (list_size_ > max_list_size_) {
+ TraceEvent* to_free = head_trace_;
+ head_trace_ = head_trace_->next();
+ Delete<TraceEvent>(to_free);
+ --list_size_;
+ }
+}
+
+void ChannelTrace::AddTraceEvent(
+ grpc_slice data, grpc_error* error,
+ grpc_connectivity_state connectivity_state,
+ RefCountedPtr<ChannelTrace> referenced_tracer) {
+ if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
+ ++num_children_seen_;
+ // create and fill up the new event
+ AddTraceEventHelper(New<TraceEvent>(data, error, connectivity_state,
+ std::move(referenced_tracer)));
+}
+
+void ChannelTrace::AddTraceEvent(grpc_slice data, grpc_error* error,
+ grpc_connectivity_state connectivity_state) {
+ AddTraceEventHelper(New<TraceEvent>(data, error, connectivity_state));
+}
+
+namespace {
+
+// returns an allocated string that represents tm according to RFC-3339.
+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;
+}
+
+} // anonymous namespace
+
+void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) {
+ grpc_json* json_iterator = nullptr;
+ json_iterator = grpc_json_create_child(json_iterator, json, "description",
+ grpc_slice_to_c_string(data_),
+ GRPC_JSON_STRING, true);
+ // TODO(ncteisen): Either format this as google.rpc.Status here, or ensure
+ // it is done in the layers above core.
+ if (error_ != GRPC_ERROR_NONE) {
+ json_iterator = grpc_json_create_child(
+ json_iterator, json, "status", gpr_strdup(grpc_error_string(error_)),
+ GRPC_JSON_STRING, true);
+ }
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "timestamp",
+ fmt_time(time_created_), GRPC_JSON_STRING, true);
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "state",
+ grpc_connectivity_state_name(connectivity_state_),
+ GRPC_JSON_STRING, false);
+ if (referenced_tracer_ != nullptr) {
+ char* uuid_str;
+ gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_tracer_->channel_uuid_);
+ json_iterator = grpc_json_create_child(json_iterator, json, "child_ref",
+ uuid_str, GRPC_JSON_NUMBER, true);
+ }
+}
+
+char* ChannelTrace::RenderTrace() {
+ if (!max_list_size_)
+ return nullptr; // tracing is disabled if max_events == 0
+ grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
+ char* num_events_logged_str;
+ gpr_asprintf(&num_events_logged_str, "%" PRId64, num_events_logged_);
+ grpc_json* json_iterator = nullptr;
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "num_events_logged",
+ num_events_logged_str, GRPC_JSON_NUMBER, true);
+ json_iterator =
+ grpc_json_create_child(json_iterator, json, "creation_time",
+ fmt_time(time_created_), GRPC_JSON_STRING, true);
+ grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
+ nullptr, GRPC_JSON_ARRAY, false);
+ json_iterator = nullptr;
+ TraceEvent* it = head_trace_;
+ while (it != nullptr) {
+ json_iterator = grpc_json_create_child(json_iterator, events, nullptr,
+ nullptr, GRPC_JSON_OBJECT, false);
+ it->RenderTraceEvent(json_iterator);
+ it = it->next();
+ }
+ char* json_str = grpc_json_dump_to_string(json, 0);
+ grpc_json_destroy(json);
+ return json_str;
+}
+
+} // namespace grpc_core
diff --git a/src/core/lib/channel/channel_tracer.h b/src/core/lib/channel/channel_tracer.h
new file mode 100644
index 0000000000..976e66c49e
--- /dev/null
+++ b/src/core/lib/channel/channel_tracer.h
@@ -0,0 +1,129 @@
+/*
+ *
+ * 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 <grpc/impl/codegen/port_platform.h>
+
+#include <grpc/grpc.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/json/json.h"
+
+namespace grpc_core {
+
+// 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> {
+ public:
+ ChannelTrace(size_t max_events);
+ ~ChannelTrace();
+
+ // returns the tracer's uuid
+ intptr_t GetUuid();
+
+ // Adds a new trace event to the tracing object
+ void AddTraceEvent(grpc_slice data, grpc_error* error,
+ grpc_connectivity_state connectivity_state);
+
+ // Adds a new trace event to the tracing object. This trace event refers to a
+ // an event on a child of the channel. For example, if this channel has
+ // 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.
+ void AddTraceEvent(grpc_slice data, grpc_error* error,
+ grpc_connectivity_state connectivity_state,
+ RefCountedPtr<ChannelTrace> referenced_tracer);
+
+ // Returns the tracing data rendered as a grpc json string.
+ // The string is owned by the caller and must be freed.
+ char* RenderTrace();
+
+ private:
+ // 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(grpc_slice data, grpc_error* error,
+ grpc_connectivity_state connectivity_state,
+ RefCountedPtr<ChannelTrace> referenced_tracer)
+ : data_(data),
+ error_(error),
+ connectivity_state_(connectivity_state),
+ next_(nullptr),
+ referenced_tracer_(std::move(referenced_tracer)) {
+ time_created_ = gpr_now(GPR_CLOCK_REALTIME);
+ }
+
+ // Constructor for a TraceEvent that does not reverence a different
+ // channel.
+ TraceEvent(grpc_slice data, grpc_error* error,
+ grpc_connectivity_state connectivity_state)
+ : data_(data),
+ error_(error),
+ connectivity_state_(connectivity_state),
+ next_(nullptr),
+ referenced_tracer_(nullptr) {
+ time_created_ = gpr_now(GPR_CLOCK_REALTIME);
+ }
+
+ ~TraceEvent();
+
+ // Renders the data inside of this TraceEvent into a json object. This is
+ // used by the ChannelTrace, when it is rendering itself.
+ void RenderTraceEvent(grpc_json* json);
+
+ // set and get for the next_ pointer.
+ TraceEvent* next() { return next_; }
+ void set_next(TraceEvent* next) { next_ = next; }
+
+ private:
+ grpc_slice data_;
+ grpc_error* error_;
+ gpr_timespec time_created_;
+ grpc_connectivity_state connectivity_state_;
+ TraceEvent* next_;
+ // the tracer object for the (sub)channel that this trace event refers to.
+ RefCountedPtr<ChannelTrace> referenced_tracer_;
+ }; // TraceEvent
+
+ // Internal helper to add and link in a trace event
+ void AddTraceEventHelper(TraceEvent* new_trace_event);
+
+ gpr_mu tracer_mu_;
+ intptr_t channel_uuid_;
+ uint64_t num_events_logged_;
+ uint64_t num_children_seen_;
+ size_t list_size_;
+ size_t max_list_size_;
+ TraceEvent* head_trace_;
+ TraceEvent* tail_trace_;
+ gpr_timespec time_created_;
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACER_H */
diff --git a/src/core/lib/channel/object_registry.cc b/src/core/lib/channel/object_registry.cc
new file mode 100644
index 0000000000..987c5366ca
--- /dev/null
+++ b/src/core/lib/channel/object_registry.cc
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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/avl/avl.h"
+#include "src/core/lib/channel/object_registry.h"
+#include "src/core/lib/gpr/useful.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+// file global lock and avl.
+static gpr_mu g_mu;
+static grpc_avl g_avl;
+static gpr_atm 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 GPR_ICMP(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<object_tracker*>(value);
+ object_tracker* new_obj =
+ static_cast<object_tracker*>(gpr_malloc(sizeof(object_tracker)));
+ new_obj->object = old->object;
+ new_obj->type = old->type;
+ return new_obj;
+}
+static const grpc_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 = grpc_avl_create(&avl_vtable);
+}
+
+void grpc_object_registry_shutdown() {
+ grpc_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<object_tracker*>(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 = grpc_avl_add(g_avl, (void*)prior, tracker, nullptr);
+ gpr_mu_unlock(&g_mu);
+ return prior;
+}
+
+void grpc_object_registry_unregister_object(intptr_t uuid) {
+ gpr_mu_lock(&g_mu);
+ g_avl = grpc_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<object_tracker*>(grpc_avl_get(g_avl, (void*)uuid, nullptr));
+ gpr_mu_unlock(&g_mu);
+ if (tracker == nullptr) {
+ *object = nullptr;
+ return GRPC_OBJECT_REGISTRY_UNKNOWN;
+ }
+ *object = tracker->object;
+ return tracker->type;
+}
diff --git a/src/core/lib/channel/object_registry.h b/src/core/lib/channel/object_registry.h
new file mode 100644
index 0000000000..446d0cb41f
--- /dev/null
+++ b/src/core/lib/channel/object_registry.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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_OBJECT_REGISTRY_H
+#define GRPC_CORE_LIB_CHANNEL_OBJECT_REGISTRY_H
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#include <stdint.h>
+
+// TODO(ncteisen): convert this file to C++
+
+// Different types that may be stored in the general object registry. For now,
+// the only use case is channel tracers, but the design has been left general.
+typedef enum {
+ // Used to hold uuid -> ChannelTracer mappings to allow for the trace data
+ // to be looked up by uuid, rather then have to walk the entire tree of
+ // trace.
+ GRPC_OBJECT_REGISTRY_CHANNEL_TRACER,
+ // Usually represents an error has occurred in the object lookup.
+ GRPC_OBJECT_REGISTRY_UNKNOWN,
+} grpc_object_registry_type;
+
+void grpc_object_registry_init();
+void grpc_object_registry_shutdown();
+
+// globally registers the object. Returns its unique uuid
+intptr_t grpc_object_registry_register_object(void* object,
+ grpc_object_registry_type type);
+// globally unregisters the object that is associated to uuid.
+void grpc_object_registry_unregister_object(intptr_t uuid);
+// if object with uuid has previously been registered, stores it in *object.
+// if not, returns GRPC_OBJECT_REGISTRY_UNKNOWN and sets *object unchanged.
+grpc_object_registry_type grpc_object_registry_get_object(intptr_t uuid,
+ void** object);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_OBJECT_REGISTRY_H */
diff --git a/src/core/lib/json/json.cc b/src/core/lib/json/json.cc
index 2141db4c5b..816241bbf0 100644
--- a/src/core/lib/json/json.cc
+++ b/src/core/lib/json/json.cc
@@ -21,6 +21,7 @@
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
#include "src/core/lib/json/json.h"
@@ -46,5 +47,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 == nullptr) {
+ GPR_ASSERT(sibling == nullptr);
+ parent->child = child;
+ return child;
+ }
+ if (sibling == nullptr) {
+ sibling = parent->child;
+ }
+ // always find the right most sibling.
+ while (sibling->next != nullptr) {
+ 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 3a62ef9cfb..f93b43048b 100644
--- a/src/core/lib/json/json.h
+++ b/src/core/lib/json/json.h
@@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
+#include <stdbool.h>
#include <stdlib.h>
#include "src/core/lib/json/json_common.h"
@@ -37,6 +38,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
@@ -67,9 +71,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/surface/channel.cc b/src/core/lib/surface/channel.cc
index 03353d6beb..1488736c49 100644
--- a/src/core/lib/surface/channel.cc
+++ b/src/core/lib/surface/channel.cc
@@ -30,8 +30,13 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_tracer.h"
+#include "src/core/lib/channel/object_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
@@ -62,6 +67,8 @@ struct grpc_channel {
gpr_mu registered_call_mu;
registered_call* registered_calls;
+ grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer;
+
char* target;
};
@@ -93,12 +100,14 @@ 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->target = target;
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
+ size_t channel_tracer_max_nodes = 0; // default to off
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = nullptr;
@@ -161,14 +170,33 @@ grpc_channel* grpc_channel_create_with_builder(
channel->compression_options.enabled_algorithms_bitset =
static_cast<uint32_t>(args->args[i].value.integer) |
0x1; /* always support no compression */
+ } else if (0 == strcmp(args->args[i].key,
+ GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE)) {
+ GPR_ASSERT(channel_tracer_max_nodes == 0);
+ // max_nodes defaults to 0 (which is off), clamped between 0 and 100.
+ const grpc_integer_options options = {0, 0, 100};
+ channel_tracer_max_nodes =
+ (size_t)grpc_channel_arg_get_integer(&args->args[i], options);
}
}
-done:
grpc_channel_args_destroy(args);
+ channel->tracer = grpc_core::MakeRefCounted<grpc_core::ChannelTrace>(
+ channel_tracer_max_nodes);
+ channel->tracer->AddTraceEvent(
+ grpc_slice_from_static_string("Channel created"), GRPC_ERROR_NONE,
+ GRPC_CHANNEL_IDLE);
return channel;
}
+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_channel* grpc_channel_create(const char* target,
const grpc_channel_args* input_args,
grpc_channel_stack_type channel_stack_type,
@@ -377,6 +405,7 @@ static void destroy_channel(void* arg, grpc_error* error) {
GRPC_MDELEM_UNREF(rc->authority);
gpr_free(rc);
}
+ channel->tracer.reset();
GRPC_MDELEM_UNREF(channel->default_authority);
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target);
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index ac9f9e6066..2d4b3b55d4 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -29,6 +29,7 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/channel/handshaker_registry.h"
+#include "src/core/lib/channel/object_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/fork.h"
@@ -128,6 +129,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();
@@ -176,6 +178,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 75156793f1..bf8fb90c5f 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -60,10 +60,12 @@ 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',
'src/core/lib/channel/handshaker_registry.cc',
+ 'src/core/lib/channel/object_registry.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index c045480ff4..1c042739a8 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -68,6 +68,8 @@ 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;
@@ -304,6 +306,8 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create");
grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create");
grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy");
+ grpc_channel_get_trace_import = (grpc_channel_get_trace_type) GetProcAddress(library, "grpc_channel_get_trace");
+ grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid");
grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel");
grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status");
grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 4f07452c68..9a09321364 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -179,6 +179,12 @@ extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_impo
typedef void(*grpc_channel_destroy_type)(grpc_channel* channel);
extern grpc_channel_destroy_type grpc_channel_destroy_import;
#define grpc_channel_destroy grpc_channel_destroy_import
+typedef char*(*grpc_channel_get_trace_type)(grpc_channel* channel);
+extern grpc_channel_get_trace_type grpc_channel_get_trace_import;
+#define grpc_channel_get_trace grpc_channel_get_trace_import
+typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel);
+extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import;
+#define grpc_channel_get_uuid grpc_channel_get_uuid_import
typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved);
extern grpc_call_cancel_type grpc_call_cancel_import;
#define grpc_call_cancel grpc_call_cancel_import
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD
index c5dfd8ef37..b215aa205c 100644
--- a/test/core/channel/BUILD
+++ b/test/core/channel/BUILD
@@ -65,3 +65,15 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
+
+grpc_cc_test(
+ name = "channel_tracer_test",
+ srcs = ["channel_tracer_test.cc"],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ ],
+)
diff --git a/test/core/channel/channel_tracer_test.cc b/test/core/channel/channel_tracer_test.cc
new file mode 100644
index 0000000000..78d4dad0b1
--- /dev/null
+++ b/test/core/channel/channel_tracer_test.cc
@@ -0,0 +1,208 @@
+/*
+ *
+ * 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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_tracer.h"
+#include "src/core/lib/channel/object_registry.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+#include "test/core/util/channel_tracing_utils.h"
+#include "test/core/util/test_config.h"
+
+using grpc_core::ChannelTrace;
+using grpc_core::MakeRefCounted;
+using grpc_core::RefCountedPtr;
+
+static void add_simple_trace_event(RefCountedPtr<ChannelTrace> tracer) {
+ tracer->AddTraceEvent(grpc_slice_from_static_string("simple trace"),
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
+ GRPC_CHANNEL_READY);
+}
+
+// checks for the existence of all the required members of the tracer.
+static void validate_tracer(RefCountedPtr<ChannelTrace> tracer,
+ size_t expected_num_event_logged,
+ size_t max_nodes) {
+ if (!max_nodes) return;
+ char* json_str = tracer->RenderTrace();
+ grpc_json* json = grpc_json_parse_string(json_str);
+ validate_channel_trace_data(json, expected_num_event_logged,
+ GPR_MIN(expected_num_event_logged, max_nodes));
+ grpc_json_destroy(json);
+ gpr_free(json_str);
+}
+
+static void validate_tracer_data_matches_uuid_lookup(
+ 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();
+ void* object;
+ grpc_object_registry_type type =
+ grpc_object_registry_get_object(uuid, &object);
+ GPR_ASSERT(type == GRPC_OBJECT_REGISTRY_CHANNEL_TRACER);
+ char* uuid_lookup_json_str =
+ static_cast<ChannelTrace*>(object)->RenderTrace();
+ GPR_ASSERT(strcmp(tracer_json_str, uuid_lookup_json_str) == 0);
+ gpr_free(tracer_json_str);
+ gpr_free(uuid_lookup_json_str);
+}
+
+// Tests basic ChannelTrace functionality like construction, adding trace, and
+// lookups by uuid.
+static void test_basic_channel_tracing(size_t max_nodes) {
+ grpc_core::ExecCtx exec_ctx;
+ RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(max_nodes);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ validate_tracer_data_matches_uuid_lookup(tracer);
+ tracer->AddTraceEvent(
+ 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);
+ tracer->AddTraceEvent(grpc_slice_from_static_string("trace four"),
+ GRPC_ERROR_NONE, GRPC_CHANNEL_SHUTDOWN);
+ validate_tracer(tracer, 4, max_nodes);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ validate_tracer(tracer, 6, max_nodes);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ validate_tracer(tracer, 10, max_nodes);
+ validate_tracer_data_matches_uuid_lookup(tracer);
+ tracer.reset(nullptr);
+}
+
+// Calls basic test with various values for max_nodes (including 0, which turns
+// the tracer off).
+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);
+}
+
+// Tests more complex functionality, like a parent channel tracking
+// subchannles. This exercises the ref/unref patterns since the parent tracer
+// and this function will both hold refs to the subchannel.
+static void test_complex_channel_tracing(size_t max_nodes) {
+ grpc_core::ExecCtx exec_ctx;
+ RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(max_nodes);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(max_nodes);
+ tracer->AddTraceEvent(grpc_slice_from_static_string("subchannel one created"),
+ GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1);
+ validate_tracer(tracer, 3, max_nodes);
+ add_simple_trace_event(sc1);
+ add_simple_trace_event(sc1);
+ add_simple_trace_event(sc1);
+ validate_tracer(sc1, 3, max_nodes);
+ add_simple_trace_event(sc1);
+ add_simple_trace_event(sc1);
+ add_simple_trace_event(sc1);
+ validate_tracer(sc1, 6, max_nodes);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ validate_tracer(tracer, 5, max_nodes);
+ validate_tracer_data_matches_uuid_lookup(tracer);
+ RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(max_nodes);
+ tracer->AddTraceEvent(grpc_slice_from_static_string("subchannel two created"),
+ GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc2);
+ tracer->AddTraceEvent(
+ grpc_slice_from_static_string("subchannel one inactive"), GRPC_ERROR_NONE,
+ GRPC_CHANNEL_IDLE, sc1);
+ validate_tracer(tracer, 7, max_nodes);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ validate_tracer_data_matches_uuid_lookup(tracer);
+ tracer.reset(nullptr);
+ sc1.reset(nullptr);
+ sc2.reset(nullptr);
+}
+
+// Calls the complex test with a sweep of sizes for max_nodes.
+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);
+}
+
+// Test a case in which the parent channel has subchannels and the subchannels
+// have connections. Ensures that everything lives as long as it should then
+// gets deleted.
+static void test_nesting() {
+ grpc_core::ExecCtx exec_ctx;
+ RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(10);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(5);
+ tracer->AddTraceEvent(grpc_slice_from_static_string("subchannel one created"),
+ GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1);
+ add_simple_trace_event(sc1);
+ RefCountedPtr<ChannelTrace> conn1 = MakeRefCounted<ChannelTrace>(5);
+ // nesting one level deeper.
+ sc1->AddTraceEvent(grpc_slice_from_static_string("connection one created"),
+ GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, conn1);
+ add_simple_trace_event(conn1);
+ add_simple_trace_event(tracer);
+ add_simple_trace_event(tracer);
+ RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(5);
+ tracer->AddTraceEvent(grpc_slice_from_static_string("subchannel two created"),
+ GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc2);
+ // this trace should not get added to the parents children since it is already
+ // present in the tracer.
+ tracer->AddTraceEvent(
+ grpc_slice_from_static_string("subchannel one inactive"), GRPC_ERROR_NONE,
+ GRPC_CHANNEL_IDLE, sc1);
+ add_simple_trace_event(tracer);
+ tracer.reset(nullptr);
+ sc1.reset(nullptr);
+ sc2.reset(nullptr);
+ conn1.reset(nullptr);
+}
+
+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_nesting();
+ grpc_shutdown();
+ return 0;
+}
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index bd4dc0b60e..d858603e47 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -106,6 +106,8 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_insecure_channel_create);
printf("%lx", (unsigned long) grpc_lame_client_channel_create);
printf("%lx", (unsigned long) grpc_channel_destroy);
+ printf("%lx", (unsigned long) grpc_channel_get_trace);
+ printf("%lx", (unsigned long) grpc_channel_get_uuid);
printf("%lx", (unsigned long) grpc_call_cancel);
printf("%lx", (unsigned long) grpc_call_cancel_with_status);
printf("%lx", (unsigned long) grpc_call_ref);
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 886cfddf86..366cf05690 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -51,6 +51,7 @@ grpc_cc_library(
grpc_cc_library(
name = "grpc_test_util_base",
srcs = [
+ "channel_tracing_utils.cc",
"cmdline.cc",
"grpc_profiler.cc",
"histogram.cc",
@@ -69,6 +70,7 @@ grpc_cc_library(
"trickle_endpoint.cc",
],
hdrs = [
+ "channel_tracing_utils.h",
"cmdline.h",
"grpc_profiler.h",
"histogram.h",
@@ -103,6 +105,8 @@ grpc_cc_library(
],
)
+
+
grpc_cc_library(
name = "grpc_test_util_unsecure",
srcs = [],
diff --git a/test/core/util/channel_tracing_utils.cc b/test/core/util/channel_tracing_utils.cc
new file mode 100644
index 0000000000..a2449cc4bd
--- /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 <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "src/core/lib/channel/channel_tracer.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/json/json.h"
+
+static grpc_json* get_json_child(grpc_json* parent, const char* key) {
+ GPR_ASSERT(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;
+}
+
+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 != nullptr; child = child->next) {
+ ++count;
+ }
+ GPR_ASSERT(count == expected_size);
+}
+
+void validate_channel_trace_data(grpc_json* json,
+ size_t num_events_logged_expected,
+ size_t actual_num_events_expected) {
+ GPR_ASSERT(json);
+ grpc_json* num_events_logged_json = get_json_child(json, "num_events_logged");
+ GPR_ASSERT(num_events_logged_json);
+ grpc_json* start_time = get_json_child(json, "creation_time");
+ GPR_ASSERT(start_time);
+ size_t num_events_logged =
+ (size_t)strtol(num_events_logged_json->value, nullptr, 0);
+ GPR_ASSERT(num_events_logged == num_events_logged_expected);
+ validate_json_array_size(json, "events", actual_num_events_expected);
+}
diff --git a/test/core/util/channel_tracing_utils.h b/test/core/util/channel_tracing_utils.h
new file mode 100644
index 0000000000..fc04d8bae6
--- /dev/null
+++ b/test/core/util/channel_tracing_utils.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * 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_trace_data(grpc_json* json,
+ size_t num_events_logged_expected,
+ size_t actual_num_events_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 ff5abc679d..4a7428e2d8 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1007,11 +1007,13 @@ 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 \
src/core/lib/channel/handshaker_factory.h \
src/core/lib/channel/handshaker_registry.h \
+src/core/lib/channel/object_registry.h \
src/core/lib/compression/algorithm_metadata.h \
src/core/lib/compression/compression_internal.h \
src/core/lib/compression/message_compress.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 57f9147f44..e1856bf9aa 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1034,6 +1034,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 \
@@ -1043,6 +1045,8 @@ src/core/lib/channel/handshaker_factory.cc \
src/core/lib/channel/handshaker_factory.h \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/handshaker_registry.h \
+src/core/lib/channel/object_registry.cc \
+src/core/lib/channel/object_registry.h \
src/core/lib/compression/algorithm_metadata.h \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 6b8b26f41b..94f45c82ca 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -926,6 +926,23 @@
"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",
+ "gpr_test_util",
+ "grpc",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c",
"name": "grpc_completion_queue_test",
"src": [
"test/core/surface/completion_queue_test.cc"
@@ -8556,10 +8573,12 @@
"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",
"src/core/lib/channel/handshaker_registry.cc",
+ "src/core/lib/channel/object_registry.cc",
"src/core/lib/compression/compression.cc",
"src/core/lib/compression/compression_internal.cc",
"src/core/lib/compression/message_compress.cc",
@@ -8713,11 +8732,13 @@
"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",
"src/core/lib/channel/handshaker_factory.h",
"src/core/lib/channel/handshaker_registry.h",
+ "src/core/lib/channel/object_registry.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/compression_internal.h",
"src/core/lib/compression/message_compress.h",
@@ -8857,11 +8878,13 @@
"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",
"src/core/lib/channel/handshaker_factory.h",
"src/core/lib/channel/handshaker_registry.h",
+ "src/core/lib/channel/object_registry.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/compression_internal.h",
"src/core/lib/compression/message_compress.h",
@@ -9504,6 +9527,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",
@@ -9532,6 +9556,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 6ce7ec28c4..fdcac9318c 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -1238,6 +1238,30 @@
"flaky": false,
"gtest": false,
"language": "c",
+ "name": "grpc_channel_tracer_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "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_completion_queue_test",
"platforms": [
"linux",