From df2893671834cf3bff02fa5c6d985e5a873c3bc0 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 31 Jul 2015 10:12:06 +0100 Subject: [PATCH] Finish async customizer --- README.adoc | 25 +++++++-- docs/src/main/asciidoc/README.adoc | 25 +++++++-- .../scheduling/LazyTraceAsyncCustomizer.java | 53 +++++++++++++++++++ .../TraceSchedulingAutoConfiguration.java | 35 +++++++++++- .../cloud/sleuth/zipkin/ZipkinProperties.java | 11 ++-- 5 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/LazyTraceAsyncCustomizer.java diff --git a/README.adoc b/README.adoc index e745c7a18..b7327f9cf 100644 --- a/README.adoc +++ b/README.adoc @@ -18,16 +18,31 @@ Spans are started and stopped, and they keep track of their timing information. == Features -* TODO: list features +* Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator. Example configuration: ++ +[source,yaml] +---- +logging: + pattern: + console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [trace=%X{X-Trace-Id:-},span=%X{X-Span-Id:-}] [%15.15t] %-40.40logger{39}: %m%n' +---- ++ +(notice the `%X` entries from the MDC). + +* Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations, key-value annotations. Loosely based on HTrace, but Zipkin (Dapper) compatible. + +* Instruments common ingress and egress points from Spring applications (servlet filter, rest template, scheduled actions). + +* If `spring-cloud-sleuth-zipkin` then the app will generate and collect Zipkin-compatible traces (using Brave). By default it sends them via Thrift to a Zipkin collector service on localhost (port 9410). Configure the location of the service using `spring.zipkin.[host,port]`. == Running the sample 1. Optionally run [Zipkin](https://github.com/openzipkin/zipkin), e.g. via docker compose (there's a `docker-compose.yml` in [Spring Cloud Sleuth](https://github.com/spring-cloud-incubator/spring-cloud-sleuth), or in [Docker Zipkin](https://github.com/openzipkin/docker-zipkin) -7. Run sample application -8. Hit `http://localhost:3380` -9. Goto `http://localhost:8082` for zipkin web +7. Run the sample application +8. Hit `http://localhost:3380`, `http://localhost:3380/call`, `http://localhost:3380/async` for some interesting sample traces (the app callas back to itself). +9. Goto `http://localhost:8082` for zipkin web (8080 if running locally from source, the host is the docker host, so if you are using boot2docker it will be different) -WARNING: The docker images for zipkin are old and don't work very well (the UI in particular). Zipkin is in a state of flux, but it should settle down soon when there is an actual release. Best result actually come from building from source and running the jar files (the query and collector services need command line arguments, so check the zipkin README for updates). +WARNING: The docker images for zipkin are old and don't work very well (the UI in particular). Zipkin is in a state of flux, but it should settle down soon when there is an actual release. Best results actually come from building from source and running the jar files (the query and collector services need command line arguments, so check the zipkin README for updates). NOTE: You can see the zipkin spans without the UI (in logs) if you just provide a `@Bean` of type `LogSpanCollector` (there's one commented out in the sample). diff --git a/docs/src/main/asciidoc/README.adoc b/docs/src/main/asciidoc/README.adoc index f72a65413..54d4ffbf5 100644 --- a/docs/src/main/asciidoc/README.adoc +++ b/docs/src/main/asciidoc/README.adoc @@ -6,16 +6,31 @@ include::intro.adoc[] == Features -* TODO: list features +* Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator. Example configuration: ++ +[source,yaml] +---- +logging: + pattern: + console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [trace=%X{X-Trace-Id:-},span=%X{X-Span-Id:-}] [%15.15t] %-40.40logger{39}: %m%n' +---- ++ +(notice the `%X` entries from the MDC). + +* Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations, key-value annotations. Loosely based on HTrace, but Zipkin (Dapper) compatible. + +* Instruments common ingress and egress points from Spring applications (servlet filter, rest template, scheduled actions). + +* If `spring-cloud-sleuth-zipkin` then the app will generate and collect Zipkin-compatible traces (using Brave). By default it sends them via Thrift to a Zipkin collector service on localhost (port 9410). Configure the location of the service using `spring.zipkin.[host,port]`. == Running the sample 1. Optionally run [Zipkin](https://github.com/openzipkin/zipkin), e.g. via docker compose (there's a `docker-compose.yml` in [Spring Cloud Sleuth](https://github.com/spring-cloud-incubator/spring-cloud-sleuth), or in [Docker Zipkin](https://github.com/openzipkin/docker-zipkin) -7. Run sample application -8. Hit `http://localhost:3380` -9. Goto `http://localhost:8082` for zipkin web +7. Run the sample application +8. Hit `http://localhost:3380`, `http://localhost:3380/call`, `http://localhost:3380/async` for some interesting sample traces (the app callas back to itself). +9. Goto `http://localhost:8082` for zipkin web (8080 if running locally from source, the host is the docker host, so if you are using boot2docker it will be different) -WARNING: The docker images for zipkin are old and don't work very well (the UI in particular). Zipkin is in a state of flux, but it should settle down soon when there is an actual release. Best result actually come from building from source and running the jar files (the query and collector services need command line arguments, so check the zipkin README for updates). +WARNING: The docker images for zipkin are old and don't work very well (the UI in particular). Zipkin is in a state of flux, but it should settle down soon when there is an actual release. Best results actually come from building from source and running the jar files (the query and collector services need command line arguments, so check the zipkin README for updates). NOTE: You can see the zipkin spans without the UI (in logs) if you just provide a `@Bean` of type `LogSpanCollector` (there's one commented out in the sample). diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/LazyTraceAsyncCustomizer.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/LazyTraceAsyncCustomizer.java new file mode 100644 index 000000000..85e66b51a --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/LazyTraceAsyncCustomizer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.sleuth.instrument.scheduling; + +import java.util.concurrent.Executor; + +import lombok.RequiredArgsConstructor; + +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.sleuth.Trace; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.AsyncConfigurerSupport; + +/** + * @author Dave Syer + * + */ +@RequiredArgsConstructor +public class LazyTraceAsyncCustomizer extends AsyncConfigurerSupport { + + private Trace trace; + private final BeanFactory beanFactory; + private final AsyncConfigurer delegate; + + @Override + public Executor getAsyncExecutor() { + if (this.trace == null) { + this.trace = this.beanFactory.getBean(Trace.class); + } + return new TraceExecutor(this.trace, this.delegate.getAsyncExecutor()); + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return this.delegate.getAsyncUncaughtExceptionHandler(); + } + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java index a8a9d3dcb..186ac0ac2 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/scheduling/TraceSchedulingAutoConfiguration.java @@ -7,13 +7,19 @@ package org.springframework.cloud.sleuth.instrument.scheduling; import java.util.concurrent.Executor; import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.sleuth.Trace; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.AsyncConfigurerSupport; import org.springframework.scheduling.annotation.EnableAsync; @@ -37,12 +43,12 @@ public class TraceSchedulingAutoConfiguration { @EnableAsync @Configuration - protected static class AsyncConfiguration extends AsyncConfigurerSupport { + @ConditionalOnMissingBean(AsyncConfigurer.class) + protected static class AsyncDefaultConfiguration extends AsyncConfigurerSupport { @Autowired private Trace trace; - // TODO: look for an existing AsyncConfigurer and steal its Executor @Override public Executor getAsyncExecutor() { return new TraceExecutor(this.trace, new SimpleAsyncTaskExecutor()); @@ -50,4 +56,29 @@ public class TraceSchedulingAutoConfiguration { } + @Configuration + @ConditionalOnBean(AsyncConfigurer.class) + protected static class AsyncCustomConfiguration implements BeanPostProcessor { + + @Autowired + private BeanFactory beanFactory; + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof AsyncConfigurer) { + AsyncConfigurer configurer = (AsyncConfigurer) bean; + return new LazyTraceAsyncCustomizer(this.beanFactory, configurer); + } + return bean; + } + + } + } diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java index ce170fd63..5e646303d 100644 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java +++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java @@ -1,16 +1,17 @@ package org.springframework.cloud.sleuth.zipkin; import lombok.Data; + import org.springframework.boot.context.properties.ConfigurationProperties; /** * @author Spencer Gibb */ -@ConfigurationProperties("spring.cloud.sleuth.zipkin") +@ConfigurationProperties("spring.zipkin") @Data public class ZipkinProperties { - // Sample rate = 1 means every request will get traced. - private int fixedSampleRate = 1; - private String host = "localhost"; - private int port = 9410; + // Sample rate = 1 means every request will get traced. + private int fixedSampleRate = 1; + private String host = "localhost"; + private int port = 9410; }