feat: get route info in spring-cloud-gateway (#9597)

This commit is contained in:
Liu Ziming 2023-11-04 00:40:35 +08:00 committed by GitHub
parent 11cac29ba7
commit 702ae30076
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 608 additions and 0 deletions

View File

@ -114,6 +114,7 @@ These are the supported libraries and frameworks:
| [Spark Web Framework](https://github.com/perwendel/spark) | 2.3+ | N/A | Provides `http.route` [2] | | [Spark Web Framework](https://github.com/perwendel/spark) | 2.3+ | N/A | Provides `http.route` [2] |
| [Spring Boot](https://spring.io/projects/spring-boot) | | [opentelemetry-spring-boot-resources](../instrumentation/spring/spring-boot-resources/library) | none | | [Spring Boot](https://spring.io/projects/spring-boot) | | [opentelemetry-spring-boot-resources](../instrumentation/spring/spring-boot-resources/library) | none |
| [Spring Batch](https://spring.io/projects/spring-batch) | 3.0+ (not including 5.0+ yet) | N/A | none | | [Spring Batch](https://spring.io/projects/spring-batch) | 3.0+ (not including 5.0+ yet) | N/A | none |
| [Spring Cloud Gateway](https://github.com/spring-cloud/spring-cloud-gateway) | 2.0+ | N/A | Provides `http.route` [2] |
| [Spring Data](https://spring.io/projects/spring-data) | 1.8+ | N/A | none | | [Spring Data](https://spring.io/projects/spring-data) | 1.8+ | N/A | none |
| [Spring Integration](https://spring.io/projects/spring-integration) | 4.1+ (not including 6.0+ yet) | [opentelemetry-spring-integration-4.1](../instrumentation/spring/spring-integration-4.1/library) | [Messaging Spans] | | [Spring Integration](https://spring.io/projects/spring-integration) | 4.1+ (not including 6.0+ yet) | [opentelemetry-spring-integration-4.1](../instrumentation/spring/spring-integration-4.1/library) | [Messaging Spans] |
| [Spring JMS](https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#jms) | 2.0+ | N/A | [Messaging Spans] | | [Spring JMS](https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#jms) | 2.0+ | N/A | [Messaging Spans] |

View File

@ -0,0 +1,5 @@
# Settings for the Spring Cloud Gateway instrumentation
| System property | Type | Default | Description |
|--------------------------------------------------------------------------| ------- | ------- |---------------------------------------------------------------------------------------------|
| `otel.instrumentation.spring-cloud-gateway.experimental-span-attributes` | Boolean | `false` | Enable the capture of experimental span attributes. |

View File

@ -0,0 +1,51 @@
plugins {
id("otel.javaagent-instrumentation")
}
muzzle {
pass {
group.set("org.springframework.cloud")
module.set("spring-cloud-starter-gateway")
versions.set("[2.0.0.RELEASE,]")
}
}
dependencies {
library("org.springframework.cloud:spring-cloud-starter-gateway:2.0.0.RELEASE")
testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent"))
testInstrumentation(project(":instrumentation:reactor:reactor-3.1:javaagent"))
testInstrumentation(project(":instrumentation:reactor:reactor-netty:reactor-netty-1.0:javaagent"))
testInstrumentation(project(":instrumentation:spring:spring-webflux:spring-webflux-5.0:javaagent"))
testImplementation(project(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-common:testing"))
testLibrary("org.springframework.boot:spring-boot-starter-test:2.0.0.RELEASE")
}
tasks.withType<Test>().configureEach {
jvmArgs("-Dotel.instrumentation.spring-cloud-gateway.experimental-span-attributes=true")
// required on jdk17
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
}
val latestDepTest = findProperty("testLatestDeps") as Boolean
if (latestDepTest) {
// spring 6 requires java 17
otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_17)
}
} else {
// spring 5 requires old logback (and therefore also old slf4j)
configurations.testRuntimeClasspath {
resolutionStrategy {
force("ch.qos.logback:logback-classic:1.2.11")
force("org.slf4j:slf4j-api:1.7.36")
}
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0;
import static java.util.Arrays.asList;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;
@AutoService(InstrumentationModule.class)
public class GatewayInstrumentationModule extends InstrumentationModule {
public GatewayInstrumentationModule() {
super("spring-cloud-gateway");
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new HandlerAdapterInstrumentation());
}
@Override
public int order() {
// Later than Spring Webflux.
return 1;
}
}

View File

@ -0,0 +1,18 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteGetter;
import org.springframework.web.server.ServerWebExchange;
public final class GatewaySingletons {
private GatewaySingletons() {}
public static HttpServerRouteGetter<ServerWebExchange> httpRouteGetter() {
return (context, exchange) -> ServerWebExchangeHelper.extractServerRoute(exchange);
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRoute;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerRouteSource;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.springframework.web.server.ServerWebExchange;
public class HandlerAdapterInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderOptimization() {
return hasClassesNamed("org.springframework.web.reactive.HandlerAdapter");
}
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return not(isAbstract())
.and(implementsInterface(named("org.springframework.web.reactive.HandlerAdapter")));
}
@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod()
.and(isPublic())
.and(named("handle"))
.and(takesArgument(0, named("org.springframework.web.server.ServerWebExchange")))
.and(takesArgument(1, Object.class))
.and(takesArguments(2)),
this.getClass().getName() + "$HandleAdvice");
}
@SuppressWarnings("unused")
public static class HandleAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void methodEnter(@Advice.Argument(0) ServerWebExchange exchange) {
Context context = Context.current();
// Update route info for server span.
HttpServerRoute.update(
context,
HttpServerRouteSource.NESTED_CONTROLLER,
GatewaySingletons.httpRouteGetter(),
exchange);
// Record route info in server span.
ServerWebExchangeHelper.extractAttributes(exchange, context);
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.internal.StringUtils;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.LocalRootSpan;
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
import java.util.regex.Pattern;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.web.server.ServerWebExchange;
public final class ServerWebExchangeHelper {
/** Route ID attribute key. */
private static final AttributeKey<String> ROUTE_ID_ATTRIBUTE =
AttributeKey.stringKey("spring-cloud-gateway.route.id");
/** Route URI attribute key. */
private static final AttributeKey<String> ROUTE_URI_ATTRIBUTE =
AttributeKey.stringKey("spring-cloud-gateway.route.uri");
/** Route order attribute key. */
private static final AttributeKey<Long> ROUTE_ORDER_ATTRIBUTE =
AttributeKey.longKey("spring-cloud-gateway.route.order");
/** Route filter size attribute key. */
private static final AttributeKey<Long> ROUTE_FILTER_SIZE_ATTRIBUTE =
AttributeKey.longKey("spring-cloud-gateway.route.filter.size");
private static final boolean CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES;
static {
CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES =
InstrumentationConfig.get()
.getBoolean(
"otel.instrumentation.spring-cloud-gateway.experimental-span-attributes", false);
}
/* Regex for UUID */
private static final Pattern UUID_REGEX =
Pattern.compile(
"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
private static final String INVALID_RANDOM_ROUTE_ID =
"org.springframework.util.AlternativeJdkIdGenerator@";
private ServerWebExchangeHelper() {}
public static void extractAttributes(ServerWebExchange exchange, Context context) {
// Record route info
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
if (route != null && CAPTURE_EXPERIMENTAL_SPAN_ATTRIBUTES) {
Span serverSpan = LocalRootSpan.fromContextOrNull(context);
if (serverSpan == null) {
return;
}
serverSpan.setAttribute(ROUTE_ID_ATTRIBUTE, route.getId());
serverSpan.setAttribute(ROUTE_URI_ATTRIBUTE, route.getUri().toASCIIString());
serverSpan.setAttribute(ROUTE_ORDER_ATTRIBUTE, route.getOrder());
serverSpan.setAttribute(ROUTE_FILTER_SIZE_ATTRIBUTE, route.getFilters().size());
}
}
public static String extractServerRoute(ServerWebExchange exchange) {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
if (route != null) {
return convergeRouteId(route);
}
return null;
}
/**
* To avoid high cardinality, we ignore random UUID generated by Spring Cloud Gateway. Spring
* Cloud Gateway generate invalid random routeID, and it is fixed until 3.1.x
*
* @see <a
* href="https://github.com/spring-cloud/spring-cloud-gateway/commit/5002fe2e0a2825ef47dd667cade37b844c276cf6"/>
*/
private static String convergeRouteId(Route route) {
String routeId = route.getId();
if (StringUtils.isNullOrEmpty(routeId)) {
return null;
}
if (UUID_REGEX.matcher(routeId).matches()) {
return null;
}
if (routeId.startsWith(INVALID_RANDOM_ROUTE_ID)) {
return null;
}
return routeId;
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.spring.gateway.common.AbstractRouteMappingTest;
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {
GatewayTestApplication.class,
GatewayRouteMappingTest.ForceNettyAutoConfiguration.class
})
class GatewayRouteMappingTest extends AbstractRouteMappingTest {
@Test
void gatewayRouteMappingTest() {
String requestBody = "gateway";
AggregatedHttpResponse response = client.post("/gateway/echo", requestBody).aggregate().join();
assertThat(response.status().code()).isEqualTo(200);
assertThat(response.contentUtf8()).isEqualTo(requestBody);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("POST path_route")
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfying(
buildAttributeAssertions("path_route", "h1c://mock.response", 0, 1)),
span -> span.hasName(WEBFLUX_SPAN_NAME).hasKind(SpanKind.INTERNAL)));
}
@Test
void gatewayRandomUuidRouteMappingTest() {
String requestBody = "gateway";
AggregatedHttpResponse response = client.post("/uuid/echo", requestBody).aggregate().join();
assertThat(response.status().code()).isEqualTo(200);
assertThat(response.contentUtf8()).isEqualTo(requestBody);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("POST")
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfying(buildAttributeAssertions("h1c://mock.uuid", 0, 1)),
span -> span.hasName(WEBFLUX_SPAN_NAME).hasKind(SpanKind.INTERNAL)));
}
@Test
void gatewayFakeUuidRouteMappingTest() {
String requestBody = "gateway";
String routeId = "ffffffff-ffff-ffff-ffff-ffff";
AggregatedHttpResponse response = client.post("/fake/echo", requestBody).aggregate().join();
assertThat(response.status().code()).isEqualTo(200);
assertThat(response.contentUtf8()).isEqualTo(requestBody);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("POST " + routeId)
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfying(
buildAttributeAssertions(routeId, "h1c://mock.fake", 0, 1)),
span -> span.hasName(WEBFLUX_SPAN_NAME).hasKind(SpanKind.INTERNAL)));
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.GatewayFilterSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.builder.UriSpec;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayTestApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
// A simple echo gateway.
return builder
.routes()
.route(
"path_route",
r ->
r.path("/gateway/**")
.filters(GatewayTestApplication::echoFunc)
.uri("h1c://mock.response"))
// The routeID should be a random UUID.
.route(
r ->
r.path("/uuid/**").filters(GatewayTestApplication::echoFunc).uri("h1c://mock.uuid"))
// Seems like an uuid but not.
.route(
"ffffffff-ffff-ffff-ffff-ffff",
r ->
r.path("/fake/**").filters(GatewayTestApplication::echoFunc).uri("h1c://mock.fake"))
.build();
}
private static UriSpec echoFunc(GatewayFilterSpec f) {
return f.filter(
(exchange, chain) -> exchange.getResponse().writeWith(exchange.getRequest().getBody()));
}
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<root level="WARN">
<appender-ref ref="console"/>
</root>
<!-- this is needed because when Spring Boot starts it overrides the debug log level that was
configured in AgentTestRunner -->
<logger name="io.opentelemetry" level="debug"/>
</configuration>

View File

@ -0,0 +1,43 @@
plugins {
id("otel.javaagent-testing")
}
dependencies {
testInstrumentation(project(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-2.0:javaagent"))
testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent"))
testInstrumentation(project(":instrumentation:reactor:reactor-3.1:javaagent"))
testInstrumentation(project(":instrumentation:reactor:reactor-netty:reactor-netty-1.0:javaagent"))
testInstrumentation(project(":instrumentation:spring:spring-webflux:spring-webflux-5.0:javaagent"))
testImplementation(project(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-common:testing"))
testLibrary("org.springframework.cloud:spring-cloud-starter-gateway:2.2.0.RELEASE")
testLibrary("org.springframework.boot:spring-boot-starter-test:2.2.0.RELEASE")
}
tasks.withType<Test>().configureEach {
jvmArgs("-Dotel.instrumentation.spring-cloud-gateway.experimental-span-attributes=true")
// required on jdk17
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
}
val latestDepTest = findProperty("testLatestDeps") as Boolean
if (latestDepTest) {
// spring 6 requires java 17
otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_17)
}
} else {
// spring 5 requires old logback (and therefore also old slf4j)
configurations.testRuntimeClasspath {
resolutionStrategy {
force("ch.qos.logback:logback-classic:1.2.11")
force("org.slf4j:slf4j-api:1.7.36")
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.gateway.v2_2;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.spring.gateway.common.AbstractRouteMappingTest;
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {
Gateway22TestApplication.class,
Gateway22RouteMappingTest.ForceNettyAutoConfiguration.class
})
class Gateway22RouteMappingTest extends AbstractRouteMappingTest {
@Test
void gatewayRouteMappingTest() {
String requestBody = "gateway";
AggregatedHttpResponse response = client.post("/gateway/echo", requestBody).aggregate().join();
assertThat(response.status().code()).isEqualTo(200);
assertThat(response.contentUtf8()).isEqualTo(requestBody);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("POST")
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfying(
// Global filter is not route filter, so filter size should be 0.
buildAttributeAssertions("h1c://mock.response", 2023, 0)),
span -> span.hasName(WEBFLUX_SPAN_NAME).hasKind(SpanKind.INTERNAL)));
}
}

View File

@ -0,0 +1,18 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.gateway.v2_2;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Gateway22TestApplication {
@Bean
public GlobalFilter echoFilter() {
return (exchange, chain) -> exchange.getResponse().writeWith(exchange.getRequest().getBody());
}
}

View File

@ -0,0 +1,8 @@
spring:
cloud:
gateway:
routes:
- uri: h1c://mock.response
predicates:
- Path=/gateway/echo
order: 2023

View File

@ -0,0 +1,9 @@
plugins {
id("otel.java-conventions")
}
dependencies {
implementation(project(":testing-common"))
compileOnly("org.springframework.boot:spring-boot-starter-test:2.0.0.RELEASE")
}

View File

@ -0,0 +1,66 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.spring.gateway.common;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.internal.StringUtils;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
import io.opentelemetry.testing.internal.armeria.client.WebClient;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
public abstract class AbstractRouteMappingTest {
@TestConfiguration
public static class ForceNettyAutoConfiguration {
@Bean
NettyReactiveWebServerFactory nettyFactory() {
return new NettyReactiveWebServerFactory();
}
}
@RegisterExtension
protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
@Value("${local.server.port}")
private int port;
protected WebClient client;
protected static final String WEBFLUX_SPAN_NAME = "FilteringWebHandler.handle";
@BeforeEach
void beforeEach() {
client = WebClient.builder("h1c://localhost:" + port).followRedirects().build();
}
protected List<AttributeAssertion> buildAttributeAssertions(
String routeId, String uri, int order, int filterSize) {
List<AttributeAssertion> assertions = new ArrayList<>();
if (!StringUtils.isNullOrEmpty(routeId)) {
assertions.add(equalTo(AttributeKey.stringKey("spring-cloud-gateway.route.id"), routeId));
}
assertions.add(equalTo(AttributeKey.stringKey("spring-cloud-gateway.route.uri"), uri));
assertions.add(equalTo(AttributeKey.longKey("spring-cloud-gateway.route.order"), order));
assertions.add(
equalTo(AttributeKey.longKey("spring-cloud-gateway.route.filter.size"), filterSize));
return assertions;
}
protected List<AttributeAssertion> buildAttributeAssertions(
String uri, int order, int filterSize) {
return buildAttributeAssertions(null, uri, order, filterSize);
}
}

View File

@ -494,6 +494,9 @@ include(":instrumentation:spring:spring-batch-3.0:javaagent")
include(":instrumentation:spring:spring-boot-actuator-autoconfigure-2.0:javaagent") include(":instrumentation:spring:spring-boot-actuator-autoconfigure-2.0:javaagent")
include(":instrumentation:spring:spring-boot-resources:library") include(":instrumentation:spring:spring-boot-resources:library")
include(":instrumentation:spring:spring-boot-resources:testing") include(":instrumentation:spring:spring-boot-resources:testing")
include(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-2.0:javaagent")
include(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-2.2:testing")
include(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-common:testing")
include(":instrumentation:spring:spring-core-2.0:javaagent") include(":instrumentation:spring:spring-core-2.0:javaagent")
include(":instrumentation:spring:spring-data:spring-data-1.8:javaagent") include(":instrumentation:spring:spring-data:spring-data-1.8:javaagent")
include(":instrumentation:spring:spring-data:spring-data-3.0:testing") include(":instrumentation:spring:spring-data:spring-data-3.0:testing")