Integrate server-side zipkin with core
This commit is contained in:
@@ -10,15 +10,10 @@ include::intro.adoc[]
|
||||
|
||||
== Running the sample
|
||||
|
||||
1. Download and build zipkin
|
||||
2. Install redis and run `redis-server`
|
||||
3. `cd zipkin`
|
||||
4. `bin/collector redis` from [here](https://github.com/twitter/zipkin/blob/master/doc/redis.md)
|
||||
5. `bin/query redis`
|
||||
6. `bin/web`
|
||||
7. run sample application
|
||||
8. hit `http://localhost:3380`
|
||||
9. goto `http://localhost:8080` for zipkin web
|
||||
1. Run [Zipkin](https://github.com/openzipkin/zipkin), e.g. via the docker images at [Zipkin Docker](https://github.com/openzipkin/zipkin-docker)
|
||||
7. Run sample application
|
||||
8. Hit `http://localhost:3380`
|
||||
9. Goto `http://localhost:8080` for zipkin web
|
||||
|
||||
== Building
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
TODO: intro Spring Cloud Sleuth
|
||||
|
||||
=== Terminology
|
||||
|
||||
Spring Cloud Sleuth borrows http://research.google.com/pubs/pub36356.html[Dapper's] terminology.
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>1.0.2.BUILD-SNAPSHOT</version>
|
||||
<version>1.1.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath/>
|
||||
<!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<!-- Only needed at compile time -->
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.NonFinal;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
|
||||
import org.springframework.cloud.sleuth.util.ExceptionUtils;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
/**
|
||||
@@ -14,6 +18,7 @@ import org.springframework.context.ApplicationEventPublisher;
|
||||
*/
|
||||
@Value
|
||||
@NonFinal
|
||||
@CommonsLog
|
||||
public class TraceScope implements Closeable {
|
||||
|
||||
private final ApplicationEventPublisher publisher;
|
||||
@@ -28,6 +33,11 @@ public class TraceScope implements Closeable {
|
||||
*/
|
||||
private final Span savedSpan;
|
||||
|
||||
/**
|
||||
* List of callbacks to run on close.
|
||||
*/
|
||||
private List<Runnable> callbacks = new ArrayList<Runnable>();
|
||||
|
||||
@NonFinal
|
||||
private boolean detached = false;
|
||||
|
||||
@@ -45,41 +55,54 @@ public class TraceScope implements Closeable {
|
||||
* @return the same Span object
|
||||
*/
|
||||
public Span detach() {
|
||||
if (detached) {
|
||||
Utils.error("Tried to detach trace span " + span + " but " +
|
||||
if (this.detached) {
|
||||
ExceptionUtils.error("Tried to detach trace span " + this.span + " but " +
|
||||
"it has already been detached.");
|
||||
}
|
||||
detached = true;
|
||||
this.detached = true;
|
||||
|
||||
Span cur = TraceContextHolder.getCurrentSpan();
|
||||
if (cur != span) {
|
||||
Utils.error("Tried to detach trace span " + span + " but " +
|
||||
if (cur != this.span) {
|
||||
ExceptionUtils.error("Tried to detach trace span " + this.span + " but " +
|
||||
"it is not the current span for the " +
|
||||
Thread.currentThread().getName() + " thread. You have " +
|
||||
"probably forgotten to close or detach " + cur);
|
||||
} else {
|
||||
TraceContextHolder.setCurrentSpan(savedSpan);
|
||||
TraceContextHolder.setCurrentSpan(this.savedSpan);
|
||||
}
|
||||
return this.span;
|
||||
}
|
||||
|
||||
public void register(Runnable callback) {
|
||||
if (!this.callbacks .contains(callback)) {
|
||||
this.callbacks.add(callback);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void close() {
|
||||
if (detached) {
|
||||
if (this.detached) {
|
||||
return;
|
||||
}
|
||||
detached = true;
|
||||
this.detached = true;
|
||||
for (Runnable callback : this.callbacks) {
|
||||
try {
|
||||
callback.run();
|
||||
} catch (Throwable e) {
|
||||
log.error("Error with callback on close", e);
|
||||
}
|
||||
}
|
||||
Span cur = TraceContextHolder.getCurrentSpan();
|
||||
if (cur != span) {
|
||||
Utils.error("Tried to close trace span " + span + " but " +
|
||||
if (cur != this.span) {
|
||||
ExceptionUtils.error("Tried to close trace span " + this.span + " but " +
|
||||
"it is not the current span for the " +
|
||||
Thread.currentThread().getName() + " thread. You have " +
|
||||
"probably forgotten to close or detach " + cur);
|
||||
} else {
|
||||
span.stop();
|
||||
this.publisher.publishEvent(new SpanStoppedEvent(this, span));
|
||||
TraceContextHolder.setCurrentSpan(savedSpan);
|
||||
this.span.stop();
|
||||
this.publisher.publishEvent(new SpanStoppedEvent(this, this.span));
|
||||
TraceContextHolder.setCurrentSpan(this.savedSpan);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.autoconfig;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.RandomUuidGenerator;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -20,13 +25,13 @@ public class TraceAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Sampler defaultSampler() {
|
||||
public Sampler<?> defaultSampler() {
|
||||
return new IsTracingSampler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Trace trace(Sampler sampler, IdGenerator idGenerator,
|
||||
public Trace trace(Sampler<?> sampler, IdGenerator idGenerator,
|
||||
ApplicationEventPublisher publisher) {
|
||||
return new DefaultTrace(sampler, idGenerator, publisher);
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
||||
/**
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
@@ -10,6 +11,7 @@ import org.springframework.cloud.sleuth.TraceScope;
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class TraceRunnable extends TraceDelegate<Runnable> implements Runnable {
|
||||
|
||||
public TraceRunnable(Trace trace, Runnable delagate) {
|
||||
|
||||
@@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceInfo;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
/**
|
||||
@@ -44,6 +46,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
* @author Marcin Grzejszczak, 4financeIT
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 5)
|
||||
public class TraceFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final Pattern DEFAULT_SKIP_PATTERN = Pattern
|
||||
@@ -65,10 +68,10 @@ public class TraceFilter extends OncePerRequestFilter {
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
throws ServletException, IOException {
|
||||
|
||||
String uri = hasText(request.getRequestURI()) ? request.getRequestURI() : "";
|
||||
boolean skip = skipPattern.matcher(uri).matches();
|
||||
boolean skip = this.skipPattern.matcher(uri).matches();
|
||||
|
||||
TraceScope traceScope = null;
|
||||
if (!skip) {
|
||||
@@ -78,13 +81,13 @@ public class TraceFilter extends OncePerRequestFilter {
|
||||
|
||||
TraceInfo traceInfo = new TraceInfo(traceId, spanId);
|
||||
// TODO: trace description?
|
||||
traceScope = trace.startSpan("traceFilter", traceInfo);
|
||||
traceScope = this.trace.startSpan("traceFilter", traceInfo);
|
||||
// Send new span id back
|
||||
addToResponseIfNotPresent(response, SPAN_ID_NAME, traceScope.getSpan()
|
||||
.getSpanId());
|
||||
}
|
||||
else {
|
||||
traceScope = trace.startSpan("traceFilter");
|
||||
traceScope = this.trace.startSpan("traceFilter");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,12 +67,12 @@ public class TraceWebAspect {
|
||||
@Around("anyControllerOrRestControllerWithPublicAsyncMethod()")
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object wrapWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Callable callable = (Callable) pjp.proceed();
|
||||
Callable<Object> callable = (Callable<Object>) pjp.proceed();
|
||||
if (TraceContextHolder.isTracing()) {
|
||||
log.debug("Wrapping callable with span ["
|
||||
+ TraceContextHolder.getCurrentSpan() + "]");
|
||||
|
||||
return new TraceCallable(this.trace, callable);
|
||||
return new TraceCallable<Object>(this.trace, callable);
|
||||
}
|
||||
else {
|
||||
return callable;
|
||||
|
||||
@@ -27,8 +27,6 @@ import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Registers beans that add tracing to requests
|
||||
@@ -55,41 +53,15 @@ public class TraceWebAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceWebAspect traceWebAspect() {
|
||||
return new TraceWebAspect(trace);
|
||||
return new TraceWebAspect(this.trace);
|
||||
}
|
||||
|
||||
//TODO: I don't think TraceHandlerInterceptor is needed with TraceFilter
|
||||
/*@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceHandlerInterceptor traceHandlerInterceptor() {
|
||||
return new TraceHandlerInterceptor(trace);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(
|
||||
TraceHandlerInterceptor handlerInterceptor) {
|
||||
return new TraceWebConfigurer(handlerInterceptor);
|
||||
}
|
||||
|
||||
protected static class TraceWebConfigurer extends WebMvcConfigurerAdapter {
|
||||
private TraceHandlerInterceptor interceptor;
|
||||
|
||||
public TraceWebConfigurer(TraceHandlerInterceptor interceptor) {
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(interceptor).addPathPatterns("/**");
|
||||
}
|
||||
}*/
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public FilterRegistrationBean traceFilter() {
|
||||
Pattern pattern = StringUtils.hasText(skipPattern) ? Pattern.compile(skipPattern)
|
||||
Pattern pattern = StringUtils.hasText(this.skipPattern) ? Pattern.compile(this.skipPattern)
|
||||
: TraceFilter.DEFAULT_SKIP_PATTERN;
|
||||
return new FilterRegistrationBean(new TraceFilter(trace, pattern));
|
||||
return new FilterRegistrationBean(new TraceFilter(this.trace, pattern));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.trace;
|
||||
|
||||
import static org.springframework.cloud.sleuth.Utils.error;
|
||||
import static org.springframework.cloud.sleuth.util.ExceptionUtils.error;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.NullScope;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceContextHolder;
|
||||
import org.springframework.cloud.sleuth.TraceInfo;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.event.SpanStartedEvent;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceRunnable;
|
||||
@@ -30,7 +38,7 @@ public class DefaultTrace implements Trace {
|
||||
|
||||
@Override
|
||||
public TraceScope startSpan(String name) {
|
||||
return this.startSpan(name, defaultSampler);
|
||||
return this.startSpan(name, this.defaultSampler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,7 +48,7 @@ public class DefaultTrace implements Trace {
|
||||
.begin(System.currentTimeMillis())
|
||||
.name(name)
|
||||
.traceId(tinfo.getTraceId())
|
||||
.spanId(idGenerator.create())
|
||||
.spanId(this.idGenerator.create())
|
||||
.parent(tinfo.getSpanId())
|
||||
.build();
|
||||
return doStart(span);
|
||||
@@ -81,8 +89,8 @@ public class DefaultTrace implements Trace {
|
||||
return MilliSpan.builder()
|
||||
.begin(System.currentTimeMillis())
|
||||
.name(name)
|
||||
.traceId(idGenerator.create())
|
||||
.spanId(idGenerator.create())
|
||||
.traceId(this.idGenerator.create())
|
||||
.spanId(this.idGenerator.create())
|
||||
.build();
|
||||
} else {
|
||||
return createChild(parent, name);
|
||||
@@ -95,14 +103,14 @@ public class DefaultTrace implements Trace {
|
||||
.name(childname)
|
||||
.traceId(parent.getTraceId())
|
||||
.parent(parent.getSpanId())
|
||||
.spanId(idGenerator.create())
|
||||
.spanId(this.idGenerator.create())
|
||||
.processId(parent.getProcessId())
|
||||
.build();
|
||||
}
|
||||
|
||||
protected TraceScope doStart(Span span) {
|
||||
if (span != null) {
|
||||
publisher.publishEvent(new SpanStartedEvent(this, span));
|
||||
this.publisher.publishEvent(new SpanStartedEvent(this, span));
|
||||
}
|
||||
return continueSpan(span);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
package org.springframework.cloud.sleuth.util;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
@@ -6,7 +6,7 @@ import lombok.extern.apachecommons.CommonsLog;
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public abstract class Utils {
|
||||
public abstract class ExceptionUtils {
|
||||
public static void error(String msg) {
|
||||
log.error(msg);
|
||||
throw new RuntimeException(msg);
|
||||
@@ -1,6 +1,6 @@
|
||||
# Auto Configuration
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.sleuth.TraceAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.slf4j.SleuthSlf4jAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.client.TraceWebClientAutoConfiguration
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.springframework.cloud.sleuth.event.SpanStartedEvent;
|
||||
import org.springframework.cloud.sleuth.event.SpanStoppedEvent;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.sampler.IsTracingSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
<artifactId>spring-cloud-sleuth-sample</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Consul Sample</name>
|
||||
<description>Spring Cloud Consul Sample</description>
|
||||
<name>Spring Cloud Sleuth Sample</name>
|
||||
<description>Spring Cloud Sleuth Sample</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
@@ -21,7 +21,6 @@
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>1.2.1.RELEASE</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -49,6 +48,10 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
|
||||
@@ -5,6 +5,10 @@ spring:
|
||||
application:
|
||||
name: testSleuthApp
|
||||
|
||||
logging:
|
||||
pattern:
|
||||
console: '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([trace=%X{Trace-Id:-},span=%X{Span-Id:-}]){yellow} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex'
|
||||
|
||||
endpoints:
|
||||
health:
|
||||
sensitive: false
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
|
||||
|
||||
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%X{Trace-Id:-} %X{Span-Id:-}]){yellow} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex"/>
|
||||
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%X{Trace-Id:-} %X{Span-Id:-}] [%t] %-40.40logger{39} : %m%n%wex"/>
|
||||
|
||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
|
||||
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="FILE" />
|
||||
</root>
|
||||
<logger name="org.springframework.web" level="DEBUG"/>
|
||||
|
||||
</configuration>
|
||||
@@ -46,6 +46,11 @@
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.kristofa</groupId>
|
||||
<artifactId>brave-client</artifactId>
|
||||
@@ -67,8 +72,9 @@
|
||||
<artifactId>brave-zipkin-spancollector</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zuul</artifactId>
|
||||
<groupId>com.netflix.zuul</groupId>
|
||||
<artifactId>zuul-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
@@ -78,7 +84,7 @@
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<!-- Only needed at compile time -->
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Data
|
||||
public class TraceData {
|
||||
private Long traceId;
|
||||
private Long spanId;
|
||||
private Long parentSpanId;
|
||||
private Boolean shouldBeSampled;
|
||||
private String spanName;
|
||||
}
|
||||
@@ -1,11 +1,26 @@
|
||||
package org.springframework.cloud.sleuth.zipkin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import com.github.kristofa.brave.AnnotationSubmitterConfig;
|
||||
import com.github.kristofa.brave.ClientTracer;
|
||||
import com.github.kristofa.brave.ClientTracerConfig;
|
||||
import com.github.kristofa.brave.EndPointSubmitterConfig;
|
||||
import com.github.kristofa.brave.FixedSampleRateTraceFilter;
|
||||
import com.github.kristofa.brave.ServerSpanThreadBinderConfig;
|
||||
import com.github.kristofa.brave.ServerTracer;
|
||||
import com.github.kristofa.brave.ServerTracerConfig;
|
||||
import com.github.kristofa.brave.SpanCollector;
|
||||
import com.github.kristofa.brave.TraceFilter;
|
||||
@@ -15,16 +30,6 @@ import com.github.kristofa.brave.client.ClientResponseInterceptor;
|
||||
import com.github.kristofa.brave.client.spanfilter.SpanNameFilter;
|
||||
import com.github.kristofa.brave.zipkin.ZipkinSpanCollector;
|
||||
import com.google.common.base.Optional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -34,15 +39,15 @@ import java.util.List;
|
||||
@ConditionalOnClass(ServerTracerConfig.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.sleuth.zipkin.enabled", matchIfMissing = true)
|
||||
@Import({ AnnotationSubmitterConfig.class, ClientTracerConfig.class,
|
||||
EndPointSubmitterConfig.class, ServerSpanThreadBinderConfig.class,
|
||||
ServerTracerConfig.class })
|
||||
EndPointSubmitterConfig.class, ServerSpanThreadBinderConfig.class,
|
||||
ServerTracerConfig.class })
|
||||
public class ZipkinAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SpanCollector spanCollector() {
|
||||
return new ZipkinSpanCollector(zipkinProperties().getHost(),
|
||||
zipkinProperties().getPort());
|
||||
return new ZipkinSpanCollector(zipkinProperties().getHost(), zipkinProperties()
|
||||
.getPort());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -61,6 +66,11 @@ public class ZipkinAutoConfiguration {
|
||||
return new TraceFilters(traceFilters);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZipkinTrace zipkinTrace(ServerTracer serverTracer, Sampler<?> sampler, IdGenerator idGenerator, ApplicationEventPublisher publisher) {
|
||||
return new ZipkinTrace(serverTracer, sampler, idGenerator, publisher);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class InterceptorConfig {
|
||||
|
||||
@@ -73,14 +83,14 @@ public class ZipkinAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ClientRequestInterceptor clientRequestInterceptor() {
|
||||
return new ClientRequestInterceptor(clientTracer,
|
||||
Optional.fromNullable(spanNameFilter));
|
||||
return new ClientRequestInterceptor(this.clientTracer,
|
||||
Optional.fromNullable(this.spanNameFilter));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ClientResponseInterceptor clientResponseInterceptor() {
|
||||
return new ClientResponseInterceptor(clientTracer);
|
||||
return new ClientResponseInterceptor(this.clientTracer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin;
|
||||
|
||||
import com.github.kristofa.brave.EndPointSubmitter;
|
||||
import com.github.kristofa.brave.ServerTracer;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public abstract class ZipkinInterceptor<T> {
|
||||
|
||||
private final ServerTracer serverTracer;
|
||||
private final EndPointSubmitter endPointSubmitter;
|
||||
|
||||
protected ZipkinInterceptor(ServerTracer serverTracer, EndPointSubmitter endPointSubmitter) {
|
||||
this.serverTracer = serverTracer;
|
||||
this.endPointSubmitter = endPointSubmitter;
|
||||
}
|
||||
|
||||
public void preTrace(T context) {
|
||||
submitEndpoint(context, endPointSubmitter);
|
||||
|
||||
final TraceData traceData = getTraceData(context);
|
||||
serverTracer.clearCurrentSpan();
|
||||
|
||||
if (Boolean.FALSE.equals(traceData.getShouldBeSampled())) {
|
||||
serverTracer.setStateNoTracing();
|
||||
log.debug("Received indication that we should NOT trace.");
|
||||
} else {
|
||||
final String spanName = getSpanName(context, traceData);
|
||||
if (traceData.getTraceId() != null && traceData.getSpanId() != null) {
|
||||
|
||||
log.debug("Received span information as part of request.");
|
||||
serverTracer.setStateCurrentTrace(traceData.getTraceId(), traceData.getSpanId(),
|
||||
traceData.getParentSpanId(), spanName);
|
||||
} else {
|
||||
log.debug("Received no span state.");
|
||||
serverTracer.setStateUnknown(spanName);
|
||||
}
|
||||
serverTracer.setServerReceived();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void submitEndpoint(T context, EndPointSubmitter endPointSubmitter);
|
||||
protected abstract TraceData getTraceData(T context);
|
||||
protected abstract String getSpanName(T context, TraceData traceData);
|
||||
|
||||
public void postTrace(T context) {
|
||||
// We can submit this in any case. When server state is not set or
|
||||
// we should not trace this request nothing will happen.
|
||||
log.debug("Sending server send.");
|
||||
try {
|
||||
serverTracer.setServerSend();
|
||||
} finally {
|
||||
serverTracer.clearCurrentSpan();
|
||||
}
|
||||
}
|
||||
|
||||
protected EndPointSubmitter getEndPointSubmitter() {
|
||||
return endPointSubmitter;
|
||||
}
|
||||
|
||||
protected ServerTracer getServerTracer() {
|
||||
return serverTracer;
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin;
|
||||
|
||||
import com.github.kristofa.brave.BraveHttpHeaders;
|
||||
import com.github.kristofa.brave.ClientRequestAdapter;
|
||||
import com.github.kristofa.brave.ClientResponseAdapter;
|
||||
import com.github.kristofa.brave.client.ClientRequestInterceptor;
|
||||
import com.github.kristofa.brave.client.ClientResponseInterceptor;
|
||||
import com.google.common.base.Optional;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ZipkinRestTemplateInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
private final ClientRequestInterceptor clientRequestInterceptor;
|
||||
private final ClientResponseInterceptor clientResponseInterceptor;
|
||||
|
||||
public ZipkinRestTemplateInterceptor(ClientRequestInterceptor clientRequestInterceptor, ClientResponseInterceptor clientResponseInterceptor) {
|
||||
this.clientRequestInterceptor = clientRequestInterceptor;
|
||||
//TODO: ClientResponseInterceptor assumes >= 300 is error
|
||||
this.clientResponseInterceptor = clientResponseInterceptor;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
||||
|
||||
RequestAdapter requestAdapter = new RequestAdapter(request);
|
||||
clientRequestInterceptor.handle(requestAdapter, Optional.<String>absent());
|
||||
|
||||
ClientHttpResponse response = null;
|
||||
Exception exception = null;
|
||||
try {
|
||||
response = execution.execute(request, body);
|
||||
} catch (final Exception e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
clientResponseInterceptor.handle(new ResponseAdapter(response));
|
||||
if(exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
class RequestAdapter implements ClientRequestAdapter {
|
||||
|
||||
HttpRequest request;
|
||||
|
||||
public RequestAdapter(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return request.getURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return request.getMethod().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getSpanName() {
|
||||
String spanNameHeader = request.getHeaders().getFirst(BraveHttpHeaders.SpanName.getName());
|
||||
return Optional.fromNullable(spanNameHeader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String header, String value) {
|
||||
request.getHeaders().add(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseAdapter implements ClientResponseAdapter {
|
||||
ClientHttpResponse response;
|
||||
|
||||
public ResponseAdapter(ClientHttpResponse response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public int getStatusCode() {
|
||||
if (response == null) {
|
||||
return 0;
|
||||
}
|
||||
return response.getRawStatusCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.springframework.cloud.sleuth.zipkin;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceScope;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTrace;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import com.github.kristofa.brave.ServerTracer;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class ZipkinTrace extends DefaultTrace {
|
||||
|
||||
private final ServerTracer serverTracer;
|
||||
|
||||
@Override
|
||||
protected TraceScope doStart(final Span span) {
|
||||
preTrace(span);
|
||||
TraceScope scope = super.doStart(span);
|
||||
scope.register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postTrace(span);
|
||||
}
|
||||
});
|
||||
return scope;
|
||||
}
|
||||
|
||||
public ZipkinTrace(ServerTracer serverTracer, Sampler<?> defaultSampler,
|
||||
IdGenerator idGenerator, ApplicationEventPublisher publisher) {
|
||||
super(defaultSampler, idGenerator, publisher);
|
||||
this.serverTracer = serverTracer;
|
||||
}
|
||||
|
||||
public void preTrace(Span context) {
|
||||
final TraceData traceData = getTraceData(context);
|
||||
this.serverTracer.clearCurrentSpan();
|
||||
|
||||
if (Boolean.FALSE.equals(traceData.getShouldBeSampled())) {
|
||||
this.serverTracer.setStateNoTracing();
|
||||
log.debug("Received indication that we should NOT trace.");
|
||||
}
|
||||
else {
|
||||
final String spanName = getSpanName(context, traceData);
|
||||
if (traceData.getTraceId() != null && traceData.getSpanId() != null) {
|
||||
|
||||
log.debug("Received span information as part of request.");
|
||||
this.serverTracer.setStateCurrentTrace(traceData.getTraceId(),
|
||||
traceData.getSpanId(), traceData.getParentSpanId(), spanName);
|
||||
}
|
||||
else {
|
||||
log.debug("Received no span state.");
|
||||
this.serverTracer.setStateUnknown(spanName);
|
||||
}
|
||||
this.serverTracer.setServerReceived();
|
||||
}
|
||||
}
|
||||
|
||||
protected TraceData getTraceData(Span context) {
|
||||
TraceData trace = new TraceData();
|
||||
trace.setTraceId(hash(context.getTraceId()));
|
||||
trace.setSpanId(hash(context.getSpanId()));
|
||||
trace.setShouldBeSampled(true);
|
||||
trace.setSpanName(context.getName());
|
||||
if (!context.getParents().isEmpty()) {
|
||||
trace.setParentSpanId(hash(context.getParents().iterator().next()));
|
||||
}
|
||||
return trace;
|
||||
};
|
||||
|
||||
protected String getSpanName(Span context, TraceData traceData) {
|
||||
return context.getName();
|
||||
}
|
||||
|
||||
public void postTrace(Span context) {
|
||||
// We can submit this in any case. When server state is not set or
|
||||
// we should not trace this request nothing will happen.
|
||||
log.debug("Sending server send.");
|
||||
try {
|
||||
this.serverTracer.setServerSend();
|
||||
}
|
||||
finally {
|
||||
this.serverTracer.clearCurrentSpan();
|
||||
}
|
||||
}
|
||||
|
||||
protected ServerTracer getServerTracer() {
|
||||
return this.serverTracer;
|
||||
}
|
||||
|
||||
private static long hash(String string) {
|
||||
long h = 1125899906842597L;
|
||||
int len = string.length();
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
h = 31 * h + string.charAt(i);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class TraceData {
|
||||
private Long traceId;
|
||||
private Long spanId;
|
||||
private Long parentSpanId;
|
||||
private Boolean shouldBeSampled;
|
||||
private String spanName;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.web;
|
||||
|
||||
import static com.github.kristofa.brave.BraveHttpHeaders.ParentSpanId;
|
||||
import static com.github.kristofa.brave.BraveHttpHeaders.Sampled;
|
||||
import static com.github.kristofa.brave.BraveHttpHeaders.SpanId;
|
||||
import static com.github.kristofa.brave.BraveHttpHeaders.SpanName;
|
||||
import static com.github.kristofa.brave.BraveHttpHeaders.TraceId;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.github.kristofa.brave.EndPointSubmitter;
|
||||
import com.github.kristofa.brave.ServerTracer;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cloud.sleuth.zipkin.TraceData;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinInterceptor;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
|
||||
import com.github.kristofa.brave.IdConversion;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class HttpServletRequestInterceptor extends ZipkinInterceptor<HttpServletRequest> {
|
||||
|
||||
public HttpServletRequestInterceptor(ServerTracer serverTracer, EndPointSubmitter endPointSubmitter) {
|
||||
super(serverTracer, endPointSubmitter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitEndpoint(HttpServletRequest servletRequest, EndPointSubmitter endPointSubmitter) {
|
||||
if (!endPointSubmitter.endPointSubmitted()) {
|
||||
final String localAddr = servletRequest.getLocalAddr();
|
||||
final int localPort = servletRequest.getLocalPort();
|
||||
final String contextPath = servletRequest.getContextPath();
|
||||
log.debug("Setting endpoint: addr: "+localAddr+", port: "+localPort+", contextpath: "+ contextPath);
|
||||
endPointSubmitter.submit(localAddr, localPort, contextPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceData getTraceData(HttpServletRequest request) {
|
||||
ServletServerHttpRequest req = new ServletServerHttpRequest(request);
|
||||
HttpHeaders headers = req.getHeaders();
|
||||
|
||||
TraceData traceData = new TraceData();
|
||||
|
||||
for (Map.Entry<String, List<String>> headerEntry : headers.entrySet()) {
|
||||
log.debug(headerEntry.getKey() +" = "+ headerEntry.getValue());
|
||||
if (TraceId.getName().equalsIgnoreCase(headerEntry.getKey())) {
|
||||
traceData.setTraceId(getFirstLong(headerEntry));
|
||||
} else if (SpanId.getName().equalsIgnoreCase(headerEntry.getKey())) {
|
||||
traceData.setSpanId(getFirstLong(headerEntry));
|
||||
} else if (ParentSpanId.getName().equalsIgnoreCase(headerEntry.getKey())) {
|
||||
traceData.setParentSpanId(getFirstLong(headerEntry));
|
||||
} else if (Sampled.getName().equalsIgnoreCase(headerEntry.getKey())) {
|
||||
traceData.setShouldBeSampled(getFirstBoolean(headerEntry));
|
||||
} else if (SpanName.getName().equalsIgnoreCase(headerEntry.getKey())) {
|
||||
traceData.setSpanName(getFirstString(headerEntry));
|
||||
}
|
||||
}
|
||||
return traceData;
|
||||
}
|
||||
|
||||
protected Long getFirstLong(final Map.Entry<String, List<String>> headerEntry) {
|
||||
final String value = getFirstString(headerEntry);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return IdConversion.convertToLong(value);
|
||||
|
||||
}
|
||||
|
||||
protected Boolean getFirstBoolean(final Map.Entry<String, List<String>> headerEntry) {
|
||||
final String firstStringValueFor = getFirstString(headerEntry);
|
||||
return firstStringValueFor == null ? null : Boolean.valueOf(firstStringValueFor);
|
||||
}
|
||||
|
||||
protected String getFirstString(final Map.Entry<String, List<String>> headerEntry) {
|
||||
final List<String> values = headerEntry.getValue();
|
||||
if (values != null && values.size() > 0) {
|
||||
return headerEntry.getValue().get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSpanName(HttpServletRequest request, TraceData traceData) {
|
||||
if (StringUtils.isNotBlank(traceData.getSpanName())) {
|
||||
return traceData.getSpanName();
|
||||
} else {
|
||||
//TODO: what is the functional equivalent of resteasy request.getPreprocessedPath();
|
||||
UriComponents components = UriComponentsBuilder.fromUriString(request.getRequestURL().toString()).build();
|
||||
StringBuilder preprocessedPath = new StringBuilder();
|
||||
for (String segment : components.getPathSegments()) {
|
||||
preprocessedPath.append("/").append(segment);
|
||||
}
|
||||
if (preprocessedPath.length() == 0) {
|
||||
preprocessedPath.append("/");
|
||||
}
|
||||
return preprocessedPath.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.web;
|
||||
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinInterceptor;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
@@ -8,36 +8,54 @@ import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import com.github.kristofa.brave.EndPointSubmitter;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 2)
|
||||
public class ZipkinFilter implements Filter {
|
||||
|
||||
private final ZipkinInterceptor zipkinInterceptor;
|
||||
@Value("${spring.application.name:application}")
|
||||
private String serviceName;
|
||||
|
||||
public ZipkinFilter(ZipkinInterceptor zipkinInterceptor) {
|
||||
this.zipkinInterceptor = zipkinInterceptor;
|
||||
}
|
||||
private EndPointSubmitter endPointSubmitter;
|
||||
|
||||
public void setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
//NOOP
|
||||
}
|
||||
public ZipkinFilter(EndPointSubmitter endPointSubmitter) {
|
||||
this.endPointSubmitter = endPointSubmitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
zipkinInterceptor.preTrace(request);
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
if (!this.endPointSubmitter.endPointSubmitted()) {
|
||||
final String localAddr = request.getLocalAddr();
|
||||
final int localPort = request.getLocalPort();
|
||||
final String contextPath = this.serviceName
|
||||
+ ((request instanceof HttpServletRequest) ? ((HttpServletRequest) request)
|
||||
.getContextPath() : "");
|
||||
this.endPointSubmitter.submit(localAddr, localPort, contextPath);
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
zipkinInterceptor.postTrace(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
//NOOP
|
||||
}
|
||||
@Override
|
||||
public void destroy() {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.web;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinInterceptor;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class ZipkinHandlerInterceptor implements HandlerInterceptor {
|
||||
|
||||
private final ZipkinInterceptor zipkinInterceptor;
|
||||
|
||||
public ZipkinHandlerInterceptor(ZipkinInterceptor zipkinInterceptor) {
|
||||
this.zipkinInterceptor = zipkinInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
zipkinInterceptor.preTrace(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
||||
zipkinInterceptor.postTrace(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +1,18 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.web;
|
||||
|
||||
import com.github.kristofa.brave.EndPointSubmitter;
|
||||
import com.github.kristofa.brave.ServerTracer;
|
||||
import com.github.kristofa.brave.ServerTracerConfig;
|
||||
import com.github.kristofa.brave.client.ClientRequestInterceptor;
|
||||
import com.github.kristofa.brave.client.ClientResponseInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinRestTemplateInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import com.github.kristofa.brave.EndPointSubmitter;
|
||||
import com.github.kristofa.brave.ServerTracerConfig;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -26,62 +22,15 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnProperty(value = "spring.cloud.sleuth.zipkin.enabled", matchIfMissing = true)
|
||||
@AutoConfigureAfter(ZipkinAutoConfiguration.class)
|
||||
@AutoConfigureBefore(TraceAutoConfiguration.class)
|
||||
public class ZipkinWebAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private EndPointSubmitter endPointSubmitter;
|
||||
|
||||
@Autowired
|
||||
private ServerTracer serverTracer;
|
||||
|
||||
@Bean
|
||||
public ZipkinHandlerInterceptor zipkinHandlerInterceptor() {
|
||||
return new ZipkinHandlerInterceptor(httpServletRequestInterceptor());
|
||||
public ZipkinFilter zipkinFilter() {
|
||||
return new ZipkinFilter(this.endPointSubmitter);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZipkinFilter zipkinFilter() {
|
||||
return new ZipkinFilter(httpServletRequestInterceptor());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpServletRequestInterceptor httpServletRequestInterceptor() {
|
||||
return new HttpServletRequestInterceptor(serverTracer, endPointSubmitter);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(ZipkinHandlerInterceptor.class)
|
||||
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(ZipkinHandlerInterceptor zipkinHandlerInterceptor) {
|
||||
return new ZipkinWebConfigurer(zipkinHandlerInterceptor);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class RestTemplateConfig {
|
||||
|
||||
@Autowired
|
||||
private ClientRequestInterceptor clientRequestInterceptor;
|
||||
|
||||
@Autowired
|
||||
private ClientResponseInterceptor clientResponseInterceptor;
|
||||
|
||||
@Bean
|
||||
public ZipkinRestTemplateInterceptor zipkinRestTemplateInterceptor() {
|
||||
return new ZipkinRestTemplateInterceptor(clientRequestInterceptor,
|
||||
clientResponseInterceptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class ZipkinWebConfigurer extends WebMvcConfigurerAdapter {
|
||||
private ZipkinHandlerInterceptor interceptor;
|
||||
|
||||
public ZipkinWebConfigurer(ZipkinHandlerInterceptor interceptor) {
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(interceptor).addPathPatterns("/**");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.zuul;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class ZipkinPostFilter extends ZuulFilter {
|
||||
|
||||
private ZipkinInterceptor zipkinInterceptor;
|
||||
|
||||
public ZipkinPostFilter(ZipkinInterceptor zipkinInterceptor) {
|
||||
this.zipkinInterceptor = zipkinInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return "post";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() {
|
||||
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
|
||||
|
||||
zipkinInterceptor.postTrace(request);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.zuul;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinInterceptor;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class ZipkinPreFilter extends ZuulFilter {
|
||||
|
||||
private ZipkinInterceptor zipkinInterceptor;
|
||||
|
||||
public ZipkinPreFilter(ZipkinInterceptor zipkinInterceptor) {
|
||||
this.zipkinInterceptor = zipkinInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return "pre";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() {
|
||||
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
|
||||
|
||||
zipkinInterceptor.preTrace(request);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.springframework.cloud.sleuth.zipkin.zuul;
|
||||
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.cloud.sleuth.zipkin.ZipkinInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(ZuulFilter.class)
|
||||
@ConditionalOnBean(ZipkinInterceptor.class)
|
||||
public class ZipkinZuulAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ZipkinPreFilter zipkinPreFilter(ZipkinInterceptor zipkinInterceptor) {
|
||||
return new ZipkinPreFilter(zipkinInterceptor);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZipkinPostFilter zipkinPostFilter(ZipkinInterceptor zipkinInterceptor) {
|
||||
return new ZipkinPostFilter(zipkinInterceptor);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user