opentelemetry-java-instrume.../instrumentation/servlet
Lauri Tulmin e76d3b19d1
Fix ServletContextPath.prepend for app server spans (#2089)
* ServletContextPath.prepend doesn't work when server span is created from app server integration

* move ServletContextPath context creation to servlet-common, make servlet2&3 depend on servlet-common so that it would be used in tests that depend on servlet3

* fix failing test

* add servlet-common dependency to modules that depend on servlet3

* add servlet-common dependency to mojarra and myfaces

* run context path instrumentation after servlet instrumentation

* add servlet-common dependency to wicket

* move servlet context path handling

* enable jetty instrumentation for all handlers

* run springmvc tests with tomcat integration, fix peer port and peer ip reporting on tomcat

* jetty integration is now enabled for all handlers

* update expected span name

* Revert "jetty integration is now enabled for all handlers"

This reverts commit 82cbb663f5.

* Revert "update expected span name"

This reverts commit c034496fc5.

* Revert "enable jetty instrumentation for all handlers"

This reverts commit 8a3d077600.

* Trigger Build
2021-02-15 23:34:15 -08:00
..
glassfish-testing Fix ServletContextPath.prepend for app server spans (#2089) 2021-02-15 23:34:15 -08:00
servlet-2.2/javaagent Fix ServletContextPath.prepend for app server spans (#2089) 2021-02-15 23:34:15 -08:00
servlet-3.0/javaagent Fix ServletContextPath.prepend for app server spans (#2089) 2021-02-15 23:34:15 -08:00
servlet-common/javaagent Refactor InMemoryExporter and move some of its methods … (#2264) 2021-02-15 17:36:14 +01:00
README.md Remove disabled by default servlet instrumentation (#1684) 2020-11-19 11:22:02 -08:00

README.md

Instrumentation for Java Servlets

A word about version

We support Servlet API starting from version 2.2. But various instrumentations apply to different versions of the API. They are divided into 3 sub-modules:

servlet-common contains instrumentations applicable to all API versions that we support.

servlet-2.2 contains instrumentations applicable to Servlet API 2.2, but not to 3+.

servlet-3.0 contains instrumentations that require Servlet API 3.0 or newer.

Implementation details

In order to fully understand how java servlet instrumentation work, let us first take a look at the following stacktrace from Spring PetClinic application. Unimportant frames are redacted, points of interests are highlighted and discussed below.

at org.springframework.samples.petclinic.owner.OwnerController.initCreationForm(OwnerController.java:60)
...
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
...
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
...
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)

Everything starts when HTTP request processing reaches the first class from Servlet specification. In the example above this is the OncePerRequestFilter.doFilter(ServletRequest, ServletResponse, FilterChain) method. Let us call this first servlet specific method an "entry point". This is the main target for Servlet3Instrumentation and Servlet2Instrumentation:

public void javax.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)

public void javax.servlet.http.HttpServlet#service(ServletRequest, ServletResponse).

These instrumentations are located in two separate submodules servlet-3.0 and servlet-2.2, because they and corresponding tests depend on different versions of the servlet specification.

At last, request processing may reach the specific framework that your application uses. In this case Spring MVC and OwnerController.initCreationForm.

If all instrumentations are enabled, then a new span will be created for every highlighted frame. All spans from Servlet API will have kind=SERVER and name based on corresponding class and method names, such as ApplicationFilterChain.doFilter or FrameworkServlet.doGet. Span created by Spring MVC instrumentation will have kind=INTERNAL and named OwnerController.initCreationForm.

The state described above has one significant problem. Observability backends usually aggregate traces based on their root spans. This means that ALL traces from any application deployed to Servlet container will be grouped together. Because their root spans will all have the same named based on common entry point. In order to alleviate this problem, instrumentations for specific frameworks, such as Spring MVC here, update name of the span corresponding to the entry point. Each framework instrumentation can decide what is the best span name based on framework implementation details. Of course, still adhering to OpenTelemetry semantic conventions.

Additional instrumentations

RequestDispatcherInstrumentationModule instruments javax.servlet.RequestDispatcher.forward and javax.servlet.RequestDispatcher.include methods to create new INTERNAL spans around their invocations.

HttpServletResponseInstrumentationModule instruments javax.servlet.http.HttpServletResponse.sendError and javax.servlet.http.HttpServletResponse.sendRedirect methods to create new INTERNAL spans around their invocations.