-
Notifications
You must be signed in to change notification settings - Fork 970
feat: get route info in spring-cloud-gateway #9597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
bbd5d11
feat: get route info in spring-cloud-gateway
123liuziming 239978f
refactor: run spotless apply to fix violations
123liuziming 43895fb
refactor: remove unnecessary comment in GatewayRouteMappingTest.java
123liuziming 95972e9
refactor: add minimal supported version and muzzle
123liuziming 982569c
rename package & low cardinality
123liuziming 8c5b87b
refactor: fix checkstyle
123liuziming b1121bb
refactor: revert commit
123liuziming 4294e74
test: rename package
123liuziming bf96609
test: verify span name
123liuziming cd15d3f
fix: rename attributes
123liuziming bc984ab
fix: fix comment
123liuziming 9c7fb40
fix: fix comment
123liuziming 15deba8
Update supported-libraries.md
123liuziming b8f1403
Reorder supported-libraries.md
123liuziming 1fddd99
Reorder settings.gradle.kts
123liuziming File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
...mentation/spring/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/build.gradle.kts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
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 { | ||
compileOnly("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")) | ||
|
||
testLibrary("org.springframework.cloud:spring-cloud-starter-gateway:2.0.0.RELEASE") | ||
testLibrary("org.springframework.boot:spring-boot-starter-test:2.0.0.RELEASE") | ||
} | ||
|
||
tasks.withType<Test>().configureEach { | ||
// TODO run tests both with and without experimental span attributes | ||
jvmArgs("-Dotel.instrumentation.spring-webflux.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") | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
.../io/opentelemetry/javaagent/instrumentation/spring/v2_0/GatewayInstrumentationModule.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.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; | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...c/main/java/io/opentelemetry/javaagent/instrumentation/spring/v2_0/GatewaySingletons.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.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); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
...io/opentelemetry/javaagent/instrumentation/spring/v2_0/HandlerAdapterInstrumentation.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.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 current span, should be webflux's span. | ||
ServerWebExchangeHelper.extractAttributes(exchange, context); | ||
} | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
.../java/io/opentelemetry/javaagent/instrumentation/spring/v2_0/ServerWebExchangeHelper.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.v2_0; | ||
|
||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; | ||
|
||
import io.opentelemetry.api.trace.Span; | ||
import io.opentelemetry.context.Context; | ||
import org.springframework.cloud.gateway.route.Route; | ||
import org.springframework.web.server.ServerWebExchange; | ||
|
||
public final class ServerWebExchangeHelper { | ||
|
||
/** Route info key. */ | ||
public static final String ROUTE_INFO_ATTRIBUTES = "ROUTE_INFO"; | ||
123liuziming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
private ServerWebExchangeHelper() {} | ||
|
||
public static void extractAttributes(ServerWebExchange exchange, Context context) { | ||
// Record route info | ||
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); | ||
if (route != null) { | ||
Span currentSpan = Span.fromContext(context); | ||
assert currentSpan != null; | ||
currentSpan.setAttribute(ROUTE_INFO_ATTRIBUTES, route.toString()); | ||
123liuziming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
public static String extractServerRoute(ServerWebExchange exchange) { | ||
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); | ||
if (route != null) { | ||
return "Route@" + route.getId(); | ||
123liuziming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return null; | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
.../opentelemetry/javaagent/instrumentation/spring/gateway/v2_0/GatewayRouteMappingTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.gateway.v2_0; | ||
|
||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; | ||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import io.opentelemetry.api.common.AttributeKey; | ||
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; | ||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; | ||
import io.opentelemetry.javaagent.instrumentation.spring.v2_0.ServerWebExchangeHelper; | ||
import io.opentelemetry.semconv.SemanticAttributes; | ||
import io.opentelemetry.testing.internal.armeria.client.WebClient; | ||
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.junit.jupiter.api.extension.RegisterExtension; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.context.TestConfiguration; | ||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
|
||
@ExtendWith(SpringExtension.class) | ||
@SpringBootTest( | ||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, | ||
classes = { | ||
GatewayTestApplication.class, | ||
GatewayRouteMappingTest.ForceNettyAutoConfiguration.class | ||
}) | ||
public class GatewayRouteMappingTest { | ||
|
||
@TestConfiguration | ||
static class ForceNettyAutoConfiguration { | ||
@Bean | ||
NettyReactiveWebServerFactory nettyFactory() { | ||
return new NettyReactiveWebServerFactory(); | ||
} | ||
} | ||
|
||
@RegisterExtension | ||
static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); | ||
|
||
@Value("${local.server.port}") | ||
private int port; | ||
|
||
private WebClient client; | ||
|
||
@BeforeEach | ||
void beforeEach() { | ||
client = WebClient.builder("h1c://localhost:" + port).followRedirects().build(); | ||
} | ||
|
||
@Test | ||
void gatewayRouteMappingTest() { | ||
String requestBody = "gateway"; | ||
String expectRoute = "Route@path_route"; | ||
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.hasAttribute(equalTo(SemanticAttributes.HTTP_ROUTE, expectRoute)), | ||
span -> | ||
span.hasAttributesSatisfying( | ||
satisfies( | ||
AttributeKey.stringKey(ServerWebExchangeHelper.ROUTE_INFO_ATTRIBUTES), | ||
s -> s.contains("id='path_route'")), | ||
satisfies( | ||
AttributeKey.stringKey(ServerWebExchangeHelper.ROUTE_INFO_ATTRIBUTES), | ||
s -> s.contains("uri=h1c://mock.response"))))); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
...o/opentelemetry/javaagent/instrumentation/spring/gateway/v2_0/GatewayTestApplication.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* 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.RouteLocatorBuilder; | ||
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", | ||
123liuziming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
r -> | ||
r.path("/gateway/**") | ||
.filters( | ||
f -> | ||
f.filter( | ||
(exchange, chain) -> | ||
exchange | ||
.getResponse() | ||
.writeWith(exchange.getRequest().getBody()))) | ||
.uri("h1c://mock.response")) | ||
.build(); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...ng/spring-cloud-gateway/spring-cloud-gateway-2.0/javaagent/src/test/resources/logback.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.