From 74e08928a330935716843bca48243b6192aec236 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 2 Sep 2020 16:47:25 +0800 Subject: [PATCH 01/61] initial code from @dio Signed-off-by: wbpcode --- CODEOWNERS | 2 + api/bazel/repositories.bzl | 19 +++ api/bazel/repository_locations.bzl | 8 + api/envoy/config/trace/v3/skywalking.proto | 26 +++ api/envoy/config/trace/v3/trace.proto | 1 + .../tracers/skywalking/v4alpha/BUILD | 13 ++ .../skywalking/v4alpha/skywalking.proto | 26 +++ generated_api_shadow/bazel/repositories.bzl | 19 +++ .../bazel/repository_locations.bzl | 8 + .../envoy/config/trace/v3/skywalking.proto | 26 +++ .../envoy/config/trace/v3/trace.proto | 1 + .../tracers/skywalking/v4alpha/BUILD | 13 ++ .../skywalking/v4alpha/skywalking.proto | 26 +++ source/common/tracing/http_tracer_impl.cc | 3 +- source/extensions/extensions_build_config.bzl | 1 + source/extensions/tracers/skywalking/BUILD | 76 +++++++++ .../extensions/tracers/skywalking/config.cc | 36 ++++ source/extensions/tracers/skywalking/config.h | 31 ++++ .../skywalking/skywalking_tracer_impl.cc | 55 ++++++ .../skywalking/skywalking_tracer_impl.h | 40 +++++ .../tracers/skywalking/skywalking_types.cc | 86 ++++++++++ .../tracers/skywalking/skywalking_types.h | 156 ++++++++++++++++++ .../skywalking/trace_segment_reporter.cc | 106 ++++++++++++ .../skywalking/trace_segment_reporter.h | 50 ++++++ .../extensions/tracers/skywalking/tracer.cc | 86 ++++++++++ source/extensions/tracers/skywalking/tracer.h | 78 +++++++++ test/extensions/tracers/skywalking/BUILD | 25 +++ .../tracers/skywalking/config_test.cc | 55 ++++++ 28 files changed, 1071 insertions(+), 1 deletion(-) create mode 100644 api/envoy/config/trace/v3/skywalking.proto create mode 100644 api/envoy/extensions/tracers/skywalking/v4alpha/BUILD create mode 100644 api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto create mode 100644 generated_api_shadow/envoy/config/trace/v3/skywalking.proto create mode 100644 generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD create mode 100644 generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto create mode 100644 source/extensions/tracers/skywalking/BUILD create mode 100644 source/extensions/tracers/skywalking/config.cc create mode 100644 source/extensions/tracers/skywalking/config.h create mode 100644 source/extensions/tracers/skywalking/skywalking_tracer_impl.cc create mode 100644 source/extensions/tracers/skywalking/skywalking_tracer_impl.h create mode 100644 source/extensions/tracers/skywalking/skywalking_types.cc create mode 100644 source/extensions/tracers/skywalking/skywalking_types.h create mode 100644 source/extensions/tracers/skywalking/trace_segment_reporter.cc create mode 100644 source/extensions/tracers/skywalking/trace_segment_reporter.h create mode 100644 source/extensions/tracers/skywalking/tracer.cc create mode 100644 source/extensions/tracers/skywalking/tracer.h create mode 100644 test/extensions/tracers/skywalking/BUILD create mode 100644 test/extensions/tracers/skywalking/config_test.cc diff --git a/CODEOWNERS b/CODEOWNERS index 1edcf7c68c1ef..1c81b0f1311ff 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -48,6 +48,8 @@ extensions/filters/common/original_src @snowp @klarose /*/extensions/tracers/datadog @cgilmour @palazzem @mattklein123 # tracers.xray extension /*/extensions/tracers/xray @marcomagdy @lavignes @mattklein123 +# tracers.skywalking extension +/*/extensions/tracers/skywalking @dio @lizan # mysql_proxy extension /*/extensions/filters/network/mysql_proxy @rshriram @venilnoronha @mattklein123 # postgres_proxy extension diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index a64e733cf74a9..c902beb8e3bc2 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -37,6 +37,11 @@ def api_dependencies(): locations = REPOSITORY_LOCATIONS, build_file_content = ZIPKINAPI_BUILD_CONTENT, ) + envoy_http_archive( + name = "com_github_apache_skywalking_data_collect_protocol", + locations = REPOSITORY_LOCATIONS, + build_file_content = SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT, + ) PROMETHEUSMETRICS_BUILD_CONTENT = """ load("@envoy_api//bazel:api_build_system.bzl", "api_cc_py_proto_library") @@ -98,3 +103,17 @@ go_proto_library( visibility = ["//visibility:public"], ) """ + +SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT = """ +load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library") +cc_proto_library( + name = "protocol_cc_proto", + srcs = [ + "common/Common.proto", + "language-agent/Tracing.proto", + ], + default_runtime = "@com_google_protobuf//:protobuf", + protoc = "@com_google_protobuf//:protoc", + visibility = ["//visibility:public"], +) +""" diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 2f0fdc723dbbd..9e4cfc3c5e0ec 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -22,6 +22,9 @@ ZIPKINAPI_SHA256 = "688c4fe170821dd589f36ec45aaadc03a618a40283bc1f97da8fa11686fc RULES_PROTO_GIT_SHA = "40298556293ae502c66579620a7ce867d5f57311" # Aug 17, 2020 RULES_PROTO_SHA256 = "aa1ee19226f707d44bee44c720915199c20c84a23318bb0597ed4e5c873ccbd5" +SKYWALKING_COLLECT_DATA_PROTOCOL_RELEASE = "8.1.0" +SKYWALKING_COLLECT_DATA_PROTOCOL_SHA256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9" + REPOSITORY_LOCATIONS = dict( bazel_skylib = dict( sha256 = BAZEL_SKYLIB_SHA256, @@ -63,4 +66,9 @@ REPOSITORY_LOCATIONS = dict( strip_prefix = "zipkin-api-" + ZIPKINAPI_RELEASE, urls = ["https://github.com/openzipkin/zipkin-api/archive/" + ZIPKINAPI_RELEASE + ".tar.gz"], ), + com_github_apache_skywalking_data_collect_protocol = dict( + sha256 = SKYWALKING_COLLECT_DATA_PROTOCOL_SHA256, + strip_prefix = "skywalking-data-collect-protocol-" + SKYWALKING_COLLECT_DATA_PROTOCOL_RELEASE, + urls = ["https://github.com/apache/skywalking-data-collect-protocol/archive/v" + SKYWALKING_COLLECT_DATA_PROTOCOL_RELEASE + ".tar.gz"], + ), ) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto new file mode 100644 index 0000000000000..8f575e70d6fff --- /dev/null +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.config.trace.v3; + +import "envoy/config/core/v3/grpc_service.proto"; + +import "udpa/annotations/migrate.proto"; +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.trace.v3"; +option java_outer_classname = "SkywalkingProto"; +option java_multiple_files = true; +option (udpa.annotations.file_migrate).move_to_package = + "envoy.extensions.tracers.skywalking.v4alpha"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: SkyWalking tracer] + +// Configuration for the SkyWalking tracer. +// [#extension: envoy.tracers.skywalking] +message SkyWalkingConfig { + // SkyWalking collector service. + core.v3.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; +} diff --git a/api/envoy/config/trace/v3/trace.proto b/api/envoy/config/trace/v3/trace.proto index e1db72a2fd5a0..0ee8df2de31d5 100644 --- a/api/envoy/config/trace/v3/trace.proto +++ b/api/envoy/config/trace/v3/trace.proto @@ -10,6 +10,7 @@ import public "envoy/config/trace/v3/http_tracer.proto"; import public "envoy/config/trace/v3/lightstep.proto"; import public "envoy/config/trace/v3/opencensus.proto"; import public "envoy/config/trace/v3/service.proto"; +import public "envoy/config/trace/v3/skywalking.proto"; import public "envoy/config/trace/v3/zipkin.proto"; option java_package = "io.envoyproxy.envoy.config.trace.v3"; diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD b/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD new file mode 100644 index 0000000000000..d8ce683c41d6a --- /dev/null +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/core/v4alpha:pkg", + "//envoy/config/trace/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto new file mode 100644 index 0000000000000..e63f758e7e855 --- /dev/null +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.extensions.tracers.skywalking.v4alpha; + +import "envoy/config/core/v4alpha/grpc_service.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.tracers.skywalking.v4alpha"; +option java_outer_classname = "SkywalkingProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: SkyWalking tracer] + +// Configuration for the SkyWalking tracer. +// [#extension: envoy.tracers.skywalking] +message SkyWalkingConfig { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.trace.v3.SkyWalkingConfig"; + + // SkyWalking collector service. + config.core.v4alpha.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; +} diff --git a/generated_api_shadow/bazel/repositories.bzl b/generated_api_shadow/bazel/repositories.bzl index a64e733cf74a9..c902beb8e3bc2 100644 --- a/generated_api_shadow/bazel/repositories.bzl +++ b/generated_api_shadow/bazel/repositories.bzl @@ -37,6 +37,11 @@ def api_dependencies(): locations = REPOSITORY_LOCATIONS, build_file_content = ZIPKINAPI_BUILD_CONTENT, ) + envoy_http_archive( + name = "com_github_apache_skywalking_data_collect_protocol", + locations = REPOSITORY_LOCATIONS, + build_file_content = SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT, + ) PROMETHEUSMETRICS_BUILD_CONTENT = """ load("@envoy_api//bazel:api_build_system.bzl", "api_cc_py_proto_library") @@ -98,3 +103,17 @@ go_proto_library( visibility = ["//visibility:public"], ) """ + +SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT = """ +load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library") +cc_proto_library( + name = "protocol_cc_proto", + srcs = [ + "common/Common.proto", + "language-agent/Tracing.proto", + ], + default_runtime = "@com_google_protobuf//:protobuf", + protoc = "@com_google_protobuf//:protoc", + visibility = ["//visibility:public"], +) +""" diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 2f0fdc723dbbd..9e4cfc3c5e0ec 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -22,6 +22,9 @@ ZIPKINAPI_SHA256 = "688c4fe170821dd589f36ec45aaadc03a618a40283bc1f97da8fa11686fc RULES_PROTO_GIT_SHA = "40298556293ae502c66579620a7ce867d5f57311" # Aug 17, 2020 RULES_PROTO_SHA256 = "aa1ee19226f707d44bee44c720915199c20c84a23318bb0597ed4e5c873ccbd5" +SKYWALKING_COLLECT_DATA_PROTOCOL_RELEASE = "8.1.0" +SKYWALKING_COLLECT_DATA_PROTOCOL_SHA256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9" + REPOSITORY_LOCATIONS = dict( bazel_skylib = dict( sha256 = BAZEL_SKYLIB_SHA256, @@ -63,4 +66,9 @@ REPOSITORY_LOCATIONS = dict( strip_prefix = "zipkin-api-" + ZIPKINAPI_RELEASE, urls = ["https://github.com/openzipkin/zipkin-api/archive/" + ZIPKINAPI_RELEASE + ".tar.gz"], ), + com_github_apache_skywalking_data_collect_protocol = dict( + sha256 = SKYWALKING_COLLECT_DATA_PROTOCOL_SHA256, + strip_prefix = "skywalking-data-collect-protocol-" + SKYWALKING_COLLECT_DATA_PROTOCOL_RELEASE, + urls = ["https://github.com/apache/skywalking-data-collect-protocol/archive/v" + SKYWALKING_COLLECT_DATA_PROTOCOL_RELEASE + ".tar.gz"], + ), ) diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto new file mode 100644 index 0000000000000..8f575e70d6fff --- /dev/null +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.config.trace.v3; + +import "envoy/config/core/v3/grpc_service.proto"; + +import "udpa/annotations/migrate.proto"; +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.trace.v3"; +option java_outer_classname = "SkywalkingProto"; +option java_multiple_files = true; +option (udpa.annotations.file_migrate).move_to_package = + "envoy.extensions.tracers.skywalking.v4alpha"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: SkyWalking tracer] + +// Configuration for the SkyWalking tracer. +// [#extension: envoy.tracers.skywalking] +message SkyWalkingConfig { + // SkyWalking collector service. + core.v3.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; +} diff --git a/generated_api_shadow/envoy/config/trace/v3/trace.proto b/generated_api_shadow/envoy/config/trace/v3/trace.proto index e1db72a2fd5a0..0ee8df2de31d5 100644 --- a/generated_api_shadow/envoy/config/trace/v3/trace.proto +++ b/generated_api_shadow/envoy/config/trace/v3/trace.proto @@ -10,6 +10,7 @@ import public "envoy/config/trace/v3/http_tracer.proto"; import public "envoy/config/trace/v3/lightstep.proto"; import public "envoy/config/trace/v3/opencensus.proto"; import public "envoy/config/trace/v3/service.proto"; +import public "envoy/config/trace/v3/skywalking.proto"; import public "envoy/config/trace/v3/zipkin.proto"; option java_package = "io.envoyproxy.envoy.config.trace.v3"; diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD new file mode 100644 index 0000000000000..d8ce683c41d6a --- /dev/null +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/core/v4alpha:pkg", + "//envoy/config/trace/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto new file mode 100644 index 0000000000000..e63f758e7e855 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.extensions.tracers.skywalking.v4alpha; + +import "envoy/config/core/v4alpha/grpc_service.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.tracers.skywalking.v4alpha"; +option java_outer_classname = "SkywalkingProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: SkyWalking tracer] + +// Configuration for the SkyWalking tracer. +// [#extension: envoy.tracers.skywalking] +message SkyWalkingConfig { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.trace.v3.SkyWalkingConfig"; + + // SkyWalking collector service. + config.core.v4alpha.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; +} diff --git a/source/common/tracing/http_tracer_impl.cc b/source/common/tracing/http_tracer_impl.cc index d6010aa083be9..18d682a6c862e 100644 --- a/source/common/tracing/http_tracer_impl.cc +++ b/source/common/tracing/http_tracer_impl.cc @@ -176,7 +176,8 @@ void HttpTracerUtility::finalizeDownstreamSpan(Span& span, if (remote_address->type() == Network::Address::Type::Ip) { const auto remote_ip = remote_address->ip(); - span.setTag(Tracing::Tags::get().PeerAddress, remote_ip->addressAsString()); + span.setTag(Tracing::Tags::get().PeerAddress, + absl::StrCat(remote_ip->addressAsString(), ":", remote_ip->port())); } else { span.setTag(Tracing::Tags::get().PeerAddress, remote_address->logicalName()); } diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 4e9f82d850b16..e3250d0cf7d48 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -153,6 +153,7 @@ EXTENSIONS = { "envoy.tracers.datadog": "//source/extensions/tracers/datadog:config", "envoy.tracers.zipkin": "//source/extensions/tracers/zipkin:config", "envoy.tracers.opencensus": "//source/extensions/tracers/opencensus:config", + "envoy.tracers.skywalking": "//source/extensions/tracers/skywalking:config", # WiP "envoy.tracers.xray": "//source/extensions/tracers/xray:config", diff --git a/source/extensions/tracers/skywalking/BUILD b/source/extensions/tracers/skywalking/BUILD new file mode 100644 index 0000000000000..ec6cf325d945f --- /dev/null +++ b/source/extensions/tracers/skywalking/BUILD @@ -0,0 +1,76 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +# Trace driver for Apache SkyWalking. + +envoy_extension_package() + +envoy_cc_library( + name = "trace_segment_reporter_lib", + srcs = ["trace_segment_reporter.cc"], + hdrs = ["trace_segment_reporter.h"], + deps = [ + ":skywalking_types_lib", + "//include/envoy/grpc:async_client_manager_interface", + "//source/common/grpc:async_client_lib", + "@com_github_apache_skywalking_data_collect_protocol//:protocol_cc_proto", + ], +) + +envoy_cc_library( + name = "skywalking_types_lib", + srcs = ["skywalking_types.cc"], + hdrs = ["skywalking_types.h"], + deps = [ + "//include/envoy/common:random_generator_interface", + "//include/envoy/common:time_interface", + "//include/envoy/http:header_map_interface", + "//source/common/common:base64_lib", + "//source/common/common:hex_lib", + "//source/common/common:utility_lib", + ], +) + +envoy_cc_library( + name = "skywalking_tracer_lib", + srcs = [ + "skywalking_tracer_impl.cc", + "tracer.cc", + ], + hdrs = [ + "skywalking_tracer_impl.h", + "tracer.h", + ], + deps = [ + ":skywalking_types_lib", + ":trace_segment_reporter_lib", + "//include/envoy/common:time_interface", + "//include/envoy/server:tracer_config_interface", + "//include/envoy/tracing:http_tracer_interface", + "//source/common/common:macros", + "//source/common/http:header_map_lib", + "//source/common/runtime:runtime_lib", + "//source/common/tracing:http_tracer_lib", + "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + security_posture = "robust_to_untrusted_downstream", + status = "wip", + deps = [ + ":skywalking_tracer_lib", + "//source/common/config:datasource_lib", + "//source/extensions/tracers/common:factory_base_lib", + "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/tracers/skywalking/config.cc b/source/extensions/tracers/skywalking/config.cc new file mode 100644 index 0000000000000..4f9e15b12f2dc --- /dev/null +++ b/source/extensions/tracers/skywalking/config.cc @@ -0,0 +1,36 @@ +#include "extensions/tracers/skywalking/config.h" + +#include "envoy/config/trace/v3/skywalking.pb.h" +#include "envoy/config/trace/v3/skywalking.pb.validate.h" +#include "envoy/registry/registry.h" + +#include "common/common/utility.h" +#include "common/tracing/http_tracer_impl.h" + +#include "extensions/tracers/skywalking/skywalking_tracer_impl.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +SkyWalkingTracerFactory::SkyWalkingTracerFactory() : FactoryBase("envoy.tracers.skywalking") {} + +Tracing::HttpTracerSharedPtr SkyWalkingTracerFactory::createHttpTracerTyped( + const envoy::config::trace::v3::SkyWalkingConfig& proto_config, + Server::Configuration::TracerFactoryContext& context) { + Tracing::DriverPtr skywalking_driver = + std::make_unique(proto_config, context); + return std::make_shared(std::move(skywalking_driver), + context.serverFactoryContext().localInfo()); +} + +/** + * Static registration for the SkyWalking tracer. @see RegisterFactory. + */ +REGISTER_FACTORY(SkyWalkingTracerFactory, Server::Configuration::TracerFactory); + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/config.h b/source/extensions/tracers/skywalking/config.h new file mode 100644 index 0000000000000..f3a2d4b1668b4 --- /dev/null +++ b/source/extensions/tracers/skywalking/config.h @@ -0,0 +1,31 @@ +#pragma once + +#include "envoy/config/trace/v3/skywalking.pb.h" +#include "envoy/config/trace/v3/skywalking.pb.validate.h" + +#include "extensions/tracers/common/factory_base.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +/** + * Config registration for the skywalking tracer. @see TracerFactory. + */ +class SkyWalkingTracerFactory + : public Common::FactoryBase { +public: + SkyWalkingTracerFactory(); + +private: + // FactoryBase + Tracing::HttpTracerSharedPtr + createHttpTracerTyped(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, + Server::Configuration::TracerFactoryContext& context) override; +}; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc new file mode 100644 index 0000000000000..39508f41ee9c6 --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -0,0 +1,55 @@ +#include "extensions/tracers/skywalking/skywalking_tracer_impl.h" + +#include + +#include "common/common/macros.h" +#include "common/common/utility.h" + +#include "extensions/tracers/skywalking/skywalking_types.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, + Server::Configuration::TracerFactoryContext& context) + : tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { + tls_slot_ptr_->set([this, proto_config, &context]( + Event::Dispatcher& dispatcher) -> ThreadLocal::ThreadLocalObjectSharedPtr { + auto& factory_context = context.serverFactoryContext(); + TracerPtr tracer = + std::make_unique(factory_context.clusterManager(), factory_context.scope(), + factory_context.localInfo(), factory_context.timeSource(), + factory_context.random(), dispatcher, proto_config.grpc_service()); + return std::make_shared(std::move(tracer), *this); + }); +} + +Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, + Http::RequestHeaderMap& request_headers, const std::string&, + Envoy::SystemTime start_time, const Tracing::Decision) { + auto& tracer = *tls_slot_ptr_->getTyped().tracer_; + + SpanContext previous_span_context; + const bool valid_context = previous_span_context.extract(request_headers); + if (!valid_context) { + return std::make_unique(); + } + + SpanContext span_context; + span_context.setParentEndpointAndNetworkAddressUsedAtPeer(Endpoint{request_headers}); + span_context.setService(tracer.service()); + span_context.setServiceInstance(tracer.node()); + + if (previous_span_context.isNew()) { + return tracer.startSpan(config, start_time, span_context, SpanContext{}); + } + + return tracer.startSpan(config, start_time, span_context, previous_span_context); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h new file mode 100644 index 0000000000000..0312e09749962 --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h @@ -0,0 +1,40 @@ +#pragma once + +#include "envoy/config/trace/v3/skywalking.pb.h" +#include "envoy/server/tracer_config.h" +#include "envoy/thread_local/thread_local.h" +#include "envoy/tracing/http_tracer.h" + +#include "common/tracing/http_tracer_impl.h" + +#include "extensions/tracers/skywalking/tracer.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class Driver : public Tracing::Driver, public Logger::Loggable { +public: + explicit Driver(const envoy::config::trace::v3::SkyWalkingConfig& config, + Server::Configuration::TracerFactoryContext& context); + + Tracing::SpanPtr startSpan(const Tracing::Config& config, Http::RequestHeaderMap& request_headers, + const std::string& operation_name, Envoy::SystemTime start_time, + const Tracing::Decision tracing_decision) override; + +private: + struct TlsTracer : ThreadLocal::ThreadLocalObject { + TlsTracer(TracerPtr tracer, Driver& driver) : tracer_(std::move(tracer)), driver_(driver) {} + + TracerPtr tracer_; + Driver& driver_; + }; + + ThreadLocal::SlotPtr tls_slot_ptr_; +}; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc new file mode 100644 index 0000000000000..1d90f301ac746 --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -0,0 +1,86 @@ +#include "extensions/tracers/skywalking/skywalking_types.h" + +#include "common/common/base64.h" +#include "common/common/fmt.h" +#include "common/common/hex.h" +#include "common/common/utility.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +namespace { + +// The standard header name is "sw8", as mentioned in: +// https://github.com/apache/skywalking/blob/6fe2041b470113e626cb3f41e3789261d31f2548/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md#standard-header-item. +const Http::LowerCaseString& propagationHeader() { + CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, "sw8"); +} + +std::string generateId(Random::RandomGenerator& random_generator) { + return absl::StrCat(Hex::uint64ToHex(random_generator.random()), + Hex::uint64ToHex(random_generator.random())); +} + +std::string base64Encode(absl::string_view input) { + return Base64::encode(input.data(), input.length()); +} + +std::string base64Decode(absl::string_view input) { return Base64::decode(std::string(input)); } + +} // namespace + +void SpanContext::initialize(Random::RandomGenerator& random_generator) { + if (trace_id_.empty()) { + trace_id_ = generateId(random_generator); + } + trace_segment_id_ = generateId(random_generator); +} + +bool SpanContext::extract(Http::RequestHeaderMap& request_headers) { + auto propagation_header = request_headers.get(propagationHeader()); + if (propagation_header == nullptr) { + // No propagation_header means a valid span context, but an empty one. + return true; + } + + const auto parts = + StringUtil::splitToken(propagation_header->value().getStringView(), "-", false, true); + // Reference: + // https://github.com/apache/skywalking/blob/6fe2041b470113e626cb3f41e3789261d31f2548/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md#values. + if (parts.size() != 8) { + return false; + } + + // TODO(dio): Per part validation. + sampled_ = parts[0] == "0" ? 0 : 1; + trace_id_ = base64Decode(parts[1]); + trace_segment_id_ = base64Decode(parts[2]); + parent_span_id_ = std::stoi(std::string(parts[3])); + service_ = base64Decode(parts[4]); + service_instance_ = base64Decode(parts[5]); + parent_endpoint_ = base64Decode(parts[6]); + network_address_used_at_peer_ = base64Decode(parts[7]); + + is_new_ = false; + + return true; +} + +void SpanContext::inject(Http::RequestHeaderMap& request_headers) const { + // Reference: + // https://github.com/apache/skywalking/blob/6fe2041b470113e626cb3f41e3789261d31f2548/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md#standard-header-item. + const auto value = absl::StrCat( + sampled_, "-", base64Encode(trace_id_), "-", base64Encode(trace_segment_id_), "-", + parent_span_id_, "-", base64Encode(service_), "-", base64Encode(service_instance_), "-", + base64Encode(parent_endpoint_), "-", base64Encode(network_address_used_at_peer_)); + request_headers.setReferenceKey(propagationHeader(), value); +} + +void SpanObject::finish() { end_time_ = DateUtil::nowToMilliseconds(time_source_); } + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h new file mode 100644 index 0000000000000..1e0c09c0a2f6a --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -0,0 +1,156 @@ +#pragma once + +#include + +#include + +#include "envoy/common/random_generator.h" +#include "envoy/common/time.h" +#include "envoy/http/header_map.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class Endpoint { +public: + explicit Endpoint(Http::RequestHeaderMap& request_headers) + : host_(request_headers.getHostValue()), + method_and_path_( + absl::StrCat("/", request_headers.getMethodValue(), request_headers.getPathValue())) {} + + const std::string& methodAndPath() const { return method_and_path_; } + const std::string& host() const { return host_; } + +private: + const std::string host_; + const std::string method_and_path_; +}; + +class SpanContext { + +public: + void initialize(Random::RandomGenerator& random_generator); + bool extract(Http::RequestHeaderMap& request_headers); + void inject(Http::RequestHeaderMap& request_headers) const; + + void setSampled(bool sampled) { sampled_ = sampled ? 1 : 0; } + void setParentSpanId(int parent_span_id) { parent_span_id_ = parent_span_id; } + void setTraceId(const std::string& trace_id) { trace_id_ = trace_id; } + void setTraceSegmentId(const std::string& trace_segment_id) { + trace_segment_id_ = trace_segment_id; + } + void setService(const std::string& service) { service_ = service; } + void setServiceInstance(const std::string& service_instance) { + service_instance_ = service_instance; + } + void setParentEndpointAndNetworkAddressUsedAtPeer(const Endpoint& endpoint) { + parent_endpoint_ = endpoint.methodAndPath(); + network_address_used_at_peer_ = endpoint.host(); + } + + int sampled() const { return sampled_; } + const std::string& traceId() const { return trace_id_; } + const std::string& traceSegmentId() const { return trace_segment_id_; } + int parentSpanId() const { return parent_span_id_; } + const std::string& service() const { return service_; } + const std::string& serviceInstance() const { return service_instance_; } + const std::string& parentEndpoint() const { return parent_endpoint_; } + const std::string& networkAddressUsedAtPeer() const { return network_address_used_at_peer_; } + + bool isNew() const { return is_new_; } + +private: + int sampled_{1}; + int parent_span_id_{0}; + + std::string trace_id_; + std::string trace_segment_id_; + std::string service_; + std::string service_instance_; + + std::string parent_endpoint_; + // The address used for calling this endpoint. + std::string network_address_used_at_peer_; + + bool is_new_{true}; +}; + +using Tag = std::pair; + +struct Log { + uint64_t timestamp_; + std::vector data_; +}; + +class SpanObject { + +public: + explicit SpanObject(const SpanContext& span_context, const SpanContext& previous_span_context, + TimeSource& time_source, Random::RandomGenerator& random_generator) + : span_context_(span_context), previous_span_context_(previous_span_context), + time_source_(time_source) { + if (!previous_span_context.isNew()) { + span_context_.setTraceId(previous_span_context.traceId()); + } + span_context_.initialize(random_generator); + } + + void finish(); + + void setSpanId(int32_t span_id) { span_id_ = span_id; } + void setParentSpanId(int32_t parent_span_id) { parent_span_id_ = parent_span_id; } + void setStartTime(uint64_t start_time) { start_time_ = start_time; } + void setEndTime(uint64_t end_time) { end_time_ = end_time; } + void setOperationName(const std::string& operation_name) { operation_name_ = operation_name; } + void setAsError(bool is_error) { is_error_ = is_error; } + void setAsEntrySpan(bool is_entry_span) { is_entry_span_ = is_entry_span; } + void setPeer(const std::string& peer) { peer_ = peer; } + void addTag(const Tag& tag) { tags_.push_back(tag); } + void addLog(const Log& log) { logs_.push_back(log); } + + const SpanContext& context() const { return span_context_; } + const SpanContext& previousContext() const { return previous_span_context_; } + + const std::string& operationName() const { return operation_name_; } + uint64_t startTime() const { return start_time_; } + uint64_t endTime() const { return end_time_; } + bool isError() const { return is_error_; } + const std::vector& tags() const { return tags_; } + const std::vector& logs() const { return logs_; } + int32_t spanId() const { return span_id_; } + int32_t parentSpanId() const { return parent_span_id_; } + const std::string& peer() const { return peer_; } + + bool isEntrySpan() const { return is_entry_span_; } + const std::vector& tags() { return tags_; }; + const std::vector& logs() { return logs_; }; + +private: + SpanContext span_context_; + SpanContext previous_span_context_; + + int32_t span_id_{0}; + int32_t parent_span_id_{-1}; + + uint64_t start_time_; + uint64_t end_time_; + + std::string operation_name_; + std::string peer_; + + bool is_error_{false}; + + bool is_entry_span_{true}; + + std::vector tags_; + std::vector logs_; + + TimeSource& time_source_; +}; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc new file mode 100644 index 0000000000000..1d937d9ef4ef3 --- /dev/null +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -0,0 +1,106 @@ +#include "extensions/tracers/skywalking/trace_segment_reporter.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +namespace { + +SegmentObject toSegmentObject(const SpanObject& span_object) { + SegmentObject segment_object; + segment_object.set_traceid(span_object.context().traceId()); + segment_object.set_tracesegmentid(span_object.context().traceSegmentId()); + segment_object.set_service(span_object.context().service()); + segment_object.set_serviceinstance(span_object.context().serviceInstance()); + + auto* span = segment_object.mutable_spans()->Add(); + // The SpanLayer is always Http. + span->set_spanlayer(SpanLayer::Http); + span->set_spantype(span_object.isEntrySpan() ? SpanType::Entry : SpanType::Exit); + + if (!span_object.peer().empty()) { + span->set_peer(span_object.peer()); + } + + span->set_componentid(6000); + span->set_starttime(span_object.startTime()); + span->set_endtime(span_object.endTime()); + span->set_iserror(span_object.isError()); + span->set_operationname(span_object.operationName().empty() + ? span_object.context().parentEndpoint() + : span_object.operationName()); + span->set_spanid(span_object.spanId()); + span->set_parentspanid(span_object.parentSpanId()); + + const auto& previous_context = span_object.previousContext(); + if (!previous_context.isNew()) { + auto* ref = span->mutable_refs()->Add(); + ref->set_traceid(previous_context.traceId()); + ref->set_parenttracesegmentid(previous_context.traceSegmentId()); + ref->set_parentspanid(previous_context.parentSpanId()); + ref->set_parentservice(previous_context.service()); + ref->set_parentserviceinstance(previous_context.serviceInstance()); + ref->set_parentendpoint(previous_context.parentEndpoint()); + ref->set_networkaddressusedatpeer(previous_context.networkAddressUsedAtPeer()); + } + + for (const auto& span_tag : span_object.tags()) { + auto* tag = span->mutable_tags()->Add(); + tag->set_key(span_tag.first); + tag->set_value(span_tag.second); + } + return segment_object; +} + +} // namespace + +TraceSegmentReporter::TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, + Event::Dispatcher& dispatcher) + : client_(factory->create()), + service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( + "TraceSegmentReportService.collect")) { + retry_timer_ = dispatcher.createTimer([this]() -> void { establishNewStream(); }); + establishNewStream(); +} + +void TraceSegmentReporter::report(const SpanObject& span_object) { + sendTraceSegment(toSegmentObject(span_object)); +} + +void TraceSegmentReporter::sendTraceSegment(const SegmentObject& request) { + // TODO(dio): Buffer when stream is not yet established + if (stream_ != nullptr) { + stream_->sendMessage(request, false); + } +} + +void TraceSegmentReporter::closeStream() { + if (stream_ != nullptr) { + stream_->closeStream(); + } +} + +void TraceSegmentReporter::onRemoteClose(Grpc::Status::GrpcStatus, const std::string&) { + stream_ = nullptr; + handleFailure(); +} + +void TraceSegmentReporter::establishNewStream() { + stream_ = client_->start(service_method_, *this, Http::AsyncClient::StreamOptions()); + if (stream_ == nullptr) { + handleFailure(); + return; + } +} + +void TraceSegmentReporter::handleFailure() { setRetryTimer(); } + +void TraceSegmentReporter::setRetryTimer() { + retry_timer_->enableTimer(std::chrono::milliseconds(5000)); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h new file mode 100644 index 0000000000000..bc4ac11892a3e --- /dev/null +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -0,0 +1,50 @@ +#pragma once + +#include "envoy/grpc/async_client_manager.h" + +#include "common/Common.pb.h" +#include "common/grpc/async_client_impl.h" + +#include "extensions/tracers/skywalking/skywalking_types.h" + +#include "language-agent/Tracing.pb.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { +public: + explicit TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, + Event::Dispatcher& dispatcher); + + // Grpc::AsyncStreamCallbacks + void onCreateInitialMetadata(Http::RequestHeaderMap&) override {} + void onReceiveInitialMetadata(Http::ResponseHeaderMapPtr&&) override {} + void onReceiveMessage(std::unique_ptr&&) override {} + void onReceiveTrailingMetadata(Http::ResponseTrailerMapPtr&&) override {} + void onRemoteClose(Grpc::Status::GrpcStatus, const std::string&) override; + + void closeStream(); + void report(const SpanObject& span_object); + +private: + void sendTraceSegment(const SegmentObject& request); + void establishNewStream(); + void handleFailure(); + void setRetryTimer(); + + Grpc::AsyncClient client_; + Grpc::AsyncStream stream_{}; + const Protobuf::MethodDescriptor& service_method_; + + Event::TimerPtr retry_timer_; +}; + +using TraceSegmentReporterPtr = std::unique_ptr; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc new file mode 100644 index 0000000000000..f69e0fa18b92e --- /dev/null +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -0,0 +1,86 @@ +#include "extensions/tracers/skywalking/tracer.h" + +#include + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +constexpr char StatusCodeTag[] = "status_code"; +constexpr char UrlTag[] = "url"; + +namespace { + +uint64_t getTimestamp(SystemTime time) { + return std::chrono::duration_cast(time.time_since_epoch()).count(); +} + +} // namespace + +Tracing::SpanPtr Tracer::startSpan(const Tracing::Config& config, SystemTime start_time, + const SpanContext& span_context, + const SpanContext& previous_context) { + SpanObject span_object(span_context, previous_context, time_source_, random_generator_); + span_object.setAsEntrySpan(config.operationName() == Tracing::OperationName::Ingress); + span_object.setStartTime(getTimestamp(start_time)); + + return std::make_unique(span_object, *this); +} + +void Tracer::report(const SpanObject& span_object) { reporter_->report(span_object); } + +Tracer::~Tracer() { reporter_->closeStream(); } + +Span::Span(SpanObject span_object, Tracer& tracer) : span_object_(span_object), tracer_(tracer) {} + +void Span::setOperation(absl::string_view) {} + +void Span::setTag(absl::string_view name, absl::string_view value) { + if (name == Tracing::Tags::get().HttpUrl) { + span_object_.addTag({UrlTag, std::string(value)}); + } + + if (name == Tracing::Tags::get().HttpStatusCode) { + span_object_.addTag({StatusCodeTag, std::string(value)}); + } + + if (name == Tracing::Tags::get().Error) { + span_object_.setAsError(value == Tracing::Tags::get().True); + } + + if (name == Tracing::Tags::get().PeerAddress && !span_object_.isEntrySpan()) { + // Set perr when it is an exit span. + span_object_.setPeer(std::string(value)); + } + + span_object_.addTag({std::string(name), std::string(value)}); +} + +void Span::log(SystemTime, const std::string&) {} + +void Span::finishSpan() { + span_object_.finish(); + tracer_.report(span_object_); +} + +void Span::injectContext(Http::RequestHeaderMap& request_headers) { + span_object_.context().inject(request_headers); +} + +Tracing::SpanPtr Span::spawnChild(const Tracing::Config& config, const std::string&, + SystemTime start_time) { + return tracer_.startSpan(config, start_time, span_object_.context(), + span_object_.previousContext()); +} + +void Span::setSampled(bool) {} + +std::string Span::getBaggage(absl::string_view) { return EMPTY_STRING; } + +void Span::setBaggage(absl::string_view, absl::string_view) {} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h new file mode 100644 index 0000000000000..ad52e21d3e602 --- /dev/null +++ b/source/extensions/tracers/skywalking/tracer.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include + +#include "envoy/common/pure.h" + +#include "common/tracing/http_tracer_impl.h" + +#include "extensions/tracers/skywalking/skywalking_types.h" +#include "extensions/tracers/skywalking/trace_segment_reporter.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class Tracer { +public: + explicit Tracer(Upstream::ClusterManager& cm, Stats::Scope& scope, + const LocalInfo::LocalInfo& local_info, TimeSource& time_source, + Random::RandomGenerator& random_generator, Event::Dispatcher& dispatcher, + const envoy::config::core::v3::GrpcService& grpc_service) + : node_(local_info.nodeName()), service_(local_info.clusterName()), + address_(absl::StrCat(local_info.address()->asString(), ":", + local_info.address()->ip()->port())), + time_source_(time_source), random_generator_(random_generator), + reporter_(std::make_unique( + cm.grpcAsyncClientManager().factoryForGrpcService(grpc_service, scope, false), + dispatcher)) {} + + ~Tracer(); + + void report(const SpanObject& span_object); + + Tracing::SpanPtr startSpan(const Tracing::Config& config, SystemTime start_time, + const SpanContext& span_context, + const SpanContext& previous_span_context); + + const std::string& node() const { return node_; } + const std::string& service() const { return service_; } + +private: + const std::string node_; + const std::string service_; + const std::string address_; + + TimeSource& time_source_; + Random::RandomGenerator& random_generator_; + TraceSegmentReporterPtr reporter_; +}; + +using TracerPtr = std::unique_ptr; + +class Span : public Tracing::Span { +public: + Span(SpanObject span_object, Tracer& tracer); + + void setOperation(absl::string_view operation) override; + void setTag(absl::string_view name, absl::string_view value) override; + void log(SystemTime timestamp, const std::string& event) override; + void finishSpan() override; + void injectContext(Http::RequestHeaderMap& request_headers) override; + Tracing::SpanPtr spawnChild(const Tracing::Config& config, const std::string& name, + SystemTime start_time) override; + void setSampled(bool sampled) override; + std::string getBaggage(absl::string_view key) override; + void setBaggage(absl::string_view key, absl::string_view value) override; + +private: + SpanObject span_object_; + Tracer& tracer_; +}; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/skywalking/BUILD b/test/extensions/tracers/skywalking/BUILD new file mode 100644 index 0000000000000..19c523cafdd1d --- /dev/null +++ b/test/extensions/tracers/skywalking/BUILD @@ -0,0 +1,25 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "config_test", + srcs = ["config_test.cc"], + extension_name = "envoy.tracers.skywalking", + deps = [ + "//source/extensions/tracers/skywalking:config", + "//test/mocks/server:tracer_factory_context_mocks", + "//test/mocks/server:tracer_factory_mocks", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/tracers/skywalking/config_test.cc b/test/extensions/tracers/skywalking/config_test.cc new file mode 100644 index 0000000000000..ce932a6e3bc77 --- /dev/null +++ b/test/extensions/tracers/skywalking/config_test.cc @@ -0,0 +1,55 @@ +#include "envoy/config/trace/v3/http_tracer.pb.h" +#include "envoy/config/trace/v3/skywalking.pb.h" +#include "envoy/config/trace/v3/skywalking.pb.validate.h" + +#include "extensions/tracers/skywalking/config.h" + +#include "test/mocks/server/tracer_factory.h" +#include "test/mocks/server/tracer_factory_context.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::Eq; +using testing::NiceMock; +using testing::Return; + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { +namespace { + +TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracer) { + NiceMock context; + EXPECT_CALL(context.server_factory_context_.cluster_manager_, get(Eq("fake_cluster"))) + .WillRepeatedly( + Return(&context.server_factory_context_.cluster_manager_.thread_local_cluster_)); + ON_CALL(*context.server_factory_context_.cluster_manager_.thread_local_cluster_.cluster_.info_, + features()) + .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); + + const std::string yaml_string = R"EOF( + http: + name: skywalking + typed_config: + "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + )EOF"; + envoy::config::trace::v3::Tracing configuration; + TestUtility::loadFromYaml(yaml_string, configuration); + + SkyWalkingTracerFactory factory; + auto message = Config::Utility::translateToFactoryConfig( + configuration.http(), ProtobufMessage::getStrictValidationVisitor(), factory); + Tracing::HttpTracerSharedPtr skywalking_tracer = factory.createHttpTracer(*message, context); + EXPECT_NE(nullptr, skywalking_tracer); +} + +} // namespace +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy From f38482023ba379b2c64c3e27f3213354bb8acb7e Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 11 Sep 2020 21:12:05 +0800 Subject: [PATCH 02/61] Tracer: support SkyWalking tracing report Signed-off-by: wbpcode --- CODEOWNERS | 2 +- api/envoy/config/trace/v3/skywalking.proto | 29 ++ .../tracers/skywalking/v4alpha/BUILD | 2 +- .../skywalking/v4alpha/skywalking.proto | 31 ++ .../envoy/config/trace/v3/skywalking.proto | 29 ++ .../tracers/skywalking/v4alpha/BUILD | 2 +- .../skywalking/v4alpha/skywalking.proto | 31 ++ source/extensions/tracers/skywalking/BUILD | 3 + source/extensions/tracers/skywalking/config.h | 2 +- .../skywalking/skywalking_tracer_impl.cc | 61 ++-- .../skywalking/skywalking_tracer_impl.h | 8 +- .../tracers/skywalking/skywalking_types.cc | 133 +++++-- .../tracers/skywalking/skywalking_types.h | 337 +++++++++++++----- .../skywalking/trace_segment_reporter.cc | 132 ++++--- .../skywalking/trace_segment_reporter.h | 32 +- .../extensions/tracers/skywalking/tracer.cc | 61 ++-- source/extensions/tracers/skywalking/tracer.h | 46 ++- test/extensions/tracers/skywalking/BUILD | 70 ++++ .../tracers/skywalking/config_test.cc | 34 ++ .../skywalking/skywalking_test_helper.h | 77 ++++ .../skywalking/skywalking_tracer_impl_test.cc | 50 +++ .../skywalking/skywalking_types_test.cc | 328 +++++++++++++++++ .../skywalking/trace_segment_reporter_test.cc | 84 +++++ .../tracers/skywalking/tracer_test.cc | 178 +++++++++ 24 files changed, 1514 insertions(+), 248 deletions(-) create mode 100644 test/extensions/tracers/skywalking/skywalking_test_helper.h create mode 100644 test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc create mode 100644 test/extensions/tracers/skywalking/skywalking_types_test.cc create mode 100644 test/extensions/tracers/skywalking/trace_segment_reporter_test.cc create mode 100644 test/extensions/tracers/skywalking/tracer_test.cc diff --git a/CODEOWNERS b/CODEOWNERS index 1c81b0f1311ff..702f7745aa9f5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -49,7 +49,7 @@ extensions/filters/common/original_src @snowp @klarose # tracers.xray extension /*/extensions/tracers/xray @marcomagdy @lavignes @mattklein123 # tracers.skywalking extension -/*/extensions/tracers/skywalking @dio @lizan +/*/extensions/tracers/skywalking @dio @lizan @wbpcode # mysql_proxy extension /*/extensions/filters/network/mysql_proxy @rshriram @venilnoronha @mattklein123 # postgres_proxy extension diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index 8f575e70d6fff..f85be5a67bc80 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -23,4 +23,33 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; message SkyWalkingConfig { // SkyWalking collector service. core.v3.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; + + ClientConfig client_config = 2; +} + +// Client config for SkyWalking tracer. +// [#next-free-field: 6] +message ClientConfig { + // Service name for SkyWalking tracer. If service_name is empty, then cluster + // name of Envoy will be used as service name. + string service_name = 1; + + // Service instance name for SkyWalking tracer. If instance_name is empty, the + // node name of Envoy will be used as service instance name. + string instance_name = 2; + + // Authentication token. Set client token if backend open token + // authentication. + string authentication = 3; + + // When this field is set to true and Envoy is not the first tracing node, it + // directly uses the downstream endpoint as its own endpoint. This is helpful + // when the user wants to use the endpoint to aggregate all span data on the + // tracing link. + bool pass_endpoint = 4; + + // Envoy caches the segment in memory when the backend service is temporarily + // unavailable. This field specifies the maximum number of segments that can + // be cached. + uint32 max_cache_size = 5; } diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD b/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD index d8ce683c41d6a..1d56979cc4660 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/BUILD @@ -1,4 +1,4 @@ -# DO NOT EDIT. This file is generated by tools/proto_sync.py. +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index e63f758e7e855..6347b97d8367f 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -23,4 +23,35 @@ message SkyWalkingConfig { // SkyWalking collector service. config.core.v4alpha.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; + + ClientConfig client_config = 2; +} + +// Client config for SkyWalking tracer. +// [#next-free-field: 6] +message ClientConfig { + option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; + + // Service name for SkyWalking tracer. If service_name is empty, then cluster + // name of Envoy will be used as service name. + string service_name = 1; + + // Service instance name for SkyWalking tracer. If instance_name is empty, the + // node name of Envoy will be used as service instance name. + string instance_name = 2; + + // Authentication token. Set client token if backend open token + // authentication. + string authentication = 3; + + // When this field is set to true and Envoy is not the first tracing node, it + // directly uses the downstream endpoint as its own endpoint. This is helpful + // when the user wants to use the endpoint to aggregate all span data on the + // tracing link. + bool pass_endpoint = 4; + + // Envoy caches the segment in memory when the backend service is temporarily + // unavailable. This field specifies the maximum number of segments that can + // be cached. + uint32 max_cache_size = 5; } diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index 8f575e70d6fff..f85be5a67bc80 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -23,4 +23,33 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; message SkyWalkingConfig { // SkyWalking collector service. core.v3.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; + + ClientConfig client_config = 2; +} + +// Client config for SkyWalking tracer. +// [#next-free-field: 6] +message ClientConfig { + // Service name for SkyWalking tracer. If service_name is empty, then cluster + // name of Envoy will be used as service name. + string service_name = 1; + + // Service instance name for SkyWalking tracer. If instance_name is empty, the + // node name of Envoy will be used as service instance name. + string instance_name = 2; + + // Authentication token. Set client token if backend open token + // authentication. + string authentication = 3; + + // When this field is set to true and Envoy is not the first tracing node, it + // directly uses the downstream endpoint as its own endpoint. This is helpful + // when the user wants to use the endpoint to aggregate all span data on the + // tracing link. + bool pass_endpoint = 4; + + // Envoy caches the segment in memory when the backend service is temporarily + // unavailable. This field specifies the maximum number of segments that can + // be cached. + uint32 max_cache_size = 5; } diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD index d8ce683c41d6a..1d56979cc4660 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/BUILD @@ -1,4 +1,4 @@ -# DO NOT EDIT. This file is generated by tools/proto_sync.py. +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index e63f758e7e855..6347b97d8367f 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -23,4 +23,35 @@ message SkyWalkingConfig { // SkyWalking collector service. config.core.v4alpha.GrpcService grpc_service = 1 [(validate.rules).message = {required: true}]; + + ClientConfig client_config = 2; +} + +// Client config for SkyWalking tracer. +// [#next-free-field: 6] +message ClientConfig { + option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; + + // Service name for SkyWalking tracer. If service_name is empty, then cluster + // name of Envoy will be used as service name. + string service_name = 1; + + // Service instance name for SkyWalking tracer. If instance_name is empty, the + // node name of Envoy will be used as service instance name. + string instance_name = 2; + + // Authentication token. Set client token if backend open token + // authentication. + string authentication = 3; + + // When this field is set to true and Envoy is not the first tracing node, it + // directly uses the downstream endpoint as its own endpoint. This is helpful + // when the user wants to use the endpoint to aggregate all span data on the + // tracing link. + bool pass_endpoint = 4; + + // Envoy caches the segment in memory when the backend service is temporarily + // unavailable. This field specifies the maximum number of segments that can + // be cached. + uint32 max_cache_size = 5; } diff --git a/source/extensions/tracers/skywalking/BUILD b/source/extensions/tracers/skywalking/BUILD index ec6cf325d945f..b0e84ea59b8bf 100644 --- a/source/extensions/tracers/skywalking/BUILD +++ b/source/extensions/tracers/skywalking/BUILD @@ -20,6 +20,7 @@ envoy_cc_library( "//include/envoy/grpc:async_client_manager_interface", "//source/common/grpc:async_client_lib", "@com_github_apache_skywalking_data_collect_protocol//:protocol_cc_proto", + "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", ], ) @@ -31,9 +32,11 @@ envoy_cc_library( "//include/envoy/common:random_generator_interface", "//include/envoy/common:time_interface", "//include/envoy/http:header_map_interface", + "//include/envoy/tracing:http_tracer_interface", "//source/common/common:base64_lib", "//source/common/common:hex_lib", "//source/common/common:utility_lib", + "@com_github_apache_skywalking_data_collect_protocol//:protocol_cc_proto", ], ) diff --git a/source/extensions/tracers/skywalking/config.h b/source/extensions/tracers/skywalking/config.h index f3a2d4b1668b4..abeffe373e5d7 100644 --- a/source/extensions/tracers/skywalking/config.h +++ b/source/extensions/tracers/skywalking/config.h @@ -11,7 +11,7 @@ namespace Tracers { namespace SkyWalking { /** - * Config registration for the skywalking tracer. @see TracerFactory. + * Config registration for the SkyWalking tracer. @see TracerFactory. */ class SkyWalkingTracerFactory : public Common::FactoryBase { diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index 39508f41ee9c6..e2eeb954fd614 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -4,6 +4,7 @@ #include "common/common/macros.h" #include "common/common/utility.h" +#include "common/http/path_utility.h" #include "extensions/tracers/skywalking/skywalking_types.h" @@ -14,39 +15,55 @@ namespace SkyWalking { Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, Server::Configuration::TracerFactoryContext& context) - : tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { - tls_slot_ptr_->set([this, proto_config, &context]( + : client_config_(proto_config.client_config()), + random_generator_(context.serverFactoryContext().random()), + tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { + + if (client_config_.service_name().empty()) { + client_config_.set_service_name(context.serverFactoryContext().localInfo().clusterName()); + } + if (client_config_.instance_name().empty()) { + client_config_.set_instance_name(context.serverFactoryContext().localInfo().nodeName()); + } + + tls_slot_ptr_->set([proto_config, &context, this]( Event::Dispatcher& dispatcher) -> ThreadLocal::ThreadLocalObjectSharedPtr { auto& factory_context = context.serverFactoryContext(); - TracerPtr tracer = - std::make_unique(factory_context.clusterManager(), factory_context.scope(), - factory_context.localInfo(), factory_context.timeSource(), - factory_context.random(), dispatcher, proto_config.grpc_service()); - return std::make_shared(std::move(tracer), *this); + TracerPtr tracer = std::make_unique( + factory_context.clusterManager(), factory_context.scope(), factory_context.timeSource(), + dispatcher, proto_config.grpc_service(), client_config_); + return std::make_shared(std::move(tracer)); }); } Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, - Http::RequestHeaderMap& request_headers, const std::string&, - Envoy::SystemTime start_time, const Tracing::Decision) { + Http::RequestHeaderMap& request_headers, + const std::string& operation_name, Envoy::SystemTime start_time, + const Tracing::Decision decision) { auto& tracer = *tls_slot_ptr_->getTyped().tracer_; - SpanContext previous_span_context; - const bool valid_context = previous_span_context.extract(request_headers); - if (!valid_context) { - return std::make_unique(); - } + try { + SpanContextPtr previous_span_context = SpanContext::spanContextFromRequest(request_headers); + auto segment_context = std::make_shared(std::move(previous_span_context), + decision, random_generator_); - SpanContext span_context; - span_context.setParentEndpointAndNetworkAddressUsedAtPeer(Endpoint{request_headers}); - span_context.setService(tracer.service()); - span_context.setServiceInstance(tracer.node()); + // Initialize fields of current span context. + segment_context->setService(client_config_.service_name()); + segment_context->setServiceInstance(client_config_.instance_name()); - if (previous_span_context.isNew()) { - return tracer.startSpan(config, start_time, span_context, SpanContext{}); - } + if (!client_config_.pass_endpoint() || !segment_context->previousSpanContext()) { + segment_context->setEndpoint( + absl::StrCat("/", request_headers.getMethodValue(), + Http::PathUtil::removeQueryAndFragment(request_headers.getPathValue()))); + } else { + segment_context->setEndpoint(segment_context->previousSpanContext()->endpoint_); + } - return tracer.startSpan(config, start_time, span_context, previous_span_context); + return tracer.startSpan(config, start_time, operation_name, std::move(segment_context), + nullptr); + } catch (const EnvoyException&) { + return std::make_unique(); + } } } // namespace SkyWalking diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h index 0312e09749962..e3579be141f8d 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h @@ -25,15 +25,19 @@ class Driver : public Tracing::Driver, public Logger::Loggable; + } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 1d90f301ac746..c6abe27159f11 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -1,6 +1,9 @@ #include "extensions/tracers/skywalking/skywalking_types.h" +#include "envoy/common/exception.h" + #include "common/common/base64.h" +#include "common/common/empty_string.h" #include "common/common/fmt.h" #include "common/common/hex.h" #include "common/common/utility.h" @@ -13,7 +16,7 @@ namespace SkyWalking { namespace { // The standard header name is "sw8", as mentioned in: -// https://github.com/apache/skywalking/blob/6fe2041b470113e626cb3f41e3789261d31f2548/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md#standard-header-item. +// https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. const Http::LowerCaseString& propagationHeader() { CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, "sw8"); } @@ -27,58 +30,118 @@ std::string base64Encode(absl::string_view input) { return Base64::encode(input.data(), input.length()); } -std::string base64Decode(absl::string_view input) { return Base64::decode(std::string(input)); } - -} // namespace - -void SpanContext::initialize(Random::RandomGenerator& random_generator) { - if (trace_id_.empty()) { - trace_id_ = generateId(random_generator); +// Decode and validate fields of propagation header. +std::string base64Decode(absl::string_view input) { + std::string result = input.length() % 4 ? EMPTY_STRING : Base64::decodeWithoutPadding(input); + if (result.empty()) { + throw EnvoyException("Invalid propagation header for SkyWalking: parse error"); } - trace_segment_id_ = generateId(random_generator); + return result; } -bool SpanContext::extract(Http::RequestHeaderMap& request_headers) { - auto propagation_header = request_headers.get(propagationHeader()); +} // namespace + +SpanContextPtr SpanContext::spanContextFromRequest(Http::RequestHeaderMap& headers) { + auto propagation_header = headers.get(propagationHeader()); if (propagation_header == nullptr) { - // No propagation_header means a valid span context, but an empty one. - return true; + // No propagation_header then Envoy is first hop. + return nullptr; } - const auto parts = - StringUtil::splitToken(propagation_header->value().getStringView(), "-", false, true); + auto header_value_string = propagation_header->value().getStringView(); + const auto parts = StringUtil::splitToken(header_value_string, "-", false, true); // Reference: - // https://github.com/apache/skywalking/blob/6fe2041b470113e626cb3f41e3789261d31f2548/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md#values. + // https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. if (parts.size() != 8) { - return false; + throw EnvoyException( + fmt::format("Invalid propagation header for SkyWalking: {}", header_value_string)); + } + + SpanContextPtr previous_span_context = std::unique_ptr(new SpanContext()); + + // Parse and validate sampling flag. + if (parts[0] == "0") { + previous_span_context->sampled_ = 0; + } else if (parts[0] == "1") { + previous_span_context->sampled_ = 1; + } else { + throw EnvoyException(fmt::format("Invalid propagation header for SkyWalking: sampling flag can " + "only be '0' or '1' but '{}' was provided", + parts[0])); } - // TODO(dio): Per part validation. - sampled_ = parts[0] == "0" ? 0 : 1; - trace_id_ = base64Decode(parts[1]); - trace_segment_id_ = base64Decode(parts[2]); - parent_span_id_ = std::stoi(std::string(parts[3])); - service_ = base64Decode(parts[4]); - service_instance_ = base64Decode(parts[5]); - parent_endpoint_ = base64Decode(parts[6]); - network_address_used_at_peer_ = base64Decode(parts[7]); + // Parse trace id. + previous_span_context->trace_id_ = base64Decode(parts[1]); + // Parse segment id. + previous_span_context->trace_segment_id_ = base64Decode(parts[2]); + + // Parse span id. + if (!absl::SimpleAtoi(parts[3], &previous_span_context->span_id_)) { + throw EnvoyException(fmt::format( + "Invalid propagation header for SkyWalking: connot convert '{}' to valid span id", + parts[3])); + } - is_new_ = false; + // Parse service. + previous_span_context->service_ = base64Decode(parts[4]); + // Parse service instance. + previous_span_context->service_instance_ = base64Decode(parts[5]); + // Parse endpoint. Operation Name of the first entry span in the previous segment. + previous_span_context->endpoint_ = base64Decode(parts[6]); + // Parse target address used at downstream side of this request. + previous_span_context->target_address_ = base64Decode(parts[7]); - return true; + return previous_span_context; } -void SpanContext::inject(Http::RequestHeaderMap& request_headers) const { +SegmentContext::SegmentContext(SpanContextPtr&& previous_span_context, Tracing::Decision decision, + Random::RandomGenerator& random_generator) + : previous_span_context_(std::move(previous_span_context)) { + + if (previous_span_context_) { + trace_id_ = previous_span_context_->trace_id_; + sampled_ = previous_span_context_->sampled_; + } else { + trace_id_ = generateId(random_generator); + sampled_ = decision.traced; + } + trace_segment_id_ = generateId(random_generator); +} + +SpanStore* SegmentContext::createSpanStore(TimeSource& time_source, SpanStore* parent_store) { + auto store = std::make_unique(this, time_source); + store->setSpanId(span_list_.size()); + if (parent_store) { + // Child span. + store->setSampled(parent_store->sampled()); + store->setParentSpanId(parent_store->spanId()); + } else { + // First span. + store->setSampled(sampled_); + store->setParentSpanId(-1); + } + SpanStore* ref = store.get(); + span_list_.emplace_back(std::move(store)); + return ref; +} + +void SpanStore::injectContext(Http::RequestHeaderMap& request_headers) const { + ASSERT(segment_context_); + + std::string target_address = peer_.empty() ? std::string(request_headers.getHostValue()) : peer_; + // Reference: - // https://github.com/apache/skywalking/blob/6fe2041b470113e626cb3f41e3789261d31f2548/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md#standard-header-item. - const auto value = absl::StrCat( - sampled_, "-", base64Encode(trace_id_), "-", base64Encode(trace_segment_id_), "-", - parent_span_id_, "-", base64Encode(service_), "-", base64Encode(service_instance_), "-", - base64Encode(parent_endpoint_), "-", base64Encode(network_address_used_at_peer_)); + // https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. + const auto value = + absl::StrCat(sampled_, "-", base64Encode(segment_context_->traceId()), "-", + base64Encode(segment_context_->traceSegmentId()), "-", span_id_, "-", + base64Encode(segment_context_->service()), "-", + base64Encode(segment_context_->serviceInstance()), "-", + base64Encode(segment_context_->endpoint()), "-", base64Encode(target_address)); request_headers.setReferenceKey(propagationHeader(), value); } -void SpanObject::finish() { end_time_ = DateUtil::nowToMilliseconds(time_source_); } +void SpanStore::finish() { end_time_ = DateUtil::nowToMilliseconds(time_source_); } } // namespace SkyWalking } // namespace Tracers diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index 1e0c09c0a2f6a..2a33af6f6ddd5 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -3,145 +3,320 @@ #include #include +#include #include "envoy/common/random_generator.h" #include "envoy/common/time.h" #include "envoy/http/header_map.h" +#include "envoy/tracing/http_tracer.h" + +#include "language-agent/Tracing.pb.h" namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { -class Endpoint { +class SegmentContext; +using SegmentContextSharedPtr = std::shared_ptr; + +class SpanStore; +using SpanStorePtr = std::unique_ptr; + +class SpanContext; +using SpanContextPtr = std::unique_ptr; + +class SpanContext { public: - explicit Endpoint(Http::RequestHeaderMap& request_headers) - : host_(request_headers.getHostValue()), - method_and_path_( - absl::StrCat("/", request_headers.getMethodValue(), request_headers.getPathValue())) {} + /* + * Parse the context of the previous span from the request and decide whether to sample it or + * not. + * + * @param headers The request headers. + * @return SpanContextPtr The previous span context parsed from request headers. + */ + static SpanContextPtr spanContextFromRequest(Http::RequestHeaderMap& headers); + + // Sampling flag. This field can only be 0 or 1. 1 means this trace need to be sampled and send to + // backend. + int sampled_{0}; + + // This span id points to the parent span in parent trace segment. + int span_id_{0}; - const std::string& methodAndPath() const { return method_and_path_; } - const std::string& host() const { return host_; } + std::string trace_id_; + + // This trace segment id points to the parent trace segment. + std::string trace_segment_id_; + + std::string service_; + std::string service_instance_; + + // Operation Name of the first entry span in the parent segment. + std::string endpoint_; + + // Target address used at client side of this request. The network address(not must be IP + port) + // used at client side to access this target service. + std::string target_address_; private: - const std::string host_; - const std::string method_and_path_; + // Private default constructor. We can only create SpanContext by 'spanContextFromRequest'. + SpanContext() = default; }; -class SpanContext { - +class SegmentContext { public: - void initialize(Random::RandomGenerator& random_generator); - bool extract(Http::RequestHeaderMap& request_headers); - void inject(Http::RequestHeaderMap& request_headers) const; - - void setSampled(bool sampled) { sampled_ = sampled ? 1 : 0; } - void setParentSpanId(int parent_span_id) { parent_span_id_ = parent_span_id; } - void setTraceId(const std::string& trace_id) { trace_id_ = trace_id; } - void setTraceSegmentId(const std::string& trace_segment_id) { - trace_segment_id_ = trace_segment_id; - } + /* + * Create a new segment context based on the previous span context that parsed from request + * headers. + * + * @param previous_span_context The previous span context. + * @param random_generator The random generator that used to create trace id and segment id. + * @param decision The tracing decision. + */ + SegmentContext(SpanContextPtr&& previous_span_context, Tracing::Decision decision, + Random::RandomGenerator& random_generator); + + /* + * Set service name. + * + * @param service The service name. + */ void setService(const std::string& service) { service_ = service; } + + /* + * Set service instance name. + * + * @param service_instance The service instance name. + */ void setServiceInstance(const std::string& service_instance) { service_instance_ = service_instance; } - void setParentEndpointAndNetworkAddressUsedAtPeer(const Endpoint& endpoint) { - parent_endpoint_ = endpoint.methodAndPath(); - network_address_used_at_peer_ = endpoint.host(); - } + + /* + * Set endpoint. + * + * @param endpoint. The endpoint value. Endpoint should be operation name of the first entry span + * in the segment. All spans in the same segment share the same endpoint. In our implementation, + * we currently use 'HTTP Method + HTTP Path Without Query' as the endpoint value. + */ + void setEndpoint(const std::string& endpoint) { endpoint_ = endpoint; } + + /* + * Create a new SpanStore object and return its pointer. The ownership of the newly created + * SpanStore object belongs to the current span context. + * + * @param time_source The time source. + * @param parent_store The pointer that point to parent SpanStore object. + * @return SpanStore* The pointer that point to newly created SpanStore object. + */ + SpanStore* createSpanStore(TimeSource& time_source, SpanStore* parent_store); + + const std::vector& spanList() const { return span_list_; } int sampled() const { return sampled_; } const std::string& traceId() const { return trace_id_; } const std::string& traceSegmentId() const { return trace_segment_id_; } - int parentSpanId() const { return parent_span_id_; } + const std::string& service() const { return service_; } const std::string& serviceInstance() const { return service_instance_; } - const std::string& parentEndpoint() const { return parent_endpoint_; } - const std::string& networkAddressUsedAtPeer() const { return network_address_used_at_peer_; } + const std::string& endpoint() const { return endpoint_; } - bool isNew() const { return is_new_; } + SpanContext* previousSpanContext() const { return previous_span_context_.get(); } private: - int sampled_{1}; - int parent_span_id_{0}; - + int sampled_{0}; + // This value is unique in the entire tracing link. If previous_context is null, we will use + // random_generator to create a trace id. std::string trace_id_; + // Envoy creates a new span when it accepts a new HTTP request. This span and all of its child + // spans belong to the same segment and share the segment id. std::string trace_segment_id_; + std::string service_; std::string service_instance_; + std::string endpoint_; - std::string parent_endpoint_; - // The address used for calling this endpoint. - std::string network_address_used_at_peer_; + // The SegmentContext parsed from the request headers. If no propagation headers in request then + // this will be nullptr. + SpanContextPtr previous_span_context_; - bool is_new_{true}; + std::vector span_list_; }; -using Tag = std::pair; - -struct Log { - uint64_t timestamp_; - std::vector data_; -}; - -class SpanObject { +using Tag = KeyStringValuePair; +/* + * A helper class for the SkyWalking span and is used to store all span-related data, including span + * id, parent span id, tags and so on. Whenever we create a new span, we create a new SpanStore + * object. The new span will hold a pointer to the newly created SpanStore object and write data to + * it or get data from it. + */ +class SpanStore { public: - explicit SpanObject(const SpanContext& span_context, const SpanContext& previous_span_context, - TimeSource& time_source, Random::RandomGenerator& random_generator) - : span_context_(span_context), previous_span_context_(previous_span_context), - time_source_(time_source) { - if (!previous_span_context.isNew()) { - span_context_.setTraceId(previous_span_context.traceId()); - } - span_context_.initialize(random_generator); - } - + /* + * Construct a SpanStore object using span context and time source. + * + * @param segment_context The pointer that point to current span context. This can not be null. + * @param time_source A time source to get the span end time. + */ + explicit SpanStore(SegmentContext* segment_context, TimeSource& time_source) + : segment_context_(segment_context), time_source_(time_source) {} + + /* + * When a SkyWalking span ends, it will be called to set the end time of the current span. + */ void finish(); - void setSpanId(int32_t span_id) { span_id_ = span_id; } - void setParentSpanId(int32_t parent_span_id) { parent_span_id_ = parent_span_id; } - void setStartTime(uint64_t start_time) { start_time_ = start_time; } - void setEndTime(uint64_t end_time) { end_time_ = end_time; } - void setOperationName(const std::string& operation_name) { operation_name_ = operation_name; } - void setAsError(bool is_error) { is_error_ = is_error; } - void setAsEntrySpan(bool is_entry_span) { is_entry_span_ = is_entry_span; } - void setPeer(const std::string& peer) { peer_ = peer; } - void addTag(const Tag& tag) { tags_.push_back(tag); } - void addLog(const Log& log) { logs_.push_back(log); } + /* + * Get operation name of span. If operation name is empty, the endpoint in the span context will + * be used instead. + */ + const std::string& operation() const { + return operation_.empty() ? segment_context_->endpoint() : operation_; + } - const SpanContext& context() const { return span_context_; } - const SpanContext& previousContext() const { return previous_span_context_; } + /* + * Get peer address. + */ + const std::string& peer() const { return peer_; } - const std::string& operationName() const { return operation_name_; } + /* + * Get span start time. + */ uint64_t startTime() const { return start_time_; } + + /* + * Get span end time. + */ uint64_t endTime() const { return end_time_; } - bool isError() const { return is_error_; } + + /* + * Get span tags. + */ const std::vector& tags() const { return tags_; } + + /* + * Get span logs. + */ const std::vector& logs() const { return logs_; } - int32_t spanId() const { return span_id_; } - int32_t parentSpanId() const { return parent_span_id_; } - const std::string& peer() const { return peer_; } + /* + * Get span sampling flag. + */ + int sampled() const { return sampled_; } + + /* + * Get span id. + */ + int spanId() const { return span_id_; } + + /* + * Get parent span id. + */ + int parentSpanId() const { return parent_span_id_; } + + /* + * Determines if an error has occurred in the current span. + */ + bool isError() const { return is_error_; } + + /* + * Determines if the current span is an entry span. + * + * Reference: + * https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Trace-Data-Protocol-v3.md + */ bool isEntrySpan() const { return is_entry_span_; } - const std::vector& tags() { return tags_; }; - const std::vector& logs() { return logs_; }; + + /* + * Set span start time. This is the time when the HTTP request started, not the time when the span + * was created. + */ + void setStartTime(uint64_t start_time) { start_time_ = start_time; } + + /* + * Set span end time. It is meaningless for now. End time will be set by finish. + */ + void setEndTime(uint64_t end_time) { end_time_ = end_time; } + + /* + * Set operation name. + */ + void setOperation(const std::string& operation) { operation_ = operation; } + + /* + * Set peer address. + */ + void setPeer(const std::string& peer) { peer_ = peer; } + + /* + * Set if the current span has an error. + */ + void setAsError(bool is_error) { is_error_ = is_error; } + + /* + * Set if the current span is a entry span. + */ + void setAsEntrySpan(bool is_entry_span) { is_entry_span_ = is_entry_span; } + + /* + * Add a new tag entry to current span. + */ + void addTag(absl::string_view name, absl::string_view value) { + Tag tag; + tag.set_key(name.data(), name.size()); + tag.set_value(value.data(), value.size()); + tags_.emplace_back(std::move(tag)); + } + + /* + * Add a new log entry to current span. Due to different data formats, log is temporarily not + * supported. + */ + void addLog(SystemTime, const std::string&) {} + + /* + * Set span id of current span. The span id in each segment is started from 0. When new span is + * created, its span id is the current max span id plus 1. + */ + void setSpanId(int span_id) { span_id_ = span_id; } + + /* + * Set parent span id. Notice that in SkyWalking, the parent span and the child span belong to the + * same segment. The first span of each segment has a parent span id of -1. + */ + void setParentSpanId(int parent_span_id) { parent_span_id_ = parent_span_id; } + + /* + * Set sampling flag. In general, the sampling flag of span is consistent with the current span + * context. + */ + void setSampled(int sampled) { sampled_ = sampled; } + + /* + * Inject current span context information to request headers. This will update original + * propagation headers. + * + * @param request_headers The request headers. + */ + void injectContext(Http::RequestHeaderMap& request_headers) const; private: - SpanContext span_context_; - SpanContext previous_span_context_; + SegmentContext* segment_context_{nullptr}; - int32_t span_id_{0}; - int32_t parent_span_id_{-1}; + int sampled_{0}; - uint64_t start_time_; - uint64_t end_time_; + int span_id_{0}; + int parent_span_id_{-1}; - std::string operation_name_; + uint64_t start_time_{0}; + uint64_t end_time_{0}; + + std::string operation_; std::string peer_; bool is_error_{false}; - bool is_entry_span_{true}; std::vector tags_; diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index 1d937d9ef4ef3..cc28317b510be 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -6,77 +6,114 @@ namespace Tracers { namespace SkyWalking { namespace { +static constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; -SegmentObject toSegmentObject(const SpanObject& span_object) { - SegmentObject segment_object; - segment_object.set_traceid(span_object.context().traceId()); - segment_object.set_tracesegmentid(span_object.context().traceSegmentId()); - segment_object.set_service(span_object.context().service()); - segment_object.set_serviceinstance(span_object.context().serviceInstance()); +// Convert SegmentContext to SegmentObject. +TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { + auto new_segment = std::make_unique(); + SegmentObject& segment_object = *new_segment; - auto* span = segment_object.mutable_spans()->Add(); - // The SpanLayer is always Http. - span->set_spanlayer(SpanLayer::Http); - span->set_spantype(span_object.isEntrySpan() ? SpanType::Entry : SpanType::Exit); + segment_object.set_traceid(segment_context.traceId()); + segment_object.set_tracesegmentid(segment_context.traceSegmentId()); + segment_object.set_service(segment_context.service()); + segment_object.set_serviceinstance(segment_context.serviceInstance()); - if (!span_object.peer().empty()) { - span->set_peer(span_object.peer()); - } + for (const auto& span_store : segment_context.spanList()) { + if (!span_store->sampled()) { + continue; + } + auto* span = segment_object.mutable_spans()->Add(); - span->set_componentid(6000); - span->set_starttime(span_object.startTime()); - span->set_endtime(span_object.endTime()); - span->set_iserror(span_object.isError()); - span->set_operationname(span_object.operationName().empty() - ? span_object.context().parentEndpoint() - : span_object.operationName()); - span->set_spanid(span_object.spanId()); - span->set_parentspanid(span_object.parentSpanId()); - - const auto& previous_context = span_object.previousContext(); - if (!previous_context.isNew()) { - auto* ref = span->mutable_refs()->Add(); - ref->set_traceid(previous_context.traceId()); - ref->set_parenttracesegmentid(previous_context.traceSegmentId()); - ref->set_parentspanid(previous_context.parentSpanId()); - ref->set_parentservice(previous_context.service()); - ref->set_parentserviceinstance(previous_context.serviceInstance()); - ref->set_parentendpoint(previous_context.parentEndpoint()); - ref->set_networkaddressusedatpeer(previous_context.networkAddressUsedAtPeer()); - } + span->set_spanlayer(SpanLayer::Http); + span->set_spantype(span_store->isEntrySpan() ? SpanType::Entry : SpanType::Exit); + span->set_componentid(6000); + + if (!span_store->peer().empty()) { + span->set_peer(span_store->peer()); + } + + span->set_spanid(span_store->spanId()); + span->set_parentspanid(span_store->parentSpanId()); + + span->set_starttime(span_store->startTime()); + span->set_endtime(span_store->endTime()); + + span->set_iserror(span_store->isError()); + + span->set_operationname(span_store->operation()); + + auto& tags = *span->mutable_tags(); + tags.Reserve(span_store->tags().size()); + + for (auto& span_tag : span_store->tags()) { + tags.Add(std::move(const_cast(span_tag))); + } + + SpanContext* previous_span_context = segment_context.previousSpanContext(); + if (!previous_span_context) { + continue; + } - for (const auto& span_tag : span_object.tags()) { - auto* tag = span->mutable_tags()->Add(); - tag->set_key(span_tag.first); - tag->set_value(span_tag.second); + auto* ref = span->mutable_refs()->Add(); + ref->set_traceid(previous_span_context->trace_id_); + ref->set_parenttracesegmentid(previous_span_context->trace_segment_id_); + ref->set_parentspanid(previous_span_context->span_id_); + ref->set_parentservice(previous_span_context->service_); + ref->set_parentserviceinstance(previous_span_context->service_instance_); + ref->set_parentendpoint(previous_span_context->endpoint_); + ref->set_networkaddressusedatpeer(previous_span_context->target_address_); } - return segment_object; + return new_segment; } } // namespace -TraceSegmentReporter::TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, - Event::Dispatcher& dispatcher) - : client_(factory->create()), +TraceSegmentReporter::TraceSegmentReporter( + Grpc::AsyncClientFactoryPtr&& factory, Event::Dispatcher& dispatcher, + const envoy::config::trace::v3::ClientConfig& client_config) + : config_(client_config), client_(factory->create()), service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "TraceSegmentReportService.collect")) { + max_delayed_segments_cache_size_ = config_.max_cache_size() == 0 + ? DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE + : config_.max_cache_size(); + retry_timer_ = dispatcher.createTimer([this]() -> void { establishNewStream(); }); establishNewStream(); } -void TraceSegmentReporter::report(const SpanObject& span_object) { - sendTraceSegment(toSegmentObject(span_object)); +void TraceSegmentReporter::onCreateInitialMetadata(Http::RequestHeaderMap& metadata) { + if (!config_.authentication().empty()) { + metadata.setReferenceKey(Http::CustomHeaders::get().Authorization, config_.authentication()); + } +} + +void TraceSegmentReporter::report(const SegmentContext& segment_context) { + sendTraceSegment(toSegmentObject(segment_context)); } -void TraceSegmentReporter::sendTraceSegment(const SegmentObject& request) { - // TODO(dio): Buffer when stream is not yet established +void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr&& request) { if (stream_ != nullptr) { - stream_->sendMessage(request, false); + stream_->sendMessage(*request, false); + return; + } + // Null stream_ and cache segment data temporarily. + delayed_segments_cache_.emplace(std::move(request)); + if (delayed_segments_cache_.size() > max_delayed_segments_cache_size_) { + delayed_segments_cache_.pop(); + } +} + +void TraceSegmentReporter::flushTraceSegments() { + while (!delayed_segments_cache_.empty() && stream_ != nullptr) { + stream_->sendMessage(*delayed_segments_cache_.front(), false); + delayed_segments_cache_.pop(); } } void TraceSegmentReporter::closeStream() { if (stream_ != nullptr) { + flushTraceSegments(); stream_->closeStream(); } } @@ -92,6 +129,7 @@ void TraceSegmentReporter::establishNewStream() { handleFailure(); return; } + flushTraceSegments(); } void TraceSegmentReporter::handleFailure() { setRetryTimer(); } diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index bc4ac11892a3e..5935b9de684e5 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -1,5 +1,8 @@ #pragma once +#include + +#include "envoy/config/trace/v3/skywalking.pb.h" #include "envoy/grpc/async_client_manager.h" #include "common/Common.pb.h" @@ -14,31 +17,52 @@ namespace Extensions { namespace Tracers { namespace SkyWalking { +using TraceSegmentPtr = std::unique_ptr; + class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { public: explicit TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, - Event::Dispatcher& dispatcher); + Event::Dispatcher& dispatcher, + const envoy::config::trace::v3::ClientConfig& client_config); // Grpc::AsyncStreamCallbacks - void onCreateInitialMetadata(Http::RequestHeaderMap&) override {} + void onCreateInitialMetadata(Http::RequestHeaderMap& metadata) override; void onReceiveInitialMetadata(Http::ResponseHeaderMapPtr&&) override {} void onReceiveMessage(std::unique_ptr&&) override {} void onReceiveTrailingMetadata(Http::ResponseTrailerMapPtr&&) override {} void onRemoteClose(Grpc::Status::GrpcStatus, const std::string&) override; + /* + * Flush all cached segment objects to the back-end tracing service and close the GRPC stream. + */ void closeStream(); - void report(const SpanObject& span_object); + + /* + * Convert the current span context into a segment object and report it to the back-end tracing + * service through the GRPC stream. + * + * @param span_context The span context. + */ + void report(const SegmentContext& span_context); private: - void sendTraceSegment(const SegmentObject& request); + void flushTraceSegments(); + + void sendTraceSegment(TraceSegmentPtr&& request); void establishNewStream(); void handleFailure(); void setRetryTimer(); + const envoy::config::trace::v3::ClientConfig& config_; + uint32_t max_delayed_segments_cache_size_{0}; Grpc::AsyncClient client_; Grpc::AsyncStream stream_{}; const Protobuf::MethodDescriptor& service_method_; + // If the connection is unavailable when reporting data, the created SegmentObject will be cached + // in the queue, and when a new connection is established, the cached data will be reported. + std::queue delayed_segments_cache_; + Event::TimerPtr retry_timer_; }; diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc index f69e0fa18b92e..728637321609d 100644 --- a/source/extensions/tracers/skywalking/tracer.cc +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -19,62 +19,67 @@ uint64_t getTimestamp(SystemTime time) { } // namespace Tracing::SpanPtr Tracer::startSpan(const Tracing::Config& config, SystemTime start_time, - const SpanContext& span_context, - const SpanContext& previous_context) { - SpanObject span_object(span_context, previous_context, time_source_, random_generator_); - span_object.setAsEntrySpan(config.operationName() == Tracing::OperationName::Ingress); - span_object.setStartTime(getTimestamp(start_time)); - - return std::make_unique(span_object, *this); + const std::string& operation_name, + SegmentContextSharedPtr segment_context, Span* parent_span) { + SpanStore* span_store = segment_context->createSpanStore( + time_source_, parent_span ? parent_span->spanStore() : nullptr); + span_store->setAsEntrySpan(config.operationName() == Tracing::OperationName::Ingress); + span_store->setStartTime(getTimestamp(start_time)); + + // TODO(wbpcode): I am not sure if the operation name and endpoint need to be consistent. So here + // may need to be improved. + span_store->setOperation(operation_name); + + return std::make_unique(std::move(segment_context), span_store, *this); } -void Tracer::report(const SpanObject& span_object) { reporter_->report(span_object); } - -Tracer::~Tracer() { reporter_->closeStream(); } - -Span::Span(SpanObject span_object, Tracer& tracer) : span_object_(span_object), tracer_(tracer) {} - -void Span::setOperation(absl::string_view) {} +void Span::setOperation(absl::string_view operation) { + span_store_->setOperation(std::string(operation)); +} void Span::setTag(absl::string_view name, absl::string_view value) { if (name == Tracing::Tags::get().HttpUrl) { - span_object_.addTag({UrlTag, std::string(value)}); + span_store_->addTag(UrlTag, value); } if (name == Tracing::Tags::get().HttpStatusCode) { - span_object_.addTag({StatusCodeTag, std::string(value)}); + span_store_->addTag(StatusCodeTag, value); } if (name == Tracing::Tags::get().Error) { - span_object_.setAsError(value == Tracing::Tags::get().True); + span_store_->setAsError(value == Tracing::Tags::get().True); } - if (name == Tracing::Tags::get().PeerAddress && !span_object_.isEntrySpan()) { - // Set perr when it is an exit span. - span_object_.setPeer(std::string(value)); + if (name == Tracing::Tags::get().PeerAddress && !span_store_->isEntrySpan()) { + // Set peer when it is an exit span. + span_store_->setPeer(std::string(value)); } - span_object_.addTag({std::string(name), std::string(value)}); + span_store_->addTag(name, value); } void Span::log(SystemTime, const std::string&) {} void Span::finishSpan() { - span_object_.finish(); - tracer_.report(span_object_); + span_store_->finish(); + // If the current span is the first span of the entire segment and its sampling flag is not false, + // the data for the entire segment is reported. + if (span_store_->sampled() && span_store_->spanId() == 0) { + tracer_.report(*segment_context_); + } } void Span::injectContext(Http::RequestHeaderMap& request_headers) { - span_object_.context().inject(request_headers); + span_store_->injectContext(request_headers); } -Tracing::SpanPtr Span::spawnChild(const Tracing::Config& config, const std::string&, +Tracing::SpanPtr Span::spawnChild(const Tracing::Config& config, const std::string& operation_name, SystemTime start_time) { - return tracer_.startSpan(config, start_time, span_object_.context(), - span_object_.previousContext()); + // The new child span will share the same context with the parent span. + return tracer_.startSpan(config, start_time, operation_name, segment_context_, this); } -void Span::setSampled(bool) {} +void Span::setSampled(bool sampled) { span_store_->setSampled(sampled ? 1 : 0); } std::string Span::getBaggage(absl::string_view) { return EMPTY_STRING; } diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h index ad52e21d3e602..ef1bdf8d2eedb 100644 --- a/source/extensions/tracers/skywalking/tracer.h +++ b/source/extensions/tracers/skywalking/tracer.h @@ -15,38 +15,27 @@ namespace Extensions { namespace Tracers { namespace SkyWalking { +class Span; + class Tracer { public: - explicit Tracer(Upstream::ClusterManager& cm, Stats::Scope& scope, - const LocalInfo::LocalInfo& local_info, TimeSource& time_source, - Random::RandomGenerator& random_generator, Event::Dispatcher& dispatcher, - const envoy::config::core::v3::GrpcService& grpc_service) - : node_(local_info.nodeName()), service_(local_info.clusterName()), - address_(absl::StrCat(local_info.address()->asString(), ":", - local_info.address()->ip()->port())), - time_source_(time_source), random_generator_(random_generator), + explicit Tracer(Upstream::ClusterManager& cm, Stats::Scope& scope, TimeSource& time_source, + Event::Dispatcher& dispatcher, + const envoy::config::core::v3::GrpcService& grpc_service, + const envoy::config::trace::v3::ClientConfig& client_config) + : time_source_(time_source), reporter_(std::make_unique( cm.grpcAsyncClientManager().factoryForGrpcService(grpc_service, scope, false), - dispatcher)) {} - - ~Tracer(); - - void report(const SpanObject& span_object); + dispatcher, client_config)) {} + void report(const SegmentContext& segment_context) { return reporter_->report(segment_context); } + ~Tracer() { reporter_->closeStream(); } Tracing::SpanPtr startSpan(const Tracing::Config& config, SystemTime start_time, - const SpanContext& span_context, - const SpanContext& previous_span_context); - - const std::string& node() const { return node_; } - const std::string& service() const { return service_; } + const std::string& operation_name, + SegmentContextSharedPtr span_context, Span* parent_span); private: - const std::string node_; - const std::string service_; - const std::string address_; - TimeSource& time_source_; - Random::RandomGenerator& random_generator_; TraceSegmentReporterPtr reporter_; }; @@ -54,8 +43,11 @@ using TracerPtr = std::unique_ptr; class Span : public Tracing::Span { public: - Span(SpanObject span_object, Tracer& tracer); + Span(SegmentContextSharedPtr segment_context, SpanStore* span_store, Tracer& tracer) + : segment_context_(std::move(segment_context)), span_store_(std::move(span_store)), + tracer_(tracer) {} + // Tracing::Span void setOperation(absl::string_view operation) override; void setTag(absl::string_view name, absl::string_view value) override; void log(SystemTime timestamp, const std::string& event) override; @@ -67,8 +59,12 @@ class Span : public Tracing::Span { std::string getBaggage(absl::string_view key) override; void setBaggage(absl::string_view key, absl::string_view value) override; + SpanStore* spanStore() const { return span_store_; } + private: - SpanObject span_object_; + SegmentContextSharedPtr segment_context_; + SpanStore* span_store_; + Tracer& tracer_; }; diff --git a/test/extensions/tracers/skywalking/BUILD b/test/extensions/tracers/skywalking/BUILD index 19c523cafdd1d..8682ad790f2fe 100644 --- a/test/extensions/tracers/skywalking/BUILD +++ b/test/extensions/tracers/skywalking/BUILD @@ -23,3 +23,73 @@ envoy_extension_cc_test( "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", ], ) + +envoy_extension_cc_test( + name = "skywalking_types_test", + srcs = ["skywalking_types_test.cc"], + extension_name = "envoy.tracers.skywalking", + deps = [ + ":skywalking_test_helper", + "//source/extensions/tracers/skywalking:skywalking_types_lib", + "//test/mocks:common_lib", + "//test/test_common:utility_lib", + ], +) + +envoy_extension_cc_test( + name = "trace_segment_reporter_test", + srcs = ["trace_segment_reporter_test.cc"], + extension_name = "envoy.tracers.skywalking", + deps = [ + ":skywalking_test_helper", + "//source/extensions/tracers/skywalking:trace_segment_reporter_lib", + "//test/mocks:common_lib", + "//test/mocks/event:event_mocks", + "//test/mocks/grpc:grpc_mocks", + "//test/test_common:utility_lib", + ], +) + +envoy_extension_cc_test( + name = "skywalking_test_helper", + srcs = ["skywalking_test_helper.h"], + extension_name = "envoy.tracers.skywalking", + deps = [ + "//source/common/common:base64_lib", + "//source/common/common:hex_lib", + "//source/extensions/tracers/skywalking:skywalking_types_lib", + "//test/test_common:utility_lib", + ], +) + +envoy_extension_cc_test( + name = "tracer_test", + srcs = ["tracer_test.cc"], + extension_name = "envoy.tracers.skywalking", + deps = [ + ":skywalking_test_helper", + "//source/extensions/tracers/skywalking:skywalking_tracer_lib", + "//test/mocks:common_lib", + "//test/mocks/event:event_mocks", + "//test/mocks/grpc:grpc_mocks", + "//test/mocks/stats:stats_mocks", + "//test/mocks/upstream:cluster_manager_mocks", + "//test/test_common:utility_lib", + ], +) + +envoy_extension_cc_test( + name = "skywalking_tracer_impl_test", + srcs = ["skywalking_tracer_impl_test.cc"], + extension_name = "envoy.tracers.skywalking", + deps = [ + ":skywalking_test_helper", + "//source/extensions/tracers/skywalking:skywalking_tracer_lib", + "//test/mocks:common_lib", + "//test/mocks/event:event_mocks", + "//test/mocks/grpc:grpc_mocks", + "//test/mocks/server:tracer_factory_context_mocks", + "//test/mocks/stats:stats_mocks", + "//test/test_common:utility_lib", + ], +) diff --git a/test/extensions/tracers/skywalking/config_test.cc b/test/extensions/tracers/skywalking/config_test.cc index ce932a6e3bc77..97b44dc2f6f6a 100644 --- a/test/extensions/tracers/skywalking/config_test.cc +++ b/test/extensions/tracers/skywalking/config_test.cc @@ -48,6 +48,40 @@ TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracer) { EXPECT_NE(nullptr, skywalking_tracer); } +TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracerWithClientConfig) { + NiceMock context; + EXPECT_CALL(context.server_factory_context_.cluster_manager_, get(Eq("fake_cluster"))) + .WillRepeatedly( + Return(&context.server_factory_context_.cluster_manager_.thread_local_cluster_)); + ON_CALL(*context.server_factory_context_.cluster_manager_.thread_local_cluster_.cluster_.info_, + features()) + .WillByDefault(Return(Upstream::ClusterInfo::Features::HTTP2)); + + const std::string yaml_string = R"EOF( + http: + name: skywalking + typed_config: + "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + client_config: + authentication: "A fake auth string for SkyWalking test" + service_name: "Test Service" + instance_name: "Test Instance" + pass_endpoint: true + max_cache_size: 2333 + )EOF"; + envoy::config::trace::v3::Tracing configuration; + TestUtility::loadFromYaml(yaml_string, configuration); + + SkyWalkingTracerFactory factory; + auto message = Config::Utility::translateToFactoryConfig( + configuration.http(), ProtobufMessage::getStrictValidationVisitor(), factory); + Tracing::HttpTracerSharedPtr skywalking_tracer = factory.createHttpTracer(*message, context); + EXPECT_NE(nullptr, skywalking_tracer); +} + } // namespace } // namespace SkyWalking } // namespace Tracers diff --git a/test/extensions/tracers/skywalking/skywalking_test_helper.h b/test/extensions/tracers/skywalking/skywalking_test_helper.h new file mode 100644 index 0000000000000..dd1699cfa0f48 --- /dev/null +++ b/test/extensions/tracers/skywalking/skywalking_test_helper.h @@ -0,0 +1,77 @@ +#pragma once + +#include "common/common/base64.h" +#include "common/common/hex.h" + +#include "extensions/tracers/skywalking/skywalking_types.h" + +#include "test/test_common/utility.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +/* + * A simple helper class for auxiliary testing. Contains some simple static functions, such as + * encoding, generating random id, creating SpanContext, etc. + */ +class SkyWalkingTestHelper { +public: + static std::string generateId(Random::RandomGenerator& random) { + return absl::StrCat(Hex::uint64ToHex(random.random()), Hex::uint64ToHex(random.random())); + } + + static std::string base64Encode(absl::string_view input) { + return Base64::encode(input.data(), input.length()); + } + + static SegmentContextSharedPtr createSegmentContext(bool sampled, std::string seed, + std::string prev_seed, + Random::RandomGenerator& random) { + SpanContextPtr previous_span_context; + if (!prev_seed.empty()) { + std::string header_value = + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", sampled ? 1 : 0, base64Encode(generateId(random)), + base64Encode(generateId(random)), random.random(), + base64Encode(prev_seed + "#SERVICE"), base64Encode(prev_seed + "#INSTANCE"), + base64Encode(prev_seed + "#ENDPOINT"), base64Encode(prev_seed + "#ADDRESS")); + + Http::TestRequestHeaderMapImpl request_headers{{"sw8", header_value}}; + previous_span_context = SpanContext::spanContextFromRequest(request_headers); + ASSERT(previous_span_context); + } + Tracing::Decision decision; + decision.traced = sampled; + + auto segment_context = + std::make_shared(std::move(previous_span_context), decision, random); + + segment_context->setService(seed + "#SERVICE"); + segment_context->setServiceInstance(seed + "#INSTANCE"); + segment_context->setEndpoint(seed + "#ENDPOINT"); + return segment_context; + } + + static SpanStore* createSpanStore(SegmentContext* segment_context, SpanStore* parent_span_store, + std::string seed, Envoy::TimeSource& time_source) { + SpanStore* span_store = segment_context->createSpanStore(time_source, parent_span_store); + + span_store->setAsEntrySpan(true); + span_store->setAsError(false); + span_store->setOperation(seed + "#OPERATION"); + span_store->setPeer(seed + "#PEER"); + span_store->setStartTime(22222222); + span_store->setEndTime(33333333); + + span_store->addTag(seed + "#TAG_KEY_A", seed + "#TAG_VALUE_A"); + span_store->addTag(seed + "#TAG_KEY_B", seed + "#TAG_VALUE_B"); + span_store->addTag(seed + "#TAG_KEY_C", seed + "#TAG_VALUE_C"); + return span_store; + } +}; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc new file mode 100644 index 0000000000000..6d234d6e4f1c0 --- /dev/null +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -0,0 +1,50 @@ +#include "extensions/tracers/skywalking/skywalking_tracer_impl.h" + +#include "test/extensions/tracers/skywalking/skywalking_test_helper.h" +#include "test/mocks/common.h" +#include "test/mocks/server/tracer_factory_context.h" +#include "test/mocks/tracing/mocks.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class SkyWalkingDriverTest : public testing::Test { +public: + void setupSkyWalkingDriver(const std::string& yaml_string) { + TestUtility::loadFromYaml(yaml_string, config_); + + driver_ = std::make_unique(config_, context_); + } + +protected: + testing::NiceMock context_; + envoy::config::trace::v3::SkyWalkingConfig config_; + DriverPtr driver_; +}; + +static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + client_config: + authentication: "A fake auth string for SkyWalking test" + service_name: "Test Service" + instance_name: "Test Instance" + pass_endpoint: true + max_cache_size: 2333 +)EOF"; + +TEST_F(SkyWalkingDriverTest, SkyWalkingDriverInitTest) { + setupSkyWalkingDriver(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc new file mode 100644 index 0000000000000..ab26699f55c5c --- /dev/null +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -0,0 +1,328 @@ +#include "common/common/base64.h" +#include "common/common/hex.h" + +#include "extensions/tracers/skywalking/skywalking_types.h" + +#include "test/extensions/tracers/skywalking/skywalking_test_helper.h" +#include "test/mocks/common.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +// Some constant strings for testing. +constexpr char TEST_SERVICE[] = "EnvoyIngressForTest"; +constexpr char TEST_INSTANCE[] = "node-2.3.4.5~ingress"; +constexpr char TEST_ADDRESS[] = "255.255.255.255"; +constexpr char TEST_ENDPOINT[] = "/POST/path/for/test"; + +// Test whether SpanContext can correctly parse data from propagation headers and throw exceptions +// when errors occur. +TEST(SpanContextTest, SpanContextCommonTest) { + testing::NiceMock mock_random_generator; + + ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(uint64_t(23333))); + + std::string trace_id = SkyWalkingTestHelper::generateId(mock_random_generator); + std::string segment_id = SkyWalkingTestHelper::generateId(mock_random_generator); + + // Create properly formatted propagation headers and test whether the propagation headers can be + // parsed correctly. + std::string header_value_with_right_format = + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 233333, + SkyWalkingTestHelper::base64Encode(TEST_SERVICE), + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); + + Http::TestRequestHeaderMapImpl headers_with_right_format{{"sw8", header_value_with_right_format}}; + + auto previous_span_context = SpanContext::spanContextFromRequest(headers_with_right_format); + EXPECT_NE(nullptr, previous_span_context.get()); + + // Verify that each field parsed from the propagation headers is correct. + EXPECT_EQ(previous_span_context->sampled_, 0); + EXPECT_EQ(previous_span_context->trace_id_, trace_id); + EXPECT_EQ(previous_span_context->trace_segment_id_, segment_id); + EXPECT_EQ(previous_span_context->span_id_, 233333); + EXPECT_EQ(previous_span_context->service_, TEST_SERVICE); + EXPECT_EQ(previous_span_context->service_instance_, TEST_INSTANCE); + EXPECT_EQ(previous_span_context->endpoint_, TEST_ENDPOINT); + EXPECT_EQ(previous_span_context->target_address_, TEST_ADDRESS); + + // Test whether an exception can be correctly thrown when some fields are missing. + std::string header_value_lost_some_parts = + fmt::format("{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 3, + SkyWalkingTestHelper::base64Encode(TEST_SERVICE), + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE)); + + Http::TestRequestHeaderMapImpl headers_lost_some_parts{{"sw8", header_value_lost_some_parts}}; + + EXPECT_THROW_WITH_MESSAGE( + SpanContext::spanContextFromRequest(headers_lost_some_parts), EnvoyException, + fmt::format("Invalid propagation header for SkyWalking: {}", header_value_lost_some_parts)); + + // Test whether an exception can be correctly thrown when the sampling flag is wrong. + Http::TestRequestHeaderMapImpl headers_with_error_sampled{ + {"sw8", + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 3, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 3, + SkyWalkingTestHelper::base64Encode(TEST_SERVICE), + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS))}}; + + EXPECT_THROW_WITH_MESSAGE(SpanContext::spanContextFromRequest(headers_with_error_sampled), + EnvoyException, + "Invalid propagation header for SkyWalking: sampling flag can only be " + "'0' or '1' but '3' was provided"); + + // Test whether an exception can be correctly thrown when the span id format is wrong. + Http::TestRequestHeaderMapImpl headers_with_error_span_id{ + {"sw8", + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 1, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), "abc", + SkyWalkingTestHelper::base64Encode(TEST_SERVICE), + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS))}}; + + EXPECT_THROW_WITH_MESSAGE( + SpanContext::spanContextFromRequest(headers_with_error_span_id), EnvoyException, + "Invalid propagation header for SkyWalking: connot convert 'abc' to valid span id"); + + // Test whether an exception can be correctly thrown when a field is empty. + std::string header_value_with_empty_field = + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 1, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 4, "", + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); + Http::TestRequestHeaderMapImpl headers_with_empty_field{{"sw8", header_value_with_empty_field}}; + + EXPECT_THROW_WITH_MESSAGE( + SpanContext::spanContextFromRequest(headers_with_empty_field), EnvoyException, + fmt::format("Invalid propagation header for SkyWalking: {}", header_value_with_empty_field)); + + // Test whether an exception can be correctly thrown when a string is not properly encoded. + Http::TestRequestHeaderMapImpl headers_with_error_field{ + {"sw8", + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 1, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 4, "hhhhhhh", + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS))}}; + + EXPECT_THROW_WITH_MESSAGE(SpanContext::spanContextFromRequest(headers_with_error_field), + EnvoyException, + "Invalid propagation header for SkyWalking: parse error"); +} + +// Test whether the SegmentContext works normally when Envoy is the root node (Propagation headers +// does not exist). +TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { + testing::NiceMock mock_random_generator; + testing::NiceMock mock_time_source; + + ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(233333)); + + SegmentContextSharedPtr segment_context = + SkyWalkingTestHelper::createSegmentContext(true, "NEW", "", mock_random_generator); + + // When previous span context is null, the value of the sampling flag depends on the tracing + // decision + EXPECT_EQ(segment_context->sampled(), 1); + // The SegmentContext will use random generator to create new trace id and new trace segment id. + EXPECT_EQ(segment_context->traceId(), SkyWalkingTestHelper::generateId(mock_random_generator)); + EXPECT_EQ(segment_context->traceSegmentId(), + SkyWalkingTestHelper::generateId(mock_random_generator)); + + EXPECT_EQ(segment_context->previousSpanContext(), nullptr); + + // Test whether the value of the fields can be set correctly and the value of the fields can be + // obtained correctly. + EXPECT_EQ(segment_context->endpoint(), "NEW#ENDPOINT"); + segment_context->setEndpoint(TEST_ENDPOINT); + EXPECT_EQ(segment_context->endpoint(), TEST_ENDPOINT); + + EXPECT_EQ(segment_context->service(), "NEW#SERVICE"); + segment_context->setService(TEST_SERVICE); + EXPECT_EQ(segment_context->service(), TEST_SERVICE); + + EXPECT_EQ(segment_context->serviceInstance(), "NEW#INSTANCE"); + segment_context->setServiceInstance(TEST_INSTANCE); + EXPECT_EQ(segment_context->serviceInstance(), TEST_INSTANCE); + + // Test whether SegmentContext can correctly create SpanStore object with null parent SpanStore. + SpanStore* root_span = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, + "PARENT", mock_time_source); + EXPECT_NE(nullptr, root_span); + + // The span id of the first SpanStore in each SegmentContext is 0. Its parent span id is -1. + EXPECT_EQ(root_span->spanId(), 0); + EXPECT_EQ(root_span->parentSpanId(), -1); + + // Verify that the SpanStore object is correctly stored in the SegmentContext. + EXPECT_EQ(segment_context->spanList().size(), 1); + EXPECT_EQ(segment_context->spanList()[0].get(), root_span); + + // Test whether SegmentContext can correctly create SpanStore object with a parent SpanStore. + SpanStore* child_span = SkyWalkingTestHelper::createSpanStore(segment_context.get(), root_span, + "CHILD", mock_time_source); + + EXPECT_NE(nullptr, child_span); + + EXPECT_EQ(child_span->spanId(), 1); + EXPECT_EQ(child_span->parentSpanId(), 0); + + EXPECT_EQ(segment_context->spanList().size(), 2); + EXPECT_EQ(segment_context->spanList()[1].get(), child_span); +} + +// Test whether the SegmentContext can work normally when a previous span context exists. +TEST(SegmentContextTest, SegmentContextTestWithPreviousSpanContext) { + testing::NiceMock mock_random_generator; + + ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(23333)); + + std::string trace_id = SkyWalkingTestHelper::generateId(mock_random_generator); + std::string segment_id = SkyWalkingTestHelper::generateId(mock_random_generator); + + std::string header_value_with_right_format = + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 233333, + SkyWalkingTestHelper::base64Encode(TEST_SERVICE), + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); + + Http::TestRequestHeaderMapImpl headers_with_right_format{{"sw8", header_value_with_right_format}}; + + auto previous_span_context = SpanContext::spanContextFromRequest(headers_with_right_format); + SpanContext* previous_span_context_bk = previous_span_context.get(); + + Tracing::Decision decision; + decision.traced = true; + + EXPECT_CALL(mock_random_generator, random()).WillRepeatedly(testing::Return(666666)); + + SegmentContext segment_context(std::move(previous_span_context), decision, mock_random_generator); + + // When a previous span context exists, the sampling flag of the SegmentContext depends on + // previous span context rather than tracing decision. + EXPECT_EQ(segment_context.sampled(), 0); + + // When previous span context exists, the trace id of SegmentContext remains the same as that of + // previous span context. + EXPECT_EQ(segment_context.traceId(), trace_id); + // SegmentContext will always create a new trace segment id. + EXPECT_NE(segment_context.traceSegmentId(), segment_id); + + EXPECT_EQ(segment_context.previousSpanContext(), previous_span_context_bk); +} + +// Test whether SpanStore can work properly. +TEST(SpanStoreTest, SpanStoreCommonTest) { + testing::NiceMock mock_random_generator; + testing::NiceMock mock_time_source; + auto now = time_system_.systemTime(); + + ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(23333)); + ON_CALL(mock_time_source, systemTime()).WillByDefault(testing::Return(now)); + + // Create segment context and first span store. + SegmentContextSharedPtr segment_context = + SkyWalkingTestHelper::createSegmentContext(true, "CURR", "PREV", mock_random_generator); + SpanStore* root_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, + "ROOT", mock_time_source); + EXPECT_NE(nullptr, root_store); + + // The span id of the first SpanStore in each SegmentContext is 0. Its parent span id is -1. + EXPECT_EQ(0, root_store->spanId()); + EXPECT_EQ(-1, root_store->parentSpanId()); + + EXPECT_EQ(1, root_store->sampled()); + + // Test whether the value of the fields can be set correctly and the value of the fields can be + // obtained correctly. + EXPECT_EQ(true, root_store->isEntrySpan()); + root_store->setAsEntrySpan(false); + EXPECT_EQ(false, root_store->isEntrySpan()); + + EXPECT_EQ(false, root_store->isError()); + root_store->setAsError(true); + EXPECT_EQ(true, root_store->isError()); + + EXPECT_EQ("ROOT#OPERATION", root_store->operation()); + root_store->setOperation("oooooop"); + EXPECT_EQ("oooooop", root_store->operation()); + root_store->setOperation(""); + // If the operation name is empty, the endpoint of the current SegmentContext will be used + // instead. + EXPECT_EQ("CURR#ENDPOINT", root_store->operation()); + + EXPECT_EQ(22222222, root_store->startTime()); + root_store->setStartTime(23333); + EXPECT_EQ(23333, root_store->startTime()); + + EXPECT_EQ(33333333, root_store->endTime()); + root_store->setEndTime(25555); + EXPECT_EQ(25555, root_store->endTime()); + + EXPECT_EQ(-1, root_store->parentSpanId()); + root_store->setParentSpanId(234); + EXPECT_EQ(234, root_store->parentSpanId()); + + // When SpanStore calls finish, the end time will be set. + root_store->finish(); + EXPECT_EQ(std::chrono::time_point_cast(now).time_since_epoch().count(), + root_store->endTime()); + + EXPECT_EQ("ROOT#PEER", root_store->peer()); + root_store->setPeer(""); + + // Test whether SpanStore can correctly inject propagation headers to request headers. + + // When the peer is empty, use the host in the request as the target address. + Http::TestRequestHeaderMapImpl request_headers_no_peer{{":authority", "test.com"}}; + root_store->injectContext(request_headers_no_peer); + std::string expected_header_value = fmt::format( + "{}-{}-{}-{}-{}-{}-{}-{}", 1, + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), + 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), + SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), + SkyWalkingTestHelper::base64Encode("test.com")); + + EXPECT_EQ(request_headers_no_peer.get_("sw8"), expected_header_value); + + root_store->setPeer(TEST_ADDRESS); + EXPECT_EQ(TEST_ADDRESS, root_store->peer()); + + Http::TestRequestHeaderMapImpl request_headers_with_peer{{":authority", "test.com"}}; + root_store->injectContext(request_headers_with_peer); + + expected_header_value = fmt::format( + "{}-{}-{}-{}-{}-{}-{}-{}", 1, + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), + 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), + SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); + + EXPECT_EQ(request_headers_with_peer.get_("sw8"), expected_header_value); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc new file mode 100644 index 0000000000000..0b664458ffbd4 --- /dev/null +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -0,0 +1,84 @@ +#include "extensions/tracers/skywalking/trace_segment_reporter.h" + +#include "test/extensions/tracers/skywalking/skywalking_test_helper.h" +#include "test/mocks/common.h" +#include "test/mocks/event/mocks.h" +#include "test/mocks/grpc/mocks.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +// TODO(wbpcode): we need stats to get internal status. + +class TraceSegmentReporterTest : public testing::Test { +public: + void setupTraceSegmentReporter(const std::string& yaml_string) { + EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { + timer_cb_ = timer_cb; + return timer_; + })); + timer_ = new testing::NiceMock(); + + auto client_factory = std::make_unique>(); + + auto client = std::make_unique>(); + mock_client_ptr_ = client.get(); + + mock_stream_ptr_ = std::make_unique>(); + + EXPECT_CALL(*client_factory, create()) + .WillOnce(testing::Return(testing::ByMove(std::move(client)))); + EXPECT_CALL(*mock_client_ptr_, startRaw(_, _, _, _)) + .WillOnce(testing::Return(mock_stream_ptr_.get())); + + TestUtility::loadFromYaml(yaml_string, client_config_); + + reporter_ = std::make_unique(std::move(client_factory), mock_dispatcher_, + client_config_); + } + +protected: + envoy::config::trace::v3::ClientConfig client_config_; + + testing::NiceMock mock_dispatcher_; + testing::NiceMock mock_random_generator_; + testing::NiceMock mock_time_source_; + + testing::NiceMock* mock_client_ptr_{nullptr}; + + std::unique_ptr> mock_stream_ptr_{nullptr}; + + testing::NiceMock* timer_; + Event::TimerCb timer_cb_; + + TraceSegmentReporterPtr reporter_; +}; + +TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { + setupTraceSegmentReporter("{}"); + + ON_CALL(mock_random_generator_, random()).WillByDefault(testing::Return(23333)); + ON_CALL(mock_time_source_, systemTime()) + .WillByDefault(testing::Return(time_system_.systemTime())); + SegmentContextSharedPtr segment_context = + SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); + SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, + "PARENT", mock_time_source_); + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", + mock_time_source_); + + EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); + + reporter_->report(*segment_context); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc new file mode 100644 index 0000000000000..0d4e7d4be22be --- /dev/null +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -0,0 +1,178 @@ +#include "extensions/tracers/skywalking/tracer.h" + +#include "test/extensions/tracers/skywalking/skywalking_test_helper.h" +#include "test/mocks/common.h" +#include "test/mocks/stats/mocks.h" +#include "test/mocks/tracing/mocks.h" +#include "test/mocks/upstream/cluster_manager.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class TracerTest : public testing::Test { +public: + void setupTracer(const std::string& yaml_string) { + EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { + timer_cb_ = timer_cb; + return timer_; + })); + timer_ = new testing::NiceMock(); + + auto client_factory = std::make_unique>(); + + auto client = std::make_unique>(); + auto client_ptr = client.get(); + + mock_stream_ptr_ = std::make_unique>(); + + EXPECT_CALL(*client_factory, create()) + .WillOnce(testing::Return(testing::ByMove(std::move(client)))); + + EXPECT_CALL(*client_ptr, startRaw(_, _, _, _)) + .WillOnce(testing::Return(mock_stream_ptr_.get())); + + EXPECT_CALL(mock_cluster_manager_, grpcAsyncClientManager()) + .WillOnce(testing::ReturnRef(mock_async_client_manager_)); + + EXPECT_CALL(mock_async_client_manager_, factoryForGrpcService(_, _, _)) + .WillOnce(testing::Return(testing::ByMove(std::move(client_factory)))); + + TestUtility::loadFromYaml(yaml_string, config_); + tracer_ = + std::make_unique(mock_cluster_manager_, stats_, mock_time_source_, mock_dispatcher_, + config_.grpc_service(), config_.client_config()); + } + +protected: + envoy::config::trace::v3::SkyWalkingConfig config_; + + testing::NiceMock mock_tracing_config_; + testing::NiceMock mock_dispatcher_; + testing::NiceMock mock_random_generator_; + testing::NiceMock mock_time_source_; + testing::NiceMock mock_cluster_manager_; + testing::NiceMock mock_async_client_manager_; + NiceMock stats_; + + std::unique_ptr> mock_stream_ptr_{nullptr}; + + testing::NiceMock* timer_; + Event::TimerCb timer_cb_; + + TracerPtr tracer_; +}; + +// Test that the basic functionality of Tracer is working, including creating Span, using Span to +// create new child Spans. +TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { + setupTracer("{}"); + EXPECT_CALL(mock_random_generator_, random()).WillRepeatedly(testing::Return(666666)); + ON_CALL(mock_time_source_, systemTime()) + .WillByDefault(testing::Return(time_system_.systemTime()); + + // Create a new SegmentContext. + SegmentContextSharedPtr segment_context = + SkyWalkingTestHelper::createSegmentContext(true, "CURR", "", mock_random_generator_); + + EXPECT_CALL(mock_tracing_config_, operationName()) + .WillOnce(testing::Return(Envoy::Tracing::OperationName::Ingress)); + Envoy::Tracing::SpanPtr org_span = tracer_->startSpan( + mock_tracing_config_, mock_time_source_.systemTime(), "", segment_context, nullptr); + Span* span = dynamic_cast(org_span.get()); + + // Since the operation name in config is Ingress, the new span is entry span. + EXPECT_EQ(true, span->spanStore()->isEntrySpan()); + + // Test whether the basic functions of Span are normal. + span->setSampled(false); + EXPECT_EQ(false, span->spanStore()->sampled()); + + EXPECT_EQ("CURR#ENDPOINT", span->spanStore()->operation()); + span->setOperation("op"); + EXPECT_EQ("op", span->spanStore()->operation()); + + span->setTag("TestTagKeyA", "TestTagValueA"); + span->setTag("TestTagKeyB", "TestTagValueB"); + EXPECT_EQ("TestTagValueA", span->spanStore()->tags().at(0).value()); + EXPECT_EQ("TestTagValueB", span->spanStore()->tags().at(1).value()); + + // Entry span does not set the peer address. + span->setTag(Tracing::Tags::get().PeerAddress, "0.0.0.0"); + EXPECT_EQ("", span->spanStore()->peer()); + + // Test the inject context function and verify the result. + Http::TestRequestHeaderMapImpl headers{{":authority", "test.com"}}; + std::string expected_header_value = fmt::format( + "{}-{}-{}-{}-{}-{}-{}-{}", 0, + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), + 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), + SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), + SkyWalkingTestHelper::base64Encode("test.com")); + span->injectContext(headers); + EXPECT_EQ(expected_header_value, headers.get_("sw8")); + + EXPECT_CALL(mock_tracing_config_, operationName()) + .WillOnce(testing::Return(Envoy::Tracing::OperationName::Egress)); + Envoy::Tracing::SpanPtr org_first_child_span = + span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); + Span* first_child_span = dynamic_cast(org_first_child_span.get()); + + // Since the operation name in config is Egress, the new span is exit span. + EXPECT_EQ(false, first_child_span->spanStore()->isEntrySpan()); + + EXPECT_EQ(0, first_child_span->spanStore()->sampled()); + EXPECT_EQ(1, first_child_span->spanStore()->spanId()); + EXPECT_EQ(0, first_child_span->spanStore()->parentSpanId()); + + // Exit span will set the peer address. + first_child_span->setTag(Tracing::Tags::get().PeerAddress, "1.1.1.1"); + EXPECT_EQ("1.1.1.1", first_child_span->spanStore()->peer()); + EXPECT_EQ("TestChild", first_child_span->spanStore()->operation()); + + Http::TestRequestHeaderMapImpl first_child_headers{{":authority", "test.com"}}; + expected_header_value = fmt::format( + "{}-{}-{}-{}-{}-{}-{}-{}", 0, + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), + SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), + 1, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), + SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), + SkyWalkingTestHelper::base64Encode("1.1.1.1")); + first_child_span->injectContext(first_child_headers); + EXPECT_EQ(expected_header_value, first_child_headers.get_("sw8")); + + // Reset sampling flag to true. + span->setSampled(true); + EXPECT_CALL(mock_tracing_config_, operationName()) + .WillOnce(testing::Return(Envoy::Tracing::OperationName::Ingress)); + Envoy::Tracing::SpanPtr org_second_child_span = + span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); + Span* second_child_span = dynamic_cast(org_second_child_span.get()); + + EXPECT_EQ(1, second_child_span->spanStore()->sampled()); + EXPECT_EQ(2, second_child_span->spanStore()->spanId()); + EXPECT_EQ(0, second_child_span->spanStore()->parentSpanId()); + + EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)).Times(1); + + // When the child span ends, the data is not reported immediately, but the end time is set. + first_child_span->finishSpan(); + second_child_span->finishSpan(); + EXPECT_NE(0, first_child_span->spanStore()->endTime()); + + // When the first span in the current segment ends, the entire segment is reported. + span->finishSpan(); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy From b8ce5a34291fa3273bf8d49f4975f349e8839950 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 13 Sep 2020 01:11:54 +0800 Subject: [PATCH 03/61] add simple stats to skywalking tracer Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/BUILD | 12 ++++ .../tracers/skywalking/skywalking_stats.h | 21 ++++++ .../skywalking/skywalking_tracer_impl.cc | 21 +++--- .../skywalking/skywalking_tracer_impl.h | 6 +- .../skywalking/trace_segment_reporter.cc | 19 +++-- .../skywalking/trace_segment_reporter.h | 7 +- source/extensions/tracers/skywalking/tracer.h | 18 ++--- test/extensions/tracers/skywalking/BUILD | 4 ++ .../skywalking/skywalking_tracer_impl_test.cc | 7 +- .../skywalking/skywalking_types_test.cc | 30 ++++---- .../skywalking/trace_segment_reporter_test.cc | 54 ++++++++------- .../tracers/skywalking/tracer_test.cc | 69 +++++++++---------- 12 files changed, 162 insertions(+), 106 deletions(-) create mode 100644 source/extensions/tracers/skywalking/skywalking_stats.h diff --git a/source/extensions/tracers/skywalking/BUILD b/source/extensions/tracers/skywalking/BUILD index b0e84ea59b8bf..ac22f3fc4298e 100644 --- a/source/extensions/tracers/skywalking/BUILD +++ b/source/extensions/tracers/skywalking/BUILD @@ -16,6 +16,7 @@ envoy_cc_library( srcs = ["trace_segment_reporter.cc"], hdrs = ["trace_segment_reporter.h"], deps = [ + ":skywalking_stats_lib", ":skywalking_types_lib", "//include/envoy/grpc:async_client_manager_interface", "//source/common/grpc:async_client_lib", @@ -29,6 +30,7 @@ envoy_cc_library( srcs = ["skywalking_types.cc"], hdrs = ["skywalking_types.h"], deps = [ + ":skywalking_stats_lib", "//include/envoy/common:random_generator_interface", "//include/envoy/common:time_interface", "//include/envoy/http:header_map_interface", @@ -64,6 +66,16 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "skywalking_stats_lib", + hdrs = [ + "skywalking_stats.h", + ], + deps = [ + "//include/envoy/stats:stats_macros", + ], +) + envoy_cc_extension( name = "config", srcs = ["config.cc"], diff --git a/source/extensions/tracers/skywalking/skywalking_stats.h b/source/extensions/tracers/skywalking/skywalking_stats.h new file mode 100644 index 0000000000000..545241df7aa07 --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_stats.h @@ -0,0 +1,21 @@ +#include "envoy/stats/stats_macros.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +#define SKYWALKING_TRACER_STATS(COUNTER) \ + COUNTER(segments_sent) \ + COUNTER(segments_dropped) \ + COUNTER(cache_flushed) \ + COUNTER(segments_flushed) + +struct SkyWalkingTracerStats { + SKYWALKING_TRACER_STATS(GENERATE_COUNTER_STRUCT) +}; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index e2eeb954fd614..e16dd54d877fb 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -15,23 +15,28 @@ namespace SkyWalking { Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, Server::Configuration::TracerFactoryContext& context) - : client_config_(proto_config.client_config()), + : tracing_stats_{SKYWALKING_TRACER_STATS( + POOL_COUNTER_PREFIX(context.serverFactoryContext().scope(), "tracing.skywalking."))}, + client_config_(proto_config.client_config()), random_generator_(context.serverFactoryContext().random()), tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { + auto& factory_context = context.serverFactoryContext(); + if (client_config_.service_name().empty()) { - client_config_.set_service_name(context.serverFactoryContext().localInfo().clusterName()); + client_config_.set_service_name(factory_context.localInfo().clusterName()); } if (client_config_.instance_name().empty()) { - client_config_.set_instance_name(context.serverFactoryContext().localInfo().nodeName()); + client_config_.set_instance_name(factory_context.localInfo().nodeName()); } - tls_slot_ptr_->set([proto_config, &context, this]( + tls_slot_ptr_->set([proto_config, &factory_context, this]( Event::Dispatcher& dispatcher) -> ThreadLocal::ThreadLocalObjectSharedPtr { - auto& factory_context = context.serverFactoryContext(); - TracerPtr tracer = std::make_unique( - factory_context.clusterManager(), factory_context.scope(), factory_context.timeSource(), - dispatcher, proto_config.grpc_service(), client_config_); + TracerPtr tracer = std::make_unique(factory_context.timeSource()); + tracer->setReporter(std::make_unique( + factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( + proto_config.grpc_service(), factory_context.scope(), false), + dispatcher, tracing_stats_, client_config_)); return std::make_shared(std::move(tracer)); }); } diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h index e3579be141f8d..4d8f6759c88b8 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h @@ -20,8 +20,8 @@ class Driver : public Tracing::Driver, public Logger::Loggablecreate()), + SkyWalkingTracerStats& stats, const envoy::config::trace::v3::ClientConfig& client_config) + : tracing_stats_(stats), simple_authentication_token_(client_config.authentication()), + client_(factory->create()), service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "TraceSegmentReportService.collect")) { - max_delayed_segments_cache_size_ = config_.max_cache_size() == 0 + max_delayed_segments_cache_size_ = client_config.max_cache_size() == 0 ? DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE - : config_.max_cache_size(); + : client_config.max_cache_size(); retry_timer_ = dispatcher.createTimer([this]() -> void { establishNewStream(); }); establishNewStream(); } void TraceSegmentReporter::onCreateInitialMetadata(Http::RequestHeaderMap& metadata) { - if (!config_.authentication().empty()) { - metadata.setReferenceKey(Http::CustomHeaders::get().Authorization, config_.authentication()); + if (!simple_authentication_token_.empty()) { + metadata.setReferenceKey(Http::CustomHeaders::get().Authorization, + simple_authentication_token_); } } @@ -94,21 +96,26 @@ void TraceSegmentReporter::report(const SegmentContext& segment_context) { void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr&& request) { if (stream_ != nullptr) { + tracing_stats_.segments_sent_.inc(); stream_->sendMessage(*request, false); return; } // Null stream_ and cache segment data temporarily. delayed_segments_cache_.emplace(std::move(request)); if (delayed_segments_cache_.size() > max_delayed_segments_cache_size_) { + tracing_stats_.segments_dropped_.inc(); delayed_segments_cache_.pop(); } } void TraceSegmentReporter::flushTraceSegments() { while (!delayed_segments_cache_.empty() && stream_ != nullptr) { + tracing_stats_.segments_sent_.inc(); + tracing_stats_.segments_flushed_.inc(); stream_->sendMessage(*delayed_segments_cache_.front(), false); delayed_segments_cache_.pop(); } + tracing_stats_.cache_flushed_.inc(); } void TraceSegmentReporter::closeStream() { diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index 5935b9de684e5..7116cb4202a01 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -8,6 +8,7 @@ #include "common/Common.pb.h" #include "common/grpc/async_client_impl.h" +#include "extensions/tracers/skywalking/skywalking_stats.h" #include "extensions/tracers/skywalking/skywalking_types.h" #include "language-agent/Tracing.pb.h" @@ -22,7 +23,7 @@ using TraceSegmentPtr = std::unique_ptr; class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { public: explicit TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, - Event::Dispatcher& dispatcher, + Event::Dispatcher& dispatcher, SkyWalkingTracerStats& stats, const envoy::config::trace::v3::ClientConfig& client_config); // Grpc::AsyncStreamCallbacks @@ -53,7 +54,9 @@ class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { void handleFailure(); void setRetryTimer(); - const envoy::config::trace::v3::ClientConfig& config_; + SkyWalkingTracerStats& tracing_stats_; + + const std::string simple_authentication_token_; uint32_t max_delayed_segments_cache_size_{0}; Grpc::AsyncClient client_; Grpc::AsyncStream stream_{}; diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h index ef1bdf8d2eedb..06cc79925b06f 100644 --- a/source/extensions/tracers/skywalking/tracer.h +++ b/source/extensions/tracers/skywalking/tracer.h @@ -19,20 +19,16 @@ class Span; class Tracer { public: - explicit Tracer(Upstream::ClusterManager& cm, Stats::Scope& scope, TimeSource& time_source, - Event::Dispatcher& dispatcher, - const envoy::config::core::v3::GrpcService& grpc_service, - const envoy::config::trace::v3::ClientConfig& client_config) - : time_source_(time_source), - reporter_(std::make_unique( - cm.grpcAsyncClientManager().factoryForGrpcService(grpc_service, scope, false), - dispatcher, client_config)) {} - void report(const SegmentContext& segment_context) { return reporter_->report(segment_context); } + explicit Tracer(TimeSource& time_source) : time_source_(time_source) {} ~Tracer() { reporter_->closeStream(); } + void setReporter(TraceSegmentReporterPtr&& reporter) { reporter_ = std::move(reporter); } + + void report(const SegmentContext& segment_context) { return reporter_->report(segment_context); } + Tracing::SpanPtr startSpan(const Tracing::Config& config, SystemTime start_time, - const std::string& operation_name, - SegmentContextSharedPtr span_context, Span* parent_span); + const std::string& operation, SegmentContextSharedPtr span_context, + Span* parent_span); private: TimeSource& time_source_; diff --git a/test/extensions/tracers/skywalking/BUILD b/test/extensions/tracers/skywalking/BUILD index 8682ad790f2fe..754037ea64a3a 100644 --- a/test/extensions/tracers/skywalking/BUILD +++ b/test/extensions/tracers/skywalking/BUILD @@ -32,6 +32,7 @@ envoy_extension_cc_test( ":skywalking_test_helper", "//source/extensions/tracers/skywalking:skywalking_types_lib", "//test/mocks:common_lib", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", ], ) @@ -46,6 +47,8 @@ envoy_extension_cc_test( "//test/mocks:common_lib", "//test/mocks/event:event_mocks", "//test/mocks/grpc:grpc_mocks", + "//test/mocks/stats:stats_mocks", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", ], ) @@ -74,6 +77,7 @@ envoy_extension_cc_test( "//test/mocks/grpc:grpc_mocks", "//test/mocks/stats:stats_mocks", "//test/mocks/upstream:cluster_manager_mocks", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", ], ) diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index 6d234d6e4f1c0..74239a683a82f 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -9,6 +9,8 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +using namespace testing; + namespace Envoy { namespace Extensions { namespace Tracers { @@ -18,12 +20,11 @@ class SkyWalkingDriverTest : public testing::Test { public: void setupSkyWalkingDriver(const std::string& yaml_string) { TestUtility::loadFromYaml(yaml_string, config_); - driver_ = std::make_unique(config_, context_); } protected: - testing::NiceMock context_; + NiceMock context_; envoy::config::trace::v3::SkyWalkingConfig config_; DriverPtr driver_; }; @@ -47,4 +48,4 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverInitTest) { } // namespace SkyWalking } // namespace Tracers } // namespace Extensions -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc index ab26699f55c5c..03fb75f9322e4 100644 --- a/test/extensions/tracers/skywalking/skywalking_types_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -5,11 +5,14 @@ #include "test/extensions/tracers/skywalking/skywalking_test_helper.h" #include "test/mocks/common.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +using namespace testing; + namespace Envoy { namespace Extensions { namespace Tracers { @@ -24,9 +27,9 @@ constexpr char TEST_ENDPOINT[] = "/POST/path/for/test"; // Test whether SpanContext can correctly parse data from propagation headers and throw exceptions // when errors occur. TEST(SpanContextTest, SpanContextCommonTest) { - testing::NiceMock mock_random_generator; + NiceMock mock_random_generator; - ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(uint64_t(23333))); + ON_CALL(mock_random_generator, random()).WillByDefault(Return(uint64_t(23333))); std::string trace_id = SkyWalkingTestHelper::generateId(mock_random_generator); std::string segment_id = SkyWalkingTestHelper::generateId(mock_random_generator); @@ -128,10 +131,10 @@ TEST(SpanContextTest, SpanContextCommonTest) { // Test whether the SegmentContext works normally when Envoy is the root node (Propagation headers // does not exist). TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { - testing::NiceMock mock_random_generator; - testing::NiceMock mock_time_source; + NiceMock mock_random_generator; + NiceMock mock_time_source; - ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(233333)); + ON_CALL(mock_random_generator, random()).WillByDefault(Return(233333)); SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "", mock_random_generator); @@ -188,9 +191,9 @@ TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { // Test whether the SegmentContext can work normally when a previous span context exists. TEST(SegmentContextTest, SegmentContextTestWithPreviousSpanContext) { - testing::NiceMock mock_random_generator; + NiceMock mock_random_generator; - ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(23333)); + ON_CALL(mock_random_generator, random()).WillByDefault(Return(23333)); std::string trace_id = SkyWalkingTestHelper::generateId(mock_random_generator); std::string segment_id = SkyWalkingTestHelper::generateId(mock_random_generator); @@ -211,7 +214,7 @@ TEST(SegmentContextTest, SegmentContextTestWithPreviousSpanContext) { Tracing::Decision decision; decision.traced = true; - EXPECT_CALL(mock_random_generator, random()).WillRepeatedly(testing::Return(666666)); + EXPECT_CALL(mock_random_generator, random()).WillRepeatedly(Return(666666)); SegmentContext segment_context(std::move(previous_span_context), decision, mock_random_generator); @@ -230,12 +233,13 @@ TEST(SegmentContextTest, SegmentContextTestWithPreviousSpanContext) { // Test whether SpanStore can work properly. TEST(SpanStoreTest, SpanStoreCommonTest) { - testing::NiceMock mock_random_generator; - testing::NiceMock mock_time_source; - auto now = time_system_.systemTime(); + NiceMock mock_random_generator; + NiceMock mock_time_source; + Event::SimulatedTimeSystem time_system; + Envoy::SystemTime now = time_system.systemTime(); - ON_CALL(mock_random_generator, random()).WillByDefault(testing::Return(23333)); - ON_CALL(mock_time_source, systemTime()).WillByDefault(testing::Return(now)); + ON_CALL(mock_random_generator, random()).WillByDefault(Return(23333)); + ON_CALL(mock_time_source, systemTime()).WillByDefault(Return(now)); // Create segment context and first span store. SegmentContextSharedPtr segment_context = diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 0b664458ffbd4..57d587699c36c 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -4,68 +4,72 @@ #include "test/mocks/common.h" #include "test/mocks/event/mocks.h" #include "test/mocks/grpc/mocks.h" +#include "test/mocks/stats/mocks.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +using namespace testing; + namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { -// TODO(wbpcode): we need stats to get internal status. - class TraceSegmentReporterTest : public testing::Test { public: + TraceSegmentReporterTest() + : tracing_stats_{ + SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))} {} + void setupTraceSegmentReporter(const std::string& yaml_string) { EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { timer_cb_ = timer_cb; return timer_; })); - timer_ = new testing::NiceMock(); + timer_ = new NiceMock(); - auto client_factory = std::make_unique>(); + auto mock_client_factory = std::make_unique>(); - auto client = std::make_unique>(); - mock_client_ptr_ = client.get(); + auto mock_client = std::make_unique>(); + mock_client_ptr_ = mock_client.get(); - mock_stream_ptr_ = std::make_unique>(); + mock_stream_ptr_ = std::make_unique>(); - EXPECT_CALL(*client_factory, create()) - .WillOnce(testing::Return(testing::ByMove(std::move(client)))); - EXPECT_CALL(*mock_client_ptr_, startRaw(_, _, _, _)) - .WillOnce(testing::Return(mock_stream_ptr_.get())); + EXPECT_CALL(*mock_client_factory, create()).WillOnce(Return(ByMove(std::move(mock_client)))); + EXPECT_CALL(*mock_client_ptr_, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); TestUtility::loadFromYaml(yaml_string, client_config_); - reporter_ = std::make_unique(std::move(client_factory), mock_dispatcher_, - client_config_); + reporter_ = std::make_unique( + std::move(mock_client_factory), mock_dispatcher_, tracing_stats_, client_config_); } protected: - envoy::config::trace::v3::ClientConfig client_config_; + NiceMock mock_dispatcher_; + NiceMock mock_random_generator_; + NiceMock mock_time_source_; + NiceMock mock_scope_; - testing::NiceMock mock_dispatcher_; - testing::NiceMock mock_random_generator_; - testing::NiceMock mock_time_source_; + NiceMock* mock_client_ptr_{nullptr}; - testing::NiceMock* mock_client_ptr_{nullptr}; + std::unique_ptr> mock_stream_ptr_{nullptr}; - std::unique_ptr> mock_stream_ptr_{nullptr}; - - testing::NiceMock* timer_; + NiceMock* timer_; Event::TimerCb timer_cb_; + envoy::config::trace::v3::ClientConfig client_config_; + SkyWalkingTracerStats tracing_stats_; TraceSegmentReporterPtr reporter_; }; TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { setupTraceSegmentReporter("{}"); - - ON_CALL(mock_random_generator_, random()).WillByDefault(testing::Return(23333)); - ON_CALL(mock_time_source_, systemTime()) - .WillByDefault(testing::Return(time_system_.systemTime())); + Event::SimulatedTimeSystem time_system; + ON_CALL(mock_random_generator_, random()).WillByDefault(Return(23333)); + ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index 0d4e7d4be22be..dc8dd2fb557d4 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -5,11 +5,14 @@ #include "test/mocks/stats/mocks.h" #include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/cluster_manager.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +using namespace testing; + namespace Envoy { namespace Extensions { namespace Tracers { @@ -17,54 +20,48 @@ namespace SkyWalking { class TracerTest : public testing::Test { public: + TracerTest() + : tracing_stats_{ + SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))} {} + void setupTracer(const std::string& yaml_string) { EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { timer_cb_ = timer_cb; return timer_; })); - timer_ = new testing::NiceMock(); - - auto client_factory = std::make_unique>(); + timer_ = new NiceMock(); - auto client = std::make_unique>(); - auto client_ptr = client.get(); + auto mock_client_factory = std::make_unique>(); - mock_stream_ptr_ = std::make_unique>(); + auto mock_client = std::make_unique>(); + auto mock_client_ptr = mock_client.get(); - EXPECT_CALL(*client_factory, create()) - .WillOnce(testing::Return(testing::ByMove(std::move(client)))); + mock_stream_ptr_ = std::make_unique>(); - EXPECT_CALL(*client_ptr, startRaw(_, _, _, _)) - .WillOnce(testing::Return(mock_stream_ptr_.get())); + EXPECT_CALL(*mock_client_factory, create()).WillOnce(Return(ByMove(std::move(mock_client)))); - EXPECT_CALL(mock_cluster_manager_, grpcAsyncClientManager()) - .WillOnce(testing::ReturnRef(mock_async_client_manager_)); + EXPECT_CALL(*mock_client_ptr, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); - EXPECT_CALL(mock_async_client_manager_, factoryForGrpcService(_, _, _)) - .WillOnce(testing::Return(testing::ByMove(std::move(client_factory)))); - - TestUtility::loadFromYaml(yaml_string, config_); - tracer_ = - std::make_unique(mock_cluster_manager_, stats_, mock_time_source_, mock_dispatcher_, - config_.grpc_service(), config_.client_config()); + TestUtility::loadFromYaml(yaml_string, client_config_); + tracer_ = std::make_unique(mock_time_source_); + tracer_->setReporter(std::make_unique( + std::move(mock_client_factory), mock_dispatcher_, tracing_stats_, client_config_)); } protected: - envoy::config::trace::v3::SkyWalkingConfig config_; - - testing::NiceMock mock_tracing_config_; - testing::NiceMock mock_dispatcher_; - testing::NiceMock mock_random_generator_; - testing::NiceMock mock_time_source_; - testing::NiceMock mock_cluster_manager_; - testing::NiceMock mock_async_client_manager_; - NiceMock stats_; + NiceMock mock_tracing_config_; + NiceMock mock_dispatcher_; + NiceMock mock_random_generator_; + NiceMock mock_time_source_; + NiceMock mock_scope_; - std::unique_ptr> mock_stream_ptr_{nullptr}; + std::unique_ptr> mock_stream_ptr_{nullptr}; - testing::NiceMock* timer_; + NiceMock* timer_; Event::TimerCb timer_cb_; + envoy::config::trace::v3::ClientConfig client_config_; + SkyWalkingTracerStats tracing_stats_; TracerPtr tracer_; }; @@ -72,16 +69,16 @@ class TracerTest : public testing::Test { // create new child Spans. TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { setupTracer("{}"); - EXPECT_CALL(mock_random_generator_, random()).WillRepeatedly(testing::Return(666666)); - ON_CALL(mock_time_source_, systemTime()) - .WillByDefault(testing::Return(time_system_.systemTime()); + EXPECT_CALL(mock_random_generator_, random()).WillRepeatedly(Return(666666)); + Event::SimulatedTimeSystem time_system; + ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); // Create a new SegmentContext. SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "CURR", "", mock_random_generator_); EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(testing::Return(Envoy::Tracing::OperationName::Ingress)); + .WillOnce(Return(Envoy::Tracing::OperationName::Ingress)); Envoy::Tracing::SpanPtr org_span = tracer_->startSpan( mock_tracing_config_, mock_time_source_.systemTime(), "", segment_context, nullptr); Span* span = dynamic_cast(org_span.get()); @@ -120,7 +117,7 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { EXPECT_EQ(expected_header_value, headers.get_("sw8")); EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(testing::Return(Envoy::Tracing::OperationName::Egress)); + .WillOnce(Return(Envoy::Tracing::OperationName::Egress)); Envoy::Tracing::SpanPtr org_first_child_span = span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); Span* first_child_span = dynamic_cast(org_first_child_span.get()); @@ -152,7 +149,7 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { // Reset sampling flag to true. span->setSampled(true); EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(testing::Return(Envoy::Tracing::OperationName::Ingress)); + .WillOnce(Return(Envoy::Tracing::OperationName::Ingress)); Envoy::Tracing::SpanPtr org_second_child_span = span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); Span* second_child_span = dynamic_cast(org_second_child_span.get()); From f95f9dd3554fdc6567ace802f6c332454f52a62a Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 14 Sep 2020 15:24:59 +0800 Subject: [PATCH 04/61] add more test for skywalking Signed-off-by: wbpcode --- .../skywalking/trace_segment_reporter.cc | 4 +- source/extensions/tracers/skywalking/tracer.h | 1 + .../skywalking/skywalking_tracer_impl_test.cc | 125 +++++++++++++++++- .../skywalking/trace_segment_reporter_test.cc | 56 ++++++++ .../tracers/skywalking/tracer_test.cc | 14 +- 5 files changed, 192 insertions(+), 8 deletions(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index 866c5ee6ba380..ec3f9031349fa 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -136,7 +136,9 @@ void TraceSegmentReporter::establishNewStream() { handleFailure(); return; } - flushTraceSegments(); + if (!delayed_segments_cache_.empty()) { + flushTraceSegments(); + } } void TraceSegmentReporter::handleFailure() { setRetryTimer(); } diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h index 06cc79925b06f..2104f552b9117 100644 --- a/source/extensions/tracers/skywalking/tracer.h +++ b/source/extensions/tracers/skywalking/tracer.h @@ -56,6 +56,7 @@ class Span : public Tracing::Span { void setBaggage(absl::string_view key, absl::string_view value) override; SpanStore* spanStore() const { return span_store_; } + SegmentContext* segmentContext() const { return segment_context_.get(); } private: SegmentContextSharedPtr segment_context_; diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index 74239a683a82f..95ed382405b17 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -19,13 +19,36 @@ namespace SkyWalking { class SkyWalkingDriverTest : public testing::Test { public: void setupSkyWalkingDriver(const std::string& yaml_string) { + auto mock_client_factory = std::make_unique>(); + auto mock_client = std::make_unique>(); + mock_stream_ptr_ = std::make_unique>(); + + EXPECT_CALL(*mock_client, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); + EXPECT_CALL(*mock_client_factory, create()).WillOnce(Return(ByMove(std::move(mock_client)))); + + auto& factory_context = context_.server_factory_context_; + + EXPECT_CALL(factory_context.cluster_manager_.async_client_manager_, + factoryForGrpcService(_, _, _)) + .WillOnce(Return(ByMove(std::move(mock_client_factory)))); + + ON_CALL(factory_context.local_info_, clusterName()).WillByDefault(ReturnRef(test_string)); + ON_CALL(factory_context.local_info_, nodeName()).WillByDefault(ReturnRef(test_string)); + TestUtility::loadFromYaml(yaml_string, config_); driver_ = std::make_unique(config_, context_); } protected: NiceMock context_; + NiceMock mock_tracing_config_; + Event::SimulatedTimeSystem time_system_; + + std::unique_ptr> mock_stream_ptr_{nullptr}; + envoy::config::trace::v3::SkyWalkingConfig config_; + std::string test_string = "ABCDEFGHIJKLMN"; + DriverPtr driver_; }; @@ -34,15 +57,109 @@ static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( envoy_grpc: cluster_name: fake_cluster client_config: - authentication: "A fake auth string for SkyWalking test" - service_name: "Test Service" - instance_name: "Test Instance" + authentication: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" + service_name: "FAKE_FAKE_FAKE" + instance_name: "FAKE_FAKE_FAKE" pass_endpoint: true max_cache_size: 2333 )EOF"; -TEST_F(SkyWalkingDriverTest, SkyWalkingDriverInitTest) { +static const std::string SKYWALKING_CONFIG_NO_CLIENT_CONFIG = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster +)EOF"; + +TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { setupSkyWalkingDriver(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); + + std::string trace_id = SkyWalkingTestHelper::generateId(context_.server_factory_context_.random_); + std::string segment_id = + SkyWalkingTestHelper::generateId(context_.server_factory_context_.random_); + + // Create new span segment with previous span context. + std::string previous_header_value = + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 233333, + SkyWalkingTestHelper::base64Encode("SERVICE"), + SkyWalkingTestHelper::base64Encode("INSTATNCE"), + SkyWalkingTestHelper::base64Encode("ENDPOINT"), + SkyWalkingTestHelper::base64Encode("ADDRESS")); + + Http::TestRequestHeaderMapImpl request_headers{{"sw8", previous_header_value}, + {":path", "/path"}, + {":method", "GET"}, + {":authority", "test.com"}}; + + ON_CALL(mock_tracing_config_, operationName()) + .WillByDefault(Return(Tracing::OperationName::Ingress)); + + Tracing::Decision decision; + decision.traced = true; + + Tracing::SpanPtr org_span = driver_->startSpan(mock_tracing_config_, request_headers, "", + time_system_.systemTime(), decision); + EXPECT_NE(nullptr, org_span.get()); + + Span* span = dynamic_cast(org_span.get()); + ASSERT(span); + + EXPECT_NE(nullptr, span->segmentContext()->previousSpanContext()); + + EXPECT_EQ("FAKE_FAKE_FAKE", span->segmentContext()->service()); + EXPECT_EQ("FAKE_FAKE_FAKE", span->segmentContext()->serviceInstance()); + + // If pass_endpoint is set to true, Envoy will use the downstream endpoint directly. + EXPECT_EQ(span->segmentContext()->endpoint(), + span->segmentContext()->previousSpanContext()->endpoint_); + + // Tracing decision will be overwrite by sampling flag in propagation headers. + EXPECT_EQ(0, span->segmentContext()->sampled()); + + // Since the sampling flag is false, no segment data is reported. + span->finishSpan(); + + auto& factory_context = context_.server_factory_context_; + EXPECT_EQ(0U, factory_context.scope_.counter("tracing.skywalking.segments_sent").value()); + + // Create new span segment with no previous span context. + Http::TestRequestHeaderMapImpl new_request_headers{ + {":path", "/path"}, {":method", "GET"}, {":authority", "test.com"}}; + + Tracing::SpanPtr org_new_span = driver_->startSpan(mock_tracing_config_, new_request_headers, "", + time_system_.systemTime(), decision); + + Span* new_span = dynamic_cast(org_new_span.get()); + ASSERT(new_span); + + EXPECT_EQ(nullptr, new_span->segmentContext()->previousSpanContext()); + // Although pass_endpoint is set to true, 'METHOD' and 'PATH' will be used as endpoint when + // previous span context is null. + EXPECT_EQ("/GET/path", new_span->segmentContext()->endpoint()); + + EXPECT_EQ(true, new_span->segmentContext()->sampled()); + + EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); + new_span->finishSpan(); + EXPECT_EQ(1U, factory_context.scope_.counter("tracing.skywalking.segments_sent").value()); +} + +TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) { + setupSkyWalkingDriver(SKYWALKING_CONFIG_NO_CLIENT_CONFIG); + + Http::TestRequestHeaderMapImpl request_headers{ + {":path", "/path"}, {":method", "GET"}, {":authority", "test.com"}}; + + Tracing::SpanPtr org_span = driver_->startSpan(mock_tracing_config_, request_headers, "", + time_system_.systemTime(), Tracing::Decision()); + EXPECT_NE(nullptr, org_span.get()); + + Span* span = dynamic_cast(org_span.get()); + ASSERT(span); + + EXPECT_EQ(test_string, span->segmentContext()->service()); + EXPECT_EQ(test_string, span->segmentContext()->serviceInstance()); + EXPECT_EQ("/GET/path", span->segmentContext()->endpoint()); } } // namespace SkyWalking diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 57d587699c36c..e5851d085b8e0 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -80,6 +80,62 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); reporter_->report(*segment_context); + + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); +} + +TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithCache) { + const std::string yaml_string = R"EOF( + max_cache_size: 3 + )EOF"; + + setupTraceSegmentReporter(yaml_string); + Event::SimulatedTimeSystem time_system; + ON_CALL(mock_random_generator_, random()).WillByDefault(Return(23333)); + ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); + SegmentContextSharedPtr segment_context = + SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); + SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, + "PARENT", mock_time_source_); + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", + mock_time_source_); + + EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)).Times(4); + + reporter_->report(*segment_context); + + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); + + // Simulates a disconnected connection. + EXPECT_CALL(*timer_, enableTimer(_, _)); + reporter_->onRemoteClose(Grpc::Status::WellKnownGrpcStatus::Unknown, ""); + + // Try to report 10 segments. Due to the disconnection, the cache size is only 3. So 7 of the + // segments will be discarded. + for (int i = 0; i < 10; i++) { + reporter_->report(*segment_context); + } + + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(7U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); + + // Simulate the situation where the connection is re-established. The remaining segments in the + // cache will be reported. + EXPECT_CALL(*mock_client_ptr_, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); + timer_cb_(); + + EXPECT_EQ(4U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(7U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(3U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); } } // namespace SkyWalking diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index dc8dd2fb557d4..7abc0ac326916 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -34,14 +34,12 @@ class TracerTest : public testing::Test { auto mock_client_factory = std::make_unique>(); auto mock_client = std::make_unique>(); - auto mock_client_ptr = mock_client.get(); mock_stream_ptr_ = std::make_unique>(); + EXPECT_CALL(*mock_client, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); EXPECT_CALL(*mock_client_factory, create()).WillOnce(Return(ByMove(std::move(mock_client)))); - EXPECT_CALL(*mock_client_ptr, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); - TestUtility::loadFromYaml(yaml_string, client_config_); tracer_ = std::make_unique(mock_time_source_); tracer_->setReporter(std::make_unique( @@ -165,8 +163,18 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { second_child_span->finishSpan(); EXPECT_NE(0, first_child_span->spanStore()->endTime()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); + // When the first span in the current segment ends, the entire segment is reported. span->finishSpan(); + + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); } } // namespace SkyWalking From bf033d8fcb9ad7bed043876a4684878ad36dce4b Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 14 Sep 2020 20:47:26 +0800 Subject: [PATCH 05/61] fix http tracer impl test Signed-off-by: wbpcode --- source/common/tracing/http_tracer_impl.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/common/tracing/http_tracer_impl.cc b/source/common/tracing/http_tracer_impl.cc index efe5f96c217a8..4e3cba7023d7b 100644 --- a/source/common/tracing/http_tracer_impl.cc +++ b/source/common/tracing/http_tracer_impl.cc @@ -177,8 +177,7 @@ void HttpTracerUtility::finalizeDownstreamSpan(Span& span, if (remote_address->type() == Network::Address::Type::Ip) { const auto remote_ip = remote_address->ip(); - span.setTag(Tracing::Tags::get().PeerAddress, - absl::StrCat(remote_ip->addressAsString(), ":", remote_ip->port())); + span.setTag(Tracing::Tags::get().PeerAddress, remote_ip->addressAsString()); } else { span.setTag(Tracing::Tags::get().PeerAddress, remote_address->logicalName()); } From 348387e5eb40e0a72044ced85bae7983f91337a9 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 16 Sep 2020 09:31:03 +0800 Subject: [PATCH 06/61] fix clang tidy check Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/skywalking_types.h | 2 -- .../tracers/skywalking/skywalking_test_helper.h | 1 + .../tracers/skywalking/trace_segment_reporter_test.cc | 7 ++----- test/extensions/tracers/skywalking/tracer_test.cc | 8 +++----- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index 2a33af6f6ddd5..82715b1db10d1 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -1,7 +1,5 @@ #pragma once -#include - #include #include diff --git a/test/extensions/tracers/skywalking/skywalking_test_helper.h b/test/extensions/tracers/skywalking/skywalking_test_helper.h index dd1699cfa0f48..9c868531753df 100644 --- a/test/extensions/tracers/skywalking/skywalking_test_helper.h +++ b/test/extensions/tracers/skywalking/skywalking_test_helper.h @@ -43,6 +43,7 @@ class SkyWalkingTestHelper { } Tracing::Decision decision; decision.traced = sampled; + decision.reason = Tracing::Reason::Sampling; auto segment_context = std::make_shared(std::move(previous_span_context), decision, random); diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index e5851d085b8e0..98aca24c89cd2 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -20,10 +20,6 @@ namespace SkyWalking { class TraceSegmentReporterTest : public testing::Test { public: - TraceSegmentReporterTest() - : tracing_stats_{ - SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))} {} - void setupTraceSegmentReporter(const std::string& yaml_string) { EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { timer_cb_ = timer_cb; @@ -61,7 +57,8 @@ class TraceSegmentReporterTest : public testing::Test { Event::TimerCb timer_cb_; envoy::config::trace::v3::ClientConfig client_config_; - SkyWalkingTracerStats tracing_stats_; + SkyWalkingTracerStats tracing_stats_{ + SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))}; TraceSegmentReporterPtr reporter_; }; diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index 7abc0ac326916..604f43b6ca2c1 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -20,15 +20,12 @@ namespace SkyWalking { class TracerTest : public testing::Test { public: - TracerTest() - : tracing_stats_{ - SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))} {} - void setupTracer(const std::string& yaml_string) { EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { timer_cb_ = timer_cb; return timer_; })); + timer_ = new NiceMock(); auto mock_client_factory = std::make_unique>(); @@ -59,7 +56,8 @@ class TracerTest : public testing::Test { Event::TimerCb timer_cb_; envoy::config::trace::v3::ClientConfig client_config_; - SkyWalkingTracerStats tracing_stats_; + SkyWalkingTracerStats tracing_stats_{ + SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))}; TracerPtr tracer_; }; From d689a8807577eae4ab6cad6581631d02cd0a55af Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 16 Sep 2020 21:52:25 +0800 Subject: [PATCH 07/61] use authentication as token key Signed-off-by: wbpcode --- .../tracers/skywalking/trace_segment_reporter.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index ec3f9031349fa..27de808195137 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -66,6 +66,10 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { return new_segment; } +const Http::LowerCaseString& authenticationTokenKey() { + CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, "Authentication"); +} + } // namespace TraceSegmentReporter::TraceSegmentReporter( @@ -85,8 +89,7 @@ TraceSegmentReporter::TraceSegmentReporter( void TraceSegmentReporter::onCreateInitialMetadata(Http::RequestHeaderMap& metadata) { if (!simple_authentication_token_.empty()) { - metadata.setReferenceKey(Http::CustomHeaders::get().Authorization, - simple_authentication_token_); + metadata.setReferenceKey(authenticationTokenKey(), simple_authentication_token_); } } From 3dcb8006fadb4114cf3940fa817e8b32cd921272 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Thu, 17 Sep 2020 11:58:34 +0800 Subject: [PATCH 08/61] peer address looks like downstream adddress Signed-off-by: wbpcode --- .../tracers/skywalking/skywalking_types.cc | 3 ++- .../tracers/skywalking/skywalking_types.h | 16 ++++++++++++---- .../tracers/skywalking/trace_segment_reporter.cc | 4 ++-- source/extensions/tracers/skywalking/tracer.cc | 9 ++++++--- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index c6abe27159f11..1cd133809a6f0 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -128,7 +128,8 @@ SpanStore* SegmentContext::createSpanStore(TimeSource& time_source, SpanStore* p void SpanStore::injectContext(Http::RequestHeaderMap& request_headers) const { ASSERT(segment_context_); - std::string target_address = peer_.empty() ? std::string(request_headers.getHostValue()) : peer_; + std::string target_address = + upstream_address_.empty() ? std::string(request_headers.getHostValue()) : upstream_address_; // Reference: // https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index 82715b1db10d1..e189739c07c44 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -177,7 +177,7 @@ class SpanStore { /* * Get peer address. */ - const std::string& peer() const { return peer_; } + const std::string& peerAddress() const { return peer_address_; } /* * Get span start time. @@ -244,9 +244,16 @@ class SpanStore { void setOperation(const std::string& operation) { operation_ = operation; } /* - * Set peer address. + * Set peer address. It should be downstream remote address currently. */ - void setPeer(const std::string& peer) { peer_ = peer; } + void setPeerAddress(const std::string& peer_address) { peer_address_ = peer_address; } + + /* + * Set upstream address. + */ + void setUpstreamAddress(const std::string& upstream_address) { + upstream_address_ = upstream_address; + } /* * Set if the current span has an error. @@ -312,7 +319,8 @@ class SpanStore { uint64_t end_time_{0}; std::string operation_; - std::string peer_; + std::string peer_address_; + std::string upstream_address_; bool is_error_{false}; bool is_entry_span_{true}; diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index 27de808195137..b979a4404da00 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -28,8 +28,8 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { span->set_spantype(span_store->isEntrySpan() ? SpanType::Entry : SpanType::Exit); span->set_componentid(6000); - if (!span_store->peer().empty()) { - span->set_peer(span_store->peer()); + if (!span_store->peerAddress().empty()) { + span->set_peer(span_store->peerAddress()); } span->set_spanid(span_store->spanId()); diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc index 728637321609d..fec1ab44b279d 100644 --- a/source/extensions/tracers/skywalking/tracer.cc +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -50,9 +50,12 @@ void Span::setTag(absl::string_view name, absl::string_view value) { span_store_->setAsError(value == Tracing::Tags::get().True); } - if (name == Tracing::Tags::get().PeerAddress && !span_store_->isEntrySpan()) { - // Set peer when it is an exit span. - span_store_->setPeer(std::string(value)); + if (name == Tracing::Tags::get().PeerAddress) { + span_store_->setPeerAddress(std::string(value)); + } + + if (name == Tracing::Tags::get().UpstreamAddress) { + span_store_->setUpstreamAddress(std::string(value)); } span_store_->addTag(name, value); From 5583fafd3a9f14a2aef368caa2b5dd47000991ed Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 18 Sep 2020 13:29:51 +0800 Subject: [PATCH 09/61] use request host as peer address for exit span Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 6 +- .../skywalking/v4alpha/skywalking.proto | 6 +- .../envoy/config/trace/v3/skywalking.proto | 6 +- .../skywalking/v4alpha/skywalking.proto | 6 +- .../skywalking/skywalking_tracer_impl.cc | 17 ++++-- .../skywalking/skywalking_tracer_impl.h | 1 + .../tracers/skywalking/skywalking_types.h | 22 ++++--- .../skywalking/trace_segment_reporter.cc | 6 +- .../extensions/tracers/skywalking/tracer.cc | 42 +++++++++---- source/extensions/tracers/skywalking/tracer.h | 44 ++++++++++++-- .../skywalking/skywalking_test_helper.h | 5 +- .../skywalking/skywalking_types_test.cc | 35 ++++++----- .../tracers/skywalking/tracer_test.cc | 59 ++++++++++++++----- 13 files changed, 185 insertions(+), 70 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index f85be5a67bc80..6907f091ce4bf 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -4,6 +4,8 @@ package envoy.config.trace.v3; import "envoy/config/core/v3/grpc_service.proto"; +import "google/protobuf/wrappers.proto"; + import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -50,6 +52,6 @@ message ClientConfig { // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can - // be cached. - uint32 max_cache_size = 5; + // be cached. If not specified, the default is 1024. + google.protobuf.UInt32Value max_cache_size = 5; } diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 6347b97d8367f..c3da41718d3b5 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -4,6 +4,8 @@ package envoy.extensions.tracers.skywalking.v4alpha; import "envoy/config/core/v4alpha/grpc_service.proto"; +import "google/protobuf/wrappers.proto"; + import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -52,6 +54,6 @@ message ClientConfig { // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can - // be cached. - uint32 max_cache_size = 5; + // be cached. If not specified, the default is 1024. + google.protobuf.UInt32Value max_cache_size = 5; } diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index f85be5a67bc80..6907f091ce4bf 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -4,6 +4,8 @@ package envoy.config.trace.v3; import "envoy/config/core/v3/grpc_service.proto"; +import "google/protobuf/wrappers.proto"; + import "udpa/annotations/migrate.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; @@ -50,6 +52,6 @@ message ClientConfig { // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can - // be cached. - uint32 max_cache_size = 5; + // be cached. If not specified, the default is 1024. + google.protobuf.UInt32Value max_cache_size = 5; } diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 6347b97d8367f..c3da41718d3b5 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -4,6 +4,8 @@ package envoy.extensions.tracers.skywalking.v4alpha; import "envoy/config/core/v4alpha/grpc_service.proto"; +import "google/protobuf/wrappers.proto"; + import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -52,6 +54,6 @@ message ClientConfig { // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can - // be cached. - uint32 max_cache_size = 5; + // be cached. If not specified, the default is 1024. + google.protobuf.UInt32Value max_cache_size = 5; } diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index e16dd54d877fb..c0962bcf6c18a 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -42,9 +42,8 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, } Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, - Http::RequestHeaderMap& request_headers, - const std::string& operation_name, Envoy::SystemTime start_time, - const Tracing::Decision decision) { + Http::RequestHeaderMap& request_headers, const std::string&, + Envoy::SystemTime start_time, const Tracing::Decision decision) { auto& tracer = *tls_slot_ptr_->getTyped().tracer_; try { @@ -56,16 +55,22 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, segment_context->setService(client_config_.service_name()); segment_context->setServiceInstance(client_config_.instance_name()); + // In order to be consistent with the existing SkyWalking agent, we use request Method and + // request Path to create an operation name. + // TODO(wbpcode): A temporary decision. This strategy still needs further consideration. + std::string operation_name = + absl::StrCat("/", request_headers.getMethodValue(), + Http::PathUtil::removeQueryAndFragment(request_headers.getPathValue())); + if (!client_config_.pass_endpoint() || !segment_context->previousSpanContext()) { - segment_context->setEndpoint( - absl::StrCat("/", request_headers.getMethodValue(), - Http::PathUtil::removeQueryAndFragment(request_headers.getPathValue()))); + segment_context->setEndpoint(operation_name); } else { segment_context->setEndpoint(segment_context->previousSpanContext()->endpoint_); } return tracer.startSpan(config, start_time, operation_name, std::move(segment_context), nullptr); + } catch (const EnvoyException&) { return std::make_unique(); } diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h index 4d8f6759c88b8..1930f48ed1d31 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h @@ -34,6 +34,7 @@ class Driver : public Tracing::Driver, public Logger::Loggablecreate()), service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "TraceSegmentReportService.collect")) { - max_delayed_segments_cache_size_ = client_config.max_cache_size() == 0 - ? DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE - : client_config.max_cache_size(); + max_delayed_segments_cache_size_ = client_config.has_max_cache_size() + ? client_config.max_cache_size().value() + : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE; retry_timer_ = dispatcher.createTimer([this]() -> void { establishNewStream(); }); establishNewStream(); diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc index fec1ab44b279d..47bcc258f963c 100644 --- a/source/extensions/tracers/skywalking/tracer.cc +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -2,6 +2,8 @@ #include +#include "common/http/url_utility.h" + namespace Envoy { namespace Extensions { namespace Tracers { @@ -16,19 +18,34 @@ uint64_t getTimestamp(SystemTime time) { return std::chrono::duration_cast(time.time_since_epoch()).count(); } +// A simple tool function. Used to extract the HTTP Host from the URL, and set the Host value as the +// peer address to the SpanStore object. +void setSkyWalkingPeerAddress(SpanStore* span_store, absl::string_view http_request_url) { + if (span_store->isEntrySpan()) { + return; + } + if (size_t host_start_pos = http_request_url.find("://"); host_start_pos != std::string::npos) { + absl::string_view host_with_path = http_request_url.substr(host_start_pos + 3); + size_t path_start_pos = host_with_path.find("/"); + if (path_start_pos == std::string::npos) { + return; + } + host_with_path.remove_suffix(host_with_path.size() - path_start_pos); + span_store->setPeerAddress(std::string(host_with_path)); + } +} + } // namespace Tracing::SpanPtr Tracer::startSpan(const Tracing::Config& config, SystemTime start_time, - const std::string& operation_name, - SegmentContextSharedPtr segment_context, Span* parent_span) { - SpanStore* span_store = segment_context->createSpanStore( - time_source_, parent_span ? parent_span->spanStore() : nullptr); + const std::string& operation, + SegmentContextSharedPtr segment_context, Span* parent) { + SpanStore* span_store = + segment_context->createSpanStore(time_source_, parent ? parent->spanStore() : nullptr); span_store->setAsEntrySpan(config.operationName() == Tracing::OperationName::Ingress); span_store->setStartTime(getTimestamp(start_time)); - // TODO(wbpcode): I am not sure if the operation name and endpoint need to be consistent. So here - // may need to be improved. - span_store->setOperation(operation_name); + span_store->setOperation(operation); return std::make_unique(std::move(segment_context), span_store, *this); } @@ -38,22 +55,25 @@ void Span::setOperation(absl::string_view operation) { } void Span::setTag(absl::string_view name, absl::string_view value) { + // Use request host as peer address and set it in ExitSpan. The request host can be parsed from + // the URL. if (name == Tracing::Tags::get().HttpUrl) { span_store_->addTag(UrlTag, value); + setSkyWalkingPeerAddress(span_store_, value); + return; } if (name == Tracing::Tags::get().HttpStatusCode) { span_store_->addTag(StatusCodeTag, value); + return; } if (name == Tracing::Tags::get().Error) { span_store_->setAsError(value == Tracing::Tags::get().True); } - if (name == Tracing::Tags::get().PeerAddress) { - span_store_->setPeerAddress(std::string(value)); - } - + // When we need to create a new propagation header and send it to upstream, use upstream address + // as the target address. if (name == Tracing::Tags::get().UpstreamAddress) { span_store_->setUpstreamAddress(std::string(value)); } diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h index 2104f552b9117..8615592d62865 100644 --- a/source/extensions/tracers/skywalking/tracer.h +++ b/source/extensions/tracers/skywalking/tracer.h @@ -22,13 +22,37 @@ class Tracer { explicit Tracer(TimeSource& time_source) : time_source_(time_source) {} ~Tracer() { reporter_->closeStream(); } + /* + * Set a trace segment reporter to the current Tracer. Whenever a SkyWalking segment ends, the + * reporter will be used to report segment data. + * + * @param reporter The unique ptr of trace segment reporter. + */ void setReporter(TraceSegmentReporterPtr&& reporter) { reporter_ = std::move(reporter); } + /* + * Report trace segment data to backend tracing service. + * + * @param segment_context The segment context. + */ void report(const SegmentContext& segment_context) { return reporter_->report(segment_context); } + /* + * Create a new span based on the segment context and parent span. + * + * @param config The tracing config. + * @param start_time Start time of span. + * @param operation Operation name of span. + * @param segment_context The SkyWalking segment context. The newly created span belongs to this + * segment. + * @param parent The parent span pointer. If parent is null, then the newly created span is first + * span of this segment. + * + * @return The unique ptr to the newly created span. + */ Tracing::SpanPtr startSpan(const Tracing::Config& config, SystemTime start_time, - const std::string& operation, SegmentContextSharedPtr span_context, - Span* parent_span); + const std::string& operation, SegmentContextSharedPtr segment_context, + Span* parent); private: TimeSource& time_source_; @@ -39,9 +63,17 @@ using TracerPtr = std::unique_ptr; class Span : public Tracing::Span { public: + /* + * Constructor of span. + * + * @param segment_context The SkyWalking segment context. + * @param span_store Pointer to a SpanStore object. Whenever a new span is created, a new + * SpanStore object is created and stored in the segment context. This parameter can never be + * null. + * @param tracer Reference to tracer. + */ Span(SegmentContextSharedPtr segment_context, SpanStore* span_store, Tracer& tracer) - : segment_context_(std::move(segment_context)), span_store_(std::move(span_store)), - tracer_(tracer) {} + : segment_context_(std::move(segment_context)), span_store_(span_store), tracer_(tracer) {} // Tracing::Span void setOperation(absl::string_view operation) override; @@ -55,6 +87,10 @@ class Span : public Tracing::Span { std::string getBaggage(absl::string_view key) override; void setBaggage(absl::string_view key, absl::string_view value) override; + /* + * Get pointer to corresponding SpanStore object. This method is mainly used in testing. Used to + * check the internal data of the span. + */ SpanStore* spanStore() const { return span_store_; } SegmentContext* segmentContext() const { return segment_context_.get(); } diff --git a/test/extensions/tracers/skywalking/skywalking_test_helper.h b/test/extensions/tracers/skywalking/skywalking_test_helper.h index 9c868531753df..3893dd8dc10d7 100644 --- a/test/extensions/tracers/skywalking/skywalking_test_helper.h +++ b/test/extensions/tracers/skywalking/skywalking_test_helper.h @@ -61,7 +61,8 @@ class SkyWalkingTestHelper { span_store->setAsEntrySpan(true); span_store->setAsError(false); span_store->setOperation(seed + "#OPERATION"); - span_store->setPeer(seed + "#PEER"); + span_store->setPeerAddress("0.0.0.0"); + span_store->setUpstreamAddress("0.0.0.0"); span_store->setStartTime(22222222); span_store->setEndTime(33333333); @@ -75,4 +76,4 @@ class SkyWalkingTestHelper { } // namespace SkyWalking } // namespace Tracers } // namespace Extensions -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc index 03fb75f9322e4..caf5902da0ca1 100644 --- a/test/extensions/tracers/skywalking/skywalking_types_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -272,6 +272,14 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { // instead. EXPECT_EQ("CURR#ENDPOINT", root_store->operation()); + EXPECT_EQ("0.0.0.0", root_store->peerAddress()); + root_store->setPeerAddress(TEST_ADDRESS); + EXPECT_EQ(TEST_ADDRESS, root_store->peerAddress()); + + EXPECT_EQ("0.0.0.0", root_store->upstreamAddress()); + root_store->setUpstreamAddress(TEST_ADDRESS); + EXPECT_EQ(TEST_ADDRESS, root_store->upstreamAddress()); + EXPECT_EQ(22222222, root_store->startTime()); root_store->setStartTime(23333); EXPECT_EQ(23333, root_store->startTime()); @@ -289,14 +297,11 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { EXPECT_EQ(std::chrono::time_point_cast(now).time_since_epoch().count(), root_store->endTime()); - EXPECT_EQ("ROOT#PEER", root_store->peer()); - root_store->setPeer(""); - // Test whether SpanStore can correctly inject propagation headers to request headers. - // When the peer is empty, use the host in the request as the target address. - Http::TestRequestHeaderMapImpl request_headers_no_peer{{":authority", "test.com"}}; - root_store->injectContext(request_headers_no_peer); + Http::TestRequestHeaderMapImpl request_headers_with_upstream{{":authority", "test.com"}}; + root_store->injectContext(request_headers_with_upstream); + std::string expected_header_value = fmt::format( "{}-{}-{}-{}-{}-{}-{}-{}", 1, SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), @@ -304,16 +309,16 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), - SkyWalkingTestHelper::base64Encode("test.com")); - - EXPECT_EQ(request_headers_no_peer.get_("sw8"), expected_header_value); + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); - root_store->setPeer(TEST_ADDRESS); - EXPECT_EQ(TEST_ADDRESS, root_store->peer()); + EXPECT_EQ(request_headers_with_upstream.get_("sw8"), expected_header_value); - Http::TestRequestHeaderMapImpl request_headers_with_peer{{":authority", "test.com"}}; - root_store->injectContext(request_headers_with_peer); + // Reset upstream address to empty. + root_store->setUpstreamAddress(""); + // When the upstream address is empty, use the host in the request as the target address. + Http::TestRequestHeaderMapImpl request_headers_no_upstream{{":authority", "test.com"}}; + root_store->injectContext(request_headers_no_upstream); expected_header_value = fmt::format( "{}-{}-{}-{}-{}-{}-{}-{}", 1, SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), @@ -321,9 +326,9 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), - SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); + SkyWalkingTestHelper::base64Encode("test.com")); - EXPECT_EQ(request_headers_with_peer.get_("sw8"), expected_header_value); + EXPECT_EQ(request_headers_no_upstream.get_("sw8"), expected_header_value); } } // namespace SkyWalking diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index 604f43b6ca2c1..d095078b0e0d9 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -74,33 +74,65 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { SkyWalkingTestHelper::createSegmentContext(true, "CURR", "", mock_random_generator_); EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(Return(Envoy::Tracing::OperationName::Ingress)); + .WillOnce(Return(Envoy::Tracing::OperationName::Egress)); Envoy::Tracing::SpanPtr org_span = tracer_->startSpan( - mock_tracing_config_, mock_time_source_.systemTime(), "", segment_context, nullptr); + mock_tracing_config_, mock_time_source_.systemTime(), "TEST_OP", segment_context, nullptr); Span* span = dynamic_cast(org_span.get()); - // Since the operation name in config is Ingress, the new span is entry span. - EXPECT_EQ(true, span->spanStore()->isEntrySpan()); + // Since the operation name in config is Egress, the new span is ExitSpan. + EXPECT_EQ(false, span->spanStore()->isEntrySpan()); // Test whether the basic functions of Span are normal. + span->setSampled(false); EXPECT_EQ(false, span->spanStore()->sampled()); + // The initial operation name is consistent with the 'operation' parameter in the 'startSpan' + // method call. + EXPECT_EQ("TEST_OP", span->spanStore()->operation()); + // Reset operation to empty. Then endpoint will be used as a replacement. + span->setOperation(""); EXPECT_EQ("CURR#ENDPOINT", span->spanStore()->operation()); span->setOperation("op"); EXPECT_EQ("op", span->spanStore()->operation()); + // Test whether the tag can be set correctly. span->setTag("TestTagKeyA", "TestTagValueA"); span->setTag("TestTagKeyB", "TestTagValueB"); EXPECT_EQ("TestTagValueA", span->spanStore()->tags().at(0).value()); EXPECT_EQ("TestTagValueB", span->spanStore()->tags().at(1).value()); - // Entry span does not set the peer address. - span->setTag(Tracing::Tags::get().PeerAddress, "0.0.0.0"); - EXPECT_EQ("", span->spanStore()->peer()); + // When setting the status code tag, the corresponding tag name will be rewritten as + // 'status_code'. + span->setTag(Tracing::Tags::get().HttpStatusCode, "200"); + EXPECT_EQ("status_code", span->spanStore()->tags().at(2).key()); + EXPECT_EQ("200", span->spanStore()->tags().at(2).value()); + + // When setting the error tag, the SpanStore object will also mark itself as an error. + span->setTag(Tracing::Tags::get().Error, Tracing::Tags::get().True); + EXPECT_EQ(Tracing::Tags::get().Error, span->spanStore()->tags().at(3).key()); + EXPECT_EQ(Tracing::Tags::get().True, span->spanStore()->tags().at(3).value()); + EXPECT_EQ(true, span->spanStore()->isError()); + + // When setting http url tag, the corresponding tag name will be rewritten as 'url'. At the same + // time, we will extract the http request host from the url value as the peer address of + // SkyWalking. + span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com/test/path"); + EXPECT_EQ("url", span->spanStore()->tags().at(4).key()); + EXPECT_EQ("http://test.com/test/path", span->spanStore()->tags().at(4).value()); + EXPECT_EQ("test.com", span->spanStore()->peerAddress()); + + // If the url format is wrong, the peer address remains empty. + span->spanStore()->setPeerAddress(""); + span->setTag(Tracing::Tags::get().HttpUrl, "http:/test.com/test/path"); + EXPECT_EQ("", span->spanStore()->peerAddress()); + + span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com"); + EXPECT_EQ("", span->spanStore()->peerAddress()); // Test the inject context function and verify the result. Http::TestRequestHeaderMapImpl headers{{":authority", "test.com"}}; + // No upstream address set and host in request headers will be used as target address. std::string expected_header_value = fmt::format( "{}-{}-{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), @@ -113,21 +145,18 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { EXPECT_EQ(expected_header_value, headers.get_("sw8")); EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(Return(Envoy::Tracing::OperationName::Egress)); + .WillOnce(Return(Envoy::Tracing::OperationName::Ingress)); Envoy::Tracing::SpanPtr org_first_child_span = span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); Span* first_child_span = dynamic_cast(org_first_child_span.get()); - // Since the operation name in config is Egress, the new span is exit span. - EXPECT_EQ(false, first_child_span->spanStore()->isEntrySpan()); + // Since the operation name in config is Ingress, the new span is EntrySpan. + EXPECT_EQ(true, first_child_span->spanStore()->isEntrySpan()); EXPECT_EQ(0, first_child_span->spanStore()->sampled()); EXPECT_EQ(1, first_child_span->spanStore()->spanId()); EXPECT_EQ(0, first_child_span->spanStore()->parentSpanId()); - // Exit span will set the peer address. - first_child_span->setTag(Tracing::Tags::get().PeerAddress, "1.1.1.1"); - EXPECT_EQ("1.1.1.1", first_child_span->spanStore()->peer()); EXPECT_EQ("TestChild", first_child_span->spanStore()->operation()); Http::TestRequestHeaderMapImpl first_child_headers{{":authority", "test.com"}}; @@ -138,7 +167,9 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { 1, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), - SkyWalkingTestHelper::base64Encode("1.1.1.1")); + SkyWalkingTestHelper::base64Encode("0.0.0.0")); + + first_child_span->setTag(Tracing::Tags::get().UpstreamAddress, "0.0.0.0"); first_child_span->injectContext(first_child_headers); EXPECT_EQ(expected_header_value, first_child_headers.get_("sw8")); From bd16737b35ba864c1eac4f98ba064b3d6702a5e1 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 22 Sep 2020 14:56:16 +0800 Subject: [PATCH 10/61] add more test to cover more code Signed-off-by: wbpcode --- .../tracers/skywalking/skywalking_types.cc | 2 +- .../tracers/skywalking/skywalking_types.h | 2 +- .../skywalking/skywalking_tracer_impl_test.cc | 13 +++ .../skywalking/skywalking_types_test.cc | 43 +++++++-- .../skywalking/trace_segment_reporter_test.cc | 93 ++++++++++++++++++- .../tracers/skywalking/tracer_test.cc | 7 ++ 6 files changed, 148 insertions(+), 12 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 1cd133809a6f0..d878522a08907 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -44,7 +44,7 @@ std::string base64Decode(absl::string_view input) { SpanContextPtr SpanContext::spanContextFromRequest(Http::RequestHeaderMap& headers) { auto propagation_header = headers.get(propagationHeader()); if (propagation_header == nullptr) { - // No propagation_header then Envoy is first hop. + // No propagation header then Envoy is first hop. return nullptr; } diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index 36022887b72ae..e143a98c9e2f6 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -305,7 +305,7 @@ class SpanStore { * Set sampling flag. In general, the sampling flag of span is consistent with the current span * context. */ - void setSampled(int sampled) { sampled_ = sampled; } + void setSampled(int sampled) { sampled_ = sampled == 0 ? 0 : 1; } /* * Inject current span context information to request headers. This will update original diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index 95ed382405b17..ea1e7bc9e0e34 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -142,6 +142,19 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); new_span->finishSpan(); EXPECT_EQ(1U, factory_context.scope_.counter("tracing.skywalking.segments_sent").value()); + + // Create new span segment with error propagation header. + Http::TestRequestHeaderMapImpl error_request_headers{{":path", "/path"}, + {":method", "GET"}, + {":authority", "test.com"}, + {"sw8", "xxxxxx-error-propagation-header"}}; + Tracing::SpanPtr org_null_span = driver_->startSpan(mock_tracing_config_, error_request_headers, + "", time_system_.systemTime(), decision); + + EXPECT_EQ(nullptr, dynamic_cast(org_null_span.get())); + + auto& null_span = *org_null_span; + EXPECT_EQ(typeid(null_span).name(), typeid(Tracing::NullSpan).name()); } TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) { diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc index caf5902da0ca1..f20e1096c5984 100644 --- a/test/extensions/tracers/skywalking/skywalking_types_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -28,12 +28,16 @@ constexpr char TEST_ENDPOINT[] = "/POST/path/for/test"; // when errors occur. TEST(SpanContextTest, SpanContextCommonTest) { NiceMock mock_random_generator; - ON_CALL(mock_random_generator, random()).WillByDefault(Return(uint64_t(23333))); std::string trace_id = SkyWalkingTestHelper::generateId(mock_random_generator); std::string segment_id = SkyWalkingTestHelper::generateId(mock_random_generator); + // No propagation header then previous span context will be null. + Http::TestRequestHeaderMapImpl headers_no_propagation; + auto null_span_context = SpanContext::spanContextFromRequest(headers_no_propagation); + EXPECT_EQ(nullptr, null_span_context.get()); + // Create properly formatted propagation headers and test whether the propagation headers can be // parsed correctly. std::string header_value_with_right_format = @@ -59,6 +63,20 @@ TEST(SpanContextTest, SpanContextCommonTest) { EXPECT_EQ(previous_span_context->endpoint_, TEST_ENDPOINT); EXPECT_EQ(previous_span_context->target_address_, TEST_ADDRESS); + std::string header_value_with_sampled = + fmt::format("{}-{}-{}-{}-{}-{}-{}-{}", 1, SkyWalkingTestHelper::base64Encode(trace_id), + SkyWalkingTestHelper::base64Encode(segment_id), 233333, + SkyWalkingTestHelper::base64Encode(TEST_SERVICE), + SkyWalkingTestHelper::base64Encode(TEST_INSTANCE), + SkyWalkingTestHelper::base64Encode(TEST_ENDPOINT), + SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); + + Http::TestRequestHeaderMapImpl headers_with_sampled{{"sw8", header_value_with_sampled}}; + + auto previous_span_context_with_sampled = + SpanContext::spanContextFromRequest(headers_with_sampled); + EXPECT_EQ(previous_span_context_with_sampled->sampled_, 1); + // Test whether an exception can be correctly thrown when some fields are missing. std::string header_value_lost_some_parts = fmt::format("{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(trace_id), @@ -247,12 +265,23 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { SpanStore* root_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "ROOT", mock_time_source); EXPECT_NE(nullptr, root_store); + EXPECT_EQ(3, root_store->tags().size()); + + root_store->addLog(now, "TestLogStringAndNeverBeStored"); + EXPECT_EQ(0, root_store->logs().size()); // The span id of the first SpanStore in each SegmentContext is 0. Its parent span id is -1. EXPECT_EQ(0, root_store->spanId()); EXPECT_EQ(-1, root_store->parentSpanId()); + root_store->setSpanId(123); + EXPECT_EQ(123, root_store->spanId()); + root_store->setParentSpanId(234); + EXPECT_EQ(234, root_store->parentSpanId()); + EXPECT_EQ(1, root_store->sampled()); + root_store->setSampled(0); + EXPECT_EQ(0, root_store->sampled()); // Test whether the value of the fields can be set correctly and the value of the fields can be // obtained correctly. @@ -288,10 +317,6 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { root_store->setEndTime(25555); EXPECT_EQ(25555, root_store->endTime()); - EXPECT_EQ(-1, root_store->parentSpanId()); - root_store->setParentSpanId(234); - EXPECT_EQ(234, root_store->parentSpanId()); - // When SpanStore calls finish, the end time will be set. root_store->finish(); EXPECT_EQ(std::chrono::time_point_cast(now).time_since_epoch().count(), @@ -303,10 +328,10 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { root_store->injectContext(request_headers_with_upstream); std::string expected_header_value = fmt::format( - "{}-{}-{}-{}-{}-{}-{}-{}", 1, + "{}-{}-{}-{}-{}-{}-{}-{}", root_store->sampled(), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), - 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + root_store->spanId(), SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); @@ -320,10 +345,10 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { Http::TestRequestHeaderMapImpl request_headers_no_upstream{{":authority", "test.com"}}; root_store->injectContext(request_headers_no_upstream); expected_header_value = fmt::format( - "{}-{}-{}-{}-{}-{}-{}-{}", 1, + "{}-{}-{}-{}-{}-{}-{}-{}", root_store->sampled(), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), - 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + root_store->spanId(), SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), SkyWalkingTestHelper::base64Encode("test.com")); diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 98aca24c89cd2..4408d73d2a029 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -62,6 +62,27 @@ class TraceSegmentReporterTest : public testing::Test { TraceSegmentReporterPtr reporter_; }; +// Test whether the reporter can correctly add metadata according to the configuration. +TEST_F(TraceSegmentReporterTest, TraceSegmentReporterInitialMetadata) { + const std::string yaml_string = R"EOF( + authentication: "FakeStringForAuthenticaion" + )EOF"; + + setupTraceSegmentReporter(yaml_string); + Http::TestRequestHeaderMapImpl metadata; + reporter_->onCreateInitialMetadata(metadata); + + EXPECT_EQ("FakeStringForAuthenticaion", metadata.get_("authentication")); +} + +TEST_F(TraceSegmentReporterTest, TraceSegmentReporterNoMetadata) { + setupTraceSegmentReporter("{}"); + Http::TestRequestHeaderMapImpl metadata; + reporter_->onCreateInitialMetadata(metadata); + + EXPECT_EQ("", metadata.get_("authentication")); +} + TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { setupTraceSegmentReporter("{}"); Event::SimulatedTimeSystem time_system; @@ -71,6 +92,15 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "PARENT", mock_time_source_); + // Parent span store has peer address. + parent_store->setPeerAddress("0.0.0.0"); + + SpanStore* first_child_sptore = SkyWalkingTestHelper::createSpanStore( + segment_context.get(), parent_store, "CHILD", mock_time_source_); + // Skip reporting the first child span. + first_child_sptore->setSampled(0); + + // Create second child span. SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", mock_time_source_); @@ -82,9 +112,70 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); + + // Create a segment context with no previous span context. + SegmentContextSharedPtr second_segment_context = SkyWalkingTestHelper::createSegmentContext( + true, "SECOND_SEGMENT", "", mock_random_generator_); + SkyWalkingTestHelper::createSpanStore(second_segment_context.get(), nullptr, "PARENT", + mock_time_source_); + + EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); + reporter_->report(*second_segment_context); + + EXPECT_EQ(2U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); +} + +TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithDefaultCache) { + setupTraceSegmentReporter("{}"); + Event::SimulatedTimeSystem time_system; + ON_CALL(mock_random_generator_, random()).WillByDefault(Return(23333)); + ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); + SegmentContextSharedPtr segment_context = + SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); + SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, + "PARENT", mock_time_source_); + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", + mock_time_source_); + + EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)).Times(1025); + + reporter_->report(*segment_context); + + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); + + // Simulates a disconnected connection. + EXPECT_CALL(*timer_, enableTimer(_, _)); + reporter_->onRemoteClose(Grpc::Status::WellKnownGrpcStatus::Unknown, ""); + + // Try to report 10 segments. Due to the disconnection, the cache size is only 3. So 7 of the + // segments will be discarded. + for (int i = 0; i < 2048; i++) { + reporter_->report(*segment_context); + } + + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(1024U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); + + // Simulate the situation where the connection is re-established. The remaining segments in the + // cache will be reported. + EXPECT_CALL(*mock_client_ptr_, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); + timer_cb_(); + + EXPECT_EQ(1025U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); + EXPECT_EQ(1024U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); + EXPECT_EQ(1U, mock_scope_.counter("tracing.skywalking.cache_flushed").value()); + EXPECT_EQ(1024U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); } -TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithCache) { +TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithCacheConfig) { const std::string yaml_string = R"EOF( max_cache_size: 3 )EOF"; diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index d095078b0e0d9..fccfb95527ac8 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -82,6 +82,9 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { // Since the operation name in config is Egress, the new span is ExitSpan. EXPECT_EQ(false, span->spanStore()->isEntrySpan()); + EXPECT_EQ("", span->getBaggage("FakeStringAndNothingToDo")); + span->setBaggage("FakeStringAndNothingToDo", "FakeStringAndNothingToDo"); + // Test whether the basic functions of Span are normal. span->setSampled(false); @@ -170,6 +173,10 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { SkyWalkingTestHelper::base64Encode("0.0.0.0")); first_child_span->setTag(Tracing::Tags::get().UpstreamAddress, "0.0.0.0"); + first_child_span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com/test/path"); + // Peer address only set in ExitSpan. + EXPECT_EQ("", span->spanStore()->peerAddress()); + first_child_span->injectContext(first_child_headers); EXPECT_EQ(expected_header_value, first_child_headers.get_("sw8")); From 44a954f116486f1d18c8061ebec36668cdd1b0a7 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 25 Sep 2020 19:59:50 +0800 Subject: [PATCH 11/61] minor change Signed-off-by: wbpcode --- CODEOWNERS | 2 +- source/extensions/extensions_build_config.bzl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 702f7745aa9f5..297dec654eb35 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -49,7 +49,7 @@ extensions/filters/common/original_src @snowp @klarose # tracers.xray extension /*/extensions/tracers/xray @marcomagdy @lavignes @mattklein123 # tracers.skywalking extension -/*/extensions/tracers/skywalking @dio @lizan @wbpcode +/*/extensions/tracers/skywalking @wbpcode @dio @lizan # mysql_proxy extension /*/extensions/filters/network/mysql_proxy @rshriram @venilnoronha @mattklein123 # postgres_proxy extension diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index e3250d0cf7d48..4eeaf44fa1aa7 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -153,9 +153,9 @@ EXTENSIONS = { "envoy.tracers.datadog": "//source/extensions/tracers/datadog:config", "envoy.tracers.zipkin": "//source/extensions/tracers/zipkin:config", "envoy.tracers.opencensus": "//source/extensions/tracers/opencensus:config", - "envoy.tracers.skywalking": "//source/extensions/tracers/skywalking:config", # WiP "envoy.tracers.xray": "//source/extensions/tracers/xray:config", + "envoy.tracers.skywalking": "//source/extensions/tracers/skywalking:config", # # Transport sockets From 6bef0f48960e5a50c9c55e8a83fa5335d302234c Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 25 Sep 2020 20:46:09 +0800 Subject: [PATCH 12/61] add backoff strategy Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/BUILD | 1 + .../tracers/skywalking/skywalking_tracer_impl.cc | 2 +- .../tracers/skywalking/trace_segment_reporter.cc | 15 ++++++++++++--- .../tracers/skywalking/trace_segment_reporter.h | 6 +++++- .../skywalking/trace_segment_reporter_test.cc | 5 +++-- test/extensions/tracers/skywalking/tracer_test.cc | 3 ++- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/source/extensions/tracers/skywalking/BUILD b/source/extensions/tracers/skywalking/BUILD index ac22f3fc4298e..1275852c7cf11 100644 --- a/source/extensions/tracers/skywalking/BUILD +++ b/source/extensions/tracers/skywalking/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( ":skywalking_stats_lib", ":skywalking_types_lib", "//include/envoy/grpc:async_client_manager_interface", + "//source/common/common:backoff_lib", "//source/common/grpc:async_client_lib", "@com_github_apache_skywalking_data_collect_protocol//:protocol_cc_proto", "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index c0962bcf6c18a..e800ef0426097 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -36,7 +36,7 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, tracer->setReporter(std::make_unique( factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( proto_config.grpc_service(), factory_context.scope(), false), - dispatcher, tracing_stats_, client_config_)); + dispatcher, factory_context.random(), tracing_stats_, client_config_)); return std::make_shared(std::move(tracer)); }); } diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index d489e6e3ff413..3eae7b69c363c 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -74,15 +74,23 @@ const Http::LowerCaseString& authenticationTokenKey() { TraceSegmentReporter::TraceSegmentReporter( Grpc::AsyncClientFactoryPtr&& factory, Event::Dispatcher& dispatcher, - SkyWalkingTracerStats& stats, const envoy::config::trace::v3::ClientConfig& client_config) + Random::RandomGenerator& random_generator, SkyWalkingTracerStats& stats, + const envoy::config::trace::v3::ClientConfig& client_config) : tracing_stats_(stats), simple_authentication_token_(client_config.authentication()), client_(factory->create()), service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( - "TraceSegmentReportService.collect")) { + "TraceSegmentReportService.collect")), + random_generator_(random_generator) { + max_delayed_segments_cache_size_ = client_config.has_max_cache_size() ? client_config.max_cache_size().value() : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE; + static constexpr uint32_t RetryInitialDelayMs = 500; + static constexpr uint32_t RetryMaxDelayMs = 30000; + backoff_strategy_ = std::make_unique( + RetryInitialDelayMs, RetryMaxDelayMs, random_generator_); + retry_timer_ = dispatcher.createTimer([this]() -> void { establishNewStream(); }); establishNewStream(); } @@ -142,12 +150,13 @@ void TraceSegmentReporter::establishNewStream() { if (!delayed_segments_cache_.empty()) { flushTraceSegments(); } + backoff_strategy_->reset(); } void TraceSegmentReporter::handleFailure() { setRetryTimer(); } void TraceSegmentReporter::setRetryTimer() { - retry_timer_->enableTimer(std::chrono::milliseconds(5000)); + retry_timer_->enableTimer(std::chrono::milliseconds(backoff_strategy_->nextBackOffMs())); } } // namespace SkyWalking diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index 7116cb4202a01..106888a0165d1 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -5,6 +5,7 @@ #include "envoy/config/trace/v3/skywalking.pb.h" #include "envoy/grpc/async_client_manager.h" +#include "common/common/backoff_strategy.h" #include "common/Common.pb.h" #include "common/grpc/async_client_impl.h" @@ -23,7 +24,8 @@ using TraceSegmentPtr = std::unique_ptr; class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { public: explicit TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, - Event::Dispatcher& dispatcher, SkyWalkingTracerStats& stats, + Event::Dispatcher& dispatcher, Random::RandomGenerator& random, + SkyWalkingTracerStats& stats, const envoy::config::trace::v3::ClientConfig& client_config); // Grpc::AsyncStreamCallbacks @@ -62,11 +64,13 @@ class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { Grpc::AsyncStream stream_{}; const Protobuf::MethodDescriptor& service_method_; + Random::RandomGenerator& random_generator_; // If the connection is unavailable when reporting data, the created SegmentObject will be cached // in the queue, and when a new connection is established, the cached data will be reported. std::queue delayed_segments_cache_; Event::TimerPtr retry_timer_; + BackOffStrategyPtr backoff_strategy_; }; using TraceSegmentReporterPtr = std::unique_ptr; diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 4408d73d2a029..57d08205b02f8 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -39,8 +39,9 @@ class TraceSegmentReporterTest : public testing::Test { TestUtility::loadFromYaml(yaml_string, client_config_); - reporter_ = std::make_unique( - std::move(mock_client_factory), mock_dispatcher_, tracing_stats_, client_config_); + reporter_ = std::make_unique(std::move(mock_client_factory), + mock_dispatcher_, mock_random_generator_, + tracing_stats_, client_config_); } protected: diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index fccfb95527ac8..f9abbccb6735a 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -40,7 +40,8 @@ class TracerTest : public testing::Test { TestUtility::loadFromYaml(yaml_string, client_config_); tracer_ = std::make_unique(mock_time_source_); tracer_->setReporter(std::make_unique( - std::move(mock_client_factory), mock_dispatcher_, tracing_stats_, client_config_)); + std::move(mock_client_factory), mock_dispatcher_, mock_random_generator_, tracing_stats_, + client_config_)); } protected: From 7c059040b441bac687ff031d1b65fb4a07b43a41 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 25 Sep 2020 23:42:30 +0800 Subject: [PATCH 13/61] fix format Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/trace_segment_reporter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index 106888a0165d1..a19bba987d715 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -5,8 +5,8 @@ #include "envoy/config/trace/v3/skywalking.pb.h" #include "envoy/grpc/async_client_manager.h" -#include "common/common/backoff_strategy.h" #include "common/Common.pb.h" +#include "common/common/backoff_strategy.h" #include "common/grpc/async_client_impl.h" #include "extensions/tracers/skywalking/skywalking_stats.h" From e57eca8947180f24790e9006e39387149e5c3136 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 4 Oct 2020 18:37:06 +0800 Subject: [PATCH 14/61] fix api Signed-off-by: wbpcode --- api/bazel/repository_locations.bzl | 4 ++-- generated_api_shadow/bazel/repository_locations.bzl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index af27714634e69..c251bf0cffb4f 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -89,10 +89,10 @@ DEPENDENCY_REPOSITORIES_SPEC = dict( ), com_github_apache_skywalking_data_collect_protocol = dict( project_name = "SkyWalking API", - project_desc = "SkyWalking's language independent model and GRPC Api Definitions" + project_desc = "SkyWalking's language independent model and GRPC Api Definitions", project_url = "https://github.com/apache/skywalking-data-collect-protocol", version = "8.1.0", - sha256 = ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9, + sha256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9", strip_prefix = "skywalking-data-collect-protocol-{version}", urls = ["https://github.com/apache/skywalking-data-collect-protocol/archive/v{version}.tar.gz"], last_updated = "2020-07-29", diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index af27714634e69..c251bf0cffb4f 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -89,10 +89,10 @@ DEPENDENCY_REPOSITORIES_SPEC = dict( ), com_github_apache_skywalking_data_collect_protocol = dict( project_name = "SkyWalking API", - project_desc = "SkyWalking's language independent model and GRPC Api Definitions" + project_desc = "SkyWalking's language independent model and GRPC Api Definitions", project_url = "https://github.com/apache/skywalking-data-collect-protocol", version = "8.1.0", - sha256 = ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9, + sha256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9", strip_prefix = "skywalking-data-collect-protocol-{version}", urls = ["https://github.com/apache/skywalking-data-collect-protocol/archive/v{version}.tar.gz"], last_updated = "2020-07-29", From 86da0e7aeeb39777ba3ac02208dd0903c4855103 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 4 Oct 2020 19:36:13 +0800 Subject: [PATCH 15/61] remove unused header file Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/tracer.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc index 47bcc258f963c..25806b08c87a5 100644 --- a/source/extensions/tracers/skywalking/tracer.cc +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -2,8 +2,6 @@ #include -#include "common/http/url_utility.h" - namespace Envoy { namespace Extensions { namespace Tracers { From a88e92d066132bfe30a92b570d80e35dd8020eca Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 4 Oct 2020 20:01:58 +0800 Subject: [PATCH 16/61] some minor update Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/skywalking_types.cc | 2 +- .../tracers/skywalking/trace_segment_reporter.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index d878522a08907..6c3eab485d673 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -26,7 +26,7 @@ std::string generateId(Random::RandomGenerator& random_generator) { Hex::uint64ToHex(random_generator.random())); } -std::string base64Encode(absl::string_view input) { +std::string base64Encode(const absl::string_view input) { return Base64::encode(input.data(), input.length()); } diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index 3eae7b69c363c..c62defe25ac2e 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -8,6 +8,10 @@ namespace SkyWalking { namespace { static constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; +const Http::LowerCaseString& authenticationTokenKey() { + CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, "Authentication"); +} + // Convert SegmentContext to SegmentObject. TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { auto new_segment = std::make_unique(); @@ -66,10 +70,6 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { return new_segment; } -const Http::LowerCaseString& authenticationTokenKey() { - CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, "Authentication"); -} - } // namespace TraceSegmentReporter::TraceSegmentReporter( From 7b1cee93b1c599f655e1e79c9ef0339b0d3b83d5 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 4 Oct 2020 21:30:21 +0800 Subject: [PATCH 17/61] update component id and add comment Signed-off-by: wbpcode --- .../extensions/tracers/skywalking/trace_segment_reporter.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index c62defe25ac2e..a2a3348c72614 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -30,7 +30,9 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { span->set_spanlayer(SpanLayer::Http); span->set_spantype(span_store->isEntrySpan() ? SpanType::Entry : SpanType::Exit); - span->set_componentid(6000); + // TODO(wbpcode): This is temporary component id for Envoy and Please check + // https://github.com/apache/skywalking/pull/5629 for more information. + span->set_componentid(9000); if (!span_store->peerAddress().empty()) { span->set_peer(span_store->peerAddress()); From 0156a825c5eea7d70ef169589b7011c1ec39bb00 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 6 Oct 2020 18:27:24 +0800 Subject: [PATCH 18/61] update comments for component Signed-off-by: wbpcode --- .../extensions/tracers/skywalking/trace_segment_reporter.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index a2a3348c72614..aed40bc2b4202 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -30,8 +30,9 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { span->set_spanlayer(SpanLayer::Http); span->set_spantype(span_store->isEntrySpan() ? SpanType::Entry : SpanType::Exit); - // TODO(wbpcode): This is temporary component id for Envoy and Please check - // https://github.com/apache/skywalking/pull/5629 for more information. + // Please check + // https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/component-libraries.yml + // get more information. span->set_componentid(9000); if (!span_store->peerAddress().empty()) { From 0a8d5e7f4ecda24a2185249500adb497166d4775 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 6 Oct 2020 19:00:49 +0800 Subject: [PATCH 19/61] add update info Signed-off-by: wbpcode --- docs/root/version_history/current.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index d6fcc7c705ab8..98b3987036bb5 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -148,6 +148,7 @@ New Features * tls: introduce new :ref:`extension point` for overriding :ref:`TLS handshaker ` behavior. * tls: switched from using socket BIOs to using custom BIOs that know how to interact with IoHandles. The feature can be disabled by setting runtime feature `envoy.reloadable_features.tls_use_io_handle_bio` to false. * tracing: added ability to set some :ref:`optional segment fields` in the AWS X-Ray tracer. +* tracing: added SkyWalking tracer. * udp_proxy: added :ref:`hash_policies ` to support hash based routing. * udp_proxy: added :ref:`use_original_src_ip ` option to replicate the downstream remote address of the packets on the upstream side of Envoy. It is similar to :ref:`original source filter `. * watchdog: support randomizing the watchdog's kill timeout to prevent synchronized kills via a maximium jitter parameter :ref:`max_kill_timeout_jitter`. From 8a1575866afc7004f02243fef279f1002fe0f297 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 9 Oct 2020 22:17:13 +0800 Subject: [PATCH 20/61] add sandbox test example for skywalking tracer Signed-off-by: wbpcode --- examples/front-proxy/service.py | 5 +- .../skywalking-tracing/Dockerfile-frontenvoy | 7 + examples/skywalking-tracing/README.md | 1 + .../skywalking-tracing/docker-compose.yaml | 112 +++++++++++++++ .../front-envoy-skywalking.yaml | 78 +++++++++++ .../service1-envoy-skywalking.yaml | 130 ++++++++++++++++++ .../service2-envoy-skywalking.yaml | 76 ++++++++++ examples/skywalking-tracing/verify.sh | 12 ++ 8 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 examples/skywalking-tracing/Dockerfile-frontenvoy create mode 100644 examples/skywalking-tracing/README.md create mode 100644 examples/skywalking-tracing/docker-compose.yaml create mode 100644 examples/skywalking-tracing/front-envoy-skywalking.yaml create mode 100644 examples/skywalking-tracing/service1-envoy-skywalking.yaml create mode 100644 examples/skywalking-tracing/service2-envoy-skywalking.yaml create mode 100755 examples/skywalking-tracing/verify.sh diff --git a/examples/front-proxy/service.py b/examples/front-proxy/service.py index 1d5d5920a8e32..c0e008d734042 100644 --- a/examples/front-proxy/service.py +++ b/examples/front-proxy/service.py @@ -19,7 +19,10 @@ 'X-B3-Flags', # Jaeger header (for native client) - "uber-trace-id" + "uber-trace-id", + + # SkyWalking headers. + "sw8" ] diff --git a/examples/skywalking-tracing/Dockerfile-frontenvoy b/examples/skywalking-tracing/Dockerfile-frontenvoy new file mode 100644 index 0000000000000..86d0a6b91b8bf --- /dev/null +++ b/examples/skywalking-tracing/Dockerfile-frontenvoy @@ -0,0 +1,7 @@ +FROM envoyproxy/envoy-dev:latest + +RUN apt-get update && apt-get -q install -y \ + curl +COPY ./front-envoy-skywalking.yaml /etc/front-envoy.yaml +RUN chmod go+r /etc/front-envoy.yaml +CMD /usr/local/bin/envoy -c /etc/front-envoy.yaml --service-cluster front-proxy diff --git a/examples/skywalking-tracing/README.md b/examples/skywalking-tracing/README.md new file mode 100644 index 0000000000000..45b6c87477a18 --- /dev/null +++ b/examples/skywalking-tracing/README.md @@ -0,0 +1 @@ +TODO(wbpcode): To add sandbox docs for skywalking. \ No newline at end of file diff --git a/examples/skywalking-tracing/docker-compose.yaml b/examples/skywalking-tracing/docker-compose.yaml new file mode 100644 index 0000000000000..9fe9396719418 --- /dev/null +++ b/examples/skywalking-tracing/docker-compose.yaml @@ -0,0 +1,112 @@ +version: "3.7" +services: + + # Front envoy. + front-envoy: + build: + context: . + dockerfile: Dockerfile-frontenvoy + networks: + - envoymesh + expose: + - "8000" + - "8001" + ports: + - "8000:8000" + - "8001:8001" + depends_on: + - skywalking-oap + # First service. + service1: + build: + context: ../front-proxy + dockerfile: Dockerfile-service + volumes: + - ./service1-envoy-skywalking.yaml:/etc/service-envoy.yaml + networks: + - envoymesh + environment: + - SERVICE_NAME=1 + expose: + - "8000" + depends_on: + - skywalking-oap + # Second service. + service2: + build: + context: ../front-proxy + dockerfile: Dockerfile-service + volumes: + - ./service2-envoy-skywalking.yaml:/etc/service-envoy.yaml + networks: + - envoymesh + environment: + - SERVICE_NAME=2 + expose: + - "8000" + depends_on: + - skywalking-oap + # Skywalking components. + elasticsearch: + image: elasticsearch:7.9.2 + container_name: elasticsearch + restart: always + networks: + - envoymesh + ports: + - 9200:9200 + healthcheck: + test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + environment: + discovery.type: single-node + expose: + - "9200" + ulimits: + memlock: + soft: -1 + hard: -1 + skywalking-oap: + image: apache/skywalking-oap-server:8.1.0-es7 + container_name: oap + networks: + - envoymesh + depends_on: + - elasticsearch + links: + - elasticsearch + restart: always + ports: + - 11800:11800 + - 12800:12800 + environment: + SW_STORAGE: elasticsearch7 + SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200 + expose: + - "11800" + - "12800" + healthcheck: + test: ["CMD-SHELL", "/skywalking/bin/swctl"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + skywalking-ui: + image: apache/skywalking-ui:8.1.0 + container_name: ui + networks: + - envoymesh + depends_on: + - skywalking-oap + links: + - skywalking-oap + restart: always + ports: + - 8080:8080 + environment: + SW_OAP_ADDRESS: skywalking-oap:12800 +networks: + envoymesh: {} diff --git a/examples/skywalking-tracing/front-envoy-skywalking.yaml b/examples/skywalking-tracing/front-envoy-skywalking.yaml new file mode 100644 index 0000000000000..e07bf4e7e85c6 --- /dev/null +++ b/examples/skywalking-tracing/front-envoy-skywalking.yaml @@ -0,0 +1,78 @@ +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 8000 + traffic_direction: OUTBOUND + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + generate_request_id: true + tracing: + provider: + name: envoy.tracers.skywalking + typed_config: + "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig + grpc_service: + envoy_grpc: + cluster_name: skywalking + timeout: 0.250s + client_config: + service_name: front-envoy + instance_name: front-envoy-1 + codec_type: auto + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: backend + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: service1 + decorator: + operation: checkAvailability + http_filters: + - name: envoy.filters.http.router + typed_config: {} + clusters: + - name: service1 + connect_timeout: 0.250s + type: strict_dns + lb_policy: round_robin + http2_protocol_options: {} + load_assignment: + cluster_name: service1 + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: service1 + port_value: 8000 + - name: skywalking + connect_timeout: 1s + type: strict_dns + lb_policy: round_robin + http2_protocol_options: {} + load_assignment: + cluster_name: skywalking + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: skywalking-oap + port_value: 11800 +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 diff --git a/examples/skywalking-tracing/service1-envoy-skywalking.yaml b/examples/skywalking-tracing/service1-envoy-skywalking.yaml new file mode 100644 index 0000000000000..63ca17c653c5e --- /dev/null +++ b/examples/skywalking-tracing/service1-envoy-skywalking.yaml @@ -0,0 +1,130 @@ +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 8000 + traffic_direction: INBOUND + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + tracing: + provider: + name: envoy.tracers.skywalking + typed_config: + "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig + grpc_service: + envoy_grpc: + cluster_name: skywalking + timeout: 0.250s + client_config: + service_name: service1-envoy + instance_name: service1-envoy-1 + codec_type: auto + stat_prefix: ingress_http + route_config: + name: service1_route + virtual_hosts: + - name: service1 + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: local_service + decorator: + operation: checkAvailability + http_filters: + - name: envoy.filters.http.router + typed_config: {} + - address: + socket_address: + address: 0.0.0.0 + port_value: 9000 + traffic_direction: OUTBOUND + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + tracing: + provider: + name: envoy.tracers.skywalking + typed_config: + "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig + grpc_service: + envoy_grpc: + cluster_name: skywalking + timeout: 0.250s + client_config: + service_name: service1-envoy + instance_name: service1-envoy-1 + codec_type: auto + stat_prefix: egress_http + route_config: + name: service2_route + virtual_hosts: + - name: service2 + domains: + - "*" + routes: + - match: + prefix: "/trace/2" + route: + cluster: service2 + decorator: + operation: checkStock + http_filters: + - name: envoy.filters.http.router + typed_config: {} + clusters: + - name: local_service + connect_timeout: 0.250s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: local_service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 + - name: service2 + connect_timeout: 0.250s + type: strict_dns + lb_policy: round_robin + http2_protocol_options: {} + load_assignment: + cluster_name: service2 + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: service2 + port_value: 8000 + - name: skywalking + connect_timeout: 1s + type: strict_dns + lb_policy: round_robin + http2_protocol_options: {} + load_assignment: + cluster_name: skywalking + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: skywalking-oap + port_value: 11800 +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 diff --git a/examples/skywalking-tracing/service2-envoy-skywalking.yaml b/examples/skywalking-tracing/service2-envoy-skywalking.yaml new file mode 100644 index 0000000000000..b150f8409ccf0 --- /dev/null +++ b/examples/skywalking-tracing/service2-envoy-skywalking.yaml @@ -0,0 +1,76 @@ +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 8000 + traffic_direction: INBOUND + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + tracing: + provider: + name: envoy.tracers.skywalking + typed_config: + "@type": type.googleapis.com/envoy.config.trace.v3.SkyWalkingConfig + grpc_service: + envoy_grpc: + cluster_name: skywalking + timeout: 0.250s + client_config: + service_name: service2-envoy + instance_name: service2-envoy-1 + codec_type: auto + stat_prefix: ingress_http + route_config: + name: local_route + virtual_hosts: + - name: service2 + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: local_service + decorator: + operation: checkStock + http_filters: + - name: envoy.filters.http.router + typed_config: {} + clusters: + - name: local_service + connect_timeout: 0.250s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: local_service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8080 + - name: skywalking + connect_timeout: 1s + type: strict_dns + lb_policy: round_robin + http2_protocol_options: {} + load_assignment: + cluster_name: skywalking + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: skywalking-oap + port_value: 11800 +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 diff --git a/examples/skywalking-tracing/verify.sh b/examples/skywalking-tracing/verify.sh new file mode 100755 index 0000000000000..c0bc2f9b51fc9 --- /dev/null +++ b/examples/skywalking-tracing/verify.sh @@ -0,0 +1,12 @@ +#!/bin/bash -e + +export NAME=skywalking + +# shellcheck source=examples/verify-common.sh +. "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" + + +run_log "Test connection" +responds_with \ + "Hello from behind Envoy (service 1)!" \ + http://localhost:8000/trace/1 From 1ae29024d1cb57a26bb2d5fd55e0872479e58c34 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 10 Oct 2020 10:54:57 +0800 Subject: [PATCH 21/61] add skywalking sandbox docs. Signed-off-by: wbpcode --- .../start/sandboxes/skywalking_tracing.rst | 82 +++++++++++++++++++ docs/root/start/start.rst | 1 + examples/skywalking-tracing/README.md | 3 +- 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 docs/root/start/sandboxes/skywalking_tracing.rst diff --git a/docs/root/start/sandboxes/skywalking_tracing.rst b/docs/root/start/sandboxes/skywalking_tracing.rst new file mode 100644 index 0000000000000..29d4709b1d5d8 --- /dev/null +++ b/docs/root/start/sandboxes/skywalking_tracing.rst @@ -0,0 +1,82 @@ +.. _install_sandboxes_skywalking_tracing: + +SkyWalking Tracing +============== + +The SkyWalking tracing sandbox demonstrates Envoy's :ref:`request tracing ` +capabilities using `SkyWalking `_ as the tracing provider. This sandbox +is very similar to the Zipkin sandbox. All containers will be deployed inside a virtual network +called ``envoymesh``. + +All incoming requests are routed via the front Envoy, which is acting as a reverse proxy +sitting on the edge of the ``envoymesh`` network. Port ``8000`` is exposed +by docker compose (see :repo:`/examples/skywalking-tracing/docker-compose.yaml`). Notice that +all Envoys are configured to collect request traces (e.g., http_connection_manager/config/tracing setup in +:repo:`/examples/skywalking-tracing/front-envoy-skywalking.yaml`) and setup to propagate the spans generated +by the SkyWalking tracer to a SkyWalking cluster (trace driver setup +in :repo:`/examples/skywalking-tracing/front-envoy-skywalking.yaml`). + +When service1 accepts the request forwarded from front envoy, it will makes an API call to service2 before +returning a response. + +Running the Sandbox +~~~~~~~~~~~~~~~~~~~ + +.. include:: _include/docker-env-setup.rst + +Step 3: Build the sandbox +************************* + +To build this sandbox example, and start the example apps run the following commands: + +.. code-block:: console + + $ pwd + envoy/examples/skywalking-tracing + $ docker-compose pull + $ docker-compose up --build -d + $ docker-compose ps + + Name Command State Ports + ----------------------------------------------------------------------------------------------------------------------------------------------- + elasticsearch /tini -- /usr/local/bin/do ... Up (healthy) 0.0.0.0:9200->9200/tcp, 9300/tcp + oap bash docker-entrypoint.sh Up (healthy) 0.0.0.0:11800->11800/tcp, 1234/tcp, 0.0.0.0:12800->12800/tcp + skywalking-tracing_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp + skywalking-tracing_service1_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp + skywalking-tracing_service2_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp + ui bash docker-entrypoint.sh Up 0.0.0.0:8080->8080/tcp + +Step 4: Generate some load +************************** + +You can now send a request to service1 via the front-envoy as follows: + +.. code-block:: console + + $ curl -v localhost:8000/trace/1 + * Trying ::1... + * TCP_NODELAY set + * Connected to localhost (::1) port 8000 (#0) + > GET /trace/1 HTTP/1.1 + > Host: localhost:8000 + > User-Agent: curl/7.58.0 + > Accept: */* + > + < HTTP/1.1 200 OK + < content-type: text/html; charset=utf-8 + < content-length: 89 + < server: envoy + < date: Sat, 10 Oct 2020 01:56:08 GMT + < x-envoy-upstream-service-time: 27 + < + Hello from behind Envoy (service 1)! hostname: 1a2ba43d6d84 resolvedhostname: 172.19.0.6 + * Connection #0 to host localhost left intact + +Step 5: View the traces in SkyWalking UI +************************************ + +Point your browser to http://localhost:8080 . You should see the SkyWalking dashboard. +Set the service to "front-envoy" and set the start time to a few minutes before +the start of the test (step 2) and hit enter. You should see traces from the front-proxy. +Click on a trace to explore the path taken by the request from front-proxy to service1 +to service2, as well as the latency incurred at each hop. diff --git a/docs/root/start/start.rst b/docs/root/start/start.rst index 2fccbb4e71c0b..059fbd1fdf94d 100644 --- a/docs/root/start/start.rst +++ b/docs/root/start/start.rst @@ -219,3 +219,4 @@ features. The following sandboxes are available: sandboxes/mysql sandboxes/redis sandboxes/zipkin_tracing + sandboxes/skywalking_tracing diff --git a/examples/skywalking-tracing/README.md b/examples/skywalking-tracing/README.md index 45b6c87477a18..5a9375b74006a 100644 --- a/examples/skywalking-tracing/README.md +++ b/examples/skywalking-tracing/README.md @@ -1 +1,2 @@ -TODO(wbpcode): To add sandbox docs for skywalking. \ No newline at end of file +To learn about this sandbox and for instructions on how to run it please head over +to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/skywalking_tracing) From fe02559cb2d44faaafc4c57055e47098299a0fb5 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 10 Oct 2020 12:17:10 +0800 Subject: [PATCH 22/61] fix docs format Signed-off-by: wbpcode --- docs/root/start/sandboxes/skywalking_tracing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/root/start/sandboxes/skywalking_tracing.rst b/docs/root/start/sandboxes/skywalking_tracing.rst index 29d4709b1d5d8..cedf9aed34371 100644 --- a/docs/root/start/sandboxes/skywalking_tracing.rst +++ b/docs/root/start/sandboxes/skywalking_tracing.rst @@ -1,7 +1,7 @@ .. _install_sandboxes_skywalking_tracing: SkyWalking Tracing -============== +================== The SkyWalking tracing sandbox demonstrates Envoy's :ref:`request tracing ` capabilities using `SkyWalking `_ as the tracing provider. This sandbox @@ -73,7 +73,7 @@ You can now send a request to service1 via the front-envoy as follows: * Connection #0 to host localhost left intact Step 5: View the traces in SkyWalking UI -************************************ +**************************************** Point your browser to http://localhost:8080 . You should see the SkyWalking dashboard. Set the service to "front-envoy" and set the start time to a few minutes before From a8ca0fcfa07d794e92176308002a8b8932b0ecf9 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 10 Oct 2020 20:40:09 +0800 Subject: [PATCH 23/61] fix version history and docs format Signed-off-by: wbpcode --- .../start/sandboxes/skywalking_tracing.rst | 16 ++-- docs/root/version_history/current.rst | 80 +------------------ 2 files changed, 9 insertions(+), 87 deletions(-) diff --git a/docs/root/start/sandboxes/skywalking_tracing.rst b/docs/root/start/sandboxes/skywalking_tracing.rst index cedf9aed34371..64d76cb836d00 100644 --- a/docs/root/start/sandboxes/skywalking_tracing.rst +++ b/docs/root/start/sandboxes/skywalking_tracing.rst @@ -37,14 +37,14 @@ To build this sandbox example, and start the example apps run the following comm $ docker-compose up --build -d $ docker-compose ps - Name Command State Ports - ----------------------------------------------------------------------------------------------------------------------------------------------- - elasticsearch /tini -- /usr/local/bin/do ... Up (healthy) 0.0.0.0:9200->9200/tcp, 9300/tcp - oap bash docker-entrypoint.sh Up (healthy) 0.0.0.0:11800->11800/tcp, 1234/tcp, 0.0.0.0:12800->12800/tcp - skywalking-tracing_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp - skywalking-tracing_service1_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp - skywalking-tracing_service2_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp - ui bash docker-entrypoint.sh Up 0.0.0.0:8080->8080/tcp + Name Command State Ports + --------------------------------------------------------------------------------------------------------------------------------------------- + elasticsearch /tini -- /usr/local/bin/do ... Up (healthy) 0.0.0.0:9200->9200/tcp, 9300/tcp + oap bash docker-entrypoint.sh Up (healthy) 0.0.0.0:11800->11800/tcp, 1234/tcp, 0.0.0.0:12800->12800/tcp + skywalking-tracing_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp + skywalking-tracing_service1_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp + skywalking-tracing_service2_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp + ui bash docker-entrypoint.sh Up 0.0.0.0:8080->8080/tcp Step 4: Generate some load ************************** diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 3b6d9d893e58a..b51239dc5b8d7 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -21,86 +21,8 @@ Removed Config or Runtime New Features ------------ -* access log: added a :ref:`dynamic metadata filter` for access logs, which filters whether to log based on matching dynamic metadata. -* access log: added support for :ref:`%DOWNSTREAM_PEER_FINGERPRINT_1% ` as a response flag. -* access log: added support for :ref:`%CONNECTION_TERMINATION_DETAILS% ` as a log command operator about why the connection is terminated by Envoy. -* access log: added support for nested objects in :ref:`JSON logging mode `. -* access log: added :ref:`omit_empty_values` option to omit unset value from formatted log. -* access log: added support for :ref:`%CONNECTION_ID% ` for the downstream connection identifier. -* admin: added :ref:`circuit breakers settings ` information to GET /clusters?format=json :ref:`cluster status `. -* admin: added :ref:`node ` information to GET /server_info :ref:`response object `. -* admin: added the ability to dump init manager unready targets information :ref:`/init_dump ` and :ref:`/init_dump?mask={} `. -* admission control: added the :ref:`admission control ` filter for client-side request throttling. -* build: enable building envoy :ref:`arm64 images ` by buildx tool in x86 CI platform. -* cluster: added new :ref:`connection_pool_per_downstream_connection ` flag, which enable creation of a new connection pool for each downstream connection. -* decompressor filter: reports compressed and uncompressed bytes in trailers. -* dns: added support for doing DNS resolution using Apple's DnsService APIs in Apple platforms (macOS, iOS). This feature is ON by default, and is only configurable via the ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime key. Note that this value is latched during server startup and changing the runtime key is a no-op during the lifetime of the process. -* dns_filter: added support for answering :ref:`service record` queries. -* dynamic_forward_proxy: added :ref:`use_tcp_for_dns_lookups` option to use TCP for DNS lookups in order to match the DNS options for :ref:`Clusters`. -* ext_authz filter: added support for emitting dynamic metadata for both :ref:`HTTP ` and :ref:`network ` filters. - The emitted dynamic metadata is set by :ref:`dynamic metadata ` field in a returned :ref:`CheckResponse `. -* ext_authz filter: added :ref:`stat_prefix ` as an optional additional prefix for the statistics emitted from `ext_authz` HTTP filter. -* ext_authz filter: added support for letting the authorization server instruct Envoy to remove headers from the original request by setting the new field :ref:`headers_to_remove ` before forwarding it to the upstream. -* ext_authz filter: added support for sending :ref:`raw bytes as request body ` of a gRPC check request by setting :ref:`pack_as_bytes ` to true. -* grpc-json: support specifying `response_body` field in for `google.api.HttpBody` message. -* hds: added :ref:`cluster_endpoints_health ` to HDS responses, keeping endpoints in the same groupings as they were configured in the HDS specifier by cluster and locality instead of as a flat list. -* hds: added :ref:`transport_socket_matches ` to HDS cluster health check specifier, so the existing match filter :ref:`transport_socket_match_criteria ` in the repeated field :ref:`health_checks ` has context to match against. This unblocks support for health checks over HTTPS and HTTP/2. -* hot restart: added :option:`--socket-path` and :option:`--socket-mode` to configure UDS path in the filesystem and set permission to it. -* http: added HTTP/2 support for :ref:`connection keepalive ` via PING. -* http: added support for :ref:`%DOWNSTREAM_PEER_FINGERPRINT_1% ` as custom header. -* http: added :ref:`allow_chunked_length ` configuration option for HTTP/1 codec to allow processing requests/responses with both Content-Length and Transfer-Encoding: chunked headers. If such message is served and option is enabled - per RFC Content-Length is ignored and removed. -* http: added :ref:`CDN Loop filter ` and :ref:`documentation `. -* http: added :ref:`MaxStreamDuration proto ` for configuring per-route downstream duration timeouts. -* http: introduced new HTTP/1 and HTTP/2 codec implementations that will remove the use of exceptions for control flow due to high risk factors and instead use error statuses. The old behavior is used by default, but the new codecs can be enabled for testing by setting the runtime feature `envoy.reloadable_features.new_codec_behavior` to true. The new codecs will be in development for one month, and then enabled by default while the old codecs are deprecated. -* http: modified the HTTP header-map data-structure to use an underlying dictionary and a list (no change to the header-map API). To conform with previous versions, the use of a dictionary is currently disabled. It can be enabled by setting the `envoy.http.headermap.lazy_map_min_size` runtime feature to a non-negative number which defines the minimal number of headers in a request/response/trailers required for using a dictionary in addition to the list. Our current benchmarks suggest that the value 3 is a good threshold for most workloads. -* load balancer: added :ref:`RingHashLbConfig` to configure the table size of Maglev consistent hash. -* load balancer: added a :ref:`configuration` option to specify the active request bias used by the least request load balancer. -* load balancer: added an :ref:`option ` to optimize subset load balancing when there is only one host per subset. -* load balancer: added support for bounded load per host for consistent hash load balancers via :ref:`hash_balance_factor `. -* local_reply config: added :ref:`content_type` field to set content-type. -* lua: added Lua APIs to access :ref:`SSL connection info ` object. -* lua: added Lua API for :ref:`base64 escaping a string `. -* lua: added Lua API for :ref:`setting the current buffer content `. -* lua: added new :ref:`source_code ` field to support the dispatching of inline Lua code in per route configuration of Lua filter. -* overload management: add :ref:`scaling ` trigger for OverloadManager actions. -* postgres network filter: :ref:`metadata ` is produced based on SQL query. -* ratelimit: added :ref:`enable_x_ratelimit_headers ` option to enable `X-RateLimit-*` headers as defined in `draft RFC `_. -* ratelimit: added :ref:`per route config ` for rate limit filter. -* ratelimit: added support for optional :ref:`descriptor_key ` to Generic Key action. -* rbac filter: added the name of the matched policy to the response code detail when a request is rejected by the RBAC filter. -* rbac filter: added a log action to the :ref:`RBAC filter ` which sets dynamic metadata to inform access loggers whether to log. -* redis: added fault injection support :ref:`fault injection for redis proxy `, described further in :ref:`configuration documentation `. -* router: added a new :ref:`rate limited retry back off ` strategy that uses headers like `Retry-After` or `X-RateLimit-Reset` to decide the back off interval. -* router: added new - :ref:`envoy-ratelimited` - retry policy, which allows retrying envoy's own rate limited responses. -* router: added new :ref:`host_rewrite_path_regex ` - option, which allows rewriting Host header based on path. -* router: added support for DYNAMIC_METADATA :ref:`header formatter `. -* router_check_tool: added support for `request_header_matches`, `response_header_matches` to :ref:`router check tool `. -* signal: added support for calling fatal error handlers without envoy's signal handler, via FatalErrorHandler::callFatalErrorHandlers(). -* stats: added optional histograms to :ref:`cluster stats ` - that track headers and body sizes of requests and responses. -* stats: allow configuring histogram buckets for stats sinks and admin endpoints that support it. -* tap: added :ref:`generic body matcher` to scan http requests and responses for text or hex patterns. -* tcp: switched the TCP connection pool to the new "shared" connection pool, sharing a common code base with HTTP and HTTP/2. Any unexpected behavioral changes can be temporarily reverted by setting `envoy.reloadable_features.new_tcp_connection_pool` to false. -* tcp_proxy: added :ref:`max_downstream_connection_duration` for downstream connection. When max duration is reached the connection will be closed. -* tcp_proxy: allow earlier network filters to set metadataMatchCriteria on the connection StreamInfo to influence load balancing. -* tls: added OCSP stapling support through the :ref:`ocsp_staple ` and :ref:`ocsp_staple_policy ` configuration options. See :ref:`OCSP Stapling ` for usage and runtime flags. -* tls: introduce new :ref:`extension point` for overriding :ref:`TLS handshaker ` behavior. -* tls: switched from using socket BIOs to using custom BIOs that know how to interact with IoHandles. The feature can be disabled by setting runtime feature `envoy.reloadable_features.tls_use_io_handle_bio` to false. -* tracing: added ability to set some :ref:`optional segment fields` in the AWS X-Ray tracer. -* tracing: added SkyWalking tracer. -* udp_proxy: added :ref:`hash_policies ` to support hash based routing. -* udp_proxy: added :ref:`use_original_src_ip ` option to replicate the downstream remote address of the packets on the upstream side of Envoy. It is similar to :ref:`original source filter `. -* watchdog: support randomizing the watchdog's kill timeout to prevent synchronized kills via a maximium jitter parameter :ref:`max_kill_timeout_jitter`. -* watchdog: supports an extension point where actions can be registered to fire on watchdog events such as miss, megamiss, kill and multikill. See ref:`watchdog actions`. -* watchdog: watchdog action extension that does cpu profiling. See ref:`Profile Action `. -* watchdog: watchdog action extension that sends SIGABRT to the stuck thread to terminate the process. See ref:`Abort Action `. -* xds: added :ref:`extension config discovery` support for HTTP filters. -* xds: added support for mixed v2/v3 discovery response, which enable type url downgrade and upgrade. This feature is disabled by default and is controlled by runtime guard `envoy.reloadable_features.enable_type_url_downgrade_and_upgrade`. -* zlib: added option to use `zlib-ng `_ as zlib library. * grpc: implemented header value syntax support when defining :ref:`initial metadata ` for gRPC-based `ext_authz` :ref:`HTTP ` and :ref:`network ` filters, and :ref:`ratelimit ` filters. +* tracing: added SkyWalking tracer. Deprecated ---------- From 4184636d3ad18f59a78247eebfdf728c7b6a6086 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 12 Oct 2020 09:09:38 +0800 Subject: [PATCH 24/61] fix for random api change Signed-off-by: wbpcode --- .../extensions/tracers/skywalking/skywalking_tracer_impl.cc | 5 ++--- .../tracers/skywalking/skywalking_tracer_impl_test.cc | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index e800ef0426097..ed786db806a72 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -18,9 +18,8 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, : tracing_stats_{SKYWALKING_TRACER_STATS( POOL_COUNTER_PREFIX(context.serverFactoryContext().scope(), "tracing.skywalking."))}, client_config_(proto_config.client_config()), - random_generator_(context.serverFactoryContext().random()), + random_generator_(context.serverFactoryContext().api().randomGenerator()), tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { - auto& factory_context = context.serverFactoryContext(); if (client_config_.service_name().empty()) { @@ -36,7 +35,7 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, tracer->setReporter(std::make_unique( factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( proto_config.grpc_service(), factory_context.scope(), false), - dispatcher, factory_context.random(), tracing_stats_, client_config_)); + dispatcher, factory_context.api().randomGenerator(), tracing_stats_, client_config_)); return std::make_shared(std::move(tracer)); }); } diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index ea1e7bc9e0e34..1c71c3d432c68 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -73,9 +73,9 @@ static const std::string SKYWALKING_CONFIG_NO_CLIENT_CONFIG = R"EOF( TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { setupSkyWalkingDriver(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); - std::string trace_id = SkyWalkingTestHelper::generateId(context_.server_factory_context_.random_); + std::string trace_id = SkyWalkingTestHelper::generateId(context_.server_factory_context_.api_.random_); std::string segment_id = - SkyWalkingTestHelper::generateId(context_.server_factory_context_.random_); + SkyWalkingTestHelper::generateId(context_.server_factory_context_.api_.random_); // Create new span segment with previous span context. std::string previous_header_value = From 647679e37d9985c3da719dd8c21d68bed3916c26 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 12 Oct 2020 10:17:19 +0800 Subject: [PATCH 25/61] if start child span is set then inject tracing context by child span Signed-off-by: wbpcode --- source/common/router/router.cc | 3 --- source/common/router/upstream_request.cc | 10 ++++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/source/common/router/router.cc b/source/common/router/router.cc index 5e6702c3cb750..2ea8076e8e0cd 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -559,9 +559,6 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers, }; } - // Inject the active span's tracing context into the request headers. - callbacks_->activeSpan().injectContext(headers); - route_entry_->finalizeRequestHeaders(headers, callbacks_->streamInfo(), !config_.suppress_envoy_headers_); FilterUtility::setUpstreamScheme(headers, diff --git a/source/common/router/upstream_request.cc b/source/common/router/upstream_request.cc index e6465f7e73aff..c94a20aea357e 100644 --- a/source/common/router/upstream_request.cc +++ b/source/common/router/upstream_request.cc @@ -61,6 +61,16 @@ UpstreamRequest::UpstreamRequest(RouterFilterInterface& parent, } } + // Inject the current span's tracing context into the request headers. + ASSERT(parent_.downstreamHeaders()); + if (!span_) { + parent_.callbacks()->activeSpan().injectContext(*parent_.downstreamHeaders()); + } else { + // If new child span is created for forward upstream request, then use it to inject tracing + // context to request headers. + span_->injectContext(*parent_.downstreamHeaders()); + } + stream_info_.healthCheck(parent_.callbacks()->streamInfo().healthCheck()); if (conn_pool_->protocol().has_value()) { stream_info_.protocol(conn_pool_->protocol().value()); From e10a47b1179135f55dc989ba713e308c3bcdcf7a Mon Sep 17 00:00:00 2001 From: wbpcode Date: Thu, 15 Oct 2020 18:00:54 +0800 Subject: [PATCH 26/61] create two span for skywalking tracer Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 10 +-- .../skywalking/v4alpha/skywalking.proto | 10 +-- .../envoy/config/trace/v3/skywalking.proto | 10 +-- .../skywalking/v4alpha/skywalking.proto | 10 +-- .../skywalking/skywalking_tracer_impl.cc | 18 +---- .../tracers/skywalking/skywalking_types.cc | 36 ++++----- .../tracers/skywalking/skywalking_types.h | 61 +++++---------- .../skywalking/trace_segment_reporter.cc | 11 +-- .../extensions/tracers/skywalking/tracer.cc | 42 ++-------- source/extensions/tracers/skywalking/tracer.h | 12 ++- .../skywalking/skywalking_test_helper.h | 8 +- .../skywalking/skywalking_tracer_impl_test.cc | 20 ++--- .../skywalking/skywalking_types_test.cc | 76 +++++++------------ .../tracers/skywalking/tracer_test.cc | 56 ++------------ 14 files changed, 113 insertions(+), 267 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index 6907f091ce4bf..615a6e6dd6db1 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -30,7 +30,7 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 6] +// [#next-free-field: 5] message ClientConfig { // Service name for SkyWalking tracer. If service_name is empty, then cluster // name of Envoy will be used as service name. @@ -44,14 +44,8 @@ message ClientConfig { // authentication. string authentication = 3; - // When this field is set to true and Envoy is not the first tracing node, it - // directly uses the downstream endpoint as its own endpoint. This is helpful - // when the user wants to use the endpoint to aggregate all span data on the - // tracing link. - bool pass_endpoint = 4; - // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can // be cached. If not specified, the default is 1024. - google.protobuf.UInt32Value max_cache_size = 5; + google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index c3da41718d3b5..a08a816e88a92 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -30,7 +30,7 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 6] +// [#next-free-field: 5] message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; @@ -46,14 +46,8 @@ message ClientConfig { // authentication. string authentication = 3; - // When this field is set to true and Envoy is not the first tracing node, it - // directly uses the downstream endpoint as its own endpoint. This is helpful - // when the user wants to use the endpoint to aggregate all span data on the - // tracing link. - bool pass_endpoint = 4; - // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can // be cached. If not specified, the default is 1024. - google.protobuf.UInt32Value max_cache_size = 5; + google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index 6907f091ce4bf..615a6e6dd6db1 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -30,7 +30,7 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 6] +// [#next-free-field: 5] message ClientConfig { // Service name for SkyWalking tracer. If service_name is empty, then cluster // name of Envoy will be used as service name. @@ -44,14 +44,8 @@ message ClientConfig { // authentication. string authentication = 3; - // When this field is set to true and Envoy is not the first tracing node, it - // directly uses the downstream endpoint as its own endpoint. This is helpful - // when the user wants to use the endpoint to aggregate all span data on the - // tracing link. - bool pass_endpoint = 4; - // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can // be cached. If not specified, the default is 1024. - google.protobuf.UInt32Value max_cache_size = 5; + google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index c3da41718d3b5..a08a816e88a92 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -30,7 +30,7 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 6] +// [#next-free-field: 5] message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; @@ -46,14 +46,8 @@ message ClientConfig { // authentication. string authentication = 3; - // When this field is set to true and Envoy is not the first tracing node, it - // directly uses the downstream endpoint as its own endpoint. This is helpful - // when the user wants to use the endpoint to aggregate all span data on the - // tracing link. - bool pass_endpoint = 4; - // Envoy caches the segment in memory when the backend service is temporarily // unavailable. This field specifies the maximum number of segments that can // be cached. If not specified, the default is 1024. - google.protobuf.UInt32Value max_cache_size = 5; + google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index ed786db806a72..0c2c2c51d6403 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -41,8 +41,9 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, } Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, - Http::RequestHeaderMap& request_headers, const std::string&, - Envoy::SystemTime start_time, const Tracing::Decision decision) { + Http::RequestHeaderMap& request_headers, + const std::string& operation_name, Envoy::SystemTime start_time, + const Tracing::Decision decision) { auto& tracer = *tls_slot_ptr_->getTyped().tracer_; try { @@ -54,19 +55,6 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, segment_context->setService(client_config_.service_name()); segment_context->setServiceInstance(client_config_.instance_name()); - // In order to be consistent with the existing SkyWalking agent, we use request Method and - // request Path to create an operation name. - // TODO(wbpcode): A temporary decision. This strategy still needs further consideration. - std::string operation_name = - absl::StrCat("/", request_headers.getMethodValue(), - Http::PathUtil::removeQueryAndFragment(request_headers.getPathValue())); - - if (!client_config_.pass_endpoint() || !segment_context->previousSpanContext()) { - segment_context->setEndpoint(operation_name); - } else { - segment_context->setEndpoint(segment_context->previousSpanContext()->endpoint_); - } - return tracer.startSpan(config, start_time, operation_name, std::move(segment_context), nullptr); diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 6c3eab485d673..0d7f37d82c167 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -108,17 +108,21 @@ SegmentContext::SegmentContext(SpanContextPtr&& previous_span_context, Tracing:: trace_segment_id_ = generateId(random_generator); } -SpanStore* SegmentContext::createSpanStore(TimeSource& time_source, SpanStore* parent_store) { - auto store = std::make_unique(this, time_source); +SpanStore* SegmentContext::createSpanStore(const SpanStore* parent_store) { + SpanStorePtr store = std::make_unique(this); store->setSpanId(span_list_.size()); - if (parent_store) { - // Child span. - store->setSampled(parent_store->sampled()); - store->setParentSpanId(parent_store->spanId()); - } else { + if (!parent_store) { // First span. store->setSampled(sampled_); store->setParentSpanId(-1); + // First span of current segment for Envoy Proxy must be a Entry Span. It is created for + // downstream HTTP request. + store->setAsEntrySpan(true); + } else { + // Child span. + store->setSampled(parent_store->sampled()); + store->setParentSpanId(parent_store->spanId()); + store->setAsEntrySpan(false); } SpanStore* ref = store.get(); span_list_.emplace_back(std::move(store)); @@ -128,22 +132,20 @@ SpanStore* SegmentContext::createSpanStore(TimeSource& time_source, SpanStore* p void SpanStore::injectContext(Http::RequestHeaderMap& request_headers) const { ASSERT(segment_context_); - std::string target_address = - upstream_address_.empty() ? std::string(request_headers.getHostValue()) : upstream_address_; + ASSERT(!is_entry_span_); + const_cast(this)->setPeerAddress(std::string(request_headers.getHostValue())); // Reference: // https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. - const auto value = - absl::StrCat(sampled_, "-", base64Encode(segment_context_->traceId()), "-", - base64Encode(segment_context_->traceSegmentId()), "-", span_id_, "-", - base64Encode(segment_context_->service()), "-", - base64Encode(segment_context_->serviceInstance()), "-", - base64Encode(segment_context_->endpoint()), "-", base64Encode(target_address)); + const auto value = absl::StrCat(sampled_, "-", base64Encode(segment_context_->traceId()), "-", + base64Encode(segment_context_->traceSegmentId()), "-", span_id_, + "-", base64Encode(segment_context_->service()), "-", + base64Encode(segment_context_->serviceInstance()), "-", + base64Encode(segment_context_->rootSpanStore()->operation()), "-", + base64Encode(peer_address_)); request_headers.setReferenceKey(propagationHeader(), value); } -void SpanStore::finish() { end_time_ = DateUtil::nowToMilliseconds(time_source_); } - } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index e143a98c9e2f6..9f43267d9c1d5 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -91,34 +91,31 @@ class SegmentContext { service_instance_ = service_instance; } - /* - * Set endpoint. - * - * @param endpoint. The endpoint value. Endpoint should be operation name of the first entry span - * in the segment. All spans in the same segment share the same endpoint. In our implementation, - * we currently use 'HTTP Method + HTTP Path Without Query' as the endpoint value. - */ - void setEndpoint(const std::string& endpoint) { endpoint_ = endpoint; } - /* * Create a new SpanStore object and return its pointer. The ownership of the newly created - * SpanStore object belongs to the current span context. + * SpanStore object belongs to the current segment context. * - * @param time_source The time source. * @param parent_store The pointer that point to parent SpanStore object. * @return SpanStore* The pointer that point to newly created SpanStore object. */ - SpanStore* createSpanStore(TimeSource& time_source, SpanStore* parent_store); + SpanStore* createSpanStore(const SpanStore* parent_store); + /* + * Get all SpanStore objects in the current segment. + */ const std::vector& spanList() const { return span_list_; } + /* + * Get root SpanStore object in the current segment. + */ + const SpanStore* rootSpanStore() { return span_list_.empty() ? nullptr : span_list_[0].get(); } + int sampled() const { return sampled_; } const std::string& traceId() const { return trace_id_; } const std::string& traceSegmentId() const { return trace_segment_id_; } const std::string& service() const { return service_; } const std::string& serviceInstance() const { return service_instance_; } - const std::string& endpoint() const { return endpoint_; } SpanContext* previousSpanContext() const { return previous_span_context_.get(); } @@ -133,7 +130,6 @@ class SegmentContext { std::string service_; std::string service_instance_; - std::string endpoint_; // The SegmentContext parsed from the request headers. If no propagation headers in request then // this will be nullptr. @@ -158,31 +154,17 @@ class SpanStore { * @param segment_context The pointer that point to current span context. This can not be null. * @param time_source A time source to get the span end time. */ - explicit SpanStore(SegmentContext* segment_context, TimeSource& time_source) - : segment_context_(segment_context), time_source_(time_source) {} - - /* - * When a SkyWalking span ends, it will be called to set the end time of the current span. - */ - void finish(); - - /* - * Get operation name of span. If operation name is empty, the endpoint in the span context will - * be used instead. - */ - const std::string& operation() const { - return operation_.empty() ? segment_context_->endpoint() : operation_; - } + explicit SpanStore(SegmentContext* segment_context) : segment_context_(segment_context) {} /* - * Get upstream address. + * Get operation name of span. */ - const std::string& upstreamAddress() const { return upstream_address_; } + const std::string& operation() const { return operation_; } /* * Get peer address. The peer in SkyWalking is different with the tag value of 'peer.address'. The * tag value of 'peer.address' in Envoy is downstream address and the peer in SkyWalking is - * request host. + * upstream address. */ const std::string& peerAddress() const { return peer_address_; } @@ -251,15 +233,9 @@ class SpanStore { void setOperation(const std::string& operation) { operation_ = operation; } /* - * Set upstream address. - */ - void setUpstreamAddress(const std::string& upstream_address) { - upstream_address_ = upstream_address; - } - - /* - * Set peer address. In SkyWalking, the peer address is only set in ExitSpan. And it should the - * request host. + * Set peer address. In SkyWalking, the peer address is only set in Exit Span. And it should the + * upstream address. Since the upstream address cannot be obtained at the request stage, the + * request host is used instead. */ void setPeerAddress(const std::string& peer_address) { peer_address_ = peer_address; } @@ -327,7 +303,6 @@ class SpanStore { uint64_t end_time_{0}; std::string operation_; - std::string upstream_address_; std::string peer_address_; bool is_error_{false}; @@ -335,8 +310,6 @@ class SpanStore { std::vector tags_; std::vector logs_; - - TimeSource& time_source_; }; } // namespace SkyWalking diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index aed40bc2b4202..5db2df629ac87 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -14,8 +14,8 @@ const Http::LowerCaseString& authenticationTokenKey() { // Convert SegmentContext to SegmentObject. TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { - auto new_segment = std::make_unique(); - SegmentObject& segment_object = *new_segment; + auto new_segment_ptr = std::make_unique(); + SegmentObject& segment_object = *new_segment_ptr; segment_object.set_traceid(segment_context.traceId()); segment_object.set_tracesegmentid(segment_context.traceSegmentId()); @@ -35,7 +35,7 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { // get more information. span->set_componentid(9000); - if (!span_store->peerAddress().empty()) { + if (!span_store->peerAddress().empty() && span_store->isEntrySpan()) { span->set_peer(span_store->peerAddress()); } @@ -57,7 +57,8 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { } SpanContext* previous_span_context = segment_context.previousSpanContext(); - if (!previous_span_context) { + + if (!previous_span_context || !span_store->isEntrySpan()) { continue; } @@ -70,7 +71,7 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { ref->set_parentendpoint(previous_span_context->endpoint_); ref->set_networkaddressusedatpeer(previous_span_context->target_address_); } - return new_segment; + return new_segment_ptr; } } // namespace diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc index 25806b08c87a5..b1c6b362430dd 100644 --- a/source/extensions/tracers/skywalking/tracer.cc +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -16,31 +16,13 @@ uint64_t getTimestamp(SystemTime time) { return std::chrono::duration_cast(time.time_since_epoch()).count(); } -// A simple tool function. Used to extract the HTTP Host from the URL, and set the Host value as the -// peer address to the SpanStore object. -void setSkyWalkingPeerAddress(SpanStore* span_store, absl::string_view http_request_url) { - if (span_store->isEntrySpan()) { - return; - } - if (size_t host_start_pos = http_request_url.find("://"); host_start_pos != std::string::npos) { - absl::string_view host_with_path = http_request_url.substr(host_start_pos + 3); - size_t path_start_pos = host_with_path.find("/"); - if (path_start_pos == std::string::npos) { - return; - } - host_with_path.remove_suffix(host_with_path.size() - path_start_pos); - span_store->setPeerAddress(std::string(host_with_path)); - } -} - } // namespace -Tracing::SpanPtr Tracer::startSpan(const Tracing::Config& config, SystemTime start_time, +Tracing::SpanPtr Tracer::startSpan(const Tracing::Config&, SystemTime start_time, const std::string& operation, SegmentContextSharedPtr segment_context, Span* parent) { - SpanStore* span_store = - segment_context->createSpanStore(time_source_, parent ? parent->spanStore() : nullptr); - span_store->setAsEntrySpan(config.operationName() == Tracing::OperationName::Ingress); + SpanStore* span_store = segment_context->createSpanStore(parent ? parent->spanStore() : nullptr); + span_store->setStartTime(getTimestamp(start_time)); span_store->setOperation(operation); @@ -53,11 +35,8 @@ void Span::setOperation(absl::string_view operation) { } void Span::setTag(absl::string_view name, absl::string_view value) { - // Use request host as peer address and set it in ExitSpan. The request host can be parsed from - // the URL. if (name == Tracing::Tags::get().HttpUrl) { span_store_->addTag(UrlTag, value); - setSkyWalkingPeerAddress(span_store_, value); return; } @@ -70,24 +49,15 @@ void Span::setTag(absl::string_view name, absl::string_view value) { span_store_->setAsError(value == Tracing::Tags::get().True); } - // When we need to create a new propagation header and send it to upstream, use upstream address - // as the target address. - if (name == Tracing::Tags::get().UpstreamAddress) { - span_store_->setUpstreamAddress(std::string(value)); - } - span_store_->addTag(name, value); } +// Logs in the SkyWalking format are temporarily unsupported. void Span::log(SystemTime, const std::string&) {} void Span::finishSpan() { - span_store_->finish(); - // If the current span is the first span of the entire segment and its sampling flag is not false, - // the data for the entire segment is reported. - if (span_store_->sampled() && span_store_->spanId() == 0) { - tracer_.report(*segment_context_); - } + span_store_->setEndTime(DateUtil::nowToMilliseconds(tracer_.time_source_)); + tryToReportSpan(); } void Span::injectContext(Http::RequestHeaderMap& request_headers) { diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h index 8615592d62865..21de76aceea57 100644 --- a/source/extensions/tracers/skywalking/tracer.h +++ b/source/extensions/tracers/skywalking/tracer.h @@ -54,8 +54,9 @@ class Tracer { const std::string& operation, SegmentContextSharedPtr segment_context, Span* parent); -private: TimeSource& time_source_; + +private: TraceSegmentReporterPtr reporter_; }; @@ -95,6 +96,15 @@ class Span : public Tracing::Span { SegmentContext* segmentContext() const { return segment_context_.get(); } private: + void tryToReportSpan() { + // If the current span is the root span of the entire segment and its sampling flag is not + // false, the data for the entire segment is reported. Please ensure that the root span is the + // last span to end in the entire segment. + if (span_store_->sampled() && span_store_->spanId() == 0) { + tracer_.report(*segment_context_); + } + } + SegmentContextSharedPtr segment_context_; SpanStore* span_store_; diff --git a/test/extensions/tracers/skywalking/skywalking_test_helper.h b/test/extensions/tracers/skywalking/skywalking_test_helper.h index 3893dd8dc10d7..e158bb535da8a 100644 --- a/test/extensions/tracers/skywalking/skywalking_test_helper.h +++ b/test/extensions/tracers/skywalking/skywalking_test_helper.h @@ -50,19 +50,17 @@ class SkyWalkingTestHelper { segment_context->setService(seed + "#SERVICE"); segment_context->setServiceInstance(seed + "#INSTANCE"); - segment_context->setEndpoint(seed + "#ENDPOINT"); + return segment_context; } static SpanStore* createSpanStore(SegmentContext* segment_context, SpanStore* parent_span_store, - std::string seed, Envoy::TimeSource& time_source) { - SpanStore* span_store = segment_context->createSpanStore(time_source, parent_span_store); + std::string seed) { + SpanStore* span_store = segment_context->createSpanStore(parent_span_store); - span_store->setAsEntrySpan(true); span_store->setAsError(false); span_store->setOperation(seed + "#OPERATION"); span_store->setPeerAddress("0.0.0.0"); - span_store->setUpstreamAddress("0.0.0.0"); span_store->setStartTime(22222222); span_store->setEndTime(33333333); diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index 1c71c3d432c68..caf93882eb851 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -60,7 +60,6 @@ static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( authentication: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" service_name: "FAKE_FAKE_FAKE" instance_name: "FAKE_FAKE_FAKE" - pass_endpoint: true max_cache_size: 2333 )EOF"; @@ -73,7 +72,8 @@ static const std::string SKYWALKING_CONFIG_NO_CLIENT_CONFIG = R"EOF( TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { setupSkyWalkingDriver(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); - std::string trace_id = SkyWalkingTestHelper::generateId(context_.server_factory_context_.api_.random_); + std::string trace_id = + SkyWalkingTestHelper::generateId(context_.server_factory_context_.api_.random_); std::string segment_id = SkyWalkingTestHelper::generateId(context_.server_factory_context_.api_.random_); @@ -97,7 +97,7 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { Tracing::Decision decision; decision.traced = true; - Tracing::SpanPtr org_span = driver_->startSpan(mock_tracing_config_, request_headers, "", + Tracing::SpanPtr org_span = driver_->startSpan(mock_tracing_config_, request_headers, "TEST_OP", time_system_.systemTime(), decision); EXPECT_NE(nullptr, org_span.get()); @@ -109,10 +109,6 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { EXPECT_EQ("FAKE_FAKE_FAKE", span->segmentContext()->service()); EXPECT_EQ("FAKE_FAKE_FAKE", span->segmentContext()->serviceInstance()); - // If pass_endpoint is set to true, Envoy will use the downstream endpoint directly. - EXPECT_EQ(span->segmentContext()->endpoint(), - span->segmentContext()->previousSpanContext()->endpoint_); - // Tracing decision will be overwrite by sampling flag in propagation headers. EXPECT_EQ(0, span->segmentContext()->sampled()); @@ -133,9 +129,6 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { ASSERT(new_span); EXPECT_EQ(nullptr, new_span->segmentContext()->previousSpanContext()); - // Although pass_endpoint is set to true, 'METHOD' and 'PATH' will be used as endpoint when - // previous span context is null. - EXPECT_EQ("/GET/path", new_span->segmentContext()->endpoint()); EXPECT_EQ(true, new_span->segmentContext()->sampled()); @@ -148,8 +141,8 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { {":method", "GET"}, {":authority", "test.com"}, {"sw8", "xxxxxx-error-propagation-header"}}; - Tracing::SpanPtr org_null_span = driver_->startSpan(mock_tracing_config_, error_request_headers, - "", time_system_.systemTime(), decision); + Tracing::SpanPtr org_null_span = driver_->startSpan( + mock_tracing_config_, error_request_headers, "TEST_OP", time_system_.systemTime(), decision); EXPECT_EQ(nullptr, dynamic_cast(org_null_span.get())); @@ -163,7 +156,7 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) { Http::TestRequestHeaderMapImpl request_headers{ {":path", "/path"}, {":method", "GET"}, {":authority", "test.com"}}; - Tracing::SpanPtr org_span = driver_->startSpan(mock_tracing_config_, request_headers, "", + Tracing::SpanPtr org_span = driver_->startSpan(mock_tracing_config_, request_headers, "TEST_OP", time_system_.systemTime(), Tracing::Decision()); EXPECT_NE(nullptr, org_span.get()); @@ -172,7 +165,6 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) { EXPECT_EQ(test_string, span->segmentContext()->service()); EXPECT_EQ(test_string, span->segmentContext()->serviceInstance()); - EXPECT_EQ("/GET/path", span->segmentContext()->endpoint()); } } // namespace SkyWalking diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc index f20e1096c5984..217459d127afe 100644 --- a/test/extensions/tracers/skywalking/skywalking_types_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -150,7 +150,6 @@ TEST(SpanContextTest, SpanContextCommonTest) { // does not exist). TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { NiceMock mock_random_generator; - NiceMock mock_time_source; ON_CALL(mock_random_generator, random()).WillByDefault(Return(233333)); @@ -169,10 +168,6 @@ TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { // Test whether the value of the fields can be set correctly and the value of the fields can be // obtained correctly. - EXPECT_EQ(segment_context->endpoint(), "NEW#ENDPOINT"); - segment_context->setEndpoint(TEST_ENDPOINT); - EXPECT_EQ(segment_context->endpoint(), TEST_ENDPOINT); - EXPECT_EQ(segment_context->service(), "NEW#SERVICE"); segment_context->setService(TEST_SERVICE); EXPECT_EQ(segment_context->service(), TEST_SERVICE); @@ -181,28 +176,36 @@ TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { segment_context->setServiceInstance(TEST_INSTANCE); EXPECT_EQ(segment_context->serviceInstance(), TEST_INSTANCE); + EXPECT_EQ(segment_context->rootSpanStore(), nullptr); + // Test whether SegmentContext can correctly create SpanStore object with null parent SpanStore. - SpanStore* root_span = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, - "PARENT", mock_time_source); + SpanStore* root_span = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "PARENT"); EXPECT_NE(nullptr, root_span); // The span id of the first SpanStore in each SegmentContext is 0. Its parent span id is -1. EXPECT_EQ(root_span->spanId(), 0); EXPECT_EQ(root_span->parentSpanId(), -1); + // Root span of current segment should be Entry Span. + EXPECT_EQ(root_span->isEntrySpan(), true); + // Verify that the SpanStore object is correctly stored in the SegmentContext. EXPECT_EQ(segment_context->spanList().size(), 1); EXPECT_EQ(segment_context->spanList()[0].get(), root_span); // Test whether SegmentContext can correctly create SpanStore object with a parent SpanStore. - SpanStore* child_span = SkyWalkingTestHelper::createSpanStore(segment_context.get(), root_span, - "CHILD", mock_time_source); + SpanStore* child_span = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), root_span, "CHILD"); EXPECT_NE(nullptr, child_span); EXPECT_EQ(child_span->spanId(), 1); EXPECT_EQ(child_span->parentSpanId(), 0); + // All child spans of current segment should be Exit Span. + EXPECT_EQ(child_span->isEntrySpan(), false); + EXPECT_EQ(segment_context->spanList().size(), 2); EXPECT_EQ(segment_context->spanList()[1].get(), child_span); } @@ -252,18 +255,17 @@ TEST(SegmentContextTest, SegmentContextTestWithPreviousSpanContext) { // Test whether SpanStore can work properly. TEST(SpanStoreTest, SpanStoreCommonTest) { NiceMock mock_random_generator; - NiceMock mock_time_source; + Event::SimulatedTimeSystem time_system; Envoy::SystemTime now = time_system.systemTime(); ON_CALL(mock_random_generator, random()).WillByDefault(Return(23333)); - ON_CALL(mock_time_source, systemTime()).WillByDefault(Return(now)); // Create segment context and first span store. SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "CURR", "PREV", mock_random_generator); - SpanStore* root_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, - "ROOT", mock_time_source); + SpanStore* root_store = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "ROOT"); EXPECT_NE(nullptr, root_store); EXPECT_EQ(3, root_store->tags().size()); @@ -294,21 +296,15 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { EXPECT_EQ(true, root_store->isError()); EXPECT_EQ("ROOT#OPERATION", root_store->operation()); + root_store->setOperation(""); + EXPECT_EQ("", root_store->operation()); root_store->setOperation("oooooop"); EXPECT_EQ("oooooop", root_store->operation()); - root_store->setOperation(""); - // If the operation name is empty, the endpoint of the current SegmentContext will be used - // instead. - EXPECT_EQ("CURR#ENDPOINT", root_store->operation()); EXPECT_EQ("0.0.0.0", root_store->peerAddress()); root_store->setPeerAddress(TEST_ADDRESS); EXPECT_EQ(TEST_ADDRESS, root_store->peerAddress()); - EXPECT_EQ("0.0.0.0", root_store->upstreamAddress()); - root_store->setUpstreamAddress(TEST_ADDRESS); - EXPECT_EQ(TEST_ADDRESS, root_store->upstreamAddress()); - EXPECT_EQ(22222222, root_store->startTime()); root_store->setStartTime(23333); EXPECT_EQ(23333, root_store->startTime()); @@ -317,42 +313,24 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { root_store->setEndTime(25555); EXPECT_EQ(25555, root_store->endTime()); - // When SpanStore calls finish, the end time will be set. - root_store->finish(); - EXPECT_EQ(std::chrono::time_point_cast(now).time_since_epoch().count(), - root_store->endTime()); + SpanStore* child_store = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), root_store, "CHILD"); // Test whether SpanStore can correctly inject propagation headers to request headers. - - Http::TestRequestHeaderMapImpl request_headers_with_upstream{{":authority", "test.com"}}; - root_store->injectContext(request_headers_with_upstream); - - std::string expected_header_value = fmt::format( - "{}-{}-{}-{}-{}-{}-{}-{}", root_store->sampled(), - SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), - SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), - root_store->spanId(), SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), - SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), - SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), - SkyWalkingTestHelper::base64Encode(TEST_ADDRESS)); - - EXPECT_EQ(request_headers_with_upstream.get_("sw8"), expected_header_value); - - // Reset upstream address to empty. - root_store->setUpstreamAddress(""); - - // When the upstream address is empty, use the host in the request as the target address. Http::TestRequestHeaderMapImpl request_headers_no_upstream{{":authority", "test.com"}}; - root_store->injectContext(request_headers_no_upstream); - expected_header_value = fmt::format( - "{}-{}-{}-{}-{}-{}-{}-{}", root_store->sampled(), + // Only child span (Exit Span) can inject context header to request headers. + child_store->injectContext(request_headers_no_upstream); + std::string expected_header_value = fmt::format( + "{}-{}-{}-{}-{}-{}-{}-{}", child_store->sampled(), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator)), - root_store->spanId(), SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), + child_store->spanId(), SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), - SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), + SkyWalkingTestHelper::base64Encode("oooooop"), SkyWalkingTestHelper::base64Encode("test.com")); + EXPECT_EQ(child_store->peerAddress(), "test.com"); + EXPECT_EQ(request_headers_no_upstream.get_("sw8"), expected_header_value); } diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index f9abbccb6735a..a961f27d2faed 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -74,14 +74,11 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "CURR", "", mock_random_generator_); - EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(Return(Envoy::Tracing::OperationName::Egress)); Envoy::Tracing::SpanPtr org_span = tracer_->startSpan( mock_tracing_config_, mock_time_source_.systemTime(), "TEST_OP", segment_context, nullptr); Span* span = dynamic_cast(org_span.get()); - // Since the operation name in config is Egress, the new span is ExitSpan. - EXPECT_EQ(false, span->spanStore()->isEntrySpan()); + EXPECT_EQ(true, span->spanStore()->isEntrySpan()); EXPECT_EQ("", span->getBaggage("FakeStringAndNothingToDo")); span->setBaggage("FakeStringAndNothingToDo", "FakeStringAndNothingToDo"); @@ -94,9 +91,6 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { // The initial operation name is consistent with the 'operation' parameter in the 'startSpan' // method call. EXPECT_EQ("TEST_OP", span->spanStore()->operation()); - // Reset operation to empty. Then endpoint will be used as a replacement. - span->setOperation(""); - EXPECT_EQ("CURR#ENDPOINT", span->spanStore()->operation()); span->setOperation("op"); EXPECT_EQ("op", span->spanStore()->operation()); @@ -118,44 +112,15 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { EXPECT_EQ(Tracing::Tags::get().True, span->spanStore()->tags().at(3).value()); EXPECT_EQ(true, span->spanStore()->isError()); - // When setting http url tag, the corresponding tag name will be rewritten as 'url'. At the same - // time, we will extract the http request host from the url value as the peer address of - // SkyWalking. + // When setting http url tag, the corresponding tag name will be rewritten as 'url'. span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com/test/path"); EXPECT_EQ("url", span->spanStore()->tags().at(4).key()); - EXPECT_EQ("http://test.com/test/path", span->spanStore()->tags().at(4).value()); - EXPECT_EQ("test.com", span->spanStore()->peerAddress()); - // If the url format is wrong, the peer address remains empty. - span->spanStore()->setPeerAddress(""); - span->setTag(Tracing::Tags::get().HttpUrl, "http:/test.com/test/path"); - EXPECT_EQ("", span->spanStore()->peerAddress()); - - span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com"); - EXPECT_EQ("", span->spanStore()->peerAddress()); - - // Test the inject context function and verify the result. - Http::TestRequestHeaderMapImpl headers{{":authority", "test.com"}}; - // No upstream address set and host in request headers will be used as target address. - std::string expected_header_value = fmt::format( - "{}-{}-{}-{}-{}-{}-{}-{}", 0, - SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), - SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), - 0, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), - SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), - SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), - SkyWalkingTestHelper::base64Encode("test.com")); - span->injectContext(headers); - EXPECT_EQ(expected_header_value, headers.get_("sw8")); - - EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(Return(Envoy::Tracing::OperationName::Ingress)); Envoy::Tracing::SpanPtr org_first_child_span = span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); Span* first_child_span = dynamic_cast(org_first_child_span.get()); - // Since the operation name in config is Ingress, the new span is EntrySpan. - EXPECT_EQ(true, first_child_span->spanStore()->isEntrySpan()); + EXPECT_EQ(false, first_child_span->spanStore()->isEntrySpan()); EXPECT_EQ(0, first_child_span->spanStore()->sampled()); EXPECT_EQ(1, first_child_span->spanStore()->spanId()); @@ -164,27 +129,19 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { EXPECT_EQ("TestChild", first_child_span->spanStore()->operation()); Http::TestRequestHeaderMapImpl first_child_headers{{":authority", "test.com"}}; - expected_header_value = fmt::format( + std::string expected_header_value = fmt::format( "{}-{}-{}-{}-{}-{}-{}-{}", 0, SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), SkyWalkingTestHelper::base64Encode(SkyWalkingTestHelper::generateId(mock_random_generator_)), 1, SkyWalkingTestHelper::base64Encode("CURR#SERVICE"), - SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), - SkyWalkingTestHelper::base64Encode("CURR#ENDPOINT"), - SkyWalkingTestHelper::base64Encode("0.0.0.0")); - - first_child_span->setTag(Tracing::Tags::get().UpstreamAddress, "0.0.0.0"); - first_child_span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com/test/path"); - // Peer address only set in ExitSpan. - EXPECT_EQ("", span->spanStore()->peerAddress()); + SkyWalkingTestHelper::base64Encode("CURR#INSTANCE"), SkyWalkingTestHelper::base64Encode("op"), + SkyWalkingTestHelper::base64Encode("test.com")); first_child_span->injectContext(first_child_headers); EXPECT_EQ(expected_header_value, first_child_headers.get_("sw8")); // Reset sampling flag to true. span->setSampled(true); - EXPECT_CALL(mock_tracing_config_, operationName()) - .WillOnce(Return(Envoy::Tracing::OperationName::Ingress)); Envoy::Tracing::SpanPtr org_second_child_span = span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); Span* second_child_span = dynamic_cast(org_second_child_span.get()); @@ -199,6 +156,7 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { first_child_span->finishSpan(); second_child_span->finishSpan(); EXPECT_NE(0, first_child_span->spanStore()->endTime()); + EXPECT_NE(0, second_child_span->spanStore()->endTime()); EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_sent").value()); EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_dropped").value()); From c9142038661e953dfd018f18e98b08df00cd46c2 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 16 Oct 2020 11:06:38 +0800 Subject: [PATCH 27/61] add start child span config in sandbox yaml Signed-off-by: wbpcode --- examples/skywalking-tracing/front-envoy-skywalking.yaml | 4 +++- .../skywalking-tracing/service1-envoy-skywalking.yaml | 8 ++++++-- .../skywalking-tracing/service2-envoy-skywalking.yaml | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/skywalking-tracing/front-envoy-skywalking.yaml b/examples/skywalking-tracing/front-envoy-skywalking.yaml index e07bf4e7e85c6..32d7de94dd07c 100644 --- a/examples/skywalking-tracing/front-envoy-skywalking.yaml +++ b/examples/skywalking-tracing/front-envoy-skywalking.yaml @@ -40,7 +40,9 @@ static_resources: operation: checkAvailability http_filters: - name: envoy.filters.http.router - typed_config: {} + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + start_child_span: true clusters: - name: service1 connect_timeout: 0.250s diff --git a/examples/skywalking-tracing/service1-envoy-skywalking.yaml b/examples/skywalking-tracing/service1-envoy-skywalking.yaml index 63ca17c653c5e..bf745e5b536ac 100644 --- a/examples/skywalking-tracing/service1-envoy-skywalking.yaml +++ b/examples/skywalking-tracing/service1-envoy-skywalking.yaml @@ -39,7 +39,9 @@ static_resources: operation: checkAvailability http_filters: - name: envoy.filters.http.router - typed_config: {} + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + start_child_span: true - address: socket_address: address: 0.0.0.0 @@ -79,7 +81,9 @@ static_resources: operation: checkStock http_filters: - name: envoy.filters.http.router - typed_config: {} + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + start_child_span: true clusters: - name: local_service connect_timeout: 0.250s diff --git a/examples/skywalking-tracing/service2-envoy-skywalking.yaml b/examples/skywalking-tracing/service2-envoy-skywalking.yaml index b150f8409ccf0..0fe2a0dd43d1f 100644 --- a/examples/skywalking-tracing/service2-envoy-skywalking.yaml +++ b/examples/skywalking-tracing/service2-envoy-skywalking.yaml @@ -39,7 +39,9 @@ static_resources: operation: checkStock http_filters: - name: envoy.filters.http.router - typed_config: {} + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + start_child_span: true clusters: - name: local_service connect_timeout: 0.250s From 75f5ed78fced7b023872d6c494cd4f70bbd21f8d Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 16 Oct 2020 11:07:10 +0800 Subject: [PATCH 28/61] add tracing log for skywalking reporter Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/trace_segment_reporter.cc | 3 +++ source/extensions/tracers/skywalking/trace_segment_reporter.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index 5db2df629ac87..e0136c60b17b6 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -110,6 +110,9 @@ void TraceSegmentReporter::report(const SegmentContext& segment_context) { } void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr&& request) { + ASSERT(request); + ENVOY_LOG(trace, "Try to report segment to SkyWalking Server:\n{}", request->DebugString()); + if (stream_ != nullptr) { tracing_stats_.segments_sent_.inc(); stream_->sendMessage(*request, false); diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index a19bba987d715..2127d79a9bbdb 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -21,7 +21,8 @@ namespace SkyWalking { using TraceSegmentPtr = std::unique_ptr; -class TraceSegmentReporter : Grpc::AsyncStreamCallbacks { +class TraceSegmentReporter : public Logger::Loggable, + public Grpc::AsyncStreamCallbacks { public: explicit TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, Event::Dispatcher& dispatcher, Random::RandomGenerator& random, From b518d3ed7baac6963d5db3091aab37ab84622249 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 16 Oct 2020 11:32:17 +0800 Subject: [PATCH 29/61] fix conflict Signed-off-by: wbpcode --- docs/root/version_history/current.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 1df8fdac79ea0..96a48d7138115 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -28,12 +28,12 @@ Removed Config or Runtime New Features ------------ * grpc: implemented header value syntax support when defining :ref:`initial metadata ` for gRPC-based `ext_authz` :ref:`HTTP ` and :ref:`network ` filters, and :ref:`ratelimit ` filters. -* tracing: added SkyWalking tracer. * hds: added support for delta updates in the :ref:`HealthCheckSpecifier `, making only the Endpoints and Health Checkers that changed be reconstructed on receiving a new message, rather than the entire HDS. * health_check: added option to use :ref:`no_traffic_healthy_interval ` which allows a different no traffic interval when the host is healthy. * mongo_proxy: the list of commands to produce metrics for is now :ref:`configurable `. * ratelimit: added :ref:`disable_x_envoy_ratelimited_header ` option to disable `X-Envoy-RateLimited` header. * tcp: added a new :ref:`envoy.overload_actions.reject_incoming_connections ` action to reject incoming TCP connections. +* tracing: added SkyWalking tracer. Deprecated ---------- From 73a7f2d06a0f8668abfc6427f76f7b3855be229c Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 16 Oct 2020 17:10:11 +0800 Subject: [PATCH 30/61] fix format Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 1 - api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto | 1 - generated_api_shadow/envoy/config/trace/v3/skywalking.proto | 1 - .../envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto | 1 - 4 files changed, 4 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index 615a6e6dd6db1..5fffa8a91161c 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -30,7 +30,6 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 5] message ClientConfig { // Service name for SkyWalking tracer. If service_name is empty, then cluster // name of Envoy will be used as service name. diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index a08a816e88a92..862b7f5ff1dac 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -30,7 +30,6 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 5] message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index 615a6e6dd6db1..5fffa8a91161c 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -30,7 +30,6 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 5] message ClientConfig { // Service name for SkyWalking tracer. If service_name is empty, then cluster // name of Envoy will be used as service name. diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index a08a816e88a92..862b7f5ff1dac 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -30,7 +30,6 @@ message SkyWalkingConfig { } // Client config for SkyWalking tracer. -// [#next-free-field: 5] message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; From 3373ab81c1ce7a069cbb59e37494a8a94831e0bb Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 17 Oct 2020 00:24:26 +0800 Subject: [PATCH 31/61] fix header map get error Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/skywalking_types.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 0d7f37d82c167..d5ccaa7a04cb5 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -43,12 +43,12 @@ std::string base64Decode(absl::string_view input) { SpanContextPtr SpanContext::spanContextFromRequest(Http::RequestHeaderMap& headers) { auto propagation_header = headers.get(propagationHeader()); - if (propagation_header == nullptr) { + if (propagation_header.empty()) { // No propagation header then Envoy is first hop. return nullptr; } - auto header_value_string = propagation_header->value().getStringView(); + auto header_value_string = propagation_header[0]->value().getStringView(); const auto parts = StringUtil::splitToken(header_value_string, "-", false, true); // Reference: // https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. From c58cf8f5af5b850bb03ac8026b41f0a5ae69f78a Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 17 Oct 2020 08:24:07 +0800 Subject: [PATCH 32/61] fix tracer reporter test Signed-off-by: wbpcode --- .../skywalking/trace_segment_reporter_test.cc | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 57d08205b02f8..0b06bbd90142a 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -91,19 +91,18 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); - SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, - "PARENT", mock_time_source_); + SpanStore* parent_store = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "PARENT"); // Parent span store has peer address. parent_store->setPeerAddress("0.0.0.0"); - SpanStore* first_child_sptore = SkyWalkingTestHelper::createSpanStore( - segment_context.get(), parent_store, "CHILD", mock_time_source_); + SpanStore* first_child_sptore = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD"); // Skip reporting the first child span. first_child_sptore->setSampled(0); // Create second child span. - SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", - mock_time_source_); + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD"); EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); @@ -117,8 +116,7 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { // Create a segment context with no previous span context. SegmentContextSharedPtr second_segment_context = SkyWalkingTestHelper::createSegmentContext( true, "SECOND_SEGMENT", "", mock_random_generator_); - SkyWalkingTestHelper::createSpanStore(second_segment_context.get(), nullptr, "PARENT", - mock_time_source_); + SkyWalkingTestHelper::createSpanStore(second_segment_context.get(), nullptr, "PARENT"); EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)); reporter_->report(*second_segment_context); @@ -136,10 +134,9 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithDefaultCache) { ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); - SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, - "PARENT", mock_time_source_); - SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", - mock_time_source_); + SpanStore* parent_store = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "PARENT"); + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD"); EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)).Times(1025); @@ -187,10 +184,9 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithCacheConfig) { ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); - SpanStore* parent_store = SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, - "PARENT", mock_time_source_); - SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD", - mock_time_source_); + SpanStore* parent_store = + SkyWalkingTestHelper::createSpanStore(segment_context.get(), nullptr, "PARENT"); + SkyWalkingTestHelper::createSpanStore(segment_context.get(), parent_store, "CHILD"); EXPECT_CALL(*mock_stream_ptr_, sendMessageRaw_(_, _)).Times(4); From f76ea47a3c475d7793781b54d61c6776f0af9534 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 17 Oct 2020 20:58:09 +0800 Subject: [PATCH 33/61] fix config test Signed-off-by: wbpcode --- test/extensions/tracers/skywalking/config_test.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/test/extensions/tracers/skywalking/config_test.cc b/test/extensions/tracers/skywalking/config_test.cc index 97b44dc2f6f6a..55e72f3619de8 100644 --- a/test/extensions/tracers/skywalking/config_test.cc +++ b/test/extensions/tracers/skywalking/config_test.cc @@ -69,7 +69,6 @@ TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracerWithClientConfig) { authentication: "A fake auth string for SkyWalking test" service_name: "Test Service" instance_name: "Test Instance" - pass_endpoint: true max_cache_size: 2333 )EOF"; envoy::config::trace::v3::Tracing configuration; From 33d9e612b283f11dbf7e08d6ef68531fffe4a8d4 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 17 Oct 2020 22:17:40 +0800 Subject: [PATCH 34/61] Revert "if start child span is set then inject tracing context by child span" This reverts commit 647679e37d9985c3da719dd8c21d68bed3916c26. Signed-off-by: wbpcode --- source/common/router/router.cc | 3 +++ source/common/router/upstream_request.cc | 10 ---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/source/common/router/router.cc b/source/common/router/router.cc index c2e977ed2bb11..739050410f744 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -559,6 +559,9 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers, }; } + // Inject the active span's tracing context into the request headers. + callbacks_->activeSpan().injectContext(headers); + route_entry_->finalizeRequestHeaders(headers, callbacks_->streamInfo(), !config_.suppress_envoy_headers_); FilterUtility::setUpstreamScheme(headers, diff --git a/source/common/router/upstream_request.cc b/source/common/router/upstream_request.cc index 709b55648bd01..b906df34fdc9a 100644 --- a/source/common/router/upstream_request.cc +++ b/source/common/router/upstream_request.cc @@ -61,16 +61,6 @@ UpstreamRequest::UpstreamRequest(RouterFilterInterface& parent, } } - // Inject the current span's tracing context into the request headers. - ASSERT(parent_.downstreamHeaders()); - if (!span_) { - parent_.callbacks()->activeSpan().injectContext(*parent_.downstreamHeaders()); - } else { - // If new child span is created for forward upstream request, then use it to inject tracing - // context to request headers. - span_->injectContext(*parent_.downstreamHeaders()); - } - stream_info_.healthCheck(parent_.callbacks()->streamInfo().healthCheck()); if (conn_pool_->protocol().has_value()) { stream_info_.protocol(conn_pool_->protocol().value()); From 46a82abf4eb101231ea52d334ccd7dcfc1b41934 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 17 Oct 2020 22:55:28 +0800 Subject: [PATCH 35/61] some minor update Signed-off-by: wbpcode --- .../tracers/skywalking/skywalking_types.cc | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index d5ccaa7a04cb5..413f559b248d2 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -108,31 +108,37 @@ SegmentContext::SegmentContext(SpanContextPtr&& previous_span_context, Tracing:: trace_segment_id_ = generateId(random_generator); } -SpanStore* SegmentContext::createSpanStore(const SpanStore* parent_store) { - SpanStorePtr store = std::make_unique(this); - store->setSpanId(span_list_.size()); - if (!parent_store) { - // First span. - store->setSampled(sampled_); - store->setParentSpanId(-1); +SpanStore* SegmentContext::createSpanStore(const SpanStore* parent_span_store) { + SpanStorePtr new_span_store = std::make_unique(this); + new_span_store->setSpanId(span_list_.size()); + if (!parent_span_store) { + // The parent SpanStore object does not exist. Create the root SpanStore object in the current + // segment. + new_span_store->setSampled(sampled_); + new_span_store->setParentSpanId(-1); // First span of current segment for Envoy Proxy must be a Entry Span. It is created for // downstream HTTP request. - store->setAsEntrySpan(true); + new_span_store->setAsEntrySpan(true); } else { - // Child span. - store->setSampled(parent_store->sampled()); - store->setParentSpanId(parent_store->spanId()); - store->setAsEntrySpan(false); + // Create child SpanStore object. + new_span_store->setSampled(parent_span_store->sampled()); + new_span_store->setParentSpanId(parent_span_store->spanId()); + new_span_store->setAsEntrySpan(false); } - SpanStore* ref = store.get(); - span_list_.emplace_back(std::move(store)); + SpanStore* ref = new_span_store.get(); + span_list_.emplace_back(std::move(new_span_store)); return ref; } void SpanStore::injectContext(Http::RequestHeaderMap& request_headers) const { ASSERT(segment_context_); - ASSERT(!is_entry_span_); + // For SkyWalking Entry Span, Envoy does not need to inject tracing context into the request + // headers. + if (is_entry_span_) { + return; + } + const_cast(this)->setPeerAddress(std::string(request_headers.getHostValue())); // Reference: From c63db99ce124e065de3eb359692bb8e116d377a2 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 17 Oct 2020 23:56:32 +0800 Subject: [PATCH 36/61] add some debug log Signed-off-by: wbpcode --- .../tracers/skywalking/skywalking_tracer_impl.cc | 3 ++- .../tracers/skywalking/skywalking_types.cc | 16 ++++++++++++++++ .../tracers/skywalking/skywalking_types.h | 6 +++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index 0c2c2c51d6403..08345e354d7a0 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -58,7 +58,8 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, return tracer.startSpan(config, start_time, operation_name, std::move(segment_context), nullptr); - } catch (const EnvoyException&) { + } catch (const EnvoyException& e) { + ENVOY_LOG(warn, "New SkyWalking Span/Segment cannot be created for error: {}", e.what()); return std::make_unique(); } } diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 413f559b248d2..209b1d9e63b28 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -106,9 +106,18 @@ SegmentContext::SegmentContext(SpanContextPtr&& previous_span_context, Tracing:: sampled_ = decision.traced; } trace_segment_id_ = generateId(random_generator); + + // Some detailed log for debug. + ENVOY_LOG(trace, "{} and create new SkyWalking segment:", + previous_span_context_ ? "Has previous span context" : "No previous span context"); + + ENVOY_LOG(trace, " Trace ID: {}", trace_id_); + ENVOY_LOG(trace, " Segment ID: {}", trace_segment_id_); + ENVOY_LOG(trace, " Sampled: {}", sampled_); } SpanStore* SegmentContext::createSpanStore(const SpanStore* parent_span_store) { + ENVOY_LOG(trace, "Create new SpanStore object for current segment: {}", trace_segment_id_); SpanStorePtr new_span_store = std::make_unique(this); new_span_store->setSpanId(span_list_.size()); if (!parent_span_store) { @@ -136,11 +145,18 @@ void SpanStore::injectContext(Http::RequestHeaderMap& request_headers) const { // For SkyWalking Entry Span, Envoy does not need to inject tracing context into the request // headers. if (is_entry_span_) { + ENVOY_LOG(debug, "Skip tracing context injection for SkyWalking Entry Span"); return; } + ENVOY_LOG(debug, "Inject or update SkyWalking propagation header in upstream request headers"); const_cast(this)->setPeerAddress(std::string(request_headers.getHostValue())); + ENVOY_LOG(trace, "'sw8' header: '({}) - ({}) - ({}) - ({}) - ({}) - ({}) - ({}) - ({})'", + sampled_, segment_context_->traceId(), segment_context_->traceSegmentId(), span_id_, + segment_context_->service(), segment_context_->serviceInstance(), + segment_context_->rootSpanStore()->operation(), peer_address_); + // Reference: // https://github.com/apache/skywalking/blob/v8.1.0/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v3.md. const auto value = absl::StrCat(sampled_, "-", base64Encode(segment_context_->traceId()), "-", diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index 9f43267d9c1d5..90fcbe639e3c3 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -24,7 +24,7 @@ using SpanStorePtr = std::unique_ptr; class SpanContext; using SpanContextPtr = std::unique_ptr; -class SpanContext { +class SpanContext : public Logger::Loggable { public: /* * Parse the context of the previous span from the request and decide whether to sample it or @@ -62,7 +62,7 @@ class SpanContext { SpanContext() = default; }; -class SegmentContext { +class SegmentContext : public Logger::Loggable { public: /* * Create a new segment context based on the previous span context that parsed from request @@ -146,7 +146,7 @@ using Tag = KeyStringValuePair; * object. The new span will hold a pointer to the newly created SpanStore object and write data to * it or get data from it. */ -class SpanStore { +class SpanStore : public Logger::Loggable { public: /* * Construct a SpanStore object using span context and time source. From 57348a3b9a95faff2b87991950018ccbee31af5d Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 20 Oct 2020 14:58:16 +0800 Subject: [PATCH 37/61] make 'authentication' oneof Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 27 ++++--- .../skywalking/v4alpha/skywalking.proto | 27 ++++--- .../envoy/config/trace/v3/skywalking.proto | 27 ++++--- .../skywalking/v4alpha/skywalking.proto | 27 ++++--- source/extensions/tracers/skywalking/BUILD | 15 ++++ .../skywalking/skywalking_client_config.cc | 40 +++++++++ .../skywalking/skywalking_client_config.h | 42 ++++++++++ .../skywalking/skywalking_tracer_impl.cc | 21 ++--- .../skywalking/skywalking_tracer_impl.h | 3 +- .../skywalking/trace_segment_reporter.cc | 23 +++--- .../skywalking/trace_segment_reporter.h | 7 +- test/extensions/tracers/skywalking/BUILD | 14 ++++ .../skywalking_client_config_test.cc | 81 +++++++++++++++++++ .../skywalking/trace_segment_reporter_test.cc | 39 ++++++--- .../tracers/skywalking/tracer_test.cc | 35 +++++--- 15 files changed, 330 insertions(+), 98 deletions(-) create mode 100644 source/extensions/tracers/skywalking/skywalking_client_config.cc create mode 100644 source/extensions/tracers/skywalking/skywalking_client_config.h create mode 100644 test/extensions/tracers/skywalking/skywalking_client_config_test.cc diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index 5fffa8a91161c..3896b392f287a 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -31,20 +31,25 @@ message SkyWalkingConfig { // Client config for SkyWalking tracer. message ClientConfig { - // Service name for SkyWalking tracer. If service_name is empty, then cluster - // name of Envoy will be used as service name. + // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will + // be used as service name. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the - // node name of Envoy will be used as service instance name. + // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy + // will be used as service instance name. string instance_name = 2; - // Authentication token. Set client token if backend open token - // authentication. - string authentication = 3; - - // Envoy caches the segment in memory when the backend service is temporarily - // unavailable. This field specifies the maximum number of segments that can - // be cached. If not specified, the default is 1024. + // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // that monitoring application data can be trusted. In current version, Token is considered as a + // simple string. + // [#comment:TODO(wbpcode): Get authentication through the SDS API.] + oneof authentication_specifier { + // Inline authentication token string. + string authentication = 3; + } + + // Envoy caches the segment in memory when the backend service is temporarily unavailable. This + // field specifies the maximum number of segments that can be cached. If not specified, the + // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 862b7f5ff1dac..90093984866da 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -33,20 +33,25 @@ message SkyWalkingConfig { message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; - // Service name for SkyWalking tracer. If service_name is empty, then cluster - // name of Envoy will be used as service name. + // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will + // be used as service name. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the - // node name of Envoy will be used as service instance name. + // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy + // will be used as service instance name. string instance_name = 2; - // Authentication token. Set client token if backend open token - // authentication. - string authentication = 3; - - // Envoy caches the segment in memory when the backend service is temporarily - // unavailable. This field specifies the maximum number of segments that can - // be cached. If not specified, the default is 1024. + // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // that monitoring application data can be trusted. In current version, Token is considered as a + // simple string. + // [#comment:TODO(wbpcode): Get authentication through the SDS API.] + oneof authentication_specifier { + // Inline authentication token string. + string authentication = 3; + } + + // Envoy caches the segment in memory when the backend service is temporarily unavailable. This + // field specifies the maximum number of segments that can be cached. If not specified, the + // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index 5fffa8a91161c..3896b392f287a 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -31,20 +31,25 @@ message SkyWalkingConfig { // Client config for SkyWalking tracer. message ClientConfig { - // Service name for SkyWalking tracer. If service_name is empty, then cluster - // name of Envoy will be used as service name. + // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will + // be used as service name. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the - // node name of Envoy will be used as service instance name. + // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy + // will be used as service instance name. string instance_name = 2; - // Authentication token. Set client token if backend open token - // authentication. - string authentication = 3; - - // Envoy caches the segment in memory when the backend service is temporarily - // unavailable. This field specifies the maximum number of segments that can - // be cached. If not specified, the default is 1024. + // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // that monitoring application data can be trusted. In current version, Token is considered as a + // simple string. + // [#comment:TODO(wbpcode): Get authentication through the SDS API.] + oneof authentication_specifier { + // Inline authentication token string. + string authentication = 3; + } + + // Envoy caches the segment in memory when the backend service is temporarily unavailable. This + // field specifies the maximum number of segments that can be cached. If not specified, the + // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 862b7f5ff1dac..90093984866da 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -33,20 +33,25 @@ message SkyWalkingConfig { message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; - // Service name for SkyWalking tracer. If service_name is empty, then cluster - // name of Envoy will be used as service name. + // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will + // be used as service name. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the - // node name of Envoy will be used as service instance name. + // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy + // will be used as service instance name. string instance_name = 2; - // Authentication token. Set client token if backend open token - // authentication. - string authentication = 3; - - // Envoy caches the segment in memory when the backend service is temporarily - // unavailable. This field specifies the maximum number of segments that can - // be cached. If not specified, the default is 1024. + // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // that monitoring application data can be trusted. In current version, Token is considered as a + // simple string. + // [#comment:TODO(wbpcode): Get authentication through the SDS API.] + oneof authentication_specifier { + // Inline authentication token string. + string authentication = 3; + } + + // Envoy caches the segment in memory when the backend service is temporarily unavailable. This + // field specifies the maximum number of segments that can be cached. If not specified, the + // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/source/extensions/tracers/skywalking/BUILD b/source/extensions/tracers/skywalking/BUILD index 1275852c7cf11..5cf90c3f976fc 100644 --- a/source/extensions/tracers/skywalking/BUILD +++ b/source/extensions/tracers/skywalking/BUILD @@ -16,6 +16,7 @@ envoy_cc_library( srcs = ["trace_segment_reporter.cc"], hdrs = ["trace_segment_reporter.h"], deps = [ + ":skywalking_client_config_lib", ":skywalking_stats_lib", ":skywalking_types_lib", "//include/envoy/grpc:async_client_manager_interface", @@ -43,6 +44,19 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "skywalking_client_config_lib", + srcs = ["skywalking_client_config.cc"], + hdrs = ["skywalking_client_config.h"], + deps = [ + "//include/envoy/secret:secret_provider_interface", + "//include/envoy/server:factory_context_interface", + "//include/envoy/server:tracer_config_interface", + "//source/common/config:datasource_lib", + "@envoy_api//envoy/config/trace/v3:pkg_cc_proto", + ], +) + envoy_cc_library( name = "skywalking_tracer_lib", srcs = [ @@ -54,6 +68,7 @@ envoy_cc_library( "tracer.h", ], deps = [ + ":skywalking_client_config_lib", ":skywalking_types_lib", ":trace_segment_reporter_lib", "//include/envoy/common:time_interface", diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc new file mode 100644 index 0000000000000..7c5d19a7ad25d --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -0,0 +1,40 @@ +#include "common/config/datasource.h" + +#include "extensions/tracers/skywalking/skywalking_client_config.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +static constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; + +SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFactoryContext& context, + const envoy::config::trace::v3::ClientConfig& config) + : factory_context_(context.serverFactoryContext()) { + + max_cache_size_ = config.has_max_cache_size() ? config.max_cache_size().value() + : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE; + + service_ = config.service_name().empty() ? factory_context_.localInfo().clusterName() + : config.service_name(); + service_instance_ = config.instance_name().empty() ? factory_context_.localInfo().nodeName() + : config.instance_name(); + + if (config.authentication_specifier_case() == + envoy::config::trace::v3::ClientConfig::AuthenticationSpecifierCase::kAuthentication || + config.authentication_specifier_case() == + envoy::config::trace::v3::ClientConfig::AuthenticationSpecifierCase:: + AUTHENTICATION_SPECIFIER_NOT_SET) { + authentication_token_ = config.authentication(); + } +} + +// TODO(wbpcode): currently, authentication token can only be configured with inline string. It +// will be possible to get authentication through the SDS API later. +const std::string& SkyWalkingClientConfig::authentication() const { return authentication_token_; } + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.h b/source/extensions/tracers/skywalking/skywalking_client_config.h new file mode 100644 index 0000000000000..eff47f3d5877f --- /dev/null +++ b/source/extensions/tracers/skywalking/skywalking_client_config.h @@ -0,0 +1,42 @@ +#pragma once + +#include "envoy/config/trace/v3/skywalking.pb.h" +#include "envoy/server/factory_context.h" +#include "envoy/server/tracer_config.h" +#include "envoy/secret/secret_provider.h" + +#include "absl/synchronization/mutex.h" + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class SkyWalkingClientConfig { +public: + SkyWalkingClientConfig(Server::Configuration::TracerFactoryContext& context, + const envoy::config::trace::v3::ClientConfig& config); + + uint32_t maxCacheSize() const { return max_cache_size_; } + + const std::string& service() const { return service_; } + const std::string& serviceInstance() const { return service_instance_; } + + const std::string& authentication() const; + +private: + uint16_t max_cache_size_{0}; + std::string service_; + std::string service_instance_; + + std::string authentication_token_; + + Server::Configuration::ServerFactoryContext& factory_context_; +}; + +using SkyWalkingClientConfigPtr = std::unique_ptr; + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index 08345e354d7a0..2aecf5f15981f 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -17,25 +17,18 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, Server::Configuration::TracerFactoryContext& context) : tracing_stats_{SKYWALKING_TRACER_STATS( POOL_COUNTER_PREFIX(context.serverFactoryContext().scope(), "tracing.skywalking."))}, - client_config_(proto_config.client_config()), + client_config_( + std::make_unique(context, proto_config.client_config())), random_generator_(context.serverFactoryContext().api().randomGenerator()), tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { - auto& factory_context = context.serverFactoryContext(); - if (client_config_.service_name().empty()) { - client_config_.set_service_name(factory_context.localInfo().clusterName()); - } - if (client_config_.instance_name().empty()) { - client_config_.set_instance_name(factory_context.localInfo().nodeName()); - } - - tls_slot_ptr_->set([proto_config, &factory_context, this]( - Event::Dispatcher& dispatcher) -> ThreadLocal::ThreadLocalObjectSharedPtr { + auto& factory_context = context.serverFactoryContext(); + tls_slot_ptr_->set([&proto_config, &factory_context, this](Event::Dispatcher& dispatcher) { TracerPtr tracer = std::make_unique(factory_context.timeSource()); tracer->setReporter(std::make_unique( factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( proto_config.grpc_service(), factory_context.scope(), false), - dispatcher, factory_context.api().randomGenerator(), tracing_stats_, client_config_)); + dispatcher, factory_context.api().randomGenerator(), tracing_stats_, *client_config_)); return std::make_shared(std::move(tracer)); }); } @@ -52,8 +45,8 @@ Tracing::SpanPtr Driver::startSpan(const Tracing::Config& config, decision, random_generator_); // Initialize fields of current span context. - segment_context->setService(client_config_.service_name()); - segment_context->setServiceInstance(client_config_.instance_name()); + segment_context->setService(client_config_->service()); + segment_context->setServiceInstance(client_config_->serviceInstance()); return tracer.startSpan(config, start_time, operation_name, std::move(segment_context), nullptr); diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h index 1930f48ed1d31..f073461deb5d5 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.h +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.h @@ -7,6 +7,7 @@ #include "common/tracing/http_tracer_impl.h" +#include "extensions/tracers/skywalking/skywalking_client_config.h" #include "extensions/tracers/skywalking/tracer.h" namespace Envoy { @@ -32,7 +33,7 @@ class Driver : public Tracing::Driver, public Logger::Loggablecreate()), +TraceSegmentReporter::TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, + Event::Dispatcher& dispatcher, + Random::RandomGenerator& random_generator, + SkyWalkingTracerStats& stats, + const SkyWalkingClientConfig& client_config) + : tracing_stats_(stats), client_config_(client_config), client_(factory->create()), service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName( "TraceSegmentReportService.collect")), random_generator_(random_generator) { - max_delayed_segments_cache_size_ = client_config.has_max_cache_size() - ? client_config.max_cache_size().value() - : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE; - static constexpr uint32_t RetryInitialDelayMs = 500; static constexpr uint32_t RetryMaxDelayMs = 30000; backoff_strategy_ = std::make_unique( @@ -100,8 +95,8 @@ TraceSegmentReporter::TraceSegmentReporter( } void TraceSegmentReporter::onCreateInitialMetadata(Http::RequestHeaderMap& metadata) { - if (!simple_authentication_token_.empty()) { - metadata.setReferenceKey(authenticationTokenKey(), simple_authentication_token_); + if (!client_config_.authentication().empty()) { + metadata.setReferenceKey(authenticationTokenKey(), client_config_.authentication()); } } @@ -120,7 +115,7 @@ void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr&& request) { } // Null stream_ and cache segment data temporarily. delayed_segments_cache_.emplace(std::move(request)); - if (delayed_segments_cache_.size() > max_delayed_segments_cache_size_) { + if (delayed_segments_cache_.size() > client_config_.maxCacheSize()) { tracing_stats_.segments_dropped_.inc(); delayed_segments_cache_.pop(); } diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index 2127d79a9bbdb..d03a74d3deedb 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -9,6 +9,7 @@ #include "common/common/backoff_strategy.h" #include "common/grpc/async_client_impl.h" +#include "extensions/tracers/skywalking/skywalking_client_config.h" #include "extensions/tracers/skywalking/skywalking_stats.h" #include "extensions/tracers/skywalking/skywalking_types.h" @@ -27,7 +28,7 @@ class TraceSegmentReporter : public Logger::Loggable, explicit TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory, Event::Dispatcher& dispatcher, Random::RandomGenerator& random, SkyWalkingTracerStats& stats, - const envoy::config::trace::v3::ClientConfig& client_config); + const SkyWalkingClientConfig& client_config); // Grpc::AsyncStreamCallbacks void onCreateInitialMetadata(Http::RequestHeaderMap& metadata) override; @@ -59,8 +60,8 @@ class TraceSegmentReporter : public Logger::Loggable, SkyWalkingTracerStats& tracing_stats_; - const std::string simple_authentication_token_; - uint32_t max_delayed_segments_cache_size_{0}; + const SkyWalkingClientConfig& client_config_; + Grpc::AsyncClient client_; Grpc::AsyncStream stream_{}; const Protobuf::MethodDescriptor& service_method_; diff --git a/test/extensions/tracers/skywalking/BUILD b/test/extensions/tracers/skywalking/BUILD index 754037ea64a3a..b18f8cfe91dcf 100644 --- a/test/extensions/tracers/skywalking/BUILD +++ b/test/extensions/tracers/skywalking/BUILD @@ -24,6 +24,18 @@ envoy_extension_cc_test( ], ) +envoy_extension_cc_test( + name = "skywalking_client_config_test", + srcs = ["skywalking_client_config_test.cc"], + extension_name = "envoy.tracers.skywalking", + deps = [ + "//source/extensions/tracers/skywalking:skywalking_client_config_lib", + "//test/mocks:common_lib", + "//test/mocks/server:tracer_factory_context_mocks", + "//test/test_common:utility_lib", + ], +) + envoy_extension_cc_test( name = "skywalking_types_test", srcs = ["skywalking_types_test.cc"], @@ -47,6 +59,7 @@ envoy_extension_cc_test( "//test/mocks:common_lib", "//test/mocks/event:event_mocks", "//test/mocks/grpc:grpc_mocks", + "//test/mocks/server:tracer_factory_context_mocks", "//test/mocks/stats:stats_mocks", "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", @@ -75,6 +88,7 @@ envoy_extension_cc_test( "//test/mocks:common_lib", "//test/mocks/event:event_mocks", "//test/mocks/grpc:grpc_mocks", + "//test/mocks/server:tracer_factory_context_mocks", "//test/mocks/stats:stats_mocks", "//test/mocks/upstream:cluster_manager_mocks", "//test/test_common:simulated_time_system_lib", diff --git a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc new file mode 100644 index 0000000000000..a83158b19b975 --- /dev/null +++ b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc @@ -0,0 +1,81 @@ +#include "extensions/tracers/skywalking/skywalking_client_config.h" + +#include "test/mocks/common.h" +#include "test/mocks/server/tracer_factory_context.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace testing; + +namespace Envoy { +namespace Extensions { +namespace Tracers { +namespace SkyWalking { + +class SkyWalkingClientConfigTest : public testing::Test { +public: + void setupSkyWalkingClientConfig(const std::string& yaml_string) { + auto& local_info = context_.server_factory_context_.local_info_; + + ON_CALL(local_info, clusterName()).WillByDefault(ReturnRef(test_string)); + ON_CALL(local_info, nodeName()).WillByDefault(ReturnRef(test_string)); + + envoy::config::trace::v3::SkyWalkingConfig proto_config; + TestUtility::loadFromYaml(yaml_string, proto_config); + + client_config_ = + std::make_unique(context_, proto_config.client_config()); + } + +protected: + NiceMock context_; + + std::string test_string = "ABCDEFGHIJKLMN"; + + SkyWalkingClientConfigPtr client_config_; +}; + +static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + client_config: + authentication: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" + service_name: "FAKE_FAKE_FAKE" + instance_name: "FAKE_FAKE_FAKE" + max_cache_size: 2333 +)EOF"; + +static const std::string SKYWALKING_CONFIG_NO_CLIENT_CONFIG = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster +)EOF"; + +// Test whether the default value can be set correctly when there is no proto client config +// provided. +TEST_F(SkyWalkingClientConfigTest, NoProtoClientConfigTest) { + setupSkyWalkingClientConfig(SKYWALKING_CONFIG_NO_CLIENT_CONFIG); + + EXPECT_EQ(client_config_->service(), test_string); + EXPECT_EQ(client_config_->serviceInstance(), test_string); + EXPECT_EQ(client_config_->maxCacheSize(), 1024); + EXPECT_EQ(client_config_->authentication(), ""); +} + +// Test whether the client config can work correctly when the proto client config is provided. +TEST_F(SkyWalkingClientConfigTest, WithProtoClientConfigTest) { + setupSkyWalkingClientConfig(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); + + EXPECT_EQ(client_config_->service(), "FAKE_FAKE_FAKE"); + EXPECT_EQ(client_config_->serviceInstance(), "FAKE_FAKE_FAKE"); + EXPECT_EQ(client_config_->maxCacheSize(), 2333); + EXPECT_EQ(client_config_->authentication(), "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE"); +} + +} // namespace SkyWalking +} // namespace Tracers +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 0b06bbd90142a..88c86008d38df 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -4,6 +4,7 @@ #include "test/mocks/common.h" #include "test/mocks/event/mocks.h" #include "test/mocks/grpc/mocks.h" +#include "test/mocks/server/tracer_factory_context.h" #include "test/mocks/stats/mocks.h" #include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" @@ -37,18 +38,29 @@ class TraceSegmentReporterTest : public testing::Test { EXPECT_CALL(*mock_client_factory, create()).WillOnce(Return(ByMove(std::move(mock_client)))); EXPECT_CALL(*mock_client_ptr_, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); - TestUtility::loadFromYaml(yaml_string, client_config_); + auto& local_info = context_.server_factory_context_.local_info_; + + ON_CALL(local_info, clusterName()).WillByDefault(ReturnRef(test_string)); + ON_CALL(local_info, nodeName()).WillByDefault(ReturnRef(test_string)); + + envoy::config::trace::v3::ClientConfig proto_client_config; + TestUtility::loadFromYaml(yaml_string, proto_client_config); + client_config_ = std::make_unique(context_, proto_client_config); reporter_ = std::make_unique(std::move(mock_client_factory), mock_dispatcher_, mock_random_generator_, - tracing_stats_, client_config_); + tracing_stats_, *client_config_); } protected: - NiceMock mock_dispatcher_; - NiceMock mock_random_generator_; - NiceMock mock_time_source_; - NiceMock mock_scope_; + NiceMock context_; + + NiceMock& mock_dispatcher_ = context_.server_factory_context_.dispatcher_; + NiceMock& mock_random_generator_ = + context_.server_factory_context_.api_.random_; + Event::GlobalTimeSystem& mock_time_source_ = context_.server_factory_context_.time_system_; + + NiceMock& mock_scope_ = context_.server_factory_context_.scope_; NiceMock* mock_client_ptr_{nullptr}; @@ -57,7 +69,10 @@ class TraceSegmentReporterTest : public testing::Test { NiceMock* timer_; Event::TimerCb timer_cb_; - envoy::config::trace::v3::ClientConfig client_config_; + std::string test_string = "ABCDEFGHIJKLMN"; + + SkyWalkingClientConfigPtr client_config_; + SkyWalkingTracerStats tracing_stats_{ SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))}; TraceSegmentReporterPtr reporter_; @@ -86,9 +101,8 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterNoMetadata) { TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { setupTraceSegmentReporter("{}"); - Event::SimulatedTimeSystem time_system; ON_CALL(mock_random_generator_, random()).WillByDefault(Return(23333)); - ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); + SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); SpanStore* parent_store = @@ -129,9 +143,8 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportTraceSegment) { TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithDefaultCache) { setupTraceSegmentReporter("{}"); - Event::SimulatedTimeSystem time_system; ON_CALL(mock_random_generator_, random()).WillByDefault(Return(23333)); - ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); + SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); SpanStore* parent_store = @@ -179,9 +192,9 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithCacheConfig) { )EOF"; setupTraceSegmentReporter(yaml_string); - Event::SimulatedTimeSystem time_system; + ON_CALL(mock_random_generator_, random()).WillByDefault(Return(23333)); - ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); + SegmentContextSharedPtr segment_context = SkyWalkingTestHelper::createSegmentContext(true, "NEW", "PRE", mock_random_generator_); SpanStore* parent_store = diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index a961f27d2faed..a1f390a87baf0 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -1,7 +1,9 @@ +#include "extensions/tracers/skywalking/skywalking_client_config.h" #include "extensions/tracers/skywalking/tracer.h" #include "test/extensions/tracers/skywalking/skywalking_test_helper.h" #include "test/mocks/common.h" +#include "test/mocks/server/tracer_factory_context.h" #include "test/mocks/stats/mocks.h" #include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/cluster_manager.h" @@ -37,28 +39,45 @@ class TracerTest : public testing::Test { EXPECT_CALL(*mock_client, startRaw(_, _, _, _)).WillOnce(Return(mock_stream_ptr_.get())); EXPECT_CALL(*mock_client_factory, create()).WillOnce(Return(ByMove(std::move(mock_client)))); - TestUtility::loadFromYaml(yaml_string, client_config_); + auto& local_info = context_.server_factory_context_.local_info_; + + ON_CALL(local_info, clusterName()).WillByDefault(ReturnRef(test_string)); + ON_CALL(local_info, nodeName()).WillByDefault(ReturnRef(test_string)); + + envoy::config::trace::v3::ClientConfig proto_client_config; + TestUtility::loadFromYaml(yaml_string, proto_client_config); + client_config_ = std::make_unique(context_, proto_client_config); + tracer_ = std::make_unique(mock_time_source_); tracer_->setReporter(std::make_unique( std::move(mock_client_factory), mock_dispatcher_, mock_random_generator_, tracing_stats_, - client_config_)); + *client_config_)); } protected: NiceMock mock_tracing_config_; - NiceMock mock_dispatcher_; - NiceMock mock_random_generator_; - NiceMock mock_time_source_; - NiceMock mock_scope_; + + NiceMock context_; + + NiceMock& mock_dispatcher_ = context_.server_factory_context_.dispatcher_; + NiceMock& mock_random_generator_ = + context_.server_factory_context_.api_.random_; + Event::GlobalTimeSystem& mock_time_source_ = context_.server_factory_context_.time_system_; + + NiceMock& mock_scope_ = context_.server_factory_context_.scope_; std::unique_ptr> mock_stream_ptr_{nullptr}; NiceMock* timer_; Event::TimerCb timer_cb_; - envoy::config::trace::v3::ClientConfig client_config_; + std::string test_string = "ABCDEFGHIJKLMN"; + + SkyWalkingClientConfigPtr client_config_; + SkyWalkingTracerStats tracing_stats_{ SKYWALKING_TRACER_STATS(POOL_COUNTER_PREFIX(mock_scope_, "tracing.skywalking."))}; + TracerPtr tracer_; }; @@ -67,8 +86,6 @@ class TracerTest : public testing::Test { TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { setupTracer("{}"); EXPECT_CALL(mock_random_generator_, random()).WillRepeatedly(Return(666666)); - Event::SimulatedTimeSystem time_system; - ON_CALL(mock_time_source_, systemTime()).WillByDefault(Return(time_system.systemTime())); // Create a new SegmentContext. SegmentContextSharedPtr segment_context = From 1adcbb28f3b50c5156ec87650314485cb1d79170 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 20 Oct 2020 18:52:22 +0800 Subject: [PATCH 38/61] add docs and fix format Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 7 +++++-- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 7 +++++-- .../envoy/config/trace/v3/skywalking.proto | 7 +++++-- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 7 +++++-- .../tracers/skywalking/skywalking_client_config.cc | 4 ++-- .../tracers/skywalking/skywalking_client_config.h | 2 +- tools/spelling/spelling_dictionary.txt | 1 + 7 files changed, 24 insertions(+), 11 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index 3896b392f287a..ed8460632a4c9 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -20,7 +20,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#protodoc-title: SkyWalking tracer] -// Configuration for the SkyWalking tracer. +// Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the +// provider of http tracer, then +// :ref:`start_child_span ` +// in the router must be set to true to get the correct topology and tracing data. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { // SkyWalking collector service. @@ -39,7 +42,7 @@ message ClientConfig { // will be used as service instance name. string instance_name = 2; - // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. // [#comment:TODO(wbpcode): Get authentication through the SDS API.] diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 90093984866da..4d356f295ae8e 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -17,7 +17,10 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // [#protodoc-title: SkyWalking tracer] -// Configuration for the SkyWalking tracer. +// Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the +// provider of http tracer, then +// :ref:`start_child_span ` +// in the router must be set to true to get the correct topology and tracing data. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { option (udpa.annotations.versioning).previous_message_type = @@ -41,7 +44,7 @@ message ClientConfig { // will be used as service instance name. string instance_name = 2; - // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. // [#comment:TODO(wbpcode): Get authentication through the SDS API.] diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index 3896b392f287a..ed8460632a4c9 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -20,7 +20,10 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#protodoc-title: SkyWalking tracer] -// Configuration for the SkyWalking tracer. +// Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the +// provider of http tracer, then +// :ref:`start_child_span ` +// in the router must be set to true to get the correct topology and tracing data. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { // SkyWalking collector service. @@ -39,7 +42,7 @@ message ClientConfig { // will be used as service instance name. string instance_name = 2; - // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. // [#comment:TODO(wbpcode): Get authentication through the SDS API.] diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 90093984866da..4d356f295ae8e 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -17,7 +17,10 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // [#protodoc-title: SkyWalking tracer] -// Configuration for the SkyWalking tracer. +// Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the +// provider of http tracer, then +// :ref:`start_child_span ` +// in the router must be set to true to get the correct topology and tracing data. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { option (udpa.annotations.versioning).previous_message_type = @@ -41,7 +44,7 @@ message ClientConfig { // will be used as service instance name. string instance_name = 2; - // Authentication token config for SkyWalking. Skywalking can use token authentication to secure + // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. // [#comment:TODO(wbpcode): Get authentication through the SDS API.] diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc index 7c5d19a7ad25d..0d8d53db931bd 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.cc +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -1,7 +1,7 @@ -#include "common/config/datasource.h" - #include "extensions/tracers/skywalking/skywalking_client_config.h" +#include "common/config/datasource.h" + namespace Envoy { namespace Extensions { namespace Tracers { diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.h b/source/extensions/tracers/skywalking/skywalking_client_config.h index eff47f3d5877f..5bf0110b6e7fc 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.h +++ b/source/extensions/tracers/skywalking/skywalking_client_config.h @@ -1,9 +1,9 @@ #pragma once #include "envoy/config/trace/v3/skywalking.pb.h" +#include "envoy/secret/secret_provider.h" #include "envoy/server/factory_context.h" #include "envoy/server/tracer_config.h" -#include "envoy/secret/secret_provider.h" #include "absl/synchronization/mutex.h" diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 5eaaceff978fc..245aefe9f5b98 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -33,6 +33,7 @@ HEXDIG HEXDIGIT LTT OWS +SkyWalking TIDs ceil CHACHA From 9804a03265088555c3d7e1cd8609b19a06effde7 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 21 Oct 2020 10:02:52 +0800 Subject: [PATCH 39/61] add annotations for authentation Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 3 ++- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 3 ++- generated_api_shadow/envoy/config/trace/v3/skywalking.proto | 3 ++- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index ed8460632a4c9..f06475db06ba7 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -7,6 +7,7 @@ import "envoy/config/core/v3/grpc_service.proto"; import "google/protobuf/wrappers.proto"; import "udpa/annotations/migrate.proto"; +import "udpa/annotations/sensitive.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -48,7 +49,7 @@ message ClientConfig { // [#comment:TODO(wbpcode): Get authentication through the SDS API.] oneof authentication_specifier { // Inline authentication token string. - string authentication = 3; + string authentication = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 4d356f295ae8e..8a61573777c99 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -6,6 +6,7 @@ import "envoy/config/core/v4alpha/grpc_service.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/sensitive.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -50,7 +51,7 @@ message ClientConfig { // [#comment:TODO(wbpcode): Get authentication through the SDS API.] oneof authentication_specifier { // Inline authentication token string. - string authentication = 3; + string authentication = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index ed8460632a4c9..f06475db06ba7 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -7,6 +7,7 @@ import "envoy/config/core/v3/grpc_service.proto"; import "google/protobuf/wrappers.proto"; import "udpa/annotations/migrate.proto"; +import "udpa/annotations/sensitive.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -48,7 +49,7 @@ message ClientConfig { // [#comment:TODO(wbpcode): Get authentication through the SDS API.] oneof authentication_specifier { // Inline authentication token string. - string authentication = 3; + string authentication = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 4d356f295ae8e..8a61573777c99 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -6,6 +6,7 @@ import "envoy/config/core/v4alpha/grpc_service.proto"; import "google/protobuf/wrappers.proto"; +import "udpa/annotations/sensitive.proto"; import "udpa/annotations/status.proto"; import "udpa/annotations/versioning.proto"; import "validate/validate.proto"; @@ -50,7 +51,7 @@ message ClientConfig { // [#comment:TODO(wbpcode): Get authentication through the SDS API.] oneof authentication_specifier { // Inline authentication token string. - string authentication = 3; + string authentication = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This From b622945d90301b4ac5769b39ee85870c692df291 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 21 Oct 2020 14:28:19 +0800 Subject: [PATCH 40/61] fix new error after merge master Signed-off-by: wbpcode --- api/bazel/repositories.bzl | 36 +++++++++++++++---- api/bazel/repository_locations.bzl | 2 +- generated_api_shadow/bazel/repositories.bzl | 36 +++++++++++++++---- .../bazel/repository_locations.bzl | 2 +- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index 0c275ef681868..6597c375793f1 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -40,9 +40,8 @@ def api_dependencies(): name = "com_github_openzipkin_zipkinapi", build_file_content = ZIPKINAPI_BUILD_CONTENT, ) - envoy_http_archive( + external_http_archive( name = "com_github_apache_skywalking_data_collect_protocol", - locations = REPOSITORY_LOCATIONS, build_file_content = SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT, ) @@ -108,15 +107,38 @@ go_proto_library( """ SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT = """ -load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library") -cc_proto_library( - name = "protocol_cc_proto", +load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_cc//cc:defs.bzl", "cc_proto_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +proto_library( + name = "protocol", srcs = [ "common/Common.proto", "language-agent/Tracing.proto", ], - default_runtime = "@com_google_protobuf//:protobuf", - protoc = "@com_google_protobuf//:protoc", + visibility = ["//visibility:public"], +) + +py_proto_library( + name = "protocol_py_proto", + srcs = [ + "common/Common.proto", + "language-agent/Tracing.proto", + ], + visibility = ["//visibility:public"], +) + +cc_proto_library( + name = "protocol_cc_proto", + deps = [":protocol"], + visibility = ["//visibility:public"], +) + +go_proto_library( + name = "protocol_go_proto", + proto = ":protocol", visibility = ["//visibility:public"], ) """ diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 35d8e95a8b254..11a129e6291e9 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -96,7 +96,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( sha256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9", strip_prefix = "skywalking-data-collect-protocol-{version}", urls = ["https://github.com/apache/skywalking-data-collect-protocol/archive/v{version}.tar.gz"], - last_updated = "2020-07-29", + release_date = "2020-07-29", use_category = ["api"], ), ) diff --git a/generated_api_shadow/bazel/repositories.bzl b/generated_api_shadow/bazel/repositories.bzl index 0c275ef681868..6597c375793f1 100644 --- a/generated_api_shadow/bazel/repositories.bzl +++ b/generated_api_shadow/bazel/repositories.bzl @@ -40,9 +40,8 @@ def api_dependencies(): name = "com_github_openzipkin_zipkinapi", build_file_content = ZIPKINAPI_BUILD_CONTENT, ) - envoy_http_archive( + external_http_archive( name = "com_github_apache_skywalking_data_collect_protocol", - locations = REPOSITORY_LOCATIONS, build_file_content = SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT, ) @@ -108,15 +107,38 @@ go_proto_library( """ SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT = """ -load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library") -cc_proto_library( - name = "protocol_cc_proto", +load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_cc//cc:defs.bzl", "cc_proto_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +proto_library( + name = "protocol", srcs = [ "common/Common.proto", "language-agent/Tracing.proto", ], - default_runtime = "@com_google_protobuf//:protobuf", - protoc = "@com_google_protobuf//:protoc", + visibility = ["//visibility:public"], +) + +py_proto_library( + name = "protocol_py_proto", + srcs = [ + "common/Common.proto", + "language-agent/Tracing.proto", + ], + visibility = ["//visibility:public"], +) + +cc_proto_library( + name = "protocol_cc_proto", + deps = [":protocol"], + visibility = ["//visibility:public"], +) + +go_proto_library( + name = "protocol_go_proto", + proto = ":protocol", visibility = ["//visibility:public"], ) """ diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 35d8e95a8b254..11a129e6291e9 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -96,7 +96,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( sha256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9", strip_prefix = "skywalking-data-collect-protocol-{version}", urls = ["https://github.com/apache/skywalking-data-collect-protocol/archive/v{version}.tar.gz"], - last_updated = "2020-07-29", + release_date = "2020-07-29", use_category = ["api"], ), ) From 641d5463bae1e00435f70d47b6f141678bb3037f Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 21 Oct 2020 14:30:14 +0800 Subject: [PATCH 41/61] remove skywalking python proto library Signed-off-by: wbpcode --- api/bazel/repositories.bzl | 10 ---------- generated_api_shadow/bazel/repositories.bzl | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index 6597c375793f1..983f15967b285 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -107,7 +107,6 @@ go_proto_library( """ SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT = """ -load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") load("@rules_cc//cc:defs.bzl", "cc_proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") @@ -121,15 +120,6 @@ proto_library( visibility = ["//visibility:public"], ) -py_proto_library( - name = "protocol_py_proto", - srcs = [ - "common/Common.proto", - "language-agent/Tracing.proto", - ], - visibility = ["//visibility:public"], -) - cc_proto_library( name = "protocol_cc_proto", deps = [":protocol"], diff --git a/generated_api_shadow/bazel/repositories.bzl b/generated_api_shadow/bazel/repositories.bzl index 6597c375793f1..983f15967b285 100644 --- a/generated_api_shadow/bazel/repositories.bzl +++ b/generated_api_shadow/bazel/repositories.bzl @@ -107,7 +107,6 @@ go_proto_library( """ SKYWALKING_DATA_COLLECT_PROTOCOL_BUILD_CONTENT = """ -load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") load("@rules_cc//cc:defs.bzl", "cc_proto_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") @@ -121,15 +120,6 @@ proto_library( visibility = ["//visibility:public"], ) -py_proto_library( - name = "protocol_py_proto", - srcs = [ - "common/Common.proto", - "language-agent/Tracing.proto", - ], - visibility = ["//visibility:public"], -) - cc_proto_library( name = "protocol_cc_proto", deps = [":protocol"], From ada59bcdda69c937427b6a87bda655b6935c451f Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 21 Oct 2020 20:56:33 +0800 Subject: [PATCH 42/61] capture value of skywalking proto config Signed-off-by: wbpcode --- source/extensions/tracers/skywalking/skywalking_tracer_impl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc index 2aecf5f15981f..130cbd6a98012 100644 --- a/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc +++ b/source/extensions/tracers/skywalking/skywalking_tracer_impl.cc @@ -23,7 +23,7 @@ Driver::Driver(const envoy::config::trace::v3::SkyWalkingConfig& proto_config, tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()) { auto& factory_context = context.serverFactoryContext(); - tls_slot_ptr_->set([&proto_config, &factory_context, this](Event::Dispatcher& dispatcher) { + tls_slot_ptr_->set([proto_config, &factory_context, this](Event::Dispatcher& dispatcher) { TracerPtr tracer = std::make_unique(factory_context.timeSource()); tracer->setReporter(std::make_unique( factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService( From 0a659b3d24f3e27716c010910c836d0558df540d Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 23 Oct 2020 20:52:23 +0800 Subject: [PATCH 43/61] update some comment and use 'EnvoyProxy' as default service/instance name Signed-off-by: wbpcode --- api/bazel/repository_locations.bzl | 2 +- api/envoy/config/trace/v3/skywalking.proto | 14 ++++++++++---- api/envoy/config/trace/v3/trace.proto | 1 - .../tracers/skywalking/v4alpha/skywalking.proto | 14 ++++++++++---- .../envoy/config/trace/v3/skywalking.proto | 14 ++++++++++---- .../envoy/config/trace/v3/trace.proto | 1 - .../tracers/skywalking/v4alpha/skywalking.proto | 14 ++++++++++---- .../skywalking/skywalking_client_config.cc | 17 ++++++++++++++--- .../tracers/skywalking/skywalking_types.h | 9 ++------- .../skywalking/trace_segment_reporter.cc | 4 +++- .../skywalking/skywalking_client_config_test.cc | 9 +++++++++ .../tracers/skywalking/tracer_test.cc | 14 +++++++------- 12 files changed, 76 insertions(+), 37 deletions(-) diff --git a/api/bazel/repository_locations.bzl b/api/bazel/repository_locations.bzl index 11a129e6291e9..d72069046b85b 100644 --- a/api/bazel/repository_locations.bzl +++ b/api/bazel/repository_locations.bzl @@ -90,7 +90,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( ), com_github_apache_skywalking_data_collect_protocol = dict( project_name = "SkyWalking API", - project_desc = "SkyWalking's language independent model and GRPC Api Definitions", + project_desc = "SkyWalking's language independent model and gRPC API Definitions", project_url = "https://github.com/apache/skywalking-data-collect-protocol", version = "8.1.0", sha256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9", diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index f06475db06ba7..ead4ea3979f9b 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -35,12 +35,18 @@ message SkyWalkingConfig { // Client config for SkyWalking tracer. message ClientConfig { - // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will - // be used as service name. + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line + // option :option:`--service-cluster` will be used. If both this field and local service cluster + // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy - // will be used as service instance name. + // Service instance name for SkyWalking tracer. If this field is empty, then local service node + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, + // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure diff --git a/api/envoy/config/trace/v3/trace.proto b/api/envoy/config/trace/v3/trace.proto index 0ee8df2de31d5..e1db72a2fd5a0 100644 --- a/api/envoy/config/trace/v3/trace.proto +++ b/api/envoy/config/trace/v3/trace.proto @@ -10,7 +10,6 @@ import public "envoy/config/trace/v3/http_tracer.proto"; import public "envoy/config/trace/v3/lightstep.proto"; import public "envoy/config/trace/v3/opencensus.proto"; import public "envoy/config/trace/v3/service.proto"; -import public "envoy/config/trace/v3/skywalking.proto"; import public "envoy/config/trace/v3/zipkin.proto"; option java_package = "io.envoyproxy.envoy.config.trace.v3"; diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 8a61573777c99..8aa405c5361a1 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -37,12 +37,18 @@ message SkyWalkingConfig { message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; - // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will - // be used as service name. + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line + // option :option:`--service-cluster` will be used. If both this field and local service cluster + // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy - // will be used as service instance name. + // Service instance name for SkyWalking tracer. If this field is empty, then local service node + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, + // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index f06475db06ba7..ead4ea3979f9b 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -35,12 +35,18 @@ message SkyWalkingConfig { // Client config for SkyWalking tracer. message ClientConfig { - // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will - // be used as service name. + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line + // option :option:`--service-cluster` will be used. If both this field and local service cluster + // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy - // will be used as service instance name. + // Service instance name for SkyWalking tracer. If this field is empty, then local service node + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, + // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure diff --git a/generated_api_shadow/envoy/config/trace/v3/trace.proto b/generated_api_shadow/envoy/config/trace/v3/trace.proto index 0ee8df2de31d5..e1db72a2fd5a0 100644 --- a/generated_api_shadow/envoy/config/trace/v3/trace.proto +++ b/generated_api_shadow/envoy/config/trace/v3/trace.proto @@ -10,7 +10,6 @@ import public "envoy/config/trace/v3/http_tracer.proto"; import public "envoy/config/trace/v3/lightstep.proto"; import public "envoy/config/trace/v3/opencensus.proto"; import public "envoy/config/trace/v3/service.proto"; -import public "envoy/config/trace/v3/skywalking.proto"; import public "envoy/config/trace/v3/zipkin.proto"; option java_package = "io.envoyproxy.envoy.config.trace.v3"; diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 8a61573777c99..8aa405c5361a1 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -37,12 +37,18 @@ message SkyWalkingConfig { message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; - // Service name for SkyWalking tracer. If service_name is empty, then cluster name of Envoy will - // be used as service name. + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line + // option :option:`--service-cluster` will be used. If both this field and local service cluster + // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; - // Service instance name for SkyWalking tracer. If instance_name is empty, the node name of Envoy - // will be used as service instance name. + // Service instance name for SkyWalking tracer. If this field is empty, then local service node + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, + // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc index 0d8d53db931bd..3a3bcd88aed1c 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.cc +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -9,6 +9,11 @@ namespace SkyWalking { static constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; +// When the user does not provide any available configuration, in order to ensure that the service +// name and instance name are not empty, use this value as the default identifier. In practice, +// user should provide accurate configuration as much as possible to avoid using the default value. +static constexpr char DEFAULT_SERVICE_AND_INSTANCE[] = "EnvoyProxy"; + SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFactoryContext& context, const envoy::config::trace::v3::ClientConfig& config) : factory_context_(context.serverFactoryContext()) { @@ -16,10 +21,16 @@ SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFact max_cache_size_ = config.has_max_cache_size() ? config.max_cache_size().value() : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE; - service_ = config.service_name().empty() ? factory_context_.localInfo().clusterName() + service_ = config.service_name().empty() ? factory_context_.localInfo().clusterName().empty() + ? DEFAULT_SERVICE_AND_INSTANCE + : factory_context_.localInfo().clusterName() : config.service_name(); - service_instance_ = config.instance_name().empty() ? factory_context_.localInfo().nodeName() - : config.instance_name(); + + service_instance_ = config.instance_name().empty() + ? factory_context_.localInfo().nodeName().empty() + ? DEFAULT_SERVICE_AND_INSTANCE + : factory_context_.localInfo().nodeName() + : config.instance_name(); if (config.authentication_specifier_case() == envoy::config::trace::v3::ClientConfig::AuthenticationSpecifierCase::kAuthentication || diff --git a/source/extensions/tracers/skywalking/skywalking_types.h b/source/extensions/tracers/skywalking/skywalking_types.h index 90fcbe639e3c3..eacd9a94a0759 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.h +++ b/source/extensions/tracers/skywalking/skywalking_types.h @@ -138,7 +138,7 @@ class SegmentContext : public Logger::Loggable { std::vector span_list_; }; -using Tag = KeyStringValuePair; +using Tag = std::pair; /* * A helper class for the SkyWalking span and is used to store all span-related data, including span @@ -252,12 +252,7 @@ class SpanStore : public Logger::Loggable { /* * Add a new tag entry to current span. */ - void addTag(absl::string_view name, absl::string_view value) { - Tag tag; - tag.set_key(name.data(), name.size()); - tag.set_value(value.data(), value.size()); - tags_.emplace_back(std::move(tag)); - } + void addTag(absl::string_view name, absl::string_view value) { tags_.emplace_back(name, value); } /* * Add a new log entry to current span. Due to different data formats, log is temporarily not diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index d8c7e9acbebfd..ce8a499eafd60 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -52,7 +52,9 @@ TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { tags.Reserve(span_store->tags().size()); for (auto& span_tag : span_store->tags()) { - tags.Add(std::move(const_cast(span_tag))); + KeyStringValuePair* new_tag = tags.Add(); + new_tag->set_key(span_tag.first); + new_tag->set_value(span_tag.second); } SpanContext* previous_span_context = segment_context.previousSpanContext(); diff --git a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc index a83158b19b975..9891661bfc4c7 100644 --- a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc @@ -75,6 +75,15 @@ TEST_F(SkyWalkingClientConfigTest, WithProtoClientConfigTest) { EXPECT_EQ(client_config_->authentication(), "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE"); } +// Test whether the client config can get default value for service name and instance name. +TEST_F(SkyWalkingClientConfigTest, BothLocalInfoAndClientConfigEmptyTest) { + test_string = ""; + setupSkyWalkingClientConfig(SKYWALKING_CONFIG_NO_CLIENT_CONFIG); + + EXPECT_EQ(client_config_->service(), "EnvoyProxy"); + EXPECT_EQ(client_config_->serviceInstance(), "EnvoyProxy"); +} + } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index a1f390a87baf0..dbf24b4eaa411 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -114,24 +114,24 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { // Test whether the tag can be set correctly. span->setTag("TestTagKeyA", "TestTagValueA"); span->setTag("TestTagKeyB", "TestTagValueB"); - EXPECT_EQ("TestTagValueA", span->spanStore()->tags().at(0).value()); - EXPECT_EQ("TestTagValueB", span->spanStore()->tags().at(1).value()); + EXPECT_EQ("TestTagValueA", span->spanStore()->tags().at(0).second); + EXPECT_EQ("TestTagValueB", span->spanStore()->tags().at(1).second); // When setting the status code tag, the corresponding tag name will be rewritten as // 'status_code'. span->setTag(Tracing::Tags::get().HttpStatusCode, "200"); - EXPECT_EQ("status_code", span->spanStore()->tags().at(2).key()); - EXPECT_EQ("200", span->spanStore()->tags().at(2).value()); + EXPECT_EQ("status_code", span->spanStore()->tags().at(2).first); + EXPECT_EQ("200", span->spanStore()->tags().at(2).second); // When setting the error tag, the SpanStore object will also mark itself as an error. span->setTag(Tracing::Tags::get().Error, Tracing::Tags::get().True); - EXPECT_EQ(Tracing::Tags::get().Error, span->spanStore()->tags().at(3).key()); - EXPECT_EQ(Tracing::Tags::get().True, span->spanStore()->tags().at(3).value()); + EXPECT_EQ(Tracing::Tags::get().Error, span->spanStore()->tags().at(3).first); + EXPECT_EQ(Tracing::Tags::get().True, span->spanStore()->tags().at(3).second); EXPECT_EQ(true, span->spanStore()->isError()); // When setting http url tag, the corresponding tag name will be rewritten as 'url'. span->setTag(Tracing::Tags::get().HttpUrl, "http://test.com/test/path"); - EXPECT_EQ("url", span->spanStore()->tags().at(4).key()); + EXPECT_EQ("url", span->spanStore()->tags().at(4).first); Envoy::Tracing::SpanPtr org_first_child_span = span->spawnChild(mock_tracing_config_, "TestChild", mock_time_source_.systemTime()); From c3fa2d95c645506da200ac7e12fd2e62d0ac9b32 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sat, 24 Oct 2020 13:28:28 +0800 Subject: [PATCH 44/61] rename authentication to backend token Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 18 +++++++++--------- .../skywalking/v4alpha/skywalking.proto | 18 +++++++++--------- .../bazel/repository_locations.bzl | 2 +- .../envoy/config/trace/v3/skywalking.proto | 18 +++++++++--------- .../skywalking/v4alpha/skywalking.proto | 18 +++++++++--------- .../skywalking/skywalking_client_config.cc | 18 +++++++++--------- .../skywalking/skywalking_client_config.h | 4 ++-- .../skywalking/trace_segment_reporter.cc | 4 ++-- .../tracers/skywalking/config_test.cc | 2 +- .../skywalking_client_config_test.cc | 6 +++--- .../skywalking/skywalking_tracer_impl_test.cc | 2 +- .../skywalking/trace_segment_reporter_test.cc | 2 +- 12 files changed, 56 insertions(+), 56 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index ead4ea3979f9b..d44bbf5d1dde4 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -35,27 +35,27 @@ message SkyWalkingConfig { // Client config for SkyWalking tracer. message ClientConfig { - // Service name for SkyWalking tracer. If this field is empty, then local service cluster name - // that configured by :ref:`Bootstrap node ` - // message's :ref:`cluster ` field or command line + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line // option :option:`--service-cluster` will be used. If both this field and local service cluster // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; // Service instance name for SkyWalking tracer. If this field is empty, then local service node - // that configured by :ref:`Bootstrap node ` - // message's :ref:`id ` field or command line option - // :option:`--service-node` will be used. If both this field and local service node are empty, + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. - // [#comment:TODO(wbpcode): Get authentication through the SDS API.] - oneof authentication_specifier { + // [#comment:TODO(wbpcode): Get backend token through the SDS API.] + oneof backend_token_specifier { // Inline authentication token string. - string authentication = 3 [(udpa.annotations.sensitive) = true]; + string backend_token = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 8aa405c5361a1..525e6d9fc9f25 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -37,27 +37,27 @@ message SkyWalkingConfig { message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; - // Service name for SkyWalking tracer. If this field is empty, then local service cluster name - // that configured by :ref:`Bootstrap node ` - // message's :ref:`cluster ` field or command line + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line // option :option:`--service-cluster` will be used. If both this field and local service cluster // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; // Service instance name for SkyWalking tracer. If this field is empty, then local service node - // that configured by :ref:`Bootstrap node ` - // message's :ref:`id ` field or command line option - // :option:`--service-node` will be used. If both this field and local service node are empty, + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. - // [#comment:TODO(wbpcode): Get authentication through the SDS API.] - oneof authentication_specifier { + // [#comment:TODO(wbpcode): Get backend token through the SDS API.] + oneof backend_token_specifier { // Inline authentication token string. - string authentication = 3 [(udpa.annotations.sensitive) = true]; + string backend_token = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/generated_api_shadow/bazel/repository_locations.bzl b/generated_api_shadow/bazel/repository_locations.bzl index 11a129e6291e9..d72069046b85b 100644 --- a/generated_api_shadow/bazel/repository_locations.bzl +++ b/generated_api_shadow/bazel/repository_locations.bzl @@ -90,7 +90,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( ), com_github_apache_skywalking_data_collect_protocol = dict( project_name = "SkyWalking API", - project_desc = "SkyWalking's language independent model and GRPC Api Definitions", + project_desc = "SkyWalking's language independent model and gRPC API Definitions", project_url = "https://github.com/apache/skywalking-data-collect-protocol", version = "8.1.0", sha256 = "ebea8a6968722524d1bcc4426fb6a29907ddc2902aac7de1559012d3eee90cf9", diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index ead4ea3979f9b..d44bbf5d1dde4 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -35,27 +35,27 @@ message SkyWalkingConfig { // Client config for SkyWalking tracer. message ClientConfig { - // Service name for SkyWalking tracer. If this field is empty, then local service cluster name - // that configured by :ref:`Bootstrap node ` - // message's :ref:`cluster ` field or command line + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line // option :option:`--service-cluster` will be used. If both this field and local service cluster // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; // Service instance name for SkyWalking tracer. If this field is empty, then local service node - // that configured by :ref:`Bootstrap node ` - // message's :ref:`id ` field or command line option - // :option:`--service-node` will be used. If both this field and local service node are empty, + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. - // [#comment:TODO(wbpcode): Get authentication through the SDS API.] - oneof authentication_specifier { + // [#comment:TODO(wbpcode): Get backend token through the SDS API.] + oneof backend_token_specifier { // Inline authentication token string. - string authentication = 3 [(udpa.annotations.sensitive) = true]; + string backend_token = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 8aa405c5361a1..525e6d9fc9f25 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -37,27 +37,27 @@ message SkyWalkingConfig { message ClientConfig { option (udpa.annotations.versioning).previous_message_type = "envoy.config.trace.v3.ClientConfig"; - // Service name for SkyWalking tracer. If this field is empty, then local service cluster name - // that configured by :ref:`Bootstrap node ` - // message's :ref:`cluster ` field or command line + // Service name for SkyWalking tracer. If this field is empty, then local service cluster name + // that configured by :ref:`Bootstrap node ` + // message's :ref:`cluster ` field or command line // option :option:`--service-cluster` will be used. If both this field and local service cluster // name are empty, ``EnvoyProxy`` is used as the service name by default. string service_name = 1; // Service instance name for SkyWalking tracer. If this field is empty, then local service node - // that configured by :ref:`Bootstrap node ` - // message's :ref:`id ` field or command line option - // :option:`--service-node` will be used. If both this field and local service node are empty, + // that configured by :ref:`Bootstrap node ` + // message's :ref:`id ` field or command line option + // :option:`--service-node` will be used. If both this field and local service node are empty, // ``EnvoyProxy`` is used as the instance name by default. string instance_name = 2; // Authentication token config for SkyWalking. SkyWalking can use token authentication to secure // that monitoring application data can be trusted. In current version, Token is considered as a // simple string. - // [#comment:TODO(wbpcode): Get authentication through the SDS API.] - oneof authentication_specifier { + // [#comment:TODO(wbpcode): Get backend token through the SDS API.] + oneof backend_token_specifier { // Inline authentication token string. - string authentication = 3 [(udpa.annotations.sensitive) = true]; + string backend_token = 3 [(udpa.annotations.sensitive) = true]; } // Envoy caches the segment in memory when the backend service is temporarily unavailable. This diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc index 3a3bcd88aed1c..a964f2b6fd00e 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.cc +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -32,18 +32,18 @@ SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFact : factory_context_.localInfo().nodeName() : config.instance_name(); - if (config.authentication_specifier_case() == - envoy::config::trace::v3::ClientConfig::AuthenticationSpecifierCase::kAuthentication || - config.authentication_specifier_case() == - envoy::config::trace::v3::ClientConfig::AuthenticationSpecifierCase:: - AUTHENTICATION_SPECIFIER_NOT_SET) { - authentication_token_ = config.authentication(); + if (config.backend_token_specifier_case() == + envoy::config::trace::v3::ClientConfig::BackendTokenSpecifierCase::kBackendToken || + config.backend_token_specifier_case() == + envoy::config::trace::v3::ClientConfig::BackendTokenSpecifierCase:: + BACKEND_TOKEN_SPECIFIER_NOT_SET) { + backend_token_ = config.backend_token(); } } -// TODO(wbpcode): currently, authentication token can only be configured with inline string. It -// will be possible to get authentication through the SDS API later. -const std::string& SkyWalkingClientConfig::authentication() const { return authentication_token_; } +// TODO(wbpcode): currently, backend authentication token can only be configured with inline string. +// It will be possible to get authentication through the SDS API later. +const std::string& SkyWalkingClientConfig::backendToken() const { return backend_token_; } } // namespace SkyWalking } // namespace Tracers diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.h b/source/extensions/tracers/skywalking/skywalking_client_config.h index 5bf0110b6e7fc..59abc1b28dba0 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.h +++ b/source/extensions/tracers/skywalking/skywalking_client_config.h @@ -22,14 +22,14 @@ class SkyWalkingClientConfig { const std::string& service() const { return service_; } const std::string& serviceInstance() const { return service_instance_; } - const std::string& authentication() const; + const std::string& backendToken() const; private: uint16_t max_cache_size_{0}; std::string service_; std::string service_instance_; - std::string authentication_token_; + std::string backend_token_; Server::Configuration::ServerFactoryContext& factory_context_; }; diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index ce8a499eafd60..a75b8df6dd70f 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -97,8 +97,8 @@ TraceSegmentReporter::TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory } void TraceSegmentReporter::onCreateInitialMetadata(Http::RequestHeaderMap& metadata) { - if (!client_config_.authentication().empty()) { - metadata.setReferenceKey(authenticationTokenKey(), client_config_.authentication()); + if (!client_config_.backendToken().empty()) { + metadata.setReferenceKey(authenticationTokenKey(), client_config_.backendToken()); } } diff --git a/test/extensions/tracers/skywalking/config_test.cc b/test/extensions/tracers/skywalking/config_test.cc index 55e72f3619de8..856b10b007a4b 100644 --- a/test/extensions/tracers/skywalking/config_test.cc +++ b/test/extensions/tracers/skywalking/config_test.cc @@ -66,7 +66,7 @@ TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracerWithClientConfig) { envoy_grpc: cluster_name: fake_cluster client_config: - authentication: "A fake auth string for SkyWalking test" + backend_token: "A fake auth string for SkyWalking test" service_name: "Test Service" instance_name: "Test Instance" max_cache_size: 2333 diff --git a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc index 9891661bfc4c7..252a0a700f530 100644 --- a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc @@ -42,7 +42,7 @@ static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( envoy_grpc: cluster_name: fake_cluster client_config: - authentication: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" + backend_token: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" service_name: "FAKE_FAKE_FAKE" instance_name: "FAKE_FAKE_FAKE" max_cache_size: 2333 @@ -62,7 +62,7 @@ TEST_F(SkyWalkingClientConfigTest, NoProtoClientConfigTest) { EXPECT_EQ(client_config_->service(), test_string); EXPECT_EQ(client_config_->serviceInstance(), test_string); EXPECT_EQ(client_config_->maxCacheSize(), 1024); - EXPECT_EQ(client_config_->authentication(), ""); + EXPECT_EQ(client_config_->backendToken(), ""); } // Test whether the client config can work correctly when the proto client config is provided. @@ -72,7 +72,7 @@ TEST_F(SkyWalkingClientConfigTest, WithProtoClientConfigTest) { EXPECT_EQ(client_config_->service(), "FAKE_FAKE_FAKE"); EXPECT_EQ(client_config_->serviceInstance(), "FAKE_FAKE_FAKE"); EXPECT_EQ(client_config_->maxCacheSize(), 2333); - EXPECT_EQ(client_config_->authentication(), "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE"); + EXPECT_EQ(client_config_->backendToken(), "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE"); } // Test whether the client config can get default value for service name and instance name. diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index caf93882eb851..2f902346fa7b0 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -57,7 +57,7 @@ static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( envoy_grpc: cluster_name: fake_cluster client_config: - authentication: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" + backend_token: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" service_name: "FAKE_FAKE_FAKE" instance_name: "FAKE_FAKE_FAKE" max_cache_size: 2333 diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 88c86008d38df..53aaeeae6f2e5 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -81,7 +81,7 @@ class TraceSegmentReporterTest : public testing::Test { // Test whether the reporter can correctly add metadata according to the configuration. TEST_F(TraceSegmentReporterTest, TraceSegmentReporterInitialMetadata) { const std::string yaml_string = R"EOF( - authentication: "FakeStringForAuthenticaion" + backend_token: "FakeStringForAuthenticaion" )EOF"; setupTraceSegmentReporter(yaml_string); From 69d7dd1ed092ee4ef621e00a30f5d094e0bc4b12 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 25 Oct 2020 12:57:04 +0800 Subject: [PATCH 45/61] update sandbox Signed-off-by: wbpcode --- .../start/sandboxes/skywalking_tracing.rst | 26 ++++++++---- .../skywalking-tracing/docker-compose.yaml | 40 ++++++++----------- examples/skywalking-tracing/verify.sh | 7 ++++ 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/docs/root/start/sandboxes/skywalking_tracing.rst b/docs/root/start/sandboxes/skywalking_tracing.rst index 64d76cb836d00..70b4e5b17a01f 100644 --- a/docs/root/start/sandboxes/skywalking_tracing.rst +++ b/docs/root/start/sandboxes/skywalking_tracing.rst @@ -37,14 +37,14 @@ To build this sandbox example, and start the example apps run the following comm $ docker-compose up --build -d $ docker-compose ps - Name Command State Ports - --------------------------------------------------------------------------------------------------------------------------------------------- - elasticsearch /tini -- /usr/local/bin/do ... Up (healthy) 0.0.0.0:9200->9200/tcp, 9300/tcp - oap bash docker-entrypoint.sh Up (healthy) 0.0.0.0:11800->11800/tcp, 1234/tcp, 0.0.0.0:12800->12800/tcp - skywalking-tracing_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp - skywalking-tracing_service1_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp - skywalking-tracing_service2_1 /bin/sh -c /usr/local/bin/ ... Up 10000/tcp, 8000/tcp - ui bash docker-entrypoint.sh Up 0.0.0.0:8080->8080/tcp + Name Command State Ports + -------------------------------------------------------------------------------------------------------------------------------------------------- + skywalking-tracing_elasticsearch_1 /tini -- /usr/local/bin/do ... Up (healthy) 0.0.0.0:9200->9200/tcp, 9300/tcp + skywalking-tracing_front-envoy_1 /docker-entrypoint.sh /bin ... Up 10000/tcp, 0.0.0.0:8000->8000/tcp, 0.0.0.0:8001->8001/tcp + skywalking-tracing_service1_1 /bin/sh /usr/local/bin/sta ... Up 10000/tcp + skywalking-tracing_service2_1 /bin/sh /usr/local/bin/sta ... Up 10000/tcp + skywalking-tracing_skywalking-oap_1 bash docker-entrypoint.sh Up (healthy) 0.0.0.0:11800->11800/tcp, 1234/tcp, 0.0.0.0:12800->12800/tcp + skywalking-tracing_skywalking-ui_1 bash docker-entrypoint.sh Up 0.0.0.0:8080->8080/tcp Step 4: Generate some load ************************** @@ -72,6 +72,16 @@ You can now send a request to service1 via the front-envoy as follows: Hello from behind Envoy (service 1)! hostname: 1a2ba43d6d84 resolvedhostname: 172.19.0.6 * Connection #0 to host localhost left intact +You can get SkyWalking stats of front-envoy after some requests as follows: + +.. code-block:: console + + $ curl -s localhost:8001/stats | grep tracing.skywalking + tracing.skywalking.cache_flushed: 0 + tracing.skywalking.segments_dropped: 0 + tracing.skywalking.segments_flushed: 0 + tracing.skywalking.segments_sent: 13 + Step 5: View the traces in SkyWalking UI **************************************** diff --git a/examples/skywalking-tracing/docker-compose.yaml b/examples/skywalking-tracing/docker-compose.yaml index 9fe9396719418..d4376d0c70513 100644 --- a/examples/skywalking-tracing/docker-compose.yaml +++ b/examples/skywalking-tracing/docker-compose.yaml @@ -1,21 +1,19 @@ version: "3.7" services: - # Front envoy. front-envoy: build: context: . dockerfile: Dockerfile-frontenvoy + restart: on-failure:3 networks: - envoymesh - expose: - - "8000" - - "8001" ports: - "8000:8000" - "8001:8001" depends_on: - - skywalking-oap + skywalking-oap: + condition: service_healthy # First service. service1: build: @@ -27,30 +25,28 @@ services: - envoymesh environment: - SERVICE_NAME=1 - expose: - - "8000" + restart: on-failure:3 depends_on: - - skywalking-oap + skywalking-oap: + condition: service_healthy # Second service. service2: build: context: ../front-proxy dockerfile: Dockerfile-service + restart: on-failure:3 volumes: - ./service2-envoy-skywalking.yaml:/etc/service-envoy.yaml networks: - envoymesh environment: - SERVICE_NAME=2 - expose: - - "8000" depends_on: - - skywalking-oap + skywalking-oap: + condition: service_healthy # Skywalking components. elasticsearch: image: elasticsearch:7.9.2 - container_name: elasticsearch - restart: always networks: - envoymesh ports: @@ -61,52 +57,48 @@ services: timeout: 10s retries: 3 start_period: 40s + restart: on-failure:3 environment: discovery.type: single-node - expose: - - "9200" ulimits: memlock: soft: -1 hard: -1 skywalking-oap: image: apache/skywalking-oap-server:8.1.0-es7 - container_name: oap networks: - envoymesh depends_on: - - elasticsearch + elasticsearch: + condition: service_healthy links: - elasticsearch - restart: always ports: - 11800:11800 - 12800:12800 environment: SW_STORAGE: elasticsearch7 SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200 - expose: - - "11800" - - "12800" healthcheck: test: ["CMD-SHELL", "/skywalking/bin/swctl"] interval: 30s timeout: 10s retries: 3 start_period: 40s + restart: on-failure:3 skywalking-ui: image: apache/skywalking-ui:8.1.0 - container_name: ui networks: - envoymesh depends_on: - - skywalking-oap + skywalking-oap: + condition: service_healthy links: - skywalking-oap - restart: always ports: - 8080:8080 environment: SW_OAP_ADDRESS: skywalking-oap:12800 + restart: on-failure:3 networks: envoymesh: {} diff --git a/examples/skywalking-tracing/verify.sh b/examples/skywalking-tracing/verify.sh index c0bc2f9b51fc9..e0e8a9f96e252 100755 --- a/examples/skywalking-tracing/verify.sh +++ b/examples/skywalking-tracing/verify.sh @@ -10,3 +10,10 @@ run_log "Test connection" responds_with \ "Hello from behind Envoy (service 1)!" \ http://localhost:8000/trace/1 + +run_log "Test stats" +# Waiting SkyWalking server to be ready. +sleep 20 +responds_with \ + "tracing.skywalking.segments_sent: 1" \ + http://localhost:8001/stats From 998c8a1ddc4cbd980d0ffaefac6070d2846c5d76 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 25 Oct 2020 12:57:22 +0800 Subject: [PATCH 46/61] update comment Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 4 ++-- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 4 ++-- generated_api_shadow/envoy/config/trace/v3/skywalking.proto | 4 ++-- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index d44bbf5d1dde4..c9e1891ee7491 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -58,8 +58,8 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the backend service is temporarily unavailable. This - // field specifies the maximum number of segments that can be cached. If not specified, the + // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 525e6d9fc9f25..15392df8a7a6b 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -60,8 +60,8 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the backend service is temporarily unavailable. This - // field specifies the maximum number of segments that can be cached. If not specified, the + // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index d44bbf5d1dde4..c9e1891ee7491 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -58,8 +58,8 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the backend service is temporarily unavailable. This - // field specifies the maximum number of segments that can be cached. If not specified, the + // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 525e6d9fc9f25..15392df8a7a6b 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -60,8 +60,8 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the backend service is temporarily unavailable. This - // field specifies the maximum number of segments that can be cached. If not specified, the + // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; } From fbc6b9300559d0986b4f676003c468ea33663deb Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 26 Oct 2020 00:06:58 +0800 Subject: [PATCH 47/61] add skywalking traceing to sandoxes docs tree Signed-off-by: wbpcode --- docs/root/start/sandboxes/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/root/start/sandboxes/index.rst b/docs/root/start/sandboxes/index.rst index 859145972cd42..13bca28adb576 100644 --- a/docs/root/start/sandboxes/index.rst +++ b/docs/root/start/sandboxes/index.rst @@ -27,3 +27,4 @@ features. The following sandboxes are available: redis wasm-cc zipkin_tracing + skywalking_tracing From 056c4598cc58e018fb860c8046ef6df8ac1db4dc Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 26 Oct 2020 08:04:58 +0800 Subject: [PATCH 48/61] fix format error Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 2 +- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 2 +- generated_api_shadow/envoy/config/trace/v3/skywalking.proto | 2 +- .../extensions/tracers/skywalking/v4alpha/skywalking.proto | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index c9e1891ee7491..6b42ec3e5fe89 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -58,7 +58,7 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // Envoy caches the segment in memory when the SkyWalking backend service is temporarily unavailable. // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 15392df8a7a6b..35d05c1c53cae 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -60,7 +60,7 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // Envoy caches the segment in memory when the SkyWalking backend service is temporarily unavailable. // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index c9e1891ee7491..6b42ec3e5fe89 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -58,7 +58,7 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // Envoy caches the segment in memory when the SkyWalking backend service is temporarily unavailable. // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 15392df8a7a6b..35d05c1c53cae 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -60,7 +60,7 @@ message ClientConfig { string backend_token = 3 [(udpa.annotations.sensitive) = true]; } - // Envoy caches the segment in memory when the SkyWakking backend service is temporarily unavailable. + // Envoy caches the segment in memory when the SkyWalking backend service is temporarily unavailable. // This field specifies the maximum number of segments that can be cached. If not specified, the // default is 1024. google.protobuf.UInt32Value max_cache_size = 4; From 82ef1fe0bfdcf1b95000e53f767bbc09c4e131cd Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 26 Oct 2020 20:40:35 +0800 Subject: [PATCH 49/61] remove depends_on.condition and add 60s delay in verify.sh Signed-off-by: wbpcode --- .../skywalking-tracing/docker-compose.yaml | 21 +++++-------------- examples/skywalking-tracing/verify.sh | 4 ++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/examples/skywalking-tracing/docker-compose.yaml b/examples/skywalking-tracing/docker-compose.yaml index d4376d0c70513..549b0afdd75da 100644 --- a/examples/skywalking-tracing/docker-compose.yaml +++ b/examples/skywalking-tracing/docker-compose.yaml @@ -5,15 +5,13 @@ services: build: context: . dockerfile: Dockerfile-frontenvoy - restart: on-failure:3 networks: - envoymesh ports: - "8000:8000" - "8001:8001" depends_on: - skywalking-oap: - condition: service_healthy + - skywalking-oap # First service. service1: build: @@ -25,16 +23,13 @@ services: - envoymesh environment: - SERVICE_NAME=1 - restart: on-failure:3 depends_on: - skywalking-oap: - condition: service_healthy + - skywalking-oap # Second service. service2: build: context: ../front-proxy dockerfile: Dockerfile-service - restart: on-failure:3 volumes: - ./service2-envoy-skywalking.yaml:/etc/service-envoy.yaml networks: @@ -42,8 +37,7 @@ services: environment: - SERVICE_NAME=2 depends_on: - skywalking-oap: - condition: service_healthy + - skywalking-oap # Skywalking components. elasticsearch: image: elasticsearch:7.9.2 @@ -57,7 +51,6 @@ services: timeout: 10s retries: 3 start_period: 40s - restart: on-failure:3 environment: discovery.type: single-node ulimits: @@ -69,8 +62,7 @@ services: networks: - envoymesh depends_on: - elasticsearch: - condition: service_healthy + - elasticsearch links: - elasticsearch ports: @@ -85,20 +77,17 @@ services: timeout: 10s retries: 3 start_period: 40s - restart: on-failure:3 skywalking-ui: image: apache/skywalking-ui:8.1.0 networks: - envoymesh depends_on: - skywalking-oap: - condition: service_healthy + - skywalking-oap links: - skywalking-oap ports: - 8080:8080 environment: SW_OAP_ADDRESS: skywalking-oap:12800 - restart: on-failure:3 networks: envoymesh: {} diff --git a/examples/skywalking-tracing/verify.sh b/examples/skywalking-tracing/verify.sh index e0e8a9f96e252..c90618ce51d71 100755 --- a/examples/skywalking-tracing/verify.sh +++ b/examples/skywalking-tracing/verify.sh @@ -5,6 +5,8 @@ export NAME=skywalking # shellcheck source=examples/verify-common.sh . "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" +# Waiting SkyWalking server to be ready. +sleep 60 run_log "Test connection" responds_with \ @@ -12,8 +14,6 @@ responds_with \ http://localhost:8000/trace/1 run_log "Test stats" -# Waiting SkyWalking server to be ready. -sleep 20 responds_with \ "tracing.skywalking.segments_sent: 1" \ http://localhost:8001/stats From f80844a332b533e2cc31ee2d495889a8ab265ba4 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 27 Oct 2020 14:23:45 +0800 Subject: [PATCH 50/61] some updates Signed-off-by: wbpcode --- api/envoy/config/trace/v3/skywalking.proto | 3 +- .../skywalking/v4alpha/skywalking.proto | 3 +- .../envoy/config/trace/v3/skywalking.proto | 3 +- .../skywalking/v4alpha/skywalking.proto | 3 +- .../skywalking/skywalking_client_config.cc | 32 +++++++++---------- .../skywalking/skywalking_client_config.h | 15 +++++---- .../tracers/skywalking/skywalking_stats.h | 6 ++-- .../tracers/skywalking/skywalking_types.cc | 2 +- .../skywalking/trace_segment_reporter.cc | 2 +- .../skywalking/trace_segment_reporter.h | 2 +- 10 files changed, 37 insertions(+), 34 deletions(-) diff --git a/api/envoy/config/trace/v3/skywalking.proto b/api/envoy/config/trace/v3/skywalking.proto index 6b42ec3e5fe89..224d474ccf985 100644 --- a/api/envoy/config/trace/v3/skywalking.proto +++ b/api/envoy/config/trace/v3/skywalking.proto @@ -24,7 +24,8 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the // provider of http tracer, then // :ref:`start_child_span ` -// in the router must be set to true to get the correct topology and tracing data. +// in the router must be set to true to get the correct topology and tracing data. Moreover, SkyWalking +// Tracer does not support SkyWalking extension header (``sw8-x``) temporarily. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { // SkyWalking collector service. diff --git a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 35d05c1c53cae..37936faa61337 100644 --- a/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/api/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -21,7 +21,8 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the // provider of http tracer, then // :ref:`start_child_span ` -// in the router must be set to true to get the correct topology and tracing data. +// in the router must be set to true to get the correct topology and tracing data. Moreover, SkyWalking +// Tracer does not support SkyWalking extension header (``sw8-x``) temporarily. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { option (udpa.annotations.versioning).previous_message_type = diff --git a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto index 6b42ec3e5fe89..224d474ccf985 100644 --- a/generated_api_shadow/envoy/config/trace/v3/skywalking.proto +++ b/generated_api_shadow/envoy/config/trace/v3/skywalking.proto @@ -24,7 +24,8 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the // provider of http tracer, then // :ref:`start_child_span ` -// in the router must be set to true to get the correct topology and tracing data. +// in the router must be set to true to get the correct topology and tracing data. Moreover, SkyWalking +// Tracer does not support SkyWalking extension header (``sw8-x``) temporarily. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { // SkyWalking collector service. diff --git a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto index 35d05c1c53cae..37936faa61337 100644 --- a/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto +++ b/generated_api_shadow/envoy/extensions/tracers/skywalking/v4alpha/skywalking.proto @@ -21,7 +21,8 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // Configuration for the SkyWalking tracer. Please note that if SkyWalking tracer is used as the // provider of http tracer, then // :ref:`start_child_span ` -// in the router must be set to true to get the correct topology and tracing data. +// in the router must be set to true to get the correct topology and tracing data. Moreover, SkyWalking +// Tracer does not support SkyWalking extension header (``sw8-x``) temporarily. // [#extension: envoy.tracers.skywalking] message SkyWalkingConfig { option (udpa.annotations.versioning).previous_message_type = diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc index a964f2b6fd00e..cb57b10280dcc 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.cc +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -7,30 +7,26 @@ namespace Extensions { namespace Tracers { namespace SkyWalking { -static constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; +constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; // When the user does not provide any available configuration, in order to ensure that the service // name and instance name are not empty, use this value as the default identifier. In practice, // user should provide accurate configuration as much as possible to avoid using the default value. -static constexpr char DEFAULT_SERVICE_AND_INSTANCE[] = "EnvoyProxy"; +constexpr char DEFAULT_SERVICE_AND_INSTANCE[] = "EnvoyProxy"; SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFactoryContext& context, const envoy::config::trace::v3::ClientConfig& config) - : factory_context_(context.serverFactoryContext()) { - - max_cache_size_ = config.has_max_cache_size() ? config.max_cache_size().value() - : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE; - - service_ = config.service_name().empty() ? factory_context_.localInfo().clusterName().empty() - ? DEFAULT_SERVICE_AND_INSTANCE - : factory_context_.localInfo().clusterName() - : config.service_name(); - - service_instance_ = config.instance_name().empty() - ? factory_context_.localInfo().nodeName().empty() - ? DEFAULT_SERVICE_AND_INSTANCE - : factory_context_.localInfo().nodeName() - : config.instance_name(); + : factory_context_(context.serverFactoryContext()), + max_cache_size_(config.has_max_cache_size() ? config.max_cache_size().value() + : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE), + service_(config.service_name().empty() ? factory_context_.localInfo().clusterName().empty() + ? DEFAULT_SERVICE_AND_INSTANCE + : factory_context_.localInfo().clusterName() + : config.service_name()), + instance_(config.instance_name().empty() ? factory_context_.localInfo().nodeName().empty() + ? DEFAULT_SERVICE_AND_INSTANCE + : factory_context_.localInfo().nodeName() + : config.instance_name()) { if (config.backend_token_specifier_case() == envoy::config::trace::v3::ClientConfig::BackendTokenSpecifierCase::kBackendToken || @@ -38,6 +34,8 @@ SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFact envoy::config::trace::v3::ClientConfig::BackendTokenSpecifierCase:: BACKEND_TOKEN_SPECIFIER_NOT_SET) { backend_token_ = config.backend_token(); + } else { + NOT_REACHED_GCOVR_EXCL_LINE; } } diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.h b/source/extensions/tracers/skywalking/skywalking_client_config.h index 59abc1b28dba0..8983a1dbf7582 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.h +++ b/source/extensions/tracers/skywalking/skywalking_client_config.h @@ -20,18 +20,19 @@ class SkyWalkingClientConfig { uint32_t maxCacheSize() const { return max_cache_size_; } const std::string& service() const { return service_; } - const std::string& serviceInstance() const { return service_instance_; } + const std::string& serviceInstance() const { return instance_; } const std::string& backendToken() const; private: - uint16_t max_cache_size_{0}; - std::string service_; - std::string service_instance_; + Server::Configuration::ServerFactoryContext& factory_context_; - std::string backend_token_; + const uint32_t max_cache_size_{0}; - Server::Configuration::ServerFactoryContext& factory_context_; + const std::string service_; + const std::string instance_; + + std::string backend_token_; }; using SkyWalkingClientConfigPtr = std::unique_ptr; @@ -39,4 +40,4 @@ using SkyWalkingClientConfigPtr = std::unique_ptr; } // namespace SkyWalking } // namespace Tracers } // namespace Extensions -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/source/extensions/tracers/skywalking/skywalking_stats.h b/source/extensions/tracers/skywalking/skywalking_stats.h index 545241df7aa07..0ad8a58f5ab59 100644 --- a/source/extensions/tracers/skywalking/skywalking_stats.h +++ b/source/extensions/tracers/skywalking/skywalking_stats.h @@ -6,10 +6,10 @@ namespace Tracers { namespace SkyWalking { #define SKYWALKING_TRACER_STATS(COUNTER) \ - COUNTER(segments_sent) \ - COUNTER(segments_dropped) \ COUNTER(cache_flushed) \ - COUNTER(segments_flushed) + COUNTER(segments_dropped) \ + COUNTER(segments_flushed) \ + COUNTER(segments_sent) struct SkyWalkingTracerStats { SKYWALKING_TRACER_STATS(GENERATE_COUNTER_STRUCT) diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 209b1d9e63b28..08e8a3cf0786a 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -107,7 +107,7 @@ SegmentContext::SegmentContext(SpanContextPtr&& previous_span_context, Tracing:: } trace_segment_id_ = generateId(random_generator); - // Some detailed log for debug. + // Some detailed log for debugging. ENVOY_LOG(trace, "{} and create new SkyWalking segment:", previous_span_context_ ? "Has previous span context" : "No previous span context"); diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index a75b8df6dd70f..e2c086b51f5c4 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -106,7 +106,7 @@ void TraceSegmentReporter::report(const SegmentContext& segment_context) { sendTraceSegment(toSegmentObject(segment_context)); } -void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr&& request) { +void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr request) { ASSERT(request); ENVOY_LOG(trace, "Try to report segment to SkyWalking Server:\n{}", request->DebugString()); diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.h b/source/extensions/tracers/skywalking/trace_segment_reporter.h index d03a74d3deedb..fd70d819917bc 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.h +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.h @@ -53,7 +53,7 @@ class TraceSegmentReporter : public Logger::Loggable, private: void flushTraceSegments(); - void sendTraceSegment(TraceSegmentPtr&& request); + void sendTraceSegment(TraceSegmentPtr request); void establishNewStream(); void handleFailure(); void setRetryTimer(); From e4a815aeccbde1198a2d4477c5cfcf61b0f72b59 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 28 Oct 2020 00:42:50 +0800 Subject: [PATCH 51/61] add some new log and comment Signed-off-by: wbpcode --- .../tracers/skywalking/trace_segment_reporter.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index e2c086b51f5c4..34979eed84af6 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -124,6 +124,7 @@ void TraceSegmentReporter::sendTraceSegment(TraceSegmentPtr request) { } void TraceSegmentReporter::flushTraceSegments() { + ENVOY_LOG(debug, "Flush segments in cache to SkyWalking backend service"); while (!delayed_segments_cache_.empty() && stream_ != nullptr) { tracing_stats_.segments_sent_.inc(); tracing_stats_.segments_flushed_.inc(); @@ -140,17 +141,24 @@ void TraceSegmentReporter::closeStream() { } } -void TraceSegmentReporter::onRemoteClose(Grpc::Status::GrpcStatus, const std::string&) { +void TraceSegmentReporter::onRemoteClose(Grpc::Status::GrpcStatus status, + const std::string& message) { + ENVOY_LOG(debug, "{} gRPC stream closed: {}, {}", service_method_.name(), status, message); stream_ = nullptr; handleFailure(); } void TraceSegmentReporter::establishNewStream() { + ENVOY_LOG(debug, "Try to create new {} gRPC stream for reporter", service_method_.name()); stream_ = client_->start(service_method_, *this, Http::AsyncClient::StreamOptions()); if (stream_ == nullptr) { - handleFailure(); + ENVOY_LOG(debug, "Failed to create {} gRPC stream", service_method_.name()); return; } + // TODO(wbpcode): Even if stream_ is not empty, there is no guarantee that the connection will be + // established correctly. If there is a connection failure, the onRemoteClose method will be + // called. Currently, we lack a way to determine whether the connection is truly available. This + // may cause partial data loss. if (!delayed_segments_cache_.empty()) { flushTraceSegments(); } From d9a12782f03425cab05aac1db37317e7824e9be8 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 28 Oct 2020 00:52:36 +0800 Subject: [PATCH 52/61] remove unnecessary config in sandbox and add new test Signed-off-by: wbpcode --- .../start/sandboxes/skywalking_tracing.rst | 3 -- .../skywalking-tracing/docker-compose.yaml | 14 ++----- .../service1-envoy-skywalking.yaml | 6 --- .../service2-envoy-skywalking.yaml | 6 --- examples/skywalking-tracing/verify.sh | 38 +++++++++++++++++-- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/docs/root/start/sandboxes/skywalking_tracing.rst b/docs/root/start/sandboxes/skywalking_tracing.rst index 70b4e5b17a01f..9be31750c1ef1 100644 --- a/docs/root/start/sandboxes/skywalking_tracing.rst +++ b/docs/root/start/sandboxes/skywalking_tracing.rst @@ -19,9 +19,6 @@ in :repo:`/examples/skywalking-tracing/front-envoy-skywalking.yaml`). When service1 accepts the request forwarded from front envoy, it will makes an API call to service2 before returning a response. -Running the Sandbox -~~~~~~~~~~~~~~~~~~~ - .. include:: _include/docker-env-setup.rst Step 3: Build the sandbox diff --git a/examples/skywalking-tracing/docker-compose.yaml b/examples/skywalking-tracing/docker-compose.yaml index 549b0afdd75da..5ac0e647a7fe4 100644 --- a/examples/skywalking-tracing/docker-compose.yaml +++ b/examples/skywalking-tracing/docker-compose.yaml @@ -8,8 +8,8 @@ services: networks: - envoymesh ports: - - "8000:8000" - - "8001:8001" + - 8000:8000 + - 8001:8001 depends_on: - skywalking-oap # First service. @@ -43,8 +43,6 @@ services: image: elasticsearch:7.9.2 networks: - envoymesh - ports: - - 9200:9200 healthcheck: test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"] interval: 30s @@ -63,11 +61,6 @@ services: - envoymesh depends_on: - elasticsearch - links: - - elasticsearch - ports: - - 11800:11800 - - 12800:12800 environment: SW_STORAGE: elasticsearch7 SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200 @@ -77,14 +70,13 @@ services: timeout: 10s retries: 3 start_period: 40s + restart: on-failure skywalking-ui: image: apache/skywalking-ui:8.1.0 networks: - envoymesh depends_on: - skywalking-oap - links: - - skywalking-oap ports: - 8080:8080 environment: diff --git a/examples/skywalking-tracing/service1-envoy-skywalking.yaml b/examples/skywalking-tracing/service1-envoy-skywalking.yaml index bf745e5b536ac..a030c63f8c9fd 100644 --- a/examples/skywalking-tracing/service1-envoy-skywalking.yaml +++ b/examples/skywalking-tracing/service1-envoy-skywalking.yaml @@ -126,9 +126,3 @@ static_resources: socket_address: address: skywalking-oap port_value: 11800 -admin: - access_log_path: "/dev/null" - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/skywalking-tracing/service2-envoy-skywalking.yaml b/examples/skywalking-tracing/service2-envoy-skywalking.yaml index 0fe2a0dd43d1f..5f0ee1b834eaa 100644 --- a/examples/skywalking-tracing/service2-envoy-skywalking.yaml +++ b/examples/skywalking-tracing/service2-envoy-skywalking.yaml @@ -70,9 +70,3 @@ static_resources: socket_address: address: skywalking-oap port_value: 11800 -admin: - access_log_path: "/dev/null" - address: - socket_address: - address: 0.0.0.0 - port_value: 8001 diff --git a/examples/skywalking-tracing/verify.sh b/examples/skywalking-tracing/verify.sh index c90618ce51d71..312686c2cfafe 100755 --- a/examples/skywalking-tracing/verify.sh +++ b/examples/skywalking-tracing/verify.sh @@ -1,13 +1,11 @@ #!/bin/bash -e export NAME=skywalking +export DELAY=200 # shellcheck source=examples/verify-common.sh . "$(dirname "${BASH_SOURCE[0]}")/../verify-common.sh" -# Waiting SkyWalking server to be ready. -sleep 60 - run_log "Test connection" responds_with \ "Hello from behind Envoy (service 1)!" \ @@ -17,3 +15,37 @@ run_log "Test stats" responds_with \ "tracing.skywalking.segments_sent: 1" \ http://localhost:8001/stats + +run_log "Test dashboard" +responds_with \ + "" \ + http://localhost:8080 + +run_log "Test OAP Server" +responds_with \ + "getEndpoints" \ + http://localhost:8080/graphql \ + -X POST \ + -H 'Content-Type:application/json' \ + -d '{ "query": "query queryEndpoints($serviceId: ID!, $keyword: String!) { + getEndpoints: searchEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) { + key: id + label: name + } + }", + "variables": { "serviceId": "", "keyword": "" } + }' + +responds_with \ + "currentTimestamp" \ + http://localhost:8080/graphql \ + -X POST \ + -H 'Content-Type:application/json' \ + -d '{ "query": "query queryOAPTimeInfo { + getTimeInfo { + timezone + currentTimestamp + } + }", + "variables": {} + }' From c3b30c82037d72b37aba836c712062f7d5836b51 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 28 Oct 2020 01:16:13 +0800 Subject: [PATCH 53/61] fix shell format Signed-off-by: wbpcode --- examples/skywalking-tracing/verify.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/skywalking-tracing/verify.sh b/examples/skywalking-tracing/verify.sh index 312686c2cfafe..3c5c4799ca900 100755 --- a/examples/skywalking-tracing/verify.sh +++ b/examples/skywalking-tracing/verify.sh @@ -26,26 +26,26 @@ responds_with \ "getEndpoints" \ http://localhost:8080/graphql \ -X POST \ - -H 'Content-Type:application/json' \ - -d '{ "query": "query queryEndpoints($serviceId: ID!, $keyword: String!) { - getEndpoints: searchEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 100) { + -H "Content-Type:application/json" \ + -d "{ \"query\": \"query queryEndpoints(\$serviceId: ID!, \$keyword: String!) { + getEndpoints: searchEndpoint(serviceId: \$serviceId, keyword: \$keyword, limit: 100) { key: id label: name } - }", - "variables": { "serviceId": "", "keyword": "" } - }' + }\", + \"variables\": { \"serviceId\": \"\", \"keyword\": \"\" } + }" responds_with \ "currentTimestamp" \ http://localhost:8080/graphql \ -X POST \ - -H 'Content-Type:application/json' \ - -d '{ "query": "query queryOAPTimeInfo { + -H "Content-Type:application/json" \ + -d "{ \"query\": \"query queryOAPTimeInfo { getTimeInfo { timezone currentTimestamp } - }", - "variables": {} - }' + }\", + \"variables\": {} + }" From b2e8661aeaf415c34bd377e77450ff30c1e44347 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Wed, 28 Oct 2020 15:40:36 +0800 Subject: [PATCH 54/61] fix typo error Signed-off-by: wbpcode --- docs/root/start/sandboxes/skywalking_tracing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/start/sandboxes/skywalking_tracing.rst b/docs/root/start/sandboxes/skywalking_tracing.rst index 9be31750c1ef1..66f07dd157180 100644 --- a/docs/root/start/sandboxes/skywalking_tracing.rst +++ b/docs/root/start/sandboxes/skywalking_tracing.rst @@ -16,7 +16,7 @@ all Envoys are configured to collect request traces (e.g., http_connection_manag by the SkyWalking tracer to a SkyWalking cluster (trace driver setup in :repo:`/examples/skywalking-tracing/front-envoy-skywalking.yaml`). -When service1 accepts the request forwarded from front envoy, it will makes an API call to service2 before +When service1 accepts the request forwarded from front envoy, it will make an API call to service2 before returning a response. .. include:: _include/docker-env-setup.rst From 753f79f27bf0041e2aac0083cfab3015d4340312 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 30 Oct 2020 16:15:14 +0800 Subject: [PATCH 55/61] simplify unnecessary logic Signed-off-by: wbpcode --- .../skywalking/skywalking_client_config.cc | 18 ++++++------------ .../tracers/skywalking/skywalking_types.cc | 3 ++- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc index cb57b10280dcc..705dc71800ea9 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.cc +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -17,8 +17,8 @@ constexpr char DEFAULT_SERVICE_AND_INSTANCE[] = "EnvoyProxy"; SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFactoryContext& context, const envoy::config::trace::v3::ClientConfig& config) : factory_context_(context.serverFactoryContext()), - max_cache_size_(config.has_max_cache_size() ? config.max_cache_size().value() - : DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE), + max_cache_size_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, max_cache_size, + DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE)), service_(config.service_name().empty() ? factory_context_.localInfo().clusterName().empty() ? DEFAULT_SERVICE_AND_INSTANCE : factory_context_.localInfo().clusterName() @@ -27,16 +27,10 @@ SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFact ? DEFAULT_SERVICE_AND_INSTANCE : factory_context_.localInfo().nodeName() : config.instance_name()) { - - if (config.backend_token_specifier_case() == - envoy::config::trace::v3::ClientConfig::BackendTokenSpecifierCase::kBackendToken || - config.backend_token_specifier_case() == - envoy::config::trace::v3::ClientConfig::BackendTokenSpecifierCase:: - BACKEND_TOKEN_SPECIFIER_NOT_SET) { - backend_token_ = config.backend_token(); - } else { - NOT_REACHED_GCOVR_EXCL_LINE; - } + // Since the SDS API to get backend token is not supported yet, we can get the value of token + // from the backend_token field directly. If the user does not provide the configuration, the + // value of token is kept empty. + backend_token_ = config.backend_token(); } // TODO(wbpcode): currently, backend authentication token can only be configured with inline string. diff --git a/source/extensions/tracers/skywalking/skywalking_types.cc b/source/extensions/tracers/skywalking/skywalking_types.cc index 08e8a3cf0786a..9c750884bc11c 100644 --- a/source/extensions/tracers/skywalking/skywalking_types.cc +++ b/source/extensions/tracers/skywalking/skywalking_types.cc @@ -32,7 +32,8 @@ std::string base64Encode(const absl::string_view input) { // Decode and validate fields of propagation header. std::string base64Decode(absl::string_view input) { - std::string result = input.length() % 4 ? EMPTY_STRING : Base64::decodeWithoutPadding(input); + // The input can be Base64 string with or without padding. + std::string result = Base64::decodeWithoutPadding(input); if (result.empty()) { throw EnvoyException("Invalid propagation header for SkyWalking: parse error"); } From 32ba20777ae18780efafd9cbe72d5a54b2ebae1d Mon Sep 17 00:00:00 2001 From: wbpcode Date: Fri, 30 Oct 2020 17:01:55 +0800 Subject: [PATCH 56/61] register authentication header for skywalking Signed-off-by: wbpcode --- source/common/http/headers.h | 1 + .../tracers/skywalking/trace_segment_reporter.cc | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/source/common/http/headers.h b/source/common/http/headers.h index 5a66f8f0ea59c..7d89713a3f764 100644 --- a/source/common/http/headers.h +++ b/source/common/http/headers.h @@ -59,6 +59,7 @@ class CustomHeaderValues { const LowerCaseString AccessControlExposeHeaders{"access-control-expose-headers"}; const LowerCaseString AccessControlMaxAge{"access-control-max-age"}; const LowerCaseString AccessControlAllowCredentials{"access-control-allow-credentials"}; + const LowerCaseString Authentication{"authentication"}; const LowerCaseString Authorization{"authorization"}; const LowerCaseString CacheControl{"cache-control"}; const LowerCaseString CdnLoop{"cdn-loop"}; diff --git a/source/extensions/tracers/skywalking/trace_segment_reporter.cc b/source/extensions/tracers/skywalking/trace_segment_reporter.cc index 34979eed84af6..5ef0046dc8001 100644 --- a/source/extensions/tracers/skywalking/trace_segment_reporter.cc +++ b/source/extensions/tracers/skywalking/trace_segment_reporter.cc @@ -1,5 +1,7 @@ #include "extensions/tracers/skywalking/trace_segment_reporter.h" +#include "envoy/http/header_map.h" + namespace Envoy { namespace Extensions { namespace Tracers { @@ -7,9 +9,8 @@ namespace SkyWalking { namespace { -const Http::LowerCaseString& authenticationTokenKey() { - CONSTRUCT_ON_FIRST_USE(Http::LowerCaseString, "Authentication"); -} +Http::RegisterCustomInlineHeader + authentication_handle(Http::CustomHeaders::get().Authentication); // Convert SegmentContext to SegmentObject. TraceSegmentPtr toSegmentObject(const SegmentContext& segment_context) { @@ -98,7 +99,7 @@ TraceSegmentReporter::TraceSegmentReporter(Grpc::AsyncClientFactoryPtr&& factory void TraceSegmentReporter::onCreateInitialMetadata(Http::RequestHeaderMap& metadata) { if (!client_config_.backendToken().empty()) { - metadata.setReferenceKey(authenticationTokenKey(), client_config_.backendToken()); + metadata.setInline(authentication_handle.handle(), client_config_.backendToken()); } } From 8fa92a2136dcb22ea1ea720f1c263454a06249d3 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Sun, 1 Nov 2020 12:46:20 +0800 Subject: [PATCH 57/61] remove global static std::string and some minor update Signed-off-by: wbpcode --- .../skywalking/skywalking_client_config.cc | 2 +- .../extensions/tracers/skywalking/tracer.cc | 4 +- source/extensions/tracers/skywalking/tracer.h | 2 +- .../tracers/skywalking/config_test.cc | 4 +- .../skywalking_client_config_test.cc | 45 +++++++++++-------- .../skywalking/skywalking_tracer_impl_test.cc | 26 ++++++----- .../skywalking/skywalking_types_test.cc | 14 +++--- .../tracers/skywalking/tracer_test.cc | 10 +---- 8 files changed, 55 insertions(+), 52 deletions(-) diff --git a/source/extensions/tracers/skywalking/skywalking_client_config.cc b/source/extensions/tracers/skywalking/skywalking_client_config.cc index 705dc71800ea9..ed692b3f72bd5 100644 --- a/source/extensions/tracers/skywalking/skywalking_client_config.cc +++ b/source/extensions/tracers/skywalking/skywalking_client_config.cc @@ -12,7 +12,7 @@ constexpr uint32_t DEFAULT_DELAYED_SEGMENTS_CACHE_SIZE = 1024; // When the user does not provide any available configuration, in order to ensure that the service // name and instance name are not empty, use this value as the default identifier. In practice, // user should provide accurate configuration as much as possible to avoid using the default value. -constexpr char DEFAULT_SERVICE_AND_INSTANCE[] = "EnvoyProxy"; +constexpr absl::string_view DEFAULT_SERVICE_AND_INSTANCE = "EnvoyProxy"; SkyWalkingClientConfig::SkyWalkingClientConfig(Server::Configuration::TracerFactoryContext& context, const envoy::config::trace::v3::ClientConfig& config) diff --git a/source/extensions/tracers/skywalking/tracer.cc b/source/extensions/tracers/skywalking/tracer.cc index b1c6b362430dd..f3845b9c42131 100644 --- a/source/extensions/tracers/skywalking/tracer.cc +++ b/source/extensions/tracers/skywalking/tracer.cc @@ -7,8 +7,8 @@ namespace Extensions { namespace Tracers { namespace SkyWalking { -constexpr char StatusCodeTag[] = "status_code"; -constexpr char UrlTag[] = "url"; +constexpr absl::string_view StatusCodeTag = "status_code"; +constexpr absl::string_view UrlTag = "url"; namespace { diff --git a/source/extensions/tracers/skywalking/tracer.h b/source/extensions/tracers/skywalking/tracer.h index 21de76aceea57..d28276b232cd2 100644 --- a/source/extensions/tracers/skywalking/tracer.h +++ b/source/extensions/tracers/skywalking/tracer.h @@ -20,7 +20,7 @@ class Span; class Tracer { public: explicit Tracer(TimeSource& time_source) : time_source_(time_source) {} - ~Tracer() { reporter_->closeStream(); } + virtual ~Tracer() { reporter_->closeStream(); } /* * Set a trace segment reporter to the current Tracer. Whenever a SkyWalking segment ends, the diff --git a/test/extensions/tracers/skywalking/config_test.cc b/test/extensions/tracers/skywalking/config_test.cc index 856b10b007a4b..19c966cf7cb7e 100644 --- a/test/extensions/tracers/skywalking/config_test.cc +++ b/test/extensions/tracers/skywalking/config_test.cc @@ -37,7 +37,7 @@ TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracer) { grpc_service: envoy_grpc: cluster_name: fake_cluster - )EOF"; + )EOF"; envoy::config::trace::v3::Tracing configuration; TestUtility::loadFromYaml(yaml_string, configuration); @@ -70,7 +70,7 @@ TEST(SkyWalkingTracerConfigTest, SkyWalkingHttpTracerWithClientConfig) { service_name: "Test Service" instance_name: "Test Instance" max_cache_size: 2333 - )EOF"; + )EOF"; envoy::config::trace::v3::Tracing configuration; TestUtility::loadFromYaml(yaml_string, configuration); diff --git a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc index 252a0a700f530..8bac0e64b913c 100644 --- a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc @@ -37,27 +37,16 @@ class SkyWalkingClientConfigTest : public testing::Test { SkyWalkingClientConfigPtr client_config_; }; -static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( - grpc_service: - envoy_grpc: - cluster_name: fake_cluster - client_config: - backend_token: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" - service_name: "FAKE_FAKE_FAKE" - instance_name: "FAKE_FAKE_FAKE" - max_cache_size: 2333 -)EOF"; - -static const std::string SKYWALKING_CONFIG_NO_CLIENT_CONFIG = R"EOF( +// Test whether the default value can be set correctly when there is no proto client config +// provided. +TEST_F(SkyWalkingClientConfigTest, NoProtoClientConfigTest) { + const std::string yaml_string = R"EOF( grpc_service: envoy_grpc: cluster_name: fake_cluster -)EOF"; + )EOF"; -// Test whether the default value can be set correctly when there is no proto client config -// provided. -TEST_F(SkyWalkingClientConfigTest, NoProtoClientConfigTest) { - setupSkyWalkingClientConfig(SKYWALKING_CONFIG_NO_CLIENT_CONFIG); + setupSkyWalkingClientConfig(yaml_string); EXPECT_EQ(client_config_->service(), test_string); EXPECT_EQ(client_config_->serviceInstance(), test_string); @@ -67,7 +56,18 @@ TEST_F(SkyWalkingClientConfigTest, NoProtoClientConfigTest) { // Test whether the client config can work correctly when the proto client config is provided. TEST_F(SkyWalkingClientConfigTest, WithProtoClientConfigTest) { - setupSkyWalkingClientConfig(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); + const std::string yaml_string = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + client_config: + backend_token: "FAKE_FAKE_FAKE_FAKE_FAKE_FAKE" + service_name: "FAKE_FAKE_FAKE" + instance_name: "FAKE_FAKE_FAKE" + max_cache_size: 2333 + )EOF"; + + setupSkyWalkingClientConfig(yaml_string); EXPECT_EQ(client_config_->service(), "FAKE_FAKE_FAKE"); EXPECT_EQ(client_config_->serviceInstance(), "FAKE_FAKE_FAKE"); @@ -78,7 +78,14 @@ TEST_F(SkyWalkingClientConfigTest, WithProtoClientConfigTest) { // Test whether the client config can get default value for service name and instance name. TEST_F(SkyWalkingClientConfigTest, BothLocalInfoAndClientConfigEmptyTest) { test_string = ""; - setupSkyWalkingClientConfig(SKYWALKING_CONFIG_NO_CLIENT_CONFIG); + + const std::string yaml_string = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + )EOF"; + + setupSkyWalkingClientConfig(yaml_string); EXPECT_EQ(client_config_->service(), "EnvoyProxy"); EXPECT_EQ(client_config_->serviceInstance(), "EnvoyProxy"); diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index 2f902346fa7b0..dca276cd78c42 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -32,6 +32,9 @@ class SkyWalkingDriverTest : public testing::Test { factoryForGrpcService(_, _, _)) .WillOnce(Return(ByMove(std::move(mock_client_factory)))); + EXPECT_CALL(factory_context.thread_local_.dispatcher_, createTimer_(_)) + .WillOnce(Invoke([](Event::TimerCb) { return new NiceMock(); })); + ON_CALL(factory_context.local_info_, clusterName()).WillByDefault(ReturnRef(test_string)); ON_CALL(factory_context.local_info_, nodeName()).WillByDefault(ReturnRef(test_string)); @@ -52,7 +55,8 @@ class SkyWalkingDriverTest : public testing::Test { DriverPtr driver_; }; -static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( +TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { + const std::string yaml_string = R"EOF( grpc_service: envoy_grpc: cluster_name: fake_cluster @@ -61,16 +65,8 @@ static const std::string SKYWALKING_CONFIG_WITH_CLIENT_CONFIG = R"EOF( service_name: "FAKE_FAKE_FAKE" instance_name: "FAKE_FAKE_FAKE" max_cache_size: 2333 -)EOF"; - -static const std::string SKYWALKING_CONFIG_NO_CLIENT_CONFIG = R"EOF( - grpc_service: - envoy_grpc: - cluster_name: fake_cluster -)EOF"; - -TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { - setupSkyWalkingDriver(SKYWALKING_CONFIG_WITH_CLIENT_CONFIG); + )EOF"; + setupSkyWalkingDriver(yaml_string); std::string trace_id = SkyWalkingTestHelper::generateId(context_.server_factory_context_.api_.random_); @@ -151,7 +147,13 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestWithClientConfig) { } TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) { - setupSkyWalkingDriver(SKYWALKING_CONFIG_NO_CLIENT_CONFIG); + const std::string yaml_string = R"EOF( + grpc_service: + envoy_grpc: + cluster_name: fake_cluster + )EOF"; + + setupSkyWalkingDriver(yaml_string); Http::TestRequestHeaderMapImpl request_headers{ {":path", "/path"}, {":method", "GET"}, {":authority", "test.com"}}; diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc index 217459d127afe..9641fba9b9311 100644 --- a/test/extensions/tracers/skywalking/skywalking_types_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -19,10 +19,10 @@ namespace Tracers { namespace SkyWalking { // Some constant strings for testing. -constexpr char TEST_SERVICE[] = "EnvoyIngressForTest"; -constexpr char TEST_INSTANCE[] = "node-2.3.4.5~ingress"; -constexpr char TEST_ADDRESS[] = "255.255.255.255"; -constexpr char TEST_ENDPOINT[] = "/POST/path/for/test"; +constexpr absl::string_view TEST_SERVICE = "EnvoyIngressForTest"; +constexpr absl::string_view TEST_INSTANCE = "node-2.3.4.5~ingress"; +constexpr absl::string_view TEST_ADDRESS = "255.255.255.255"; +constexpr absl::string_view TEST_ENDPOINT = "/POST/path/for/test"; // Test whether SpanContext can correctly parse data from propagation headers and throw exceptions // when errors occur. @@ -169,11 +169,11 @@ TEST(SegmentContextTest, SegmentContextTestWithEmptyPreviousSpanContext) { // Test whether the value of the fields can be set correctly and the value of the fields can be // obtained correctly. EXPECT_EQ(segment_context->service(), "NEW#SERVICE"); - segment_context->setService(TEST_SERVICE); + segment_context->setService(std::string(TEST_SERVICE)); EXPECT_EQ(segment_context->service(), TEST_SERVICE); EXPECT_EQ(segment_context->serviceInstance(), "NEW#INSTANCE"); - segment_context->setServiceInstance(TEST_INSTANCE); + segment_context->setServiceInstance(std::string(TEST_INSTANCE)); EXPECT_EQ(segment_context->serviceInstance(), TEST_INSTANCE); EXPECT_EQ(segment_context->rootSpanStore(), nullptr); @@ -302,7 +302,7 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { EXPECT_EQ("oooooop", root_store->operation()); EXPECT_EQ("0.0.0.0", root_store->peerAddress()); - root_store->setPeerAddress(TEST_ADDRESS); + root_store->setPeerAddress(std::string(TEST_ADDRESS)); EXPECT_EQ(TEST_ADDRESS, root_store->peerAddress()); EXPECT_EQ(22222222, root_store->startTime()); diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index dbf24b4eaa411..d9e26c2d8fc83 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -23,13 +23,10 @@ namespace SkyWalking { class TracerTest : public testing::Test { public: void setupTracer(const std::string& yaml_string) { - EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([this](Event::TimerCb timer_cb) { - timer_cb_ = timer_cb; - return timer_; + EXPECT_CALL(mock_dispatcher_, createTimer_(_)).WillOnce(Invoke([](Event::TimerCb) { + return new NiceMock(); })); - timer_ = new NiceMock(); - auto mock_client_factory = std::make_unique>(); auto mock_client = std::make_unique>(); @@ -68,9 +65,6 @@ class TracerTest : public testing::Test { std::unique_ptr> mock_stream_ptr_{nullptr}; - NiceMock* timer_; - Event::TimerCb timer_cb_; - std::string test_string = "ABCDEFGHIJKLMN"; SkyWalkingClientConfigPtr client_config_; From fdc58a0b8e66ffbd04d87d07b95eba519e03f1ae Mon Sep 17 00:00:00 2001 From: wbpcode Date: Mon, 2 Nov 2020 12:44:20 +0800 Subject: [PATCH 58/61] remove using namespace & wrap test by anonymous namespace Signed-off-by: wbpcode --- .../tracers/skywalking/skywalking_client_config_test.cc | 5 ++++- test/extensions/tracers/skywalking/skywalking_test_helper.h | 2 ++ .../tracers/skywalking/skywalking_tracer_impl_test.cc | 6 +++++- test/extensions/tracers/skywalking/skywalking_types_test.cc | 5 ++++- .../tracers/skywalking/trace_segment_reporter_test.cc | 6 +++++- test/extensions/tracers/skywalking/tracer_test.cc | 6 +++++- 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc index 8bac0e64b913c..c0d4131a8e9d5 100644 --- a/test/extensions/tracers/skywalking/skywalking_client_config_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_client_config_test.cc @@ -7,12 +7,14 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using namespace testing; +using testing::NiceMock; +using testing::ReturnRef; namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { +namespace { class SkyWalkingClientConfigTest : public testing::Test { public: @@ -91,6 +93,7 @@ TEST_F(SkyWalkingClientConfigTest, BothLocalInfoAndClientConfigEmptyTest) { EXPECT_EQ(client_config_->serviceInstance(), "EnvoyProxy"); } +} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/skywalking/skywalking_test_helper.h b/test/extensions/tracers/skywalking/skywalking_test_helper.h index e158bb535da8a..52ab74af4207b 100644 --- a/test/extensions/tracers/skywalking/skywalking_test_helper.h +++ b/test/extensions/tracers/skywalking/skywalking_test_helper.h @@ -11,6 +11,7 @@ namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { +namespace { /* * A simple helper class for auxiliary testing. Contains some simple static functions, such as @@ -71,6 +72,7 @@ class SkyWalkingTestHelper { } }; +} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc index dca276cd78c42..cb5075665dcc0 100644 --- a/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_tracer_impl_test.cc @@ -9,12 +9,15 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using namespace testing; +using testing::NiceMock; +using testing::Return; +using testing::ReturnRef; namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { +namespace { class SkyWalkingDriverTest : public testing::Test { public: @@ -169,6 +172,7 @@ TEST_F(SkyWalkingDriverTest, SkyWalkingDriverStartSpanTestNoClientConfig) { EXPECT_EQ(test_string, span->segmentContext()->serviceInstance()); } +} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/skywalking/skywalking_types_test.cc b/test/extensions/tracers/skywalking/skywalking_types_test.cc index 9641fba9b9311..eb1d3147558f6 100644 --- a/test/extensions/tracers/skywalking/skywalking_types_test.cc +++ b/test/extensions/tracers/skywalking/skywalking_types_test.cc @@ -11,12 +11,14 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using namespace testing; +using testing::NiceMock; +using testing::Return; namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { +namespace { // Some constant strings for testing. constexpr absl::string_view TEST_SERVICE = "EnvoyIngressForTest"; @@ -334,6 +336,7 @@ TEST(SpanStoreTest, SpanStoreCommonTest) { EXPECT_EQ(request_headers_no_upstream.get_("sw8"), expected_header_value); } +} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc index 53aaeeae6f2e5..fa3f59effdb55 100644 --- a/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc +++ b/test/extensions/tracers/skywalking/trace_segment_reporter_test.cc @@ -12,12 +12,15 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using namespace testing; +using testing::NiceMock; +using testing::Return; +using testing::ReturnRef; namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { +namespace { class TraceSegmentReporterTest : public testing::Test { public: @@ -236,6 +239,7 @@ TEST_F(TraceSegmentReporterTest, TraceSegmentReporterReportWithCacheConfig) { EXPECT_EQ(3U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); } +} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions diff --git a/test/extensions/tracers/skywalking/tracer_test.cc b/test/extensions/tracers/skywalking/tracer_test.cc index d9e26c2d8fc83..c0d9356f1d50c 100644 --- a/test/extensions/tracers/skywalking/tracer_test.cc +++ b/test/extensions/tracers/skywalking/tracer_test.cc @@ -13,12 +13,15 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using namespace testing; +using testing::NiceMock; +using testing::Return; +using testing::ReturnRef; namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { +namespace { class TracerTest : public testing::Test { public: @@ -183,6 +186,7 @@ TEST_F(TracerTest, TracerTestCreateNewSpanWithNoPropagationHeaders) { EXPECT_EQ(0U, mock_scope_.counter("tracing.skywalking.segments_flushed").value()); } +} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions From f95b77d4703dddbcefd94498a404b09c620fb444 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 3 Nov 2020 08:45:30 +0800 Subject: [PATCH 59/61] fix docs after merge master Signed-off-by: wbpcode --- docs/root/version_history/current.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 0a2a2d49575dd..cf39ae606ad70 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -51,8 +51,8 @@ New Features * ratelimit: added support for use of various :ref:`metadata ` as a ratelimit action. * ratelimit: added :ref:`disable_x_envoy_ratelimited_header ` option to disable `X-Envoy-RateLimited` header. * tcp: added a new :ref:`envoy.overload_actions.reject_incoming_connections ` action to reject incoming TCP connections. -* tracing: added SkyWalking tracer. * tls: added support for RSA certificates with 4096-bit keys in FIPS mode. +* tracing: added SkyWalking tracer. * xds: added support for resource TTLs. A TTL is specified on the :ref:`Resource `. For SotW, a :ref:`Resource ` can be embedded in the list of resources to specify the TTL. From 6aab97cf76ea78d31778b11032937126f00b1a22 Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 3 Nov 2020 11:30:44 +0800 Subject: [PATCH 60/61] Kick CI Signed-off-by: wbpcode From fe434412b3869b2c6c614a395aacb478fbfacbfc Mon Sep 17 00:00:00 2001 From: wbpcode Date: Tue, 3 Nov 2020 12:01:28 +0800 Subject: [PATCH 61/61] anonymous namespace in header Signed-off-by: wbpcode --- test/extensions/tracers/skywalking/skywalking_test_helper.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/extensions/tracers/skywalking/skywalking_test_helper.h b/test/extensions/tracers/skywalking/skywalking_test_helper.h index 52ab74af4207b..e158bb535da8a 100644 --- a/test/extensions/tracers/skywalking/skywalking_test_helper.h +++ b/test/extensions/tracers/skywalking/skywalking_test_helper.h @@ -11,7 +11,6 @@ namespace Envoy { namespace Extensions { namespace Tracers { namespace SkyWalking { -namespace { /* * A simple helper class for auxiliary testing. Contains some simple static functions, such as @@ -72,7 +71,6 @@ class SkyWalkingTestHelper { } }; -} // namespace } // namespace SkyWalking } // namespace Tracers } // namespace Extensions