add TraceWebAspect to wrap Callable's returned in Controllers.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Aspect that adds correlation id to
|
||||
* <p/>
|
||||
* <ul>
|
||||
* <li>{@link RestController} annotated classes with public {@link Callable} methods</li>
|
||||
* <li>{@link Controller} annotated classes with public {@link Callable} methods</li>
|
||||
* </ul>
|
||||
* <p/>
|
||||
* For controllers an around aspect is created that wraps the {@link Callable#call()}
|
||||
* method execution in {@link TraceCallable}
|
||||
* <p/>
|
||||
*
|
||||
* @see RestController
|
||||
* @see Controller
|
||||
* @see RestOperations
|
||||
* @see TraceCallable
|
||||
* @see Trace
|
||||
*
|
||||
* @author Tomasz Nurkewicz, 4financeIT
|
||||
* @author Marcin Grzejszczak, 4financeIT
|
||||
* @author Michal Chmielarz, 4financeIT
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Aspect
|
||||
@CommonsLog
|
||||
public class TraceWebAspect {
|
||||
|
||||
private final Trace trace;
|
||||
|
||||
public TraceWebAspect(Trace trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@Pointcut("@target(org.springframework.web.bind.annotation.RestController)")
|
||||
private void anyRestControllerAnnotated() {
|
||||
}
|
||||
|
||||
@Pointcut("@target(org.springframework.stereotype.Controller)")
|
||||
private void anyControllerAnnotated() {
|
||||
}
|
||||
|
||||
@Pointcut("execution(public java.util.concurrent.Callable *(..))")
|
||||
private void anyPublicMethodReturningCallable() {
|
||||
}
|
||||
|
||||
@Pointcut("(anyRestControllerAnnotated() || anyControllerAnnotated()) && anyPublicMethodReturningCallable()")
|
||||
private void anyControllerOrRestControllerWithPublicAsyncMethod() {
|
||||
}
|
||||
|
||||
@Around("anyControllerOrRestControllerWithPublicAsyncMethod()")
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object wrapWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Callable callable = (Callable) pjp.proceed();
|
||||
if (TraceContextHolder.isTracing()) {
|
||||
log.debug("Wrapping callable with span ["
|
||||
+ TraceContextHolder.getCurrentSpan() + "]");
|
||||
|
||||
return new TraceCallable(this.trace, callable);
|
||||
}
|
||||
else {
|
||||
return callable;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -52,6 +52,12 @@ public class TraceWebAutoConfiguration {
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceWebAspect traceWebAspect() {
|
||||
return new TraceWebAspect(trace);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceHandlerInterceptor traceHandlerInterceptor() {
|
||||
|
||||
@@ -1,90 +1,38 @@
|
||||
package org.springframework.cloud.sleuth.sample;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableAspectJAutoProxy
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
@EnableAsync
|
||||
@Slf4j
|
||||
public class SampleApplication {
|
||||
|
||||
public static final String CLIENT_NAME = "testApp";
|
||||
|
||||
@RestController
|
||||
protected static class SampleController implements
|
||||
ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private int port;
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/")
|
||||
public String hi() {
|
||||
final Random random = new Random();
|
||||
Thread.sleep(random.nextInt(1000));
|
||||
|
||||
String s = restTemplate.getForObject("http://localhost:" + port + "/hi2",
|
||||
String.class);
|
||||
return "hi/" + s;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/hi2")
|
||||
public String hi2() {
|
||||
final Random random = new Random();
|
||||
Thread.sleep(random.nextInt(1000));
|
||||
return "hi2";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/traced")
|
||||
public String traced() {
|
||||
TraceScope scope = trace.startSpan("customTraceEndpoint", new AlwaysSampler());
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
log.info("Sleeping for {} millis", millis);
|
||||
Thread.sleep(millis);
|
||||
|
||||
String s = restTemplate.getForObject("http://localhost:" + port + "/hi2", String.class);
|
||||
scope.close();
|
||||
return "hi/" + s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
|
||||
port = event.getEmbeddedServletContainer().getPort();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Sampler defaultSampler() {
|
||||
return new AlwaysSampler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SampleController sampleController() {
|
||||
return new SampleController();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleApplication.class, args);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.springframework.cloud.sleuth.sample;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
class SampleController implements
|
||||
ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Autowired
|
||||
private Trace trace;
|
||||
private int port;
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/")
|
||||
public String hi() {
|
||||
final Random random = new Random();
|
||||
Thread.sleep(random.nextInt(1000));
|
||||
|
||||
String s = restTemplate.getForObject("http://localhost:" + port + "/hi2",
|
||||
String.class);
|
||||
return "hi/" + s;
|
||||
}
|
||||
|
||||
@RequestMapping("/call")
|
||||
public Callable<String> call() {
|
||||
return new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
Span currentSpan = TraceContextHolder.getCurrentSpan();
|
||||
return "async hi: "+currentSpan;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/hi2")
|
||||
public String hi2() {
|
||||
final Random random = new Random();
|
||||
Thread.sleep(random.nextInt(1000));
|
||||
return "hi2";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/traced")
|
||||
public String traced() {
|
||||
TraceScope scope = trace.startSpan("customTraceEndpoint", new AlwaysSampler());
|
||||
final Random random = new Random();
|
||||
int millis = random.nextInt(1000);
|
||||
log.info("Sleeping for {} millis", millis);
|
||||
Thread.sleep(millis);
|
||||
|
||||
String s = restTemplate.getForObject("http://localhost:" + port + "/hi2", String.class);
|
||||
scope.close();
|
||||
return "hi/" + s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
|
||||
port = event.getEmbeddedServletContainer().getPort();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user