Updated for Greenwich
still reactor is broken
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -274,7 +274,7 @@
|
||||
<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>
|
||||
<brave.version>5.2.0</brave.version>
|
||||
<spring-security-boot-autoconfigure.version>2.0.0.RELEASE</spring-security-boot-autoconfigure.version>
|
||||
<spring-security-boot-autoconfigure.version>2.0.4.RELEASE</spring-security-boot-autoconfigure.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reactivestreams</groupId>
|
||||
<artifactId>reactive-streams</artifactId>
|
||||
@@ -107,6 +112,11 @@
|
||||
<version>2.2.0.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
|
||||
@@ -134,7 +134,7 @@ public class TraceAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
CurrentTraceContext currentTraceContext(CurrentTraceContext.Builder builder) {
|
||||
CurrentTraceContext sleuthCurrentTraceContext(CurrentTraceContext.Builder builder) {
|
||||
for (CurrentTraceContext.ScopeDecorator scopeDecorator : this.scopeDecorators) {
|
||||
builder.addScopeDecorator(scopeDecorator);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||
* @author Jesus Alonso
|
||||
* @since 2.1.0
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(SleuthAsyncProperties.class)
|
||||
public class AsyncAutoConfiguration {
|
||||
|
||||
@@ -17,15 +17,12 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
@@ -36,8 +33,6 @@ import brave.httpclient.TracingHttpClientBuilder;
|
||||
import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import brave.spring.web.TracingClientHttpRequestInterceptor;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
@@ -51,7 +46,6 @@ import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
@@ -76,16 +70,11 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.ipc.netty.NettyContext;
|
||||
import reactor.ipc.netty.NettyOutbound;
|
||||
import reactor.ipc.netty.NettyPipeline;
|
||||
import reactor.ipc.netty.channel.data.FileChunkedStrategy;
|
||||
import reactor.ipc.netty.http.client.HttpClient;
|
||||
import reactor.ipc.netty.http.client.HttpClientRequest;
|
||||
import reactor.ipc.netty.http.client.HttpClientResponse;
|
||||
import reactor.ipc.netty.http.websocket.WebsocketOutbound;
|
||||
import reactor.netty.NettyOutbound;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientRequest;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
@@ -309,17 +298,16 @@ class NettyAspect {
|
||||
this.instrumentation = TracingHttpClientInstrumentation.create(httpTracing);
|
||||
}
|
||||
|
||||
@Pointcut("execution(public * reactor.ipc.netty.http.client.HttpClient.request(..)) && args(method, url, handler)")
|
||||
private void anyHttpClientRequestSending(HttpMethod method,
|
||||
String url, Function<? super HttpClientRequest, ? extends Publisher<Void>> handler) { } // NOSONAR
|
||||
@Pointcut("execution(public * reactor.netty.http.client.HttpClient.RequestSender.send(..)) && args(function)")
|
||||
private void anyHttpClientRequestSending(
|
||||
BiFunction<? super HttpClientRequest,? super NettyOutbound,? extends Publisher<Void>> function) { } // NOSONAR
|
||||
|
||||
@Around("anyHttpClientRequestSending(method, url, handler)")
|
||||
@Around("anyHttpClientRequestSending(function)")
|
||||
public Object wrapHttpClientRequestSending(ProceedingJoinPoint pjp,
|
||||
HttpMethod method,
|
||||
String url, Function<? super HttpClientRequest, ? extends Publisher<Void>> handler) throws Throwable {
|
||||
BiFunction<? super HttpClientRequest,? super NettyOutbound,? extends Publisher<Void>> function) throws Throwable {
|
||||
return Mono.defer(() -> {
|
||||
try {
|
||||
return this.instrumentation.wrapHttpClientRequestSending(pjp, method, url, handler);
|
||||
return this.instrumentation.wrapHttpClientRequestSending(pjp, function);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return Mono.error(e);
|
||||
@@ -370,13 +358,12 @@ class TracingHttpClientInstrumentation {
|
||||
}
|
||||
|
||||
Mono<HttpClientResponse> wrapHttpClientRequestSending(ProceedingJoinPoint pjp,
|
||||
HttpMethod method,
|
||||
String url, Function<? super HttpClientRequest, ? extends Publisher<Void>> handler) throws Throwable {
|
||||
BiFunction<? super HttpClientRequest,? super NettyOutbound,? extends Publisher<Void>> function) throws Throwable {
|
||||
// add headers and set CS
|
||||
final Span currentSpan = this.tracer.currentSpan();
|
||||
final AtomicReference<Span> span = new AtomicReference<>();
|
||||
Function<HttpClientRequest, Publisher<Void>> combinedFunction =
|
||||
req -> {
|
||||
BiFunction<HttpClientRequest, NettyOutbound, Publisher<Void>> combinedFunction =
|
||||
(req, nettyOutbound) -> {
|
||||
try (Tracer.SpanInScope spanInScope = this.tracer.withSpanInScope(currentSpan)) {
|
||||
io.netty.handler.codec.http.HttpHeaders originalHeaders = req
|
||||
.requestHeaders().copy();
|
||||
@@ -392,13 +379,13 @@ class TracingHttpClientInstrumentation {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Created a new client span for Netty client");
|
||||
}
|
||||
return handle(handler, new TracedHttpClientRequest(req, addedHeaders));
|
||||
return handle(function, new TracedHttpClientRequest(req, addedHeaders), nettyOutbound);
|
||||
}
|
||||
}
|
||||
};
|
||||
// run
|
||||
Mono<HttpClientResponse> responseMono =
|
||||
(Mono<HttpClientResponse>) pjp.proceed(new Object[] { method , url, combinedFunction });
|
||||
(Mono<HttpClientResponse>) pjp.proceed(new Object[] { combinedFunction });
|
||||
// get response
|
||||
return responseMono.doOnSuccessOrError((httpClientResponse, throwable) -> {
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span.get())) {
|
||||
@@ -441,38 +428,6 @@ class TracingHttpClientInstrumentation {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest context(
|
||||
Consumer<NettyContext> contextCallback) {
|
||||
this.delegate = this.delegate.context(contextCallback);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest chunkedTransfer(boolean chunked) {
|
||||
this.delegate = this.delegate.chunkedTransfer(chunked);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest options(
|
||||
Consumer<? super NettyPipeline.SendOptions> configurator) {
|
||||
this.delegate = this.delegate.options(configurator);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest followRedirect() {
|
||||
this.delegate = this.delegate.followRedirect();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest failOnClientError(boolean shouldFail) {
|
||||
this.delegate = this.delegate.failOnClientError(shouldFail);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest failOnServerError(boolean shouldFail) {
|
||||
this.delegate = this.delegate.failOnServerError(shouldFail);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public boolean hasSentHeaders() {
|
||||
return this.delegate.hasSentHeaders();
|
||||
}
|
||||
@@ -498,12 +453,6 @@ class TracingHttpClientInstrumentation {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public HttpClientRequest onWriteIdle(long idleTimeout,
|
||||
Runnable onWriteIdle) {
|
||||
this.delegate = this.delegate.onWriteIdle(idleTimeout, onWriteIdle);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public String[] redirectedFrom() {
|
||||
return this.delegate.redirectedFrom();
|
||||
}
|
||||
@@ -512,99 +461,6 @@ class TracingHttpClientInstrumentation {
|
||||
return this.delegate.requestHeaders();
|
||||
}
|
||||
|
||||
@Override public Mono<Void> send() {
|
||||
return this.delegate.send();
|
||||
}
|
||||
|
||||
@Override public Flux<Long> sendForm(Consumer<Form> formCallback) {
|
||||
return this.delegate.sendForm(formCallback);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendHeaders() {
|
||||
return this.delegate.sendHeaders();
|
||||
}
|
||||
|
||||
@Override public WebsocketOutbound sendWebsocket() {
|
||||
return this.delegate.sendWebsocket();
|
||||
}
|
||||
|
||||
@Override public WebsocketOutbound sendWebsocket(String subprotocols) {
|
||||
return this.delegate.sendWebsocket(subprotocols);
|
||||
}
|
||||
|
||||
@Override public ByteBufAllocator alloc() {
|
||||
return this.delegate.alloc();
|
||||
}
|
||||
|
||||
@Override public NettyContext context() {
|
||||
return this.delegate.context();
|
||||
}
|
||||
|
||||
@Override public FileChunkedStrategy getFileChunkedStrategy() {
|
||||
return this.delegate.getFileChunkedStrategy();
|
||||
}
|
||||
|
||||
@Override public Mono<Void> neverComplete() {
|
||||
return this.delegate.neverComplete();
|
||||
}
|
||||
|
||||
@Override public NettyOutbound send(Publisher<? extends ByteBuf> dataStream) {
|
||||
return this.delegate.send(dataStream);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendByteArray(
|
||||
Publisher<? extends byte[]> dataStream) {
|
||||
return this.delegate.sendByteArray(dataStream);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendFile(Path file) {
|
||||
return this.delegate.sendFile(file);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendFile(Path file, long position, long count) {
|
||||
return this.delegate.sendFile(file, position, count);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendFileChunked(Path file, long position,
|
||||
long count) {
|
||||
return this.delegate.sendFileChunked(file, position, count);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendGroups(
|
||||
Publisher<? extends Publisher<? extends ByteBuf>> dataStreams) {
|
||||
return this.delegate.sendGroups(dataStreams);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendObject(Publisher<?> dataStream) {
|
||||
return this.delegate.sendObject(dataStream);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendObject(Object msg) {
|
||||
return this.delegate.sendObject(msg);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendString(
|
||||
Publisher<? extends String> dataStream) {
|
||||
return this.delegate.sendString(dataStream);
|
||||
}
|
||||
|
||||
@Override public NettyOutbound sendString(Publisher<? extends String> dataStream,
|
||||
Charset charset) {
|
||||
return this.delegate.sendString(dataStream, charset);
|
||||
}
|
||||
|
||||
@Override public void subscribe(Subscriber<? super Void> s) {
|
||||
this.delegate.subscribe(s);
|
||||
}
|
||||
|
||||
@Override public Mono<Void> then() {
|
||||
return this.delegate.then();
|
||||
}
|
||||
|
||||
@Override public NettyOutbound then(Publisher<Void> other) {
|
||||
return this.delegate.then(other);
|
||||
}
|
||||
|
||||
@Override public Map<CharSequence, Set<Cookie>> cookies() {
|
||||
return this.delegate.cookies();
|
||||
}
|
||||
@@ -635,12 +491,12 @@ class TracingHttpClientInstrumentation {
|
||||
}
|
||||
|
||||
private Publisher<Void> handle(
|
||||
Function<? super HttpClientRequest, ? extends Publisher<Void>> handler,
|
||||
HttpClientRequest req) {
|
||||
BiFunction<? super HttpClientRequest, ? super NettyOutbound, ? extends Publisher<Void>> handler,
|
||||
HttpClientRequest req, NettyOutbound nettyOutbound) {
|
||||
if (handler != null) {
|
||||
return handler.apply(req);
|
||||
return handler.apply(req, nettyOutbound);
|
||||
}
|
||||
return req;
|
||||
return nettyOutbound;
|
||||
}
|
||||
|
||||
static final class HttpAdapter
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2018 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Import(PermitAllServletConfiguration.class)
|
||||
@Target({ ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DisableSecurity {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2018 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Import(PermitAllWebFluxSecurityConfiguration.class)
|
||||
@Target({ ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DisableWebFluxSecurity {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2018 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;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@Order(99)
|
||||
public class PermitAllServletConfiguration extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/*").permitAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2018 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;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
||||
@Configuration
|
||||
public class PermitAllWebFluxSecurityConfiguration {
|
||||
@Bean SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
|
||||
return http.authorizeExchange()
|
||||
.anyExchange().permitAll()
|
||||
.and()
|
||||
.csrf().disable()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2013-2018 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;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration
|
||||
public class SleuthTestAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
static class ReactiveConfiguration {
|
||||
@Import(PermitAllWebFluxSecurityConfiguration.class)
|
||||
static class ImportConfiguration {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
static class ServletConfiguration {
|
||||
@Import(PermitAllServletConfiguration.class)
|
||||
static class ImportConfiguration {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -53,7 +54,7 @@ public class SpanAdjusterTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableAutoConfiguration(exclude = IntegrationAutoConfiguration.class)
|
||||
static class SpanAdjusterAspectTestsConfig {
|
||||
@Bean Sampler sampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.sleuth.DisableWebFluxSecurity;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -191,7 +192,8 @@ public class SleuthSpanCreatorAspectWebFluxTests {
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = {org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.class, ReactiveUserDetailsServiceAutoConfiguration.class})
|
||||
@EnableAutoConfiguration
|
||||
@DisableWebFluxSecurity
|
||||
protected static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -47,7 +47,8 @@ public class SleuthSpanCreatorCircularDependencyTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration @EnableAutoConfiguration
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class TestConfiguration {
|
||||
@Bean Reporter<Span> spanReporter() {
|
||||
return new ArrayListSpanReporter();
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import brave.Span;
|
||||
@@ -39,12 +38,10 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.ExecutorChannel;
|
||||
import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
@@ -128,7 +125,9 @@ public class ITTracingChannelInterceptor implements MessageHandler {
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Configuration @EnableAutoConfiguration static class App {
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
static class App {
|
||||
|
||||
@Bean List<zipkin2.Span> spans() {
|
||||
return new ArrayList<>();
|
||||
@@ -162,10 +161,5 @@ public class ITTracingChannelInterceptor implements MessageHandler {
|
||||
@Bean public MessagingTemplate messagingTemplate() {
|
||||
return new MessagingTemplate(directChannel());
|
||||
}
|
||||
|
||||
@Bean @GlobalChannelInterceptor
|
||||
public ChannelInterceptor tracingChannelInterceptor(Tracing tracing) {
|
||||
return TracingChannelInterceptor.create(tracing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.cloud.sleuth.util.SpanUtil;
|
||||
|
||||
@@ -16,25 +16,37 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.messaging;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import brave.Tracer;
|
||||
import brave.kafka.clients.KafkaTracing;
|
||||
import brave.sampler.Sampler;
|
||||
import brave.spring.rabbit.SpringRabbitTracing;
|
||||
import org.apache.kafka.clients.consumer.Consumer;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
import org.apache.kafka.clients.producer.Producer;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.BDDMockito;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.kafka.annotation.KafkaListener;
|
||||
import org.springframework.kafka.core.ConsumerFactory;
|
||||
import org.springframework.kafka.core.ProducerFactory;
|
||||
import org.springframework.kafka.listener.MessageListenerContainer;
|
||||
import org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@@ -124,18 +136,18 @@ class MySleuthKafkaAspect extends SleuthKafkaAspect {
|
||||
@Override public Object wrapProducerFactory(ProceedingJoinPoint pjp)
|
||||
throws Throwable {
|
||||
this.producerWrapped = true;
|
||||
return super.wrapProducerFactory(pjp);
|
||||
return Mockito.mock(Producer.class);
|
||||
}
|
||||
|
||||
@Override public Object wrapConsumerFactory(ProceedingJoinPoint pjp)
|
||||
throws Throwable {
|
||||
this.consumerWrapped = true;
|
||||
return super.wrapConsumerFactory(pjp);
|
||||
return Mockito.mock(Consumer.class);
|
||||
}
|
||||
|
||||
@Override public Object wrapListenerContainerCreation(ProceedingJoinPoint pjp)
|
||||
throws Throwable {
|
||||
this.adapterWrapped = true;
|
||||
return super.wrapListenerContainerCreation(pjp);
|
||||
return Mockito.mock(MessageListenerContainer.class);
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,9 @@ public class TraceWebSocketAutoConfigurationTests {
|
||||
.hasAtLeastOneElementOfType(TracingChannelInterceptor.class);
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration @Configuration @EnableWebSocketMessageBroker
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
public static class Config extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.multiple;
|
||||
package org.springframework.cloud.sleuth.instrument.multiple;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -43,8 +43,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@IntegrationComponentScan
|
||||
public class DemoApplication {
|
||||
|
||||
private static final Log log = LogFactory.getLog(
|
||||
DemoApplication.class);
|
||||
private static final Log log = LogFactory.getLog(DemoApplication.class);
|
||||
|
||||
Span httpSpan;
|
||||
Span splitterSpan;
|
||||
@@ -98,6 +97,7 @@ public class DemoApplication {
|
||||
public List<Span> allSpans() {
|
||||
return Arrays.asList(this.httpSpan, this.splitterSpan, this.aggregatorSpan, this.serviceActivatorSpan);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MessagingGateway(name = "greeter")
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.multiple;
|
||||
package org.springframework.cloud.sleuth.instrument.multiple;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
@@ -184,5 +184,6 @@ public class MultipleHopsIntegrationTests {
|
||||
@Bean Sampler defaultTraceSampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,16 +31,14 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.rule.OutputCapture;
|
||||
import org.springframework.cloud.sleuth.DisableWebFluxSecurity;
|
||||
import org.springframework.cloud.sleuth.instrument.reactor.Issue866Configuration;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -49,7 +47,6 @@ import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import zipkin2.Span;
|
||||
|
||||
@@ -149,9 +146,8 @@ public class FlatMapTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(
|
||||
exclude = { ReactiveUserDetailsServiceAutoConfiguration.class,
|
||||
ReactiveSecurityAutoConfiguration.class })
|
||||
@EnableAutoConfiguration
|
||||
@DisableWebFluxSecurity
|
||||
static class TestConfiguration {
|
||||
|
||||
brave.Span spanInFoo;
|
||||
@@ -159,11 +155,11 @@ public class FlatMapTests {
|
||||
@Bean RouterFunction<ServerResponse> handlers(Tracer tracer, RequestSender requestSender) {
|
||||
return route(GET("/noFlatMap"), request -> {
|
||||
LOGGER.info("noFlatMap");
|
||||
Flux<Integer> one = requestSender.getAll().map(string -> string.length());
|
||||
Flux<Integer> one = requestSender.getAll().map(String::length);
|
||||
return ServerResponse.ok().body(one, Integer.class);
|
||||
}).andRoute(GET("/withFlatMap"), request -> {
|
||||
LOGGER.info("withFlatMap");
|
||||
Flux<Integer> one = requestSender.getAll().map(string -> string.length());
|
||||
Flux<Integer> one = requestSender.getAll().map(String::length);
|
||||
Flux<Integer> response = one.flatMap(size -> requestSender.getAll()
|
||||
.doOnEach(sig -> LOGGER.info(sig.getContext().toString())))
|
||||
.map(string -> {
|
||||
|
||||
@@ -507,7 +507,7 @@ public class TraceFilterTests {
|
||||
then(this.reporter.getSpans())
|
||||
.hasSize(1);
|
||||
then(this.reporter.getSpans().get(0).tags())
|
||||
.containsEntry("http.status_code", status.toString());
|
||||
.containsEntry("http.status_code", "500");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.cloud.sleuth.instrument.web;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
@@ -39,7 +40,7 @@ public class TraceNoWebEnvironmentTests {
|
||||
@Test
|
||||
public void should_work_when_using_web_client_without_the_web_environment() {
|
||||
SpringApplication springApplication = new SpringApplication(Config.class);
|
||||
springApplication.setWebEnvironment(false);
|
||||
springApplication.setWebApplicationType(WebApplicationType.NONE);
|
||||
|
||||
try (ConfigurableApplicationContext context = springApplication.run()) {
|
||||
Config.SomeFeignClient client = context.getBean(Config.SomeFeignClient.class);
|
||||
@@ -52,11 +53,10 @@ public class TraceNoWebEnvironmentTests {
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableFeignClients
|
||||
@EnableFeignClients(clients = Config.SomeFeignClient.class)
|
||||
@EnableCircuitBreaker
|
||||
public static class Config {
|
||||
|
||||
|
||||
@FeignClient(name = "google", url = "https://www.google.com/")
|
||||
public interface SomeFeignClient {
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.sampler.Sampler;
|
||||
@@ -27,9 +25,8 @@ import org.junit.Test;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.sleuth.DisableWebFluxSecurity;
|
||||
import org.springframework.cloud.sleuth.instrument.web.client.TraceWebClientAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -41,7 +38,10 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.server.*;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -162,10 +162,8 @@ public class TraceWebFluxTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(
|
||||
exclude = { TraceWebClientAutoConfiguration.class,
|
||||
ReactiveUserDetailsServiceAutoConfiguration.class,
|
||||
ReactiveSecurityAutoConfiguration.class })
|
||||
@EnableAutoConfiguration(exclude = { TraceWebClientAutoConfiguration.class })
|
||||
@DisableWebFluxSecurity
|
||||
static class Config {
|
||||
|
||||
@Bean WebClient webClient() {
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client.exceptionresolver;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.Instant;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracing;
|
||||
import brave.sampler.Sampler;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
@@ -44,8 +45,6 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
|
||||
@@ -53,8 +53,7 @@ public class Issue307Tests {
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Import({
|
||||
ParticipantsBean.class, ParticipantsClient.class})
|
||||
@Import({ ParticipantsBean.class})
|
||||
@RestController
|
||||
@EnableFeignClients
|
||||
@EnableCircuitBreaker
|
||||
|
||||
@@ -77,8 +77,7 @@ public class Issue350Tests {
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = TraceWebServletAutoConfiguration.class)
|
||||
@EnableFeignClients(basePackageClasses = {
|
||||
SleuthTestController.class})
|
||||
@EnableFeignClients(basePackageClasses = { SleuthTestController.class})
|
||||
class Application {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -115,8 +115,7 @@ public class Issue362Tests {
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = TraceWebServletAutoConfiguration.class)
|
||||
@EnableFeignClients(basePackageClasses = {
|
||||
SleuthTestController.class})
|
||||
@EnableFeignClients(basePackageClasses = { SleuthTestController.class})
|
||||
class Application {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -88,8 +88,8 @@ 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.ipc.netty.http.client.HttpClient;
|
||||
import reactor.ipc.netty.http.client.HttpClientResponse;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
import zipkin2.Annotation;
|
||||
import zipkin2.reporter.Reporter;
|
||||
|
||||
@@ -246,7 +246,10 @@ public class WebClientTests {
|
||||
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
|
||||
HttpClientResponse response = this.nettyHttpClient
|
||||
.get("http://localhost:" + port).block();
|
||||
.get()
|
||||
.uri("http://localhost:" + port)
|
||||
.response()
|
||||
.block();
|
||||
|
||||
then(response).isNotNull();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Auto Configuration
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.sleuth.SleuthTestAutoConfiguration
|
||||
@@ -18,6 +18,5 @@ spring.sleuth.rxjava.schedulers.ignoredthreads: HystixMetricPoller,^MyCustomThre
|
||||
|
||||
logging.level.org.springframework.cloud: DEBUG
|
||||
|
||||
|
||||
#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
|
||||
@@ -39,11 +39,6 @@
|
||||
<artifactId>spring-cloud-sleuth-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-reactor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin-legacy</artifactId>
|
||||
@@ -64,11 +59,6 @@
|
||||
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zipkin-legacy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zipkin</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user