diff --git a/pom.xml b/pom.xml
index 14159e310..7342cdb50 100644
--- a/pom.xml
+++ b/pom.xml
@@ -217,7 +217,7 @@
2.4.2
- 1.0.3.BUILD-SNAPSHOT
+ 1.1.0.BUILD-SNAPSHOT
1.8.4
1.0-groovy-2.4
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java
new file mode 100644
index 000000000..21d7b609e
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceRestClientRibbonCommandFactory.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2013-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.zuul;
+
+import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME;
+import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME;
+import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME;
+import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME;
+import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME;
+import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME;
+import static org.springframework.cloud.sleuth.TraceContextHolder.getCurrentSpan;
+import static org.springframework.cloud.sleuth.TraceContextHolder.isTracing;
+
+import java.io.InputStream;
+import java.net.URISyntaxException;
+
+import lombok.SneakyThrows;
+
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommand;
+import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommandFactory;
+import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandContext;
+import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.event.ClientSentEvent;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+import org.springframework.util.MultiValueMap;
+
+import com.netflix.client.http.HttpRequest;
+import com.netflix.niws.client.http.RestClient;
+
+/**
+ * @author Spencer Gibb
+ */
+public class TraceRestClientRibbonCommandFactory extends RestClientRibbonCommandFactory
+ implements ApplicationEventPublisherAware {
+
+ private ApplicationEventPublisher publisher;
+
+ public TraceRestClientRibbonCommandFactory(SpringClientFactory clientFactory) {
+ super(clientFactory);
+ }
+
+ @Override
+ public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
+ this.publisher = publisher;
+ }
+
+ @Override
+ @SneakyThrows
+ @SuppressWarnings("deprecation")
+ public RestClientRibbonCommand create(RibbonCommandContext context) {
+ RestClient restClient = getClientFactory().getClient(context.getServiceId(),
+ RestClient.class);
+ return new TraceRestClientRibbonCommand(
+ context.getServiceId(), restClient, getVerb(context.getVerb()),
+ context.getUri(), context.getRetryable(), context.getHeaders(),
+ context.getParams(), context.getRequestEntity(), publisher);
+ }
+
+ class TraceRestClientRibbonCommand extends RestClientRibbonCommand {
+
+ private ApplicationEventPublisher publisher;
+
+ @SuppressWarnings("deprecation")
+ public TraceRestClientRibbonCommand(String commandKey, RestClient restClient, HttpRequest.Verb verb, String uri, Boolean retryable, MultiValueMap headers, MultiValueMap params, InputStream requestEntity, ApplicationEventPublisher publisher) throws URISyntaxException {
+ super(commandKey, restClient, verb, uri, retryable, headers, params, requestEntity);
+ this.publisher = publisher;
+ }
+
+ @Override
+ protected void customizeRequest(HttpRequest.Builder requestBuilder) {
+ if (getCurrentSpan() == null) {
+ setHeader(requestBuilder, NOT_SAMPLED_NAME, "");
+ return;
+ }
+
+ setHeader(requestBuilder, SPAN_ID_NAME, getCurrentSpan().getSpanId());
+ setHeader(requestBuilder, TRACE_ID_NAME, getCurrentSpan().getTraceId());
+ setHeader(requestBuilder, SPAN_NAME_NAME, getCurrentSpan().getName());
+ setHeader(requestBuilder, PARENT_ID_NAME, getParentId(getCurrentSpan()));
+ setHeader(requestBuilder, PROCESS_ID_NAME, getCurrentSpan().getProcessId());
+ publish(new ClientSentEvent(this, getCurrentSpan()));
+ }
+
+ private void publish(ApplicationEvent event) {
+ if (this.publisher != null) {
+ this.publisher.publishEvent(event);
+ }
+ }
+
+ private String getParentId(Span span) {
+ return span.getParents() != null && !span.getParents().isEmpty() ? span
+ .getParents().get(0) : null;
+ }
+
+ public void setHeader(HttpRequest.Builder builder, String name, String value) {
+ if (value != null && isTracing()) {
+ builder.header(name, value);
+ }
+ }
+ }
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java
index 1450c2d16..05e1438ca 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/zuul/TraceZuulAutoConfiguration.java
@@ -21,6 +21,7 @@ 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.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.sleuth.Trace;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.context.annotation.Bean;
@@ -47,4 +48,9 @@ public class TraceZuulAutoConfiguration {
return new TracePreZuulFilter();
}
+ @Bean
+ public TraceRestClientRibbonCommandFactory traceRestClientRibbonCommandFactory(SpringClientFactory factory) {
+ return new TraceRestClientRibbonCommandFactory(factory);
+ }
+
}