Fixed the Gateway integration with Sleuth
fixes gh-1141
This commit is contained in:
8
pom.xml
8
pom.xml
@@ -154,6 +154,13 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-gateway-dependencies</artifactId>
|
||||
<version>${spring-cloud-gateway.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-dependencies</artifactId>
|
||||
@@ -244,6 +251,7 @@
|
||||
<maven.compiler.testSource>1.8</maven.compiler.testSource>
|
||||
<spring-cloud-build.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-build.version>
|
||||
<spring-cloud-commons.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-gateway.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-gateway.version>
|
||||
<spring-cloud-stream.version>Fishtown.BUILD-SNAPSHOT</spring-cloud-stream.version>
|
||||
<spring-cloud-netflix.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-netflix.version>
|
||||
<spring-cloud-openfeign.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-openfeign.version>
|
||||
|
||||
@@ -81,6 +81,11 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.web.client;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.http.HttpClientHandler;
|
||||
import brave.http.HttpTracing;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.Connection;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientRequest;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
class HttpClientBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
HttpClientBeanPostProcessor(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof HttpClient) {
|
||||
return ((HttpClient) bean).mapConnect(new TracingMapConnect(this.beanFactory))
|
||||
.doOnRequest(TracingDoOnRequest.create(this.beanFactory))
|
||||
.doOnRequestError(TracingDoOnErrorRequest.create(this.beanFactory))
|
||||
.doOnResponse(TracingDoOnResponse.create(this.beanFactory))
|
||||
.doOnResponseError(TracingDoOnErrorResponse.create(this.beanFactory));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private static class TracingMapConnect implements
|
||||
BiFunction<Mono<? extends Connection>, Bootstrap, Mono<? extends Connection>> {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private Tracer tracer;
|
||||
|
||||
TracingMapConnect(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<? extends Connection> apply(Mono<? extends Connection> mono,
|
||||
Bootstrap bootstrap) {
|
||||
return mono.subscriberContext(context -> context.put(AtomicReference.class,
|
||||
new AtomicReference<>(tracer().currentSpan())));
|
||||
}
|
||||
|
||||
private Tracer tracer() {
|
||||
if (this.tracer == null) {
|
||||
this.tracer = this.beanFactory.getBean(Tracer.class);
|
||||
}
|
||||
return this.tracer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnRequest
|
||||
implements BiConsumer<HttpClientRequest, Connection> {
|
||||
|
||||
static final Propagation.Setter<HttpHeaders, String> SETTER = new Propagation.Setter<HttpHeaders, String>() {
|
||||
@Override
|
||||
public void put(HttpHeaders carrier, String key, String value) {
|
||||
if (!carrier.contains(key)) {
|
||||
carrier.add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpHeaders::add";
|
||||
}
|
||||
};
|
||||
|
||||
final Tracer tracer;
|
||||
|
||||
final HttpClientHandler<HttpClientRequest, HttpClientResponse> handler;
|
||||
|
||||
final TraceContext.Injector<HttpHeaders> injector;
|
||||
|
||||
final HttpTracing httpTracing;
|
||||
|
||||
final Propagation<String> propagation;
|
||||
|
||||
TracingDoOnRequest(HttpTracing httpTracing) {
|
||||
this.tracer = httpTracing.tracing().tracer();
|
||||
this.handler = HttpClientHandler.create(httpTracing, new HttpAdapter());
|
||||
this.propagation = httpTracing.tracing().propagation();
|
||||
this.injector = this.propagation.injector(SETTER);
|
||||
this.httpTracing = httpTracing;
|
||||
}
|
||||
|
||||
static TracingDoOnRequest create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnRequest(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientRequest req, Connection connection) {
|
||||
if (this.propagation.keys().stream()
|
||||
.anyMatch(key -> req.requestHeaders().contains(key))) {
|
||||
// request already instrumented
|
||||
return;
|
||||
}
|
||||
AtomicReference reference = req.currentContext()
|
||||
.getOrDefault(AtomicReference.class, new AtomicReference());
|
||||
Span span = this.handler.handleSend(this.injector, req.requestHeaders(), req,
|
||||
(Span) reference.get());
|
||||
reference.set(span);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnResponse extends AbstractTracingDoOnHandler
|
||||
implements BiConsumer<HttpClientResponse, Connection> {
|
||||
|
||||
TracingDoOnResponse(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
static TracingDoOnResponse create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnResponse(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientResponse httpClientResponse, Connection connection) {
|
||||
handle(httpClientResponse, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnErrorRequest extends AbstractTracingDoOnHandler
|
||||
implements BiConsumer<HttpClientRequest, Throwable> {
|
||||
|
||||
TracingDoOnErrorRequest(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
static TracingDoOnErrorRequest create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnErrorRequest(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientRequest request, Throwable throwable) {
|
||||
handle(null, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnErrorResponse extends AbstractTracingDoOnHandler
|
||||
implements BiConsumer<HttpClientResponse, Throwable> {
|
||||
|
||||
TracingDoOnErrorResponse(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
static TracingDoOnErrorResponse create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnErrorResponse(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientResponse httpClientResponse, Throwable throwable) {
|
||||
handle(httpClientResponse, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static abstract class AbstractTracingDoOnHandler {
|
||||
|
||||
final Tracer tracer;
|
||||
|
||||
final HttpClientHandler<HttpClientRequest, HttpClientResponse> handler;
|
||||
|
||||
AbstractTracingDoOnHandler(HttpTracing httpTracing) {
|
||||
this.tracer = httpTracing.tracing().tracer();
|
||||
this.handler = HttpClientHandler.create(httpTracing, new HttpAdapter());
|
||||
}
|
||||
|
||||
protected void handle(HttpClientResponse httpClientResponse,
|
||||
Throwable throwable) {
|
||||
AtomicReference reference = httpClientResponse.currentContext()
|
||||
.getOrDefault(AtomicReference.class, null);
|
||||
if (reference == null || reference.get() == null) {
|
||||
return;
|
||||
}
|
||||
this.handler.handleReceive(httpClientResponse, throwable,
|
||||
(Span) reference.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class HttpAdapter
|
||||
extends brave.http.HttpClientAdapter<HttpClientRequest, HttpClientResponse> {
|
||||
|
||||
@Override
|
||||
public String method(HttpClientRequest request) {
|
||||
return request.method().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url(HttpClientRequest request) {
|
||||
return request.uri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestHeader(HttpClientRequest request, String name) {
|
||||
Object result = request.requestHeaders().get(name);
|
||||
return result != null ? result.toString() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer statusCode(HttpClientResponse response) {
|
||||
return response.status().code();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.web.client;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.http.HttpClientHandler;
|
||||
import brave.http.HttpTracing;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
class TraceRequestHttpHeadersFilter extends AbstractHttpHeadersFilter {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceRequestHttpHeadersFilter.class);
|
||||
|
||||
static HttpHeadersFilter create(HttpTracing httpTracing) {
|
||||
return new TraceRequestHttpHeadersFilter(httpTracing);
|
||||
}
|
||||
|
||||
private TraceRequestHttpHeadersFilter(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) {
|
||||
Object storedSpan = exchange.getAttribute(SPAN_ATTRIBUTE);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will instrument the HTTP request headers");
|
||||
}
|
||||
Span span = clientSent(exchange, storedSpan);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Client span created for the request " + span);
|
||||
}
|
||||
exchange.getAttributes().put(SPAN_ATTRIBUTE, span);
|
||||
return new HttpHeaders(exchange.getRequest().getHeaders());
|
||||
}
|
||||
|
||||
private Span clientSent(ServerWebExchange exchange, Object storedSpan) {
|
||||
if (storedSpan != null) {
|
||||
return this.handler.handleSend(this.injector, exchange.getRequest(),
|
||||
(Span) storedSpan);
|
||||
}
|
||||
return this.handler.handleSend(this.injector, exchange.getRequest());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Type type) {
|
||||
return type.equals(Type.REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TraceResponseHttpHeadersFilter extends AbstractHttpHeadersFilter {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceResponseHttpHeadersFilter.class);
|
||||
|
||||
static HttpHeadersFilter create(HttpTracing httpTracing) {
|
||||
return new TraceResponseHttpHeadersFilter(httpTracing);
|
||||
}
|
||||
|
||||
private TraceResponseHttpHeadersFilter(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) {
|
||||
Object storedSpan = exchange.getAttribute(SPAN_ATTRIBUTE);
|
||||
if (storedSpan == null) {
|
||||
return input;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will instrument the response");
|
||||
}
|
||||
this.handler.handleReceive(exchange.getResponse(), null, (Span) storedSpan);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("The response was handled");
|
||||
}
|
||||
return new HttpHeaders(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Type type) {
|
||||
return type.equals(Type.RESPONSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractHttpHeadersFilter implements HttpHeadersFilter {
|
||||
|
||||
static final String SPAN_ATTRIBUTE = Span.class.getName();
|
||||
|
||||
private static final Propagation.Setter<ServerHttpRequest, String> SETTER = new Propagation.Setter<ServerHttpRequest, String>() {
|
||||
@Override
|
||||
public void put(ServerHttpRequest carrier, String key, String value) {
|
||||
if (!carrier.getHeaders().containsKey(key)) {
|
||||
carrier.getHeaders().add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerHttpRequest::HttpHeaders::add";
|
||||
}
|
||||
};
|
||||
|
||||
final Tracer tracer;
|
||||
|
||||
final HttpClientHandler<ServerHttpRequest, ServerHttpResponse> handler;
|
||||
|
||||
final TraceContext.Injector<ServerHttpRequest> injector;
|
||||
|
||||
final HttpTracing httpTracing;
|
||||
|
||||
AbstractHttpHeadersFilter(HttpTracing httpTracing) {
|
||||
this.tracer = httpTracing.tracing().tracer();
|
||||
this.handler = HttpClientHandler.create(httpTracing, new ServerHttpAdapter());
|
||||
this.injector = httpTracing.tracing().propagation().injector(SETTER);
|
||||
this.httpTracing = httpTracing;
|
||||
}
|
||||
|
||||
private static class ServerHttpAdapter
|
||||
extends brave.http.HttpClientAdapter<ServerHttpRequest, ServerHttpResponse> {
|
||||
|
||||
@Override
|
||||
public String method(ServerHttpRequest request) {
|
||||
return request.getMethodValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url(ServerHttpRequest request) {
|
||||
return request.getURI().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestHeader(ServerHttpRequest request, String name) {
|
||||
Object result = request.getHeaders().get(name);
|
||||
return result != null ? result.toString() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer statusCode(ServerHttpResponse response) {
|
||||
return response.getStatusCode() != null ? response.getStatusCode().value()
|
||||
: null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,30 +19,14 @@ package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.http.HttpClientHandler;
|
||||
import brave.http.HttpTracing;
|
||||
import brave.httpasyncclient.TracingHttpAsyncClientBuilder;
|
||||
import brave.httpclient.TracingHttpClientBuilder;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import brave.spring.web.TracingClientHttpRequestInterceptor;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.Connection;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientRequest;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -57,6 +41,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer;
|
||||
import org.springframework.boot.web.client.RestTemplateCustomizer;
|
||||
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
|
||||
import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -102,7 +87,7 @@ public class TraceWebClientAutoConfiguration {
|
||||
private TracingClientHttpRequestInterceptor clientInterceptor;
|
||||
|
||||
@Bean
|
||||
static TraceRestTemplateBeanPostProcessor traceRestTemplateBPP(
|
||||
static TraceRestTemplateBeanPostProcessor traceRestTemplateBeanPostProcessor(
|
||||
ListableBeanFactory beanFactory) {
|
||||
return new TraceRestTemplateBeanPostProcessor(beanFactory);
|
||||
}
|
||||
@@ -153,6 +138,22 @@ public class TraceWebClientAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(HttpHeadersFilter.class)
|
||||
static class HttpHeadersFilterConfig {
|
||||
|
||||
@Bean
|
||||
HttpHeadersFilter traceRequestHttpHeadersFilter(HttpTracing httpTracing) {
|
||||
return TraceRequestHttpHeadersFilter.create(httpTracing);
|
||||
}
|
||||
|
||||
@Bean
|
||||
HttpHeadersFilter traceResponseHttpHeadersFilter(HttpTracing httpTracing) {
|
||||
return TraceResponseHttpHeadersFilter.create(httpTracing);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(HttpClient.class)
|
||||
static class NettyConfiguration {
|
||||
@@ -315,210 +316,6 @@ class LazyTracingClientHttpRequestInterceptor implements ClientHttpRequestInterc
|
||||
|
||||
}
|
||||
|
||||
class HttpClientBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
HttpClientBeanPostProcessor(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof HttpClient) {
|
||||
return ((HttpClient) bean).mapConnect(new TracingMapConnect(this.beanFactory))
|
||||
.doOnRequest(TracingDoOnRequest.create(this.beanFactory))
|
||||
.doOnRequestError(TracingDoOnErrorRequest.create(this.beanFactory))
|
||||
.doOnResponse(TracingDoOnResponse.create(this.beanFactory))
|
||||
.doOnResponseError(TracingDoOnErrorResponse.create(this.beanFactory));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private static class TracingMapConnect implements
|
||||
BiFunction<Mono<? extends Connection>, Bootstrap, Mono<? extends Connection>> {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private Tracer tracer;
|
||||
|
||||
TracingMapConnect(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<? extends Connection> apply(Mono<? extends Connection> mono,
|
||||
Bootstrap bootstrap) {
|
||||
return mono.subscriberContext(context -> context.put(AtomicReference.class,
|
||||
new AtomicReference<>(tracer().currentSpan())));
|
||||
}
|
||||
|
||||
private Tracer tracer() {
|
||||
if (this.tracer == null) {
|
||||
this.tracer = this.beanFactory.getBean(Tracer.class);
|
||||
}
|
||||
return this.tracer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnRequest
|
||||
implements BiConsumer<HttpClientRequest, Connection> {
|
||||
|
||||
static final Propagation.Setter<HttpHeaders, String> SETTER = new Propagation.Setter<HttpHeaders, String>() {
|
||||
@Override
|
||||
public void put(HttpHeaders carrier, String key, String value) {
|
||||
if (!carrier.contains(key)) {
|
||||
carrier.add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpHeaders::add";
|
||||
}
|
||||
};
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(TracingDoOnRequest.class);
|
||||
|
||||
final Tracer tracer;
|
||||
|
||||
final HttpClientHandler<HttpClientRequest, HttpClientResponse> handler;
|
||||
|
||||
final TraceContext.Injector<HttpHeaders> injector;
|
||||
|
||||
final HttpTracing httpTracing;
|
||||
|
||||
TracingDoOnRequest(HttpTracing httpTracing) {
|
||||
this.tracer = httpTracing.tracing().tracer();
|
||||
this.handler = HttpClientHandler.create(httpTracing, new HttpAdapter());
|
||||
this.injector = httpTracing.tracing().propagation().injector(SETTER);
|
||||
this.httpTracing = httpTracing;
|
||||
}
|
||||
|
||||
static TracingDoOnRequest create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnRequest(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientRequest req, Connection connection) {
|
||||
AtomicReference reference = req.currentContext()
|
||||
.getOrDefault(AtomicReference.class, new AtomicReference());
|
||||
Span span = this.handler.handleSend(this.injector, req.requestHeaders(), req,
|
||||
(Span) reference.get());
|
||||
reference.set(span);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnResponse extends AbstractTracingDoOnHandler
|
||||
implements BiConsumer<HttpClientResponse, Connection> {
|
||||
|
||||
TracingDoOnResponse(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
static TracingDoOnResponse create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnResponse(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientResponse httpClientResponse, Connection connection) {
|
||||
handle(httpClientResponse, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnErrorRequest extends AbstractTracingDoOnHandler
|
||||
implements BiConsumer<HttpClientRequest, Throwable> {
|
||||
|
||||
TracingDoOnErrorRequest(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
static TracingDoOnErrorRequest create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnErrorRequest(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientRequest request, Throwable throwable) {
|
||||
handle(null, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TracingDoOnErrorResponse extends AbstractTracingDoOnHandler
|
||||
implements BiConsumer<HttpClientResponse, Throwable> {
|
||||
|
||||
TracingDoOnErrorResponse(HttpTracing httpTracing) {
|
||||
super(httpTracing);
|
||||
}
|
||||
|
||||
static TracingDoOnErrorResponse create(BeanFactory beanFactory) {
|
||||
return new TracingDoOnErrorResponse(beanFactory.getBean(HttpTracing.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpClientResponse httpClientResponse, Throwable throwable) {
|
||||
handle(httpClientResponse, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static abstract class AbstractTracingDoOnHandler {
|
||||
|
||||
final Tracer tracer;
|
||||
|
||||
final HttpClientHandler<HttpClientRequest, HttpClientResponse> handler;
|
||||
|
||||
AbstractTracingDoOnHandler(HttpTracing httpTracing) {
|
||||
this.tracer = httpTracing.tracing().tracer();
|
||||
this.handler = HttpClientHandler.create(httpTracing, new HttpAdapter());
|
||||
}
|
||||
|
||||
protected void handle(HttpClientResponse httpClientResponse,
|
||||
Throwable throwable) {
|
||||
AtomicReference reference = httpClientResponse.currentContext()
|
||||
.getOrDefault(AtomicReference.class, null);
|
||||
if (reference == null || reference.get() == null) {
|
||||
return;
|
||||
}
|
||||
this.handler.handleReceive(httpClientResponse, throwable,
|
||||
(Span) reference.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class HttpAdapter
|
||||
extends brave.http.HttpClientAdapter<HttpClientRequest, HttpClientResponse> {
|
||||
|
||||
@Override
|
||||
public String method(HttpClientRequest request) {
|
||||
return request.method().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url(HttpClientRequest request) {
|
||||
return request.uri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestHeader(HttpClientRequest request, String name) {
|
||||
Object result = request.requestHeaders().get(name);
|
||||
return result != null ? result.toString() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer statusCode(HttpClientResponse response) {
|
||||
return response.status().code();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TraceUserInfoRestTemplateCustomizer implements UserInfoRestTemplateCustomizer {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
@@ -545,4 +342,4 @@ class TraceUserInfoRestTemplateCustomizer implements UserInfoRestTemplateCustomi
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.JMSException;
|
||||
@@ -37,15 +38,19 @@ import brave.propagation.TraceContext;
|
||||
import org.apache.activemq.ra.ActiveMQActivationSpec;
|
||||
import org.apache.activemq.ra.ActiveMQResourceAdapter;
|
||||
import org.junit.Test;
|
||||
import zipkin2.Annotation;
|
||||
import zipkin2.Span;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
|
||||
import org.springframework.boot.jms.XAConnectionFactoryWrapper;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jca.support.ResourceAdapterFactoryBean;
|
||||
@@ -57,8 +62,6 @@ import org.springframework.jms.config.JmsListenerEndpointRegistrar;
|
||||
import org.springframework.jms.config.SimpleJmsListenerEndpoint;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.jms.listener.endpoint.JmsMessageEndpointManager;
|
||||
import zipkin2.Annotation;
|
||||
import zipkin2.Span;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -273,7 +276,8 @@ public class JmsTracingConfigurationTest {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableAutoConfiguration(exclude = { GatewayAutoConfiguration.class,
|
||||
GatewayClassPathWarningAutoConfiguration.class })
|
||||
class JmsTestTracingConfiguration {
|
||||
|
||||
static final String CONTEXT_LEAK = "context.leak";
|
||||
|
||||
@@ -30,12 +30,15 @@ import org.awaitility.Awaitility;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import zipkin2.Span;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -49,8 +52,6 @@ import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import zipkin2.Span;
|
||||
|
||||
import static org.assertj.core.api.Assertions.tuple;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@@ -114,7 +115,8 @@ public class SpringDataInstrumentationTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
|
||||
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
|
||||
GatewayAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class })
|
||||
@EntityScan(basePackageClasses = Reservation.class)
|
||||
class ReservationServiceApplication {
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.Optional;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import brave.Span;
|
||||
@@ -55,6 +56,13 @@ import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
import zipkin2.Annotation;
|
||||
import zipkin2.reporter.Reporter;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@@ -66,6 +74,8 @@ import org.springframework.boot.web.client.RestTemplateCustomizer;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
|
||||
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
@@ -86,12 +96,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
import zipkin2.Annotation;
|
||||
import zipkin2.reporter.Reporter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
@@ -510,7 +514,9 @@ public class WebClientTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = TraceWebServletAutoConfiguration.class)
|
||||
@EnableAutoConfiguration(exclude = { TraceWebServletAutoConfiguration.class,
|
||||
GatewayClassPathWarningAutoConfiguration.class,
|
||||
GatewayAutoConfiguration.class })
|
||||
@EnableFeignClients
|
||||
@RibbonClient(value = "fooservice", configuration = SimpleRibbonClientConfiguration.class)
|
||||
public static class TestConfiguration {
|
||||
|
||||
@@ -20,6 +20,6 @@ logging.level.org.springframework.cloud: DEBUG
|
||||
logging.level.org.springframework.cloud.sleuth.instrument.web.client.feign: TRACE
|
||||
|
||||
#disable hibernate by default
|
||||
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
|
||||
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration, org.springframework.cloud.gateway.config.GatewayAutoConfiguration, org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration
|
||||
spring.data.jdbc.repositories.enabled: false
|
||||
spring.data.jpa.repositories.enabled: false
|
||||
Reference in New Issue
Block a user