Move helper class to spring package so that loadClass can find it (#3718)
* Move helper class to spring package so that loadClass can find it * spotless * Add tests * Add comments * remove unneeded dependency * comments
This commit is contained in:
parent
8d90462a28
commit
38c8f8940c
|
@ -0,0 +1,18 @@
|
|||
plugins {
|
||||
id("otel.javaagent-instrumentation")
|
||||
}
|
||||
|
||||
muzzle {
|
||||
pass {
|
||||
group.set("org.springframework")
|
||||
module.set("spring-web")
|
||||
versions.set("[3.1.0.RELEASE,]")
|
||||
// these versions depend on javax.faces:jsf-api:1.1 which was released as pom only
|
||||
skip("1.2.1", "1.2.2", "1.2.3", "1.2.4")
|
||||
assertInverse.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.springframework:spring-web:3.1.0.RELEASE")
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.springweb;
|
||||
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class SpringWebInstrumentationModule extends InstrumentationModule {
|
||||
public SpringWebInstrumentationModule() {
|
||||
super("spring-web", "spring-web-3.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
||||
// class added in 3.1
|
||||
return hasClassesNamed("org.springframework.web.method.HandlerMethod");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new WebApplicationContextInstrumentation());
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.springwebmvc;
|
||||
package io.opentelemetry.javaagent.instrumentation.springweb;
|
||||
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||
|
@ -11,6 +11,7 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.
|
|||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON;
|
||||
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
|
@ -19,9 +20,10 @@ import net.bytebuddy.description.type.TypeDescription;
|
|||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
|
||||
/**
|
||||
* This instrumentation adds the HandlerMappingResourceNameFilter definition to the spring context
|
||||
* This instrumentation adds the OpenTelemetryHandlerMappingFilter definition to the spring context
|
||||
* When the context is created, the filter will be added to the beginning of the filter chain.
|
||||
*/
|
||||
public class WebApplicationContextInstrumentation implements TypeInstrumentation {
|
||||
|
@ -59,10 +61,29 @@ public class WebApplicationContextInstrumentation implements TypeInstrumentation
|
|||
public static void onEnter(@Advice.Argument(0) ConfigurableListableBeanFactory beanFactory) {
|
||||
if (beanFactory instanceof BeanDefinitionRegistry
|
||||
&& !beanFactory.containsBean("otelAutoDispatcherFilter")) {
|
||||
try {
|
||||
// Firstly check whether DispatcherServlet is present. We need to load an instrumented
|
||||
// class from spring-webmvc to trigger injection that makes
|
||||
// OpenTelemetryHandlerMappingFilter available.
|
||||
beanFactory
|
||||
.getBeanClassLoader()
|
||||
.loadClass("org.springframework.web.servlet.DispatcherServlet");
|
||||
|
||||
((BeanDefinitionRegistry) beanFactory)
|
||||
.registerBeanDefinition(
|
||||
"otelAutoDispatcherFilter", new HandlerMappingResourceNameFilter.BeanDefinition());
|
||||
// Now attempt to load our injected instrumentation class.
|
||||
Class<?> clazz =
|
||||
beanFactory
|
||||
.getBeanClassLoader()
|
||||
.loadClass("org.springframework.web.servlet.OpenTelemetryHandlerMappingFilter");
|
||||
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
|
||||
beanDefinition.setScope(SCOPE_SINGLETON);
|
||||
beanDefinition.setBeanClass(clazz);
|
||||
beanDefinition.setBeanClassName(clazz.getName());
|
||||
|
||||
((BeanDefinitionRegistry) beanFactory)
|
||||
.registerBeanDefinition("otelAutoDispatcherFilter", beanDefinition);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,17 +15,6 @@ muzzle {
|
|||
extraDependency("javax.servlet:javax.servlet-api:3.0.1")
|
||||
assertInverse.set(true)
|
||||
}
|
||||
|
||||
// FIXME: webmvc depends on web, so we need a separate instrumentation for spring-web specifically.
|
||||
fail {
|
||||
group.set("org.springframework")
|
||||
module.set("spring-web")
|
||||
versions.set("[,]")
|
||||
// these versions depend on org.springframework:spring-web which has a bad dependency on
|
||||
// javax.faces:jsf-api:1.1 which was released as pom only
|
||||
skip("1.2.1", "1.2.2", "1.2.3", "1.2.4")
|
||||
extraDependency("javax.servlet:javax.servlet-api:3.0.1")
|
||||
}
|
||||
}
|
||||
|
||||
val versions: Map<String, String> by project
|
||||
|
@ -36,12 +25,11 @@ dependencies {
|
|||
// compileOnly("org.springframework:spring-webmvc:2.5.6")
|
||||
// compileOnly("javax.servlet:servlet-api:2.4")
|
||||
|
||||
testImplementation(project(":testing-common"))
|
||||
|
||||
// Include servlet instrumentation for verifying the tomcat requests
|
||||
testInstrumentation(project(":instrumentation:servlet:servlet-3.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:servlet:servlet-javax-common:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:tomcat:tomcat-7.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:spring:spring-web-3.1:javaagent"))
|
||||
|
||||
testImplementation("javax.validation:validation-api:1.1.0.Final")
|
||||
testImplementation("org.hibernate:hibernate-validator:5.4.2.Final")
|
||||
|
|
|
@ -24,6 +24,7 @@ import net.bytebuddy.matcher.ElementMatcher;
|
|||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.OpenTelemetryHandlerMappingFilter;
|
||||
|
||||
public class DispatcherServletInstrumentation implements TypeInstrumentation {
|
||||
|
||||
|
@ -62,8 +63,8 @@ public class DispatcherServletInstrumentation implements TypeInstrumentation {
|
|||
@Advice.Argument(0) ApplicationContext springCtx,
|
||||
@Advice.FieldValue("handlerMappings") List<HandlerMapping> handlerMappings) {
|
||||
if (springCtx.containsBean("otelAutoDispatcherFilter")) {
|
||||
HandlerMappingResourceNameFilter filter =
|
||||
(HandlerMappingResourceNameFilter) springCtx.getBean("otelAutoDispatcherFilter");
|
||||
OpenTelemetryHandlerMappingFilter filter =
|
||||
(OpenTelemetryHandlerMappingFilter) springCtx.getBean("otelAutoDispatcherFilter");
|
||||
if (handlerMappings != null && filter != null) {
|
||||
filter.setHandlerMappings(handlerMappings);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,14 @@ public class SpringWebMvcInstrumentationModule extends InstrumentationModule {
|
|||
super("spring-webmvc", "spring-webmvc-3.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHelperClass(String className) {
|
||||
return className.startsWith(
|
||||
"org.springframework.web.servlet.OpenTelemetryHandlerMappingFilter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return asList(
|
||||
new WebApplicationContextInstrumentation(),
|
||||
new DispatcherServletInstrumentation(),
|
||||
new HandlerAdapterInstrumentation());
|
||||
return asList(new DispatcherServletInstrumentation(), new HandlerAdapterInstrumentation());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.springwebmvc;
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTROLLER;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||
import io.opentelemetry.javaagent.instrumentation.springwebmvc.SpringWebMvcServerSpanNaming;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -20,13 +21,10 @@ import javax.servlet.ServletRequest;
|
|||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
public class HandlerMappingResourceNameFilter implements Filter, Ordered {
|
||||
public class OpenTelemetryHandlerMappingFilter implements Filter, Ordered {
|
||||
private volatile List<HandlerMapping> handlerMappings;
|
||||
|
||||
@Override
|
||||
|
@ -122,12 +120,4 @@ public class HandlerMappingResourceNameFilter implements Filter, Ordered {
|
|||
// Run after all HIGHEST_PRECEDENCE items
|
||||
return Ordered.HIGHEST_PRECEDENCE + 1;
|
||||
}
|
||||
|
||||
public static class BeanDefinition extends GenericBeanDefinition {
|
||||
public BeanDefinition() {
|
||||
setScope(SCOPE_SINGLETON);
|
||||
setBeanClass(HandlerMappingResourceNameFilter.class);
|
||||
setBeanClassName(HandlerMappingResourceNameFilter.class.getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
plugins {
|
||||
id("otel.javaagent-testing")
|
||||
}
|
||||
|
||||
val testServer by configurations.creating
|
||||
val appLibrary by configurations.creating
|
||||
|
||||
configurations.named("testCompileOnly") {
|
||||
extendsFrom(appLibrary)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
appLibrary("org.springframework:spring-webmvc:3.1.0.RELEASE")
|
||||
testImplementation("javax.servlet:javax.servlet-api:3.1.0")
|
||||
|
||||
val arquillianVersion = "1.4.0.Final"
|
||||
testImplementation("org.jboss.arquillian.junit:arquillian-junit-container:${arquillianVersion}")
|
||||
testImplementation("org.jboss.arquillian.protocol:arquillian-protocol-servlet:${arquillianVersion}")
|
||||
testImplementation("org.jboss.arquillian.spock:arquillian-spock-container:1.0.0.CR1")
|
||||
testImplementation("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6")
|
||||
|
||||
testRuntimeOnly("org.wildfly.arquillian:wildfly-arquillian-container-embedded:2.2.0.Final")
|
||||
|
||||
testInstrumentation(project(":instrumentation:servlet:servlet-3.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:spring:spring-webmvc-3.1:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:spring:spring-web-3.1:javaagent"))
|
||||
|
||||
// wildfly version used to run tests
|
||||
testServer("org.wildfly:wildfly-dist:18.0.0.Final@zip")
|
||||
}
|
||||
|
||||
tasks {
|
||||
// extract wildfly dist, path is used from arquillian.xml
|
||||
val setupServer by registering(Copy::class) {
|
||||
from(zipTree(testServer.singleFile))
|
||||
into(file("build/server/"))
|
||||
}
|
||||
|
||||
// logback-classic contains /META-INF/services/javax.servlet.ServletContainerInitializer
|
||||
// that breaks deploy on embedded wildfly
|
||||
// create a copy of logback-classic jar that does not have this file
|
||||
val modifyLogbackJar by registering(Jar::class) {
|
||||
destinationDirectory.set(file("$buildDir/tmp"))
|
||||
archiveFileName.set("logback-classic-modified.jar")
|
||||
exclude("/META-INF/services/javax.servlet.ServletContainerInitializer")
|
||||
doFirst {
|
||||
configurations.configureEach {
|
||||
if (name.toLowerCase().endsWith("testruntimeclasspath")) {
|
||||
val logbackJar = find { it.name.contains("logback-classic") }
|
||||
from(zipTree(logbackJar))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val copyDependencies by registering(Copy::class) {
|
||||
// test looks for spring jars that are bundled inside deployed application from this directory
|
||||
from(appLibrary).into("$buildDir/app-libs")
|
||||
}
|
||||
|
||||
named<Test>("test") {
|
||||
dependsOn(modifyLogbackJar)
|
||||
dependsOn(setupServer)
|
||||
dependsOn(copyDependencies)
|
||||
|
||||
doFirst {
|
||||
// --add-modules is unrecognized on jdk8, ignore it instead of failing
|
||||
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
|
||||
// needed for java 11 to avoid org.jboss.modules.ModuleNotFoundException: java.se
|
||||
jvmArgs("--add-modules=java.se")
|
||||
// add offset to default port values
|
||||
jvmArgs("-Djboss.socket.binding.port-offset=300")
|
||||
|
||||
// remove logback-classic from classpath
|
||||
classpath = classpath.filter {
|
||||
!it.absolutePath.contains("logback-classic")
|
||||
}
|
||||
// add modified copy of logback-classic to classpath
|
||||
classpath = classpath.plus(files("$buildDir/tmp/logback-classic-modified.jar"))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
|
||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
||||
|
||||
import com.example.hello.HelloController
|
||||
import com.example.hello.TestFilter
|
||||
import io.opentelemetry.api.trace.StatusCode
|
||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||
import io.opentelemetry.testing.internal.armeria.client.WebClient
|
||||
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
|
||||
import org.jboss.arquillian.container.test.api.Deployment
|
||||
import org.jboss.arquillian.container.test.api.RunAsClient
|
||||
import org.jboss.arquillian.spock.ArquillianSputnik
|
||||
import org.jboss.arquillian.test.api.ArquillianResource
|
||||
import org.jboss.shrinkwrap.api.Archive
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap
|
||||
import org.jboss.shrinkwrap.api.spec.EnterpriseArchive
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(ArquillianSputnik)
|
||||
@RunAsClient
|
||||
// Test that OpenTelemetryHandlerMappingFilter injection works when spring libraries are in various
|
||||
// locations inside deployment.
|
||||
abstract class OpenTelemetryHandlerMappingFilterTest extends AgentInstrumentationSpecification {
|
||||
|
||||
static WebClient client = WebClient.of()
|
||||
|
||||
@ArquillianResource
|
||||
static URI url
|
||||
|
||||
def getAddress(String service) {
|
||||
return url.resolve(service).toString()
|
||||
}
|
||||
|
||||
def "test success"() {
|
||||
when:
|
||||
AggregatedHttpResponse response = client.get(getAddress("hello/world")).aggregate().join()
|
||||
|
||||
then:
|
||||
response.status().code() == 200
|
||||
response.contentUtf8() == "hello world"
|
||||
|
||||
and:
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "/hello/{name}"
|
||||
kind SERVER
|
||||
hasNoParent()
|
||||
}
|
||||
span(1) {
|
||||
name "HelloController.hello"
|
||||
kind INTERNAL
|
||||
childOf(span(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "test exception"() {
|
||||
when:
|
||||
AggregatedHttpResponse response = client.get(getAddress("hello/exception")).aggregate().join()
|
||||
|
||||
then:
|
||||
response.status().code() == 500
|
||||
|
||||
and:
|
||||
assertTraces(1) {
|
||||
trace(0, 1) {
|
||||
span(0) {
|
||||
name "/hello/{name}"
|
||||
kind SERVER
|
||||
status StatusCode.ERROR
|
||||
hasNoParent()
|
||||
|
||||
event(0) {
|
||||
eventName(SemanticAttributes.EXCEPTION_EVENT_NAME)
|
||||
attributes {
|
||||
"${SemanticAttributes.EXCEPTION_TYPE.key}" "javax.servlet.ServletException"
|
||||
"${SemanticAttributes.EXCEPTION_MESSAGE.key}" "exception"
|
||||
"${SemanticAttributes.EXCEPTION_STACKTRACE.key}" { it == null || it instanceof String }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spring is inside ear/lib
|
||||
class LibsInEarTest extends OpenTelemetryHandlerMappingFilterTest {
|
||||
@Deployment
|
||||
static Archive<?> createDeployment() {
|
||||
WebArchive war = ShrinkWrap.create(WebArchive, "test.war")
|
||||
.addAsWebInfResource("web.xml")
|
||||
.addAsWebInfResource("dispatcher-servlet.xml")
|
||||
.addAsWebInfResource("applicationContext.xml")
|
||||
.addClass(HelloController)
|
||||
.addClass(TestFilter)
|
||||
|
||||
EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive)
|
||||
.setApplicationXML("application.xml")
|
||||
.addAsModule(war)
|
||||
.addAsLibraries(new File("build/app-libs").listFiles())
|
||||
|
||||
return ear
|
||||
}
|
||||
}
|
||||
|
||||
// spring is inside war/WEB-INF/lib
|
||||
class LibsInWarTest extends OpenTelemetryHandlerMappingFilterTest {
|
||||
@Deployment
|
||||
static Archive<?> createDeployment() {
|
||||
WebArchive war = ShrinkWrap.create(WebArchive, "test.war")
|
||||
.addAsWebInfResource("web.xml")
|
||||
.addAsWebInfResource("dispatcher-servlet.xml")
|
||||
.addAsWebInfResource("applicationContext.xml")
|
||||
.addClass(HelloController)
|
||||
.addClass(TestFilter)
|
||||
.addAsLibraries(new File("build/app-libs").listFiles())
|
||||
|
||||
EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive)
|
||||
.setApplicationXML("application.xml")
|
||||
.addAsModule(war)
|
||||
|
||||
return ear
|
||||
}
|
||||
}
|
||||
|
||||
// Everything except spring-webmvc is in ear/lib, spring-webmvc is in war/WEB-INF/lib
|
||||
class MixedLibsTest extends OpenTelemetryHandlerMappingFilterTest {
|
||||
@Deployment
|
||||
static Archive<?> createDeployment() {
|
||||
WebArchive war = ShrinkWrap.create(WebArchive, "test.war")
|
||||
.addAsWebInfResource("web.xml")
|
||||
.addAsWebInfResource("dispatcher-servlet.xml")
|
||||
.addAsWebInfResource("applicationContext.xml")
|
||||
.addClass(HelloController)
|
||||
.addClass(TestFilter)
|
||||
.addAsLibraries(new File("build/app-libs").listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
boolean accept(File dir, String name) {
|
||||
return name.contains("spring-webmvc")
|
||||
}
|
||||
}))
|
||||
|
||||
EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive)
|
||||
.setApplicationXML("application.xml")
|
||||
.addAsModule(war)
|
||||
.addAsLibraries(new File("build/app-libs").listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
boolean accept(File dir, String name) {
|
||||
return !name.contains("spring-webmvc")
|
||||
}
|
||||
}))
|
||||
|
||||
return ear
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.example.hello;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class HelloController {
|
||||
|
||||
@RequestMapping("/hello/{name}")
|
||||
@ResponseBody
|
||||
public String hello(@PathVariable("name") String name) {
|
||||
return "hello " + name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.example.hello;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("testFilter")
|
||||
public class TestFilter implements Filter {
|
||||
public TestFilter() {}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
// To test OpenTelemetryHandlerMappingFilter we need to stop the request before it reaches
|
||||
// HandlerAdapter which gives server span the same name as OpenTelemetryHandlerMappingFilter.
|
||||
// Throwing an exception from servlet filter works for that.
|
||||
if (httpServletRequest.getRequestURI().contains("exception")) {
|
||||
throw new ServletException("exception");
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<application xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd" version="7">
|
||||
<display-name>hello-ear</display-name>
|
||||
<module>
|
||||
<web>
|
||||
<web-uri>test.war</web-uri>
|
||||
<context-root>/</context-root>
|
||||
</web>
|
||||
</module>
|
||||
<library-directory>lib</library-directory>
|
||||
</application>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
|
||||
|
||||
<mvc:annotation-driven/>
|
||||
|
||||
<context:component-scan base-package="com.example.hello"/>
|
||||
</beans>
|
|
@ -0,0 +1,15 @@
|
|||
<arquillian xmlns="http://jboss.org/schema/arquillian"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://jboss.org/schema/arquillian
|
||||
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
|
||||
|
||||
<defaultProtocol type="Servlet 3.0" />
|
||||
|
||||
<container qualifier="wildfly-embedded" default="true">
|
||||
<configuration>
|
||||
<property name="jbossHome">build/server/wildfly-18.0.0.Final</property>
|
||||
<property name="modulePath">build/server/wildfly-18.0.0.Final/modules</property>
|
||||
</configuration>
|
||||
</container>
|
||||
</arquillian>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<servlet>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!--
|
||||
Spring boot automatically registers a servlet filter when spring bean implements
|
||||
javax.servlet.Filter but vanilla spring does not so we need to add a placeholder
|
||||
for our servlet filter here.
|
||||
-->
|
||||
<filter>
|
||||
<filter-name>otelAutoDispatcherFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<filter-name>testFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
</filter>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>otelAutoDispatcherFilter</filter-name>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>testFilter</filter-name>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
</filter-mapping>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
</web-app>
|
|
@ -306,10 +306,12 @@ include(":instrumentation:spring:spring-integration-4.1:library")
|
|||
include(":instrumentation:spring:spring-integration-4.1:testing")
|
||||
include(":instrumentation:spring:spring-rabbit-1.0:javaagent")
|
||||
include(":instrumentation:spring:spring-scheduling-3.1:javaagent")
|
||||
include(":instrumentation:spring:spring-web-3.1:javaagent")
|
||||
include(":instrumentation:spring:spring-web-3.1:library")
|
||||
include(":instrumentation:spring:spring-web-3.1:testing")
|
||||
include(":instrumentation:spring:spring-webmvc-3.1:javaagent")
|
||||
include(":instrumentation:spring:spring-webmvc-3.1:library")
|
||||
include(":instrumentation:spring:spring-webmvc-3.1:wildfly-testing")
|
||||
include(":instrumentation:spring:spring-webflux-5.0:javaagent")
|
||||
include(":instrumentation:spring:spring-webflux-5.0:library")
|
||||
include(":instrumentation:spring:spring-ws-2.0:javaagent")
|
||||
|
|
Loading…
Reference in New Issue