Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
* <li>{@link jakarta.servlet.Filter#init(jakarta.servlet.FilterConfig)}</li>
* <li>{@link javax.servlet.Servlet#init(javax.servlet.ServletConfig)}</li>
* <li>{@link jakarta.servlet.Servlet#init(jakarta.servlet.ServletConfig)}</li>
* <li>{@link javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)}</li>
* <li>{@link jakarta.servlet.ServletContextListener#contextInitialized(jakarta.servlet.ServletContextEvent)}</li>
* </ul>
*
* Determines the service name based on the webapp's {@code META-INF/MANIFEST.MF} file early in the startup process.
Expand All @@ -54,19 +56,24 @@ public abstract class InitServiceNameInstrumentation extends AbstractServletInst

@Override
public ElementMatcher<? super NamedElement> getTypeMatcherPreFilter() {
return nameContains("Filter").or(nameContains("Servlet"));
return nameContains("Filter").or(nameContains("Servlet")).or(nameContains("Listener"));
}

@Override
public ElementMatcher<? super TypeDescription> getTypeMatcher() {
return not(isInterface()).and(hasSuperType(namedOneOf("javax.servlet.Filter", "javax.servlet.Servlet", "jakarta.servlet.Filter", "jakarta.servlet.Servlet")));
return not(isInterface()).and(hasSuperType(namedOneOf(
"javax.servlet.ServletContextListener", "javax.servlet.Filter", "javax.servlet.Servlet",
"jakarta.servlet.ServletContextListener", "jakarta.servlet.Filter", "jakarta.servlet.Servlet")));
}

@Override
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
return named("init")
.and(takesArguments(1))
.and(takesArgument(0, nameEndsWith("Config")));
.and(takesArgument(0, nameEndsWith("Config")))
.or(named("contextInitialized")
.and(takesArguments(1))
.and(takesArgument(0, nameEndsWith("ServletContextEvent"))));
}

public static class JavaxInitServiceNameInstrumentation extends InitServiceNameInstrumentation {
Expand All @@ -80,15 +87,14 @@ public String rootClassNameThatClassloaderCanLoad() {

public static class AdviceClass {
@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void onEnter(@Advice.Argument(0) @Nullable Object config) {
if (config == null) {
return;
}
public static void onEnter(@Advice.Argument(0) @Nullable Object arg) {
javax.servlet.ServletContext servletContext;
if (config instanceof javax.servlet.FilterConfig) {
servletContext = adapter.getServletContextFromFilterConfig((javax.servlet.FilterConfig) config);
} else if (config instanceof javax.servlet.ServletConfig) {
servletContext = adapter.getServletContextFromServletConfig((javax.servlet.ServletConfig) config);
if (arg instanceof javax.servlet.FilterConfig) {
servletContext = adapter.getServletContextFromFilterConfig((javax.servlet.FilterConfig) arg);
} else if (arg instanceof javax.servlet.ServletConfig) {
servletContext = adapter.getServletContextFromServletConfig((javax.servlet.ServletConfig) arg);
} else if (arg instanceof javax.servlet.ServletContextEvent) {
servletContext = adapter.getServletContextFromServletContextEvent((javax.servlet.ServletContextEvent) arg);
} else {
return;
}
Expand All @@ -109,15 +115,14 @@ public String rootClassNameThatClassloaderCanLoad() {
public static class AdviceClass {

@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void onEnter(@Advice.Argument(0) @Nullable Object config) {
if (config == null) {
return;
}
public static void onEnter(@Advice.Argument(0) @Nullable Object arg) {
jakarta.servlet.ServletContext servletContext;
if (config instanceof jakarta.servlet.FilterConfig) {
servletContext = adapter.getServletContextFromFilterConfig((jakarta.servlet.FilterConfig) config);
} else if (config instanceof jakarta.servlet.ServletConfig) {
servletContext = adapter.getServletContextFromServletConfig((jakarta.servlet.ServletConfig) config);
if (arg instanceof jakarta.servlet.FilterConfig) {
servletContext = adapter.getServletContextFromFilterConfig((jakarta.servlet.FilterConfig) arg);
} else if (arg instanceof jakarta.servlet.ServletConfig) {
servletContext = adapter.getServletContextFromServletConfig((jakarta.servlet.ServletConfig) arg);
} else if (arg instanceof jakarta.servlet.ServletContextEvent) {
servletContext = adapter.getServletContextFromServletContextEvent((jakarta.servlet.ServletContextEvent) arg);
} else {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ public abstract class ServletApiAdvice {
private static final List<String> requestExceptionAttributes = Arrays.asList("javax.servlet.error.exception", "jakarta.servlet.error.exception", "exception", "org.springframework.web.servlet.DispatcherServlet.EXCEPTION", "co.elastic.apm.exception");

@Nullable
public static <HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> Object onServletEnter(
ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> adapter,
public static <HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> Object onServletEnter(
ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> adapter,
Object servletRequest) {

ElasticApmTracer tracer = GlobalTracer.getTracerImpl();
Expand Down Expand Up @@ -159,8 +159,8 @@ public static <HttpServletRequest, HttpServletResponse, ServletContext, FilterCo
return ret;
}

public static <HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> void onExitServlet(
ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> adapter,
public static <HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> void onExitServlet(
ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> adapter,
Object servletRequest,
Object servletResponse,
@Nullable Object transactionOrScopeOrSpan,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -38,7 +39,7 @@
import java.util.Enumeration;
import java.util.Map;

public class JakartaServletApiAdapter implements ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> {
public class JakartaServletApiAdapter implements ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> {

public static final JakartaServletApiAdapter INSTANCE = new JakartaServletApiAdapter();

Expand Down Expand Up @@ -214,6 +215,11 @@ public boolean isInstanceOfHttpServlet(Object object) {
return object instanceof HttpServlet;
}

@Override
public ServletContext getServletContextFromServletContextEvent(ServletContextEvent servletContextEvent) {
return servletContextEvent.getServletContext();
}

@Override
public ServletContext getServletContextFromServletConfig(ServletConfig filterConfig) {
return filterConfig.getServletContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -38,7 +39,7 @@
import java.util.Enumeration;
import java.util.Map;

public class JavaxServletApiAdapter implements ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> {
public class JavaxServletApiAdapter implements ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> {

private static final JavaxServletApiAdapter INSTANCE = new JavaxServletApiAdapter();

Expand Down Expand Up @@ -213,6 +214,11 @@ public boolean isInstanceOfHttpServlet(Object object) {
return object instanceof HttpServlet;
}

@Override
public ServletContext getServletContextFromServletContextEvent(ServletContextEvent servletContextEvent) {
return servletContextEvent.getServletContext();
}

@Override
public ServletContext getServletContextFromServletConfig(ServletConfig filterConfig) {
return filterConfig.getServletContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import co.elastic.apm.agent.sdk.state.GlobalState;

@GlobalState
public interface ServletAdapter<ServletConfig, ServletContext> {
public interface ServletAdapter<ServletContextEvent, ServletConfig, ServletContext> {

boolean isInstanceOfHttpServlet(Object object);

ServletContext getServletContextFromServletContextEvent(ServletContextEvent servletContextEvent);

ServletContext getServletContextFromServletConfig(ServletConfig filterConfig);

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
import co.elastic.apm.agent.sdk.state.GlobalState;

@GlobalState
public interface ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, FilterConfig, ServletConfig> extends
public interface ServletApiAdapter<HttpServletRequest, HttpServletResponse, ServletContext, ServletContextEvent, FilterConfig, ServletConfig> extends
ServletRequestResponseAdapter<HttpServletRequest, HttpServletResponse, ServletContext>,
ServletContextAdapter<ServletContext>,
ServletAdapter<ServletConfig, ServletContext>,
ServletAdapter<ServletContextEvent, ServletConfig, ServletContext>,
FilterAdapter<FilterConfig, ServletContext> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockServletConfig;
import org.springframework.mock.web.MockServletContext;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.Servlet;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
Expand All @@ -38,6 +41,19 @@

class InitServiceNameInstrumentationTest extends AbstractInstrumentationTest {

@Test
void testContextInitialized() {
ServletContextListener servletContextListener = new NoopServletContextListener();

CustomManifestLoader cl = new CustomManifestLoader(() -> getClass().getResourceAsStream("/TEST-MANIFEST.MF"));
CustomManifestLoader.withThreadContextClassLoader(cl, () -> {
servletContextListener.contextInitialized(new ServletContextEvent(new MockServletContext()));
tracer.startRootTransaction(cl).end();
});

assertServiceInfo();
}

@Test
void testServletInit() {
Servlet servlet = new HttpServlet() {
Expand Down Expand Up @@ -71,6 +87,16 @@ private void assertServiceInfo() {
assertThat(traceContext.getServiceVersion()).isEqualTo("1.42.0");
}

private static class NoopServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}

private static class NoopFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
Expand Down