Skip to content

Commit

Permalink
Separates MVC AsyncHandler as it requires Spring 3+; lowers java levels
Browse files Browse the repository at this point in the history
This separates out the async MVC functionality and tests the synchronous
part works with Spring 2.5.

This also lowers the minimum java level of instrumentation likely to be
used in Spring 2.5 applications.
  • Loading branch information
Adrian Cole committed Dec 12, 2017
1 parent 5c51589 commit 78fe610
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 13 deletions.
2 changes: 2 additions & 0 deletions instrumentation/httpclient/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

<properties>
<main.basedir>${project.basedir}/../..</main.basedir>
<main.java.version>1.6</main.java.version>
<main.signature.artifact>java16</main.signature.artifact>
</properties>

<dependencies>
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/jaxrs2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

<properties>
<main.basedir>${project.basedir}/../..</main.basedir>
<main.java.version>1.6</main.java.version>
<main.signature.artifact>java16</main.signature.artifact>
</properties>

<dependencies>
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/mysql/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

<properties>
<main.basedir>${project.basedir}/../..</main.basedir>
<main.java.version>1.6</main.java.version>
<main.signature.artifact>java16</main.signature.artifact>
</properties>

<dependencies>
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/servlet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

<properties>
<main.basedir>${project.basedir}/../..</main.basedir>
<main.java.version>1.6</main.java.version>
<main.signature.artifact>java16</main.signature.artifact>
</properties>

<dependencies>
Expand Down
15 changes: 8 additions & 7 deletions instrumentation/spring-webmvc/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# brave-instrumentation-spring-webmvc
This module contains a tracing interceptor for [Spring WebMVC](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html)
`TracingHandlerInterceptor` extracts trace state from incoming requests.
Then, it reports Zipkin how long each request takes, along with relevant
tags like the http url.
This module contains tracing interceptors for [Spring WebMVC](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html)
`TracingAsyncHandlerInterceptor` and `TracingHandlerInterceptor` extract trace state from incoming
requests. Then, they report Zipkin how long each request takes, along with relevant tags like the
http url.

## Configuration

Expand All @@ -11,19 +11,20 @@ it is in place before proceeding. Here's an example in [XML](https://github.com/

Then, configure `TracingHandlerInterceptor` in either XML or Java.

Here's an example of using the synchronous handler, which works with Spring 2.5+
```xml
<mvc:interceptors>
<bean class="brave.spring.servlet.TracingHandlerInterceptor">
</bean>
<bean class="brave.spring.servlet.TracingHandlerInterceptor"/>
</mvc:interceptors>
```

Here's an example of the asynchronous-capable handler, which works with Spring 3+
```java
@Configuration
@EnableWebMvc
class TracingConfig extends WebMvcConfigurerAdapter {
@Bean AsyncHandlerInterceptor tracingInterceptor(HttpTracing httpTracing) {
return TracingHandlerInterceptor.create(httpTracing);
return TracingAsyncHandlerInterceptor.create(httpTracing);
}

@Autowired
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/spring-webmvc/src/it/spring25/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# nozipkin1
This tests that Tracing can be initialized without a runtime dependency on `io.zipkin.java:zipkin`
74 changes: 74 additions & 0 deletions instrumentation/spring-webmvc/src/it/spring25/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>@project.groupId@</groupId>
<artifactId>spring-webmvc-spring25</artifactId>
<version>@project.version@</version>
<name>spring-webmvc-spring25</name>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>2.5.6</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>@jetty-servlet25.version@</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>brave-instrumentation-spring-webmvc</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>brave-instrumentation-http-tests</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>@junit.version@</version>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>@assertj.version@</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>@maven-failsafe-plugin.version@</version>
<configuration>
<failIfNoTests>true</failIfNoTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package brave.spring.webmvc25;

import brave.Tracer;
import brave.http.HttpTracing;
import brave.http.ITServletContainer;
import brave.spring.webmvc.TracingHandlerInterceptor;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;

import static org.springframework.web.servlet.DispatcherServlet.HANDLER_ADAPTER_BEAN_NAME;
import static org.springframework.web.servlet.DispatcherServlet.HANDLER_MAPPING_BEAN_NAME;

public class ITTracingHandlerInterceptor extends ITServletContainer {

@Controller
public static class TestController {
final Tracer tracer;

@Autowired public TestController(HttpTracing httpTracing) {
this.tracer = httpTracing.tracing().tracer();
}

@RequestMapping(value = "/foo")
public void foo(HttpServletResponse response) throws IOException {
response.getWriter().write("foo");
}

@RequestMapping(value = "/badrequest")
public void badrequest(HttpServletResponse response) throws IOException {
response.sendError(400);
response.flushBuffer();
}

@RequestMapping(value = "/child")
public void child() {
tracer.nextSpan().name("child").start().finish();
}

@RequestMapping(value = "/exception")
public void disconnect() throws IOException {
throw new IOException();
}
}

// TODO: investigate why the status isn't being added as a tag
@Override @Test(expected = AssertionError.class)
public void addsStatusCode_badRequest() throws Exception {
super.addsStatusCode_badRequest();
}

@Override public void init(ServletContextHandler handler) {
StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.getBeanFactory()
.registerSingleton("testController", new TestController(httpTracing)); // the test resource

DefaultAnnotationHandlerMapping mapping = new DefaultAnnotationHandlerMapping();
mapping.setInterceptors(new Object[] {TracingHandlerInterceptor.create(httpTracing)});
mapping.setApplicationContext(wac);

wac.getBeanFactory().registerSingleton(HANDLER_MAPPING_BEAN_NAME, mapping);
wac.getBeanFactory().registerSingleton(HANDLER_ADAPTER_BEAN_NAME, new AnnotationMethodHandlerAdapter());

handler.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
handler.addServlet(new ServletHolder(new DispatcherServlet() {
{
wac.refresh();
setDetectAllHandlerMappings(false);
setDetectAllHandlerAdapters(false);
setPublishEvents(false);
}

@Override protected WebApplicationContext initWebApplicationContext() throws BeansException {
onRefresh(wac);
return wac;
}
}), "/*");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package brave.spring.webmvc;

import brave.Tracing;
import brave.http.HttpTracing;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
* Tracing interceptor for Spring Web MVC, which can be used as both an {@link
* AsyncHandlerInterceptor} or a normal {@link HandlerInterceptor}.
*/
public final class TracingAsyncHandlerInterceptor extends HandlerInterceptorAdapter {
public static AsyncHandlerInterceptor create(Tracing tracing) {
return new TracingAsyncHandlerInterceptor(HttpTracing.create(tracing));
}

public static AsyncHandlerInterceptor create(HttpTracing httpTracing) {
return new TracingAsyncHandlerInterceptor(httpTracing);
}

final HandlerInterceptor delegate;

@Autowired TracingAsyncHandlerInterceptor(HttpTracing httpTracing) { // internal
delegate = TracingHandlerInterceptor.create(httpTracing);
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o)
throws Exception {
return delegate.preHandle(request, response, o);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object o, Exception ex) throws Exception {
delegate.afterCompletion(request, response, o, ex);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
* Tracing interceptor for Spring Web MVC, which can be used as both an {@link
* AsyncHandlerInterceptor} or a normal {@link HandlerInterceptor}.
*/
public final class TracingHandlerInterceptor extends HandlerInterceptorAdapter {
public final class TracingHandlerInterceptor implements HandlerInterceptor {
static final Propagation.Getter<HttpServletRequest, String> GETTER =
new Propagation.Getter<HttpServletRequest, String>() {
@Override public String get(HttpServletRequest carrier, String key) {
Expand All @@ -32,11 +33,11 @@ public final class TracingHandlerInterceptor extends HandlerInterceptorAdapter {
}
};

public static AsyncHandlerInterceptor create(Tracing tracing) {
public static HandlerInterceptor create(Tracing tracing) {
return new TracingHandlerInterceptor(HttpTracing.create(tracing));
}

public static AsyncHandlerInterceptor create(HttpTracing httpTracing) {
public static HandlerInterceptor create(HttpTracing httpTracing) {
return new TracingHandlerInterceptor(httpTracing);
}

Expand All @@ -61,6 +62,11 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object o, Exception ex) {
Expand Down
Loading

0 comments on commit 78fe610

Please sign in to comment.