Instrument java.servlet.Filter directly (#1606)

* Instrument filter directly

* Remove some additional ignores

* Fix OncePerRequestFilter not being instrumented itself
This commit is contained in:
Trask Stalnaker 2020-11-18 19:59:28 -08:00 committed by GitHub
parent cecdfc2cd0
commit 80b068b459
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 16 deletions

View File

@ -42,7 +42,7 @@ public class Servlet2InstrumentationModule extends InstrumentationModule {
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return Arrays.asList(
new HttpServletResponseInstrumentation(), new ServletAndFilterChainInstrumentation());
new HttpServletResponseInstrumentation(), new ServletAndFilterInstrumentation());
}
@Override

View File

@ -19,7 +19,7 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
final class ServletAndFilterChainInstrumentation implements TypeInstrumentation {
final class ServletAndFilterInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
@ -29,8 +29,7 @@ final class ServletAndFilterChainInstrumentation implements TypeInstrumentation
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return safeHasSuperType(
namedOneOf("javax.servlet.FilterChain", "javax.servlet.http.HttpServlet"));
return safeHasSuperType(namedOneOf("javax.servlet.Filter", "javax.servlet.http.HttpServlet"));
}
/**

View File

@ -31,6 +31,6 @@ public class Servlet3InstrumentationModule extends InstrumentationModule {
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new AsyncContextInstrumentation(), new ServletAndFilterChainInstrumentation());
return asList(new AsyncContextInstrumentation(), new ServletAndFilterInstrumentation());
}
}

View File

@ -19,7 +19,7 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
final class ServletAndFilterChainInstrumentation implements TypeInstrumentation {
final class ServletAndFilterInstrumentation implements TypeInstrumentation {
@Override
public ElementMatcher<ClassLoader> classLoaderMatcher() {
// Optimization for expensive typeMatcher.
@ -28,8 +28,7 @@ final class ServletAndFilterChainInstrumentation implements TypeInstrumentation
@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return safeHasSuperType(
namedOneOf("javax.servlet.FilterChain", "javax.servlet.http.HttpServlet"));
return safeHasSuperType(namedOneOf("javax.servlet.Filter", "javax.servlet.http.HttpServlet"));
}
/**

View File

@ -12,33 +12,44 @@ import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import java.io.IOException;
import java.util.List;
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 javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
public class HandlerMappingResourceNameFilter extends OncePerRequestFilter implements Ordered {
public class HandlerMappingResourceNameFilter implements Filter, Ordered {
private volatile List<HandlerMapping> handlerMappings;
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
public void init(FilterConfig filterConfig) {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
filterChain.doFilter(request, response);
return;
}
Context context = Context.current();
Span serverSpan = BaseTracer.getCurrentServerSpan(context);
if (handlerMappings != null && serverSpan != null) {
try {
if (findMapping(request)) {
if (findMapping((HttpServletRequest) request)) {
// Name the parent span based on the matching pattern
// Let the parent span resource name be set with the attribute set in findMapping.
tracer().onRequest(context, serverSpan, request);
tracer().onRequest(context, serverSpan, (HttpServletRequest) request);
}
} catch (Exception ignored) {
// mapping.getHandler() threw exception. Ignore
@ -48,6 +59,9 @@ public class HandlerMappingResourceNameFilter extends OncePerRequestFilter imple
filterChain.doFilter(request, response);
}
@Override
public void destroy() {}
/**
* When a HandlerMapping matches a request, it sets HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE
* as an attribute on the request. This attribute is read by SpringWebMvcDecorator.onRequest and

View File

@ -167,6 +167,7 @@ public class AdditionalLibraryIgnoresMatcher<T extends TypeDescription>
if (name.startsWith("org.springframework.web.")) {
if (name.startsWith("org.springframework.web.servlet.")
|| name.startsWith("org.springframework.web.filter.")
|| name.startsWith("org.springframework.web.reactive.")
|| name.startsWith("org.springframework.web.context.request.async.")
|| name.equals(
@ -306,7 +307,7 @@ public class AdditionalLibraryIgnoresMatcher<T extends TypeDescription>
return false;
}
private static Set<String> INSTRUMENTED_SPRING_BOOT_CLASSES =
private static final Set<String> INSTRUMENTED_SPRING_BOOT_CLASSES =
Sets.newHashSet(
"org.springframework.boot.autoconfigure.BackgroundPreinitializer$",
"org.springframework.boot.autoconfigure.condition.OnClassCondition$",
@ -319,7 +320,12 @@ public class AdditionalLibraryIgnoresMatcher<T extends TypeDescription>
"org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext",
"org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext",
"org.springframework.boot.web.embedded.tomcat.TomcatWebServer$",
"org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader");
"org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader",
"org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean$",
"org.springframework.boot.web.filter.OrderedCharacterEncodingFilter",
"org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter",
"org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter",
"org.springframework.boot.web.filter.OrderedRequestContextFilter");
private static String outerClassName(final String name) {
int separator = name.indexOf('$');