├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── RELEASE.md ├── .gitignore ├── opentracing-spring-web-starter ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── spring.factories │ │ └── java │ │ │ └── io │ │ │ └── opentracing │ │ │ └── contrib │ │ │ └── spring │ │ │ └── web │ │ │ └── starter │ │ │ ├── WebClientTracingProperties.java │ │ │ ├── client │ │ │ └── TracingRestTemplateCustomizer.java │ │ │ ├── WebTracingProperties.java │ │ │ ├── WebClientTracingAutoConfiguration.java │ │ │ └── WebFluxTracingAutoConfiguration.java │ └── test │ │ ├── resources │ │ └── application-test.yml │ │ └── java │ │ └── io │ │ └── opentracing │ │ └── contrib │ │ └── spring │ │ └── web │ │ └── starter │ │ ├── AutoConfigurationBaseTest.java │ │ ├── ServerTracingAutoConfigurationDisabledForReactiveTest.java │ │ ├── WebFluxTracingAutoConfigurationDisabledTest.java │ │ ├── ServerTracingAutoConfigurationDisabledTest.java │ │ ├── SkipPatternTest.java │ │ ├── WebClientTracingAutoConfigurationTest.java │ │ ├── AsyncRestTemplatePostProcessingConfigurationTest.java │ │ ├── RestTemplatePostProcessingConfigurationTest.java │ │ ├── WebFluxTracingAutoConfigurationDefaultsTest.java │ │ ├── SkipEndPointsWithoutContextPathAndWithoutBasePathTest.java │ │ ├── SkipEndPointsWithContextPathWithoutBasePathTest.java │ │ ├── ServerTracingAutoConfigurationDefaultsTest.java │ │ ├── DisabledRestTemplateTracingAutoConfigurationTest.java │ │ ├── SkipEndPointsWithoutContextPathAndBasePathTest.java │ │ └── SkipEndPointsWithContextPathAndBasePathTest.java └── pom.xml ├── header.txt ├── opentracing-spring-web-itest ├── boot │ ├── src │ │ ├── main │ │ │ └── webapp │ │ │ │ └── WEB-INF │ │ │ │ └── jsp │ │ │ │ └── staticView.jsp │ │ └── test │ │ │ ├── resources │ │ │ └── application.properties │ │ │ └── java │ │ │ └── io │ │ │ └── opentracing │ │ │ └── contrib │ │ │ └── spring │ │ │ └── web │ │ │ └── interceptor │ │ │ └── itest │ │ │ └── boot │ │ │ ├── BootITest.java │ │ │ └── SpringBootConfiguration.java │ └── pom.xml ├── mvc │ ├── src │ │ └── test │ │ │ ├── webapp │ │ │ └── WEB-INF │ │ │ │ ├── jsp │ │ │ │ └── staticView.jsp │ │ │ │ └── web.xml │ │ │ └── java │ │ │ └── io │ │ │ └── opentracing │ │ │ └── contrib │ │ │ └── spring │ │ │ └── web │ │ │ └── interceptor │ │ │ └── itest │ │ │ └── mvc │ │ │ └── SpringMVCConfiguration.java │ └── pom.xml ├── pom.xml ├── common │ ├── src │ │ └── test │ │ │ └── java │ │ │ └── io │ │ │ └── opentracing │ │ │ └── contrib │ │ │ └── spring │ │ │ └── web │ │ │ └── interceptor │ │ │ └── itest │ │ │ └── common │ │ │ └── app │ │ │ ├── TracingBeansConfiguration.java │ │ │ ├── TestInterceptor.java │ │ │ ├── WebSecurityConfig.java │ │ │ ├── ExceptionFilter.java │ │ │ └── SpanCheckerFilter.java │ └── pom.xml └── webflux │ ├── pom.xml │ └── src │ └── test │ └── java │ └── io │ └── opentracing │ └── contrib │ └── spring │ └── webflux │ └── webfilter │ └── itest │ └── webflux │ └── WebFluxJettyMinimalIntegrationTest.java ├── opentracing-spring-web ├── src │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── opentracing │ │ │ └── contrib │ │ │ └── spring │ │ │ └── web │ │ │ ├── webfilter │ │ │ ├── package-info.java │ │ │ ├── SkipPattern.java │ │ │ ├── HttpHeadersExtractAdapter.java │ │ │ ├── TracingOperator.java │ │ │ ├── TracingSubscriber.java │ │ │ └── TracingWebFilter.java │ │ │ └── client │ │ │ ├── HttpHeadersCarrier.java │ │ │ ├── TracingExchangeFilterFunction.java │ │ │ ├── TracingWebClientBeanPostProcessor.java │ │ │ ├── TracingClientResponseMono.java │ │ │ ├── WebClientSpanDecorator.java │ │ │ ├── RestTemplateSpanDecorator.java │ │ │ ├── TracingClientResponseSubscriber.java │ │ │ ├── TracingRestTemplateInterceptor.java │ │ │ └── TracingAsyncRestTemplateInterceptor.java │ └── test │ │ ├── resources │ │ └── test-context.xml │ │ └── java │ │ └── io │ │ └── opentracing │ │ └── contrib │ │ └── spring │ │ └── web │ │ ├── interceptor │ │ ├── TracingHandlerInterceptorXmlConfigIntegrationTest.java │ │ ├── TracingHandlerInterceptorJavaConfigIntegrationTest.java │ │ └── TracingHandlerInterceptorTest.java │ │ └── client │ │ ├── TracingRestTemplateTest.java │ │ ├── TracingWebClientTest.java │ │ └── TracingAsyncRestTemplateTest.java └── pom.xml ├── .settings.xml ├── .travis.yml ├── travis └── publish.sh └── mvnw.cmd /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opentracing-contrib/java-spring-web/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # OpenTracing Release Process 2 | 3 | This repo uses semantic versions. Please keep this in mind when choosing version numbers. 4 | 5 | For the up-to-date release process, please refer the 6 | [release process from the OpenTracing Java API](https://github.com/opentracing/opentracing-java/blob/master/RELEASE.md). 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.war 8 | *.ear 9 | 10 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 11 | hs_err_pid* 12 | 13 | target 14 | 15 | # IntelliJ project files 16 | .idea/ 17 | *.iml 18 | 19 | # Eclipse 20 | .project 21 | .classpath 22 | .settings 23 | 24 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | io.opentracing.contrib.spring.web.starter.ServerTracingAutoConfiguration,\ 3 | io.opentracing.contrib.spring.web.starter.SkipPatternAutoConfiguration,\ 4 | io.opentracing.contrib.spring.web.starter.RestTemplateTracingAutoConfiguration,\ 5 | io.opentracing.contrib.spring.web.starter.WebClientTracingAutoConfiguration,\ 6 | io.opentracing.contrib.spring.web.starter.WebFluxTracingAutoConfiguration 7 | -------------------------------------------------------------------------------- /header.txt: -------------------------------------------------------------------------------- 1 | Copyright ${license.git.copyrightYears} The OpenTracing Authors 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 4 | in compliance with the License. You may obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software distributed under the License 9 | is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 10 | or implied. See the License for the specific language governing permissions and limitations under 11 | the License. 12 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/boot/src/main/webapp/WEB-INF/jsp/staticView.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | Copyright 2016-2019 The OpenTracing Authors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software distributed under the License 11 | is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | or implied. See the License for the specific language governing permissions and limitations under 13 | the License. 14 | 15 | --%> 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/mvc/src/test/webapp/WEB-INF/jsp/staticView.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | Copyright 2016-2019 The OpenTracing Authors 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 6 | in compliance with the License. You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software distributed under the License 11 | is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | or implied. See the License for the specific language governing permissions and limitations under 13 | the License. 14 | 15 | --%> 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/boot/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-2019 The OpenTracing Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License 10 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | # or implied. See the License for the specific language governing permissions and limitations under 12 | # the License. 13 | # 14 | 15 | spring.mvc.view.prefix: WEB-INF/jsp/ 16 | spring.mvc.view.suffix: .jsp 17 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-2019 The OpenTracing Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License 10 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | # or implied. See the License for the specific language governing permissions and limitations under 12 | # the License. 13 | # 14 | 15 | opentracing: 16 | spring: 17 | web: 18 | urlPatterns: 19 | - /hello 20 | - /excluded 21 | order: 99 22 | skipPattern: "/excluded" 23 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | @NonNullApi 15 | @NonNullFields 16 | 17 | package io.opentracing.contrib.spring.web.webfilter; 18 | 19 | import org.springframework.lang.NonNullApi; 20 | import org.springframework.lang.NonNullFields; 21 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/SkipPattern.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.webfilter; 15 | 16 | import java.util.Optional; 17 | import java.util.regex.Pattern; 18 | 19 | /** 20 | * @author Gilles Robert 21 | */ 22 | public interface SkipPattern { 23 | 24 | Optional pattern(); 25 | } 26 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/resources/test-context.xml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/interceptor/TracingHandlerInterceptorXmlConfigIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor; 15 | 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.test.context.ContextConfiguration; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | 22 | import static org.junit.Assert.assertNotNull; 23 | 24 | 25 | @RunWith(SpringRunner.class) 26 | @ContextConfiguration("classpath:/test-context.xml") 27 | public class TracingHandlerInterceptorXmlConfigIntegrationTest { 28 | @Autowired 29 | TracingHandlerInterceptor interceptor; 30 | 31 | @Test 32 | public void testAutowired() { 33 | assertNotNull(interceptor); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/HttpHeadersCarrier.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import io.opentracing.propagation.TextMap; 17 | import org.springframework.http.HttpHeaders; 18 | 19 | import java.util.Iterator; 20 | import java.util.Map; 21 | 22 | /** 23 | * @author Pavol Loffay 24 | */ 25 | public class HttpHeadersCarrier implements TextMap { 26 | 27 | private HttpHeaders httpHeaders; 28 | 29 | public HttpHeadersCarrier(HttpHeaders httpHeaders) { 30 | this.httpHeaders = httpHeaders; 31 | } 32 | 33 | @Override 34 | public void put(String key, String value) { 35 | httpHeaders.add(key, value); 36 | } 37 | 38 | @Override 39 | public Iterator> iterator() { 40 | throw new UnsupportedOperationException("Should be used only with tracer#inject()"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 21 | 22 | 23 | sonatype 24 | ${env.SONATYPE_USER} 25 | ${env.SONATYPE_PASSWORD} 26 | 27 | 28 | bintray 29 | ${env.BINTRAY_USER} 30 | ${env.BINTRAY_KEY} 31 | 32 | 33 | jfrog-snapshots 34 | ${env.BINTRAY_USER} 35 | ${env.BINTRAY_KEY} 36 | 37 | 38 | github.com 39 | ${env.GH_USER} 40 | ${env.GH_TOKEN} 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/client/TracingRestTemplateTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import org.springframework.http.ResponseEntity; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import java.util.Collections; 20 | 21 | /** 22 | * @author Pavol Loffay 23 | */ 24 | public class TracingRestTemplateTest extends AbstractTracingClientTest { 25 | 26 | public TracingRestTemplateTest() { 27 | super(tracer -> { 28 | final RestTemplate restTemplate = new RestTemplate(); 29 | restTemplate.setInterceptors(Collections.singletonList( 30 | new TracingRestTemplateInterceptor(tracer))); 31 | 32 | return new Client() { 33 | @Override 34 | public ResponseEntity getForEntity(String url, Class clazz) { 35 | return restTemplate.getForEntity(url, clazz); 36 | } 37 | }; 38 | }, RestTemplateSpanDecorator.StandardTags.COMPONENT_NAME); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/AutoConfigurationBaseTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.lang.reflect.Field; 17 | import org.junit.BeforeClass; 18 | import io.opentracing.Tracer; 19 | import io.opentracing.noop.NoopTracerFactory; 20 | import io.opentracing.util.GlobalTracer; 21 | 22 | public class AutoConfigurationBaseTest { 23 | 24 | // Temporary solution until https://github.com/opentracing/opentracing-java/issues/170 resolved 25 | private static void _setGlobal(Tracer tracer) { 26 | try { 27 | Field globalTracerField = GlobalTracer.class.getDeclaredField("tracer"); 28 | globalTracerField.setAccessible(true); 29 | globalTracerField.set(null, tracer); 30 | globalTracerField.setAccessible(false); 31 | } catch (Exception e) { 32 | throw new RuntimeException("Error reflecting globalTracer: " + e.getMessage(), e); 33 | } 34 | } 35 | 36 | @BeforeClass 37 | public static void clearGlobalTracer() { 38 | _setGlobal(NoopTracerFactory.create()); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web-itest-parent 26 | pom 27 | 28 | 29 | ${project.basedir}/.. 30 | 31 | 32 | 33 | common 34 | boot 35 | mvc 36 | webflux 37 | 38 | 39 | 40 | 41 | 42 | maven-deploy-plugin 43 | ${version.maven-deploy-plugin} 44 | 45 | true 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/common/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/common/app/TracingBeansConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.common.app; 15 | 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | import org.mockito.Mockito; 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | 23 | import io.opentracing.contrib.spring.web.interceptor.HandlerInterceptorSpanDecorator; 24 | import io.opentracing.mock.MockTracer; 25 | import io.opentracing.util.ThreadLocalScopeManager; 26 | 27 | /** 28 | * @author Pavol Loffay 29 | */ 30 | @Configuration 31 | public class TracingBeansConfiguration { 32 | 33 | public static final MockTracer mockTracer = Mockito.spy(new MockTracer(new ThreadLocalScopeManager(), 34 | MockTracer.Propagator.TEXT_MAP)); 35 | 36 | @Bean 37 | public MockTracer mockTracerBean() { 38 | return mockTracer; 39 | } 40 | 41 | @Bean 42 | public List spanDecorators() { 43 | return Arrays.asList(HandlerInterceptorSpanDecorator.STANDARD_LOGS, 44 | HandlerInterceptorSpanDecorator.HANDLER_METHOD_OPERATION_NAME); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/common/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/common/app/TestInterceptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.common.app; 15 | 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpServletResponse; 18 | 19 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 20 | 21 | /** 22 | * @author Pavol Loffay 23 | */ 24 | public class TestInterceptor extends HandlerInterceptorAdapter { 25 | 26 | public static final String EXCEPTION_MESSAGE = "interceptorException"; 27 | 28 | @Override 29 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 30 | throws Exception { 31 | if(request.getRequestURL().toString().contains("/sync")) { 32 | // stop request 33 | return false; 34 | } 35 | return true; 36 | } 37 | 38 | @Override 39 | public void afterCompletion( 40 | HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 41 | throws Exception { 42 | 43 | if(request.getRequestURL().toString().contains("/sync")) { 44 | throw new Exception(EXCEPTION_MESSAGE); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/main/java/io/opentracing/contrib/spring/web/starter/WebClientTracingProperties.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import org.springframework.boot.context.properties.ConfigurationProperties; 17 | 18 | /** 19 | * Configuration for tracing of HTTP clients. 20 | * Supports RestTemplate, AsyncRestTemplate, and WebClient beans. 21 | * 22 | * @author Michal Dvorak 23 | * @see RestTemplateTracingAutoConfiguration, 24 | * @see WebClientTracingAutoConfiguration 25 | * @since 4/5/18 26 | */ 27 | @ConfigurationProperties(WebClientTracingProperties.CONFIGURATION_PREFIX) 28 | public class WebClientTracingProperties { 29 | 30 | public static final String CONFIGURATION_PREFIX = WebTracingProperties.CONFIGURATION_PREFIX + ".client"; 31 | 32 | /** 33 | * When set to true (default), it enables automatic tracing of RestTemplate, AsyncRestTemplate, and WebClient beans, 34 | * as well as instances created using default RestTemplateBuilder and WebClient.Builder beans. 35 | * Does not affect instances created manually. 36 | */ 37 | private boolean enabled = true; 38 | 39 | public boolean isEnabled() { 40 | return enabled; 41 | } 42 | 43 | public void setEnabled(boolean enabled) { 44 | this.enabled = enabled; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/boot/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/boot/BootITest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.boot; 15 | 16 | import org.junit.runner.RunWith; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.boot.test.context.SpringBootTest; 19 | import org.springframework.boot.test.web.client.TestRestTemplate; 20 | import org.springframework.boot.web.server.LocalServerPort; 21 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 22 | 23 | import io.opentracing.contrib.spring.web.interceptor.itest.common.AbstractBaseITests; 24 | 25 | /** 26 | * @author Pavol Loffay 27 | */ 28 | @SpringBootTest( 29 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 30 | classes = {SpringBootConfiguration.class}) 31 | @RunWith(SpringJUnit4ClassRunner.class) 32 | public class BootITest extends AbstractBaseITests { 33 | 34 | @Autowired 35 | private TestRestTemplate testRestTemplate; 36 | 37 | @LocalServerPort 38 | private int serverPort; 39 | 40 | @Override 41 | protected String getUrl(String path) { 42 | return "http://localhost:" + serverPort + path; 43 | } 44 | 45 | @Override 46 | protected TestRestTemplate getRestTemplate() { 47 | return testRestTemplate; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/TracingExchangeFilterFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2019 the original author or authors. Copyright 2019 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.client; 17 | 18 | import io.opentracing.Tracer; 19 | import org.springframework.web.reactive.function.client.ClientRequest; 20 | import org.springframework.web.reactive.function.client.ClientResponse; 21 | import org.springframework.web.reactive.function.client.ExchangeFilterFunction; 22 | import org.springframework.web.reactive.function.client.ExchangeFunction; 23 | import reactor.core.publisher.Mono; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * Similar to {@code TraceExchangeFilterFunction} from spring-cloud-sleuth-core. 29 | * 30 | * @author Csaba Kos 31 | */ 32 | public class TracingExchangeFilterFunction implements ExchangeFilterFunction { 33 | private final Tracer tracer; 34 | private final List spanDecorators; 35 | 36 | public TracingExchangeFilterFunction(final Tracer tracer, final List spanDecorators) { 37 | this.tracer = tracer; 38 | this.spanDecorators = spanDecorators; 39 | } 40 | 41 | @Override 42 | public Mono filter(final ClientRequest clientRequest, final ExchangeFunction next) { 43 | return new TracingClientResponseMono(clientRequest, next, tracer, spanDecorators); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/common/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/common/app/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.common.app; 15 | 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.context.annotation.Configuration; 18 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 19 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 20 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 21 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 22 | 23 | /** 24 | * @author Pavol Loffay 25 | */ 26 | @Configuration 27 | @EnableWebSecurity 28 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 29 | 30 | @Override 31 | protected void configure(HttpSecurity http) throws Exception { 32 | http.authorizeRequests() 33 | .antMatchers("/secured").authenticated() 34 | .anyRequest().permitAll() 35 | .and().httpBasic(); 36 | } 37 | 38 | @Autowired 39 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 40 | auth.inMemoryAuthentication() 41 | .withUser("user").password("{noop}password").roles("USER"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/common/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/common/app/ExceptionFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.common.app; 15 | 16 | import java.io.IOException; 17 | 18 | import javax.servlet.Filter; 19 | import javax.servlet.FilterChain; 20 | import javax.servlet.FilterConfig; 21 | import javax.servlet.ServletException; 22 | import javax.servlet.ServletRequest; 23 | import javax.servlet.ServletResponse; 24 | import javax.servlet.http.HttpServletRequest; 25 | 26 | /** 27 | * @author Pavol Loffay 28 | */ 29 | public class ExceptionFilter implements Filter { 30 | 31 | public static final String EXCEPTION_URL = "/filterException"; 32 | public static final String EXCEPTION_MESSAGE = "filterMessage"; 33 | 34 | @Override 35 | public void init(FilterConfig filterConfig) throws ServletException {} 36 | 37 | @Override 38 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 39 | throws IOException, ServletException { 40 | 41 | HttpServletRequest httpServletRequest = (HttpServletRequest) request; 42 | 43 | if (httpServletRequest.getRequestURL().toString().contains(EXCEPTION_URL)) { 44 | throw new RuntimeException(EXCEPTION_MESSAGE); 45 | } 46 | 47 | chain.doFilter(request, response); 48 | } 49 | 50 | @Override 51 | public void destroy() {} 52 | } 53 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/interceptor/TracingHandlerInterceptorJavaConfigIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor; 15 | 16 | import io.opentracing.Tracer; 17 | import io.opentracing.mock.MockTracer; 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.test.context.ContextConfiguration; 24 | import org.springframework.test.context.junit4.SpringRunner; 25 | 26 | import static org.junit.Assert.assertNotNull; 27 | 28 | @RunWith(SpringRunner.class) 29 | @ContextConfiguration(classes = TracingHandlerInterceptorJavaConfigIntegrationTest.TestConfiguration.class) 30 | public class TracingHandlerInterceptorJavaConfigIntegrationTest { 31 | 32 | @Autowired 33 | private TracingHandlerInterceptor interceptor; 34 | 35 | @Test 36 | public void testAutowired() { 37 | assertNotNull(interceptor); 38 | } 39 | 40 | 41 | @Configuration 42 | static class TestConfiguration { 43 | 44 | @Bean 45 | TracingHandlerInterceptor tracingHandlerInterceptor(final Tracer tracer) { 46 | return new TracingHandlerInterceptor(tracer); 47 | } 48 | 49 | @Bean 50 | Tracer tracer() { 51 | return new MockTracer(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/mvc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-itest-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web-itest-mvc 26 | 27 | 28 | ${project.basedir}/../.. 29 | 30 | 31 | 32 | 33 | ${project.groupId} 34 | opentracing-spring-web-itest-common 35 | ${project.version} 36 | test-jar 37 | test 38 | 39 | 40 | 41 | org.eclipse.jetty 42 | jetty-server 43 | test 44 | 45 | 46 | org.eclipse.jetty 47 | jetty-servlet 48 | test 49 | 50 | 51 | org.eclipse.jetty 52 | jetty-webapp 53 | test 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/common/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/common/app/SpanCheckerFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.common.app; 15 | 16 | import io.opentracing.Span; 17 | import io.opentracing.util.GlobalTracer; 18 | import org.springframework.web.filter.GenericFilterBean; 19 | 20 | import javax.servlet.FilterChain; 21 | import javax.servlet.ServletException; 22 | import javax.servlet.ServletRequest; 23 | import javax.servlet.ServletResponse; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | import java.io.IOException; 27 | 28 | /** 29 | * This ensure that when the {@link io.opentracing.contrib.web.servlet.filter.TracingFilter} has opened a span, 30 | * this span is still (and the same) when we return from the doFilter(). 31 | * 32 | * @author Alexander Schwartz 33 | */ 34 | public class SpanCheckerFilter extends GenericFilterBean { 35 | 36 | @Override 37 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { 38 | HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; 39 | HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; 40 | Span span = GlobalTracer.get().activeSpan(); 41 | chain.doFilter(httpRequest, httpResponse); 42 | if (span != GlobalTracer.get().activeSpan()) { 43 | throw new RuntimeException("we should see the same span before and after"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/boot/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-itest-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web-itest-boot 26 | 27 | 28 | ${project.basedir}/../.. 29 | 30 | 31 | 32 | 33 | ${project.groupId} 34 | opentracing-spring-web-itest-common 35 | ${project.version} 36 | test 37 | test-jar 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-test 42 | test 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-web 47 | test 48 | 49 | 50 | 51 | 52 | org.apache.tomcat.embed 53 | tomcat-embed-jasper 54 | test 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/webflux/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-itest-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web-itest-webflux 26 | 27 | 28 | ${project.basedir}/../.. 29 | 30 | 31 | 32 | 33 | ${project.groupId} 34 | opentracing-spring-web-itest-common 35 | ${project.version} 36 | test-jar 37 | test 38 | 39 | 40 | 41 | org.springframework 42 | spring-webflux 43 | test 44 | 45 | 46 | org.eclipse.jetty 47 | jetty-server 48 | test 49 | 50 | 51 | org.eclipse.jetty 52 | jetty-servlet 53 | test 54 | 55 | 56 | org.eclipse.jetty 57 | jetty-webapp 58 | test 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/HttpHeadersExtractAdapter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.webfilter; 15 | 16 | import io.opentracing.propagation.TextMap; 17 | import org.springframework.http.HttpHeaders; 18 | 19 | import java.util.AbstractMap; 20 | import java.util.Iterator; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.stream.Stream; 24 | 25 | /** 26 | * Tracer extract adapter for {@link HttpHeaders}. 27 | * 28 | * @author Csaba Kos 29 | */ 30 | class HttpHeadersExtractAdapter implements TextMap { 31 | private static final Stream STREAM_OF_NULL = Stream.of(new String[]{ null }); 32 | 33 | private final HttpHeaders httpHeaders; 34 | 35 | HttpHeadersExtractAdapter(final HttpHeaders httpHeaders) { 36 | this.httpHeaders = httpHeaders; 37 | } 38 | 39 | @Override 40 | public Iterator> iterator() { 41 | return httpHeaders.entrySet() 42 | .stream() 43 | .flatMap(entry -> getValuesStream(entry.getValue()) 44 | .map(value -> newEntry(entry.getKey(), value))) 45 | .iterator(); 46 | } 47 | 48 | private static Stream getValuesStream(final List values) { 49 | return values.isEmpty() ? STREAM_OF_NULL : values.stream(); 50 | } 51 | 52 | private static Map.Entry newEntry(final String key, final String value) { 53 | return new AbstractMap.SimpleImmutableEntry<>(key, value); 54 | } 55 | 56 | @Override 57 | public void put(String key, String value) { 58 | throw new UnsupportedOperationException("This class should be used only with Tracer.inject()!"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/interceptor/TracingHandlerInterceptorTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor; 15 | 16 | import static org.junit.Assert.assertFalse; 17 | import static org.junit.Assert.assertTrue; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | 21 | import org.junit.Test; 22 | import org.mockito.Mockito; 23 | 24 | import io.opentracing.SpanContext; 25 | import io.opentracing.contrib.web.servlet.filter.TracingFilter; 26 | 27 | public class TracingHandlerInterceptorTest { 28 | 29 | @Test 30 | public void testIsTraced() { 31 | HttpServletRequest request = Mockito.mock(HttpServletRequest.class); 32 | Mockito.when(request.getAttribute(TracingFilter.SERVER_SPAN_CONTEXT)).thenReturn(Mockito.mock(SpanContext.class)); 33 | assertTrue(TracingHandlerInterceptor.isTraced(request)); 34 | } 35 | 36 | @Test 37 | public void testIsNotTraced() { 38 | HttpServletRequest request = Mockito.mock(HttpServletRequest.class); 39 | Mockito.when(request.getAttribute(TracingFilter.SERVER_SPAN_CONTEXT)).thenReturn(null); 40 | assertFalse(TracingHandlerInterceptor.isTraced(request)); 41 | } 42 | 43 | @Test 44 | public void testNoSpan() throws Exception { 45 | HttpServletRequest request = Mockito.mock(HttpServletRequest.class); 46 | Mockito.when(request.getAttribute(TracingFilter.SERVER_SPAN_CONTEXT)).thenReturn(null); 47 | 48 | TracingHandlerInterceptor interceptor = new TracingHandlerInterceptor(null); 49 | assertTrue(interceptor.preHandle(request, null, null)); 50 | interceptor.afterConcurrentHandlingStarted(request, null, null); 51 | interceptor.afterCompletion(request, null, null, null); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/ServerTracingAutoConfigurationDisabledForReactiveTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.beans.factory.annotation.Qualifier; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 23 | import org.springframework.context.annotation.Configuration; 24 | import org.springframework.test.context.ActiveProfiles; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 27 | 28 | import static org.junit.Assert.assertNull; 29 | 30 | /** 31 | * @author Gilles Robert 32 | */ 33 | @SpringBootTest( 34 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 35 | classes = {ServerTracingAutoConfigurationDisabledForReactiveTest.SpringConfiguration.class}, 36 | properties = {"spring.main.web-application-type=reactive"}) 37 | @RunWith(SpringJUnit4ClassRunner.class) 38 | @ActiveProfiles("test") 39 | public class ServerTracingAutoConfigurationDisabledForReactiveTest extends AutoConfigurationBaseTest { 40 | 41 | @Autowired(required = false) 42 | @Qualifier("tracingFilter") 43 | private FilterRegistrationBean tracingFilter; 44 | @Autowired(required = false) 45 | @Qualifier("tracingHandlerInterceptor") 46 | private WebMvcConfigurerAdapter tracingHandlerInterceptor; 47 | 48 | @Configuration 49 | @EnableAutoConfiguration 50 | public static class SpringConfiguration { 51 | 52 | } 53 | 54 | @Test 55 | public void testWebConfigurationDisabled() { 56 | assertNull(tracingFilter); 57 | assertNull(tracingHandlerInterceptor); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/WebFluxTracingAutoConfigurationDisabledTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.contrib.spring.web.webfilter.TracingWebFilter; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.context.annotation.Bean; 23 | import org.springframework.context.annotation.Configuration; 24 | import org.springframework.test.context.ActiveProfiles; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.client.AsyncRestTemplate; 27 | import org.springframework.web.client.RestTemplate; 28 | 29 | import static org.junit.Assert.assertNull; 30 | 31 | /** 32 | * @author Csaba Kos 33 | */ 34 | @SpringBootTest( 35 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 36 | classes = {WebFluxTracingAutoConfigurationDisabledTest.SpringConfiguration.class}, 37 | properties = {"opentracing.spring.web.enabled=false", "spring.main.web-application-type=reactive"}) 38 | @RunWith(SpringJUnit4ClassRunner.class) 39 | @ActiveProfiles("test") 40 | public class WebFluxTracingAutoConfigurationDisabledTest extends AutoConfigurationBaseTest { 41 | 42 | @Autowired(required = false) 43 | private TracingWebFilter tracingWebFilter; 44 | 45 | @Configuration 46 | @EnableAutoConfiguration 47 | public static class SpringConfiguration { 48 | 49 | @Bean 50 | public RestTemplate restTemplate() { 51 | return new RestTemplate(); 52 | } 53 | 54 | @Bean 55 | public AsyncRestTemplate asyncRestTemplate() { 56 | return new AsyncRestTemplate(); 57 | } 58 | } 59 | 60 | @Test 61 | public void testWebConfigurationDisabled() { 62 | assertNull(tracingWebFilter); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/main/java/io/opentracing/contrib/spring/web/starter/client/TracingRestTemplateCustomizer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter.client; 15 | 16 | import io.opentracing.Tracer; 17 | import io.opentracing.contrib.spring.web.client.RestTemplateSpanDecorator; 18 | import io.opentracing.contrib.spring.web.client.TracingRestTemplateInterceptor; 19 | import org.springframework.boot.web.client.RestTemplateBuilder; 20 | import org.springframework.boot.web.client.RestTemplateCustomizer; 21 | import org.springframework.http.client.ClientHttpRequestInterceptor; 22 | import org.springframework.web.client.RestTemplate; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.Objects; 27 | 28 | /** 29 | * Customizer used by {@link RestTemplateBuilder}. 30 | *

31 | * When registered as bean, default {@link RestTemplateBuilder} bean provided by Spring Boot 32 | * will pick it up. 33 | * 34 | * @author Michal Dvorak 35 | * @see RestTemplate 36 | * @see RestTemplateBuilder 37 | */ 38 | public class TracingRestTemplateCustomizer implements RestTemplateCustomizer { 39 | 40 | private final Tracer tracer; 41 | private final List spanDecorators; 42 | 43 | public TracingRestTemplateCustomizer(Tracer tracer, List spanDecorators) { 44 | this.tracer = Objects.requireNonNull(tracer); 45 | this.spanDecorators = Objects.requireNonNull(spanDecorators); 46 | } 47 | 48 | @Override 49 | public void customize(RestTemplate restTemplate) { 50 | List interceptors = restTemplate.getInterceptors(); 51 | 52 | for (ClientHttpRequestInterceptor interceptor : interceptors) { 53 | if (interceptor instanceof TracingRestTemplateInterceptor) { 54 | return; 55 | } 56 | } 57 | 58 | interceptors = new ArrayList<>(interceptors); 59 | interceptors.add(new TracingRestTemplateInterceptor(tracer, spanDecorators)); 60 | restTemplate.setInterceptors(interceptors); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/main/java/io/opentracing/contrib/spring/web/starter/WebTracingProperties.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | import org.springframework.boot.context.properties.ConfigurationProperties; 20 | 21 | /** 22 | * @author Pavol Loffay 23 | * @author Gilles Robert 24 | */ 25 | @ConfigurationProperties(WebTracingProperties.CONFIGURATION_PREFIX) 26 | public class WebTracingProperties { 27 | 28 | public static final String CONFIGURATION_PREFIX = "opentracing.spring.web"; 29 | 30 | static final String DEFAULT_SKIP_PATTERN = "/api-docs.*|/swagger.*|.*\\.png|.*\\.css|.*\\.js|.*\\.html|/favicon.ico|/hystrix.stream"; 31 | 32 | private boolean enabled = true; 33 | private String skipPattern = DEFAULT_SKIP_PATTERN; 34 | private int order = Integer.MIN_VALUE; 35 | 36 | /** 37 | * List of URL patterns that should be traced. 38 | * 39 | * For servlet web stack, the URL pattern syntax is defined in the Servlet spec, under "Specification of Mappings". 40 | * For reactive (WebFlux), see the documentation of {@link org.springframework.web.util.pattern.PathPattern} for 41 | * the syntax. 42 | * 43 | * By default, the list is empty, which means that all requests will be traced (unless {@link #skipPattern} says 44 | * otherwise.) 45 | */ 46 | private List urlPatterns = Collections.emptyList(); 47 | 48 | public boolean isEnabled() { 49 | return enabled; 50 | } 51 | 52 | public void setEnabled(boolean enabled) { 53 | this.enabled = enabled; 54 | } 55 | 56 | public String getSkipPattern() { 57 | return skipPattern; 58 | } 59 | 60 | public void setSkipPattern(String skipPattern) { 61 | this.skipPattern = skipPattern; 62 | } 63 | 64 | public List getUrlPatterns() { 65 | return urlPatterns; 66 | } 67 | 68 | public void setUrlPatterns(List urlPatterns) { 69 | this.urlPatterns = urlPatterns; 70 | } 71 | 72 | public int getOrder() { 73 | return order; 74 | } 75 | 76 | public void setOrder(int order) { 77 | this.order = order; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/TracingWebClientBeanPostProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2019 the original author or authors. Copyright 2019 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.client; 17 | 18 | import io.opentracing.Tracer; 19 | import org.springframework.beans.BeansException; 20 | import org.springframework.beans.factory.config.BeanPostProcessor; 21 | import org.springframework.web.reactive.function.client.ExchangeFilterFunction; 22 | import org.springframework.web.reactive.function.client.WebClient; 23 | 24 | import java.util.List; 25 | import java.util.function.Consumer; 26 | 27 | /** 28 | * {@link BeanPostProcessor} for instrumenting {@link WebClient} with tracing. 29 | * 30 | * Similar to {@code TraceWebClientBeanPostProcessor} from spring-cloud-sleuth-core. 31 | * 32 | * @author Csaba Kos 33 | */ 34 | public class TracingWebClientBeanPostProcessor implements BeanPostProcessor { 35 | private final Tracer tracer; 36 | private final List spanDecorators; 37 | 38 | public TracingWebClientBeanPostProcessor(final Tracer tracer, final List spanDecorators) { 39 | this.tracer = tracer; 40 | this.spanDecorators = spanDecorators; 41 | } 42 | 43 | @Override 44 | public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { 45 | return bean; 46 | } 47 | 48 | @Override 49 | public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException { 50 | if (bean instanceof WebClient) { 51 | final WebClient webClient = (WebClient) bean; 52 | return webClient.mutate() 53 | .filters(addTraceExchangeFilterFunctionIfNotPresent()).build(); 54 | } else if (bean instanceof WebClient.Builder) { 55 | final WebClient.Builder webClientBuilder = (WebClient.Builder) bean; 56 | return webClientBuilder.filters(addTraceExchangeFilterFunctionIfNotPresent()); 57 | } 58 | return bean; 59 | } 60 | 61 | private Consumer> addTraceExchangeFilterFunctionIfNotPresent() { 62 | return functions -> { 63 | if (functions.stream() 64 | .noneMatch(function -> function instanceof TracingExchangeFilterFunction)) { 65 | functions.add(new TracingExchangeFilterFunction(tracer, spanDecorators)); 66 | } 67 | }; 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/ServerTracingAutoConfigurationDisabledTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.beans.factory.annotation.Qualifier; 18 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 19 | import org.springframework.boot.test.context.SpringBootTest; 20 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.test.context.ActiveProfiles; 24 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 25 | import org.springframework.web.client.AsyncRestTemplate; 26 | import org.springframework.web.client.RestTemplate; 27 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 28 | 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | 32 | import static org.junit.Assert.assertNull; 33 | 34 | /** 35 | * @author Gilles Robert 36 | */ 37 | @SpringBootTest( 38 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 39 | classes = {ServerTracingAutoConfigurationDisabledTest.SpringConfiguration.class}, 40 | properties = {"opentracing.spring.web.enabled=false"}) 41 | @RunWith(SpringJUnit4ClassRunner.class) 42 | @ActiveProfiles("test") 43 | public class ServerTracingAutoConfigurationDisabledTest extends AutoConfigurationBaseTest { 44 | 45 | @Autowired(required = false) 46 | @Qualifier("tracingFilter") 47 | private FilterRegistrationBean tracingFilter; 48 | @Autowired(required = false) 49 | @Qualifier("tracingHandlerInterceptor") 50 | private WebMvcConfigurerAdapter tracingHandlerInterceptor; 51 | 52 | @Configuration 53 | @EnableAutoConfiguration 54 | public static class SpringConfiguration { 55 | 56 | @Bean 57 | public RestTemplate restTemplate() { 58 | return new RestTemplate(); 59 | } 60 | 61 | @Bean 62 | public AsyncRestTemplate asyncRestTemplate() { 63 | return new AsyncRestTemplate(); 64 | } 65 | } 66 | 67 | @Test 68 | public void testWebConfigurationDisabled() { 69 | assertNull(tracingFilter); 70 | assertNull(tracingHandlerInterceptor); 71 | } 72 | } -------------------------------------------------------------------------------- /opentracing-spring-web-itest/common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-itest-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web-itest-common 26 | 27 | 28 | ${project.basedir}/../.. 29 | 30 | 31 | 32 | 33 | ${project.groupId} 34 | opentracing-spring-web 35 | 36 | 37 | org.springframework 38 | spring-webmvc 39 | 40 | 41 | javax.servlet 42 | javax.servlet-api 43 | 44 | 45 | 46 | 47 | io.opentracing 48 | opentracing-mock 49 | 50 | 51 | org.awaitility 52 | awaitility 53 | ${version.org.awaitility-awaitility} 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-test 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-security 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-web 68 | 69 | 70 | 71 | 72 | 73 | 74 | maven-jar-plugin 75 | ${version.maven-jar-plugin} 76 | 77 | 78 | 79 | test-jar 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /opentracing-spring-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web 26 | 27 | 28 | ${project.basedir}/.. 29 | 30 | 31 | 32 | 33 | io.opentracing.contrib 34 | opentracing-web-servlet-filter 35 | 36 | 37 | 38 | org.springframework 39 | spring-webmvc 40 | provided 41 | 42 | 43 | org.springframework 44 | spring-webflux 45 | true 46 | 47 | 48 | javax.servlet 49 | javax.servlet-api 50 | provided 51 | 52 | 53 | 54 | io.opentracing 55 | opentracing-mock 56 | test 57 | 58 | 59 | org.springframework 60 | spring-test 61 | ${version.org.springframework} 62 | test 63 | 64 | 65 | com.github.tomakehurst 66 | wiremock-jre8 67 | ${version.com.github.tomakehurst-wiremock-jre8} 68 | test 69 | 70 | 71 | io.projectreactor.netty 72 | reactor-netty 73 | ${version.io.projectreactor.netty-reactor-netty} 74 | test 75 | 76 | 77 | org.awaitility 78 | awaitility 79 | test 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/main/java/io/opentracing/contrib/spring/web/starter/WebClientTracingAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.Tracer; 17 | import io.opentracing.contrib.spring.tracer.configuration.TracerAutoConfiguration; 18 | import io.opentracing.contrib.spring.web.client.TracingWebClientBeanPostProcessor; 19 | import io.opentracing.contrib.spring.web.client.WebClientSpanDecorator; 20 | import org.springframework.beans.factory.ObjectProvider; 21 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 26 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | import org.springframework.web.reactive.function.client.WebClient; 30 | 31 | import java.util.List; 32 | 33 | /** 34 | * Instrumentation of {@link WebClient}. It also instruments {@link WebClient.Builder} and all instances created with it. 35 | * 36 | * @author Csaba Kos 37 | */ 38 | @Configuration 39 | @ConditionalOnBean(Tracer.class) 40 | @ConditionalOnClass(WebClient.class) 41 | @ConditionalOnProperty(prefix = WebClientTracingProperties.CONFIGURATION_PREFIX, name = "enabled", matchIfMissing = true) 42 | @AutoConfigureAfter(TracerAutoConfiguration.class) 43 | @EnableConfigurationProperties(WebClientTracingProperties.class) 44 | public class WebClientTracingAutoConfiguration { 45 | @ConditionalOnMissingBean(WebClientSpanDecorator.class) 46 | @Configuration 47 | static class DefaultWebClientSpanDecorators { 48 | @Bean 49 | WebClientSpanDecorator standardTagsWebClientSpanDecorator() { 50 | return new WebClientSpanDecorator.StandardTags(); 51 | } 52 | } 53 | 54 | @Bean 55 | public static TracingWebClientBeanPostProcessor tracingWebClientBeanPostProcessor( 56 | final Tracer tracer, 57 | final ObjectProvider> webClientSpanDecorators 58 | ) { 59 | return new TracingWebClientBeanPostProcessor( 60 | tracer, 61 | webClientSpanDecorators.getObject() 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/TracingOperator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2019 the original author or authors. Copyright 2019 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.webfilter; 17 | 18 | import io.opentracing.Scope; 19 | import io.opentracing.Span; 20 | import io.opentracing.SpanContext; 21 | import io.opentracing.Tracer; 22 | import io.opentracing.propagation.Format; 23 | import io.opentracing.tag.Tags; 24 | import org.springframework.http.server.reactive.ServerHttpRequest; 25 | import org.springframework.web.server.ServerWebExchange; 26 | import reactor.core.CoreSubscriber; 27 | import reactor.core.publisher.Mono; 28 | import reactor.core.publisher.MonoOperator; 29 | import reactor.util.context.Context; 30 | 31 | import java.util.List; 32 | 33 | /** 34 | * Similar to {@code MonoWebFilterTrace} from spring-cloud-sleuth-core. 35 | * 36 | * @author Csaba Kos 37 | */ 38 | class TracingOperator extends MonoOperator { 39 | private final Tracer tracer; 40 | private final ServerWebExchange exchange; 41 | private final List spanDecorators; 42 | 43 | TracingOperator( 44 | final Mono source, 45 | final ServerWebExchange exchange, 46 | final Tracer tracer, 47 | final List spanDecorators 48 | ) { 49 | super(source); 50 | this.tracer = tracer; 51 | this.exchange = exchange; 52 | this.spanDecorators = spanDecorators; 53 | } 54 | 55 | @Override 56 | public void subscribe(final CoreSubscriber subscriber) { 57 | final Context context = subscriber.currentContext(); 58 | final Span parentSpan = context.getOrEmpty(Span.class).orElseGet(tracer::activeSpan); 59 | final ServerHttpRequest request = exchange.getRequest(); 60 | 61 | final SpanContext extractedContext; 62 | if (parentSpan != null) { 63 | extractedContext = parentSpan.context(); 64 | } else { 65 | extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS, new HttpHeadersExtractAdapter(request.getHeaders())); 66 | } 67 | 68 | final Span span = tracer.buildSpan(request.getMethodValue()) 69 | .asChildOf(extractedContext) 70 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) 71 | .start(); 72 | 73 | try (final Scope scope = tracer.scopeManager().activate(span)) { 74 | exchange.getAttributes().put(TracingWebFilter.SERVER_SPAN_CONTEXT, span.context()); 75 | source.subscribe(new TracingSubscriber(subscriber, exchange, context, span, spanDecorators)); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/TracingClientResponseMono.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2019 the original author or authors. Copyright 2019 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.client; 17 | 18 | import io.opentracing.Scope; 19 | import io.opentracing.Span; 20 | import io.opentracing.Tracer; 21 | import io.opentracing.propagation.Format; 22 | import io.opentracing.tag.Tags; 23 | import org.springframework.web.reactive.function.client.ClientRequest; 24 | import org.springframework.web.reactive.function.client.ClientResponse; 25 | import org.springframework.web.reactive.function.client.ExchangeFunction; 26 | import reactor.core.CoreSubscriber; 27 | import reactor.core.publisher.Mono; 28 | import reactor.util.context.Context; 29 | 30 | import java.util.List; 31 | 32 | /** 33 | * Similar to {@code MonoWebClientTrace} from spring-cloud-sleuth-core. 34 | * 35 | * @author Csaba Kos 36 | */ 37 | class TracingClientResponseMono extends Mono { 38 | private final ClientRequest request; 39 | private final ExchangeFunction next; 40 | private final Tracer tracer; 41 | private final List spanDecorators; 42 | 43 | TracingClientResponseMono( 44 | final ClientRequest clientRequest, 45 | final ExchangeFunction next, 46 | final Tracer tracer, 47 | final List spanDecorators 48 | ) { 49 | this.request = clientRequest; 50 | this.next = next; 51 | this.tracer = tracer; 52 | this.spanDecorators = spanDecorators; 53 | } 54 | 55 | @Override 56 | public void subscribe(final CoreSubscriber subscriber) { 57 | final Context context = subscriber.currentContext(); 58 | final Span parentSpan = context.getOrEmpty(Span.class).orElseGet(tracer::activeSpan); 59 | 60 | final Span span = tracer.buildSpan(request.method().toString()) 61 | .asChildOf(parentSpan) 62 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) 63 | .start(); 64 | 65 | try (final Scope scope = tracer.scopeManager().activate(span)) { 66 | final ClientRequest.Builder requestBuilder = ClientRequest.from(request); 67 | requestBuilder.headers(httpHeaders -> 68 | tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersCarrier(httpHeaders))); 69 | final ClientRequest mutatedRequest = requestBuilder.build(); 70 | 71 | next.exchange(mutatedRequest).subscribe( 72 | new TracingClientResponseSubscriber(subscriber, mutatedRequest, context, span, spanDecorators) 73 | ); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/SkipPatternTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.mock.MockSpan; 17 | import io.opentracing.mock.MockTracer; 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 22 | import org.springframework.boot.test.context.SpringBootTest; 23 | import org.springframework.boot.test.web.client.TestRestTemplate; 24 | import org.springframework.context.annotation.Bean; 25 | import org.springframework.context.annotation.Configuration; 26 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 27 | import org.springframework.web.bind.annotation.RequestMapping; 28 | import org.springframework.web.bind.annotation.RestController; 29 | 30 | import java.util.List; 31 | import java.util.concurrent.Callable; 32 | 33 | import static org.awaitility.Awaitility.await; 34 | import static org.junit.Assert.assertEquals; 35 | 36 | /** 37 | * @author Pavol Loffay 38 | * @author Gilles Robert 39 | */ 40 | @SpringBootTest( 41 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 42 | classes = {SkipPatternTest.SpringConfiguration.class, SkipPatternTest.Controller.class}, 43 | properties = { 44 | "opentracing.spring.web.skipPattern=/skip", 45 | "opentracing.spring.web.client.enabled=false" 46 | }) 47 | @RunWith(SpringJUnit4ClassRunner.class) 48 | public class SkipPatternTest { 49 | 50 | @Configuration 51 | @EnableAutoConfiguration 52 | public static class SpringConfiguration { 53 | @Bean 54 | public MockTracer tracer() { 55 | return new MockTracer(); 56 | } 57 | } 58 | 59 | @RestController 60 | public static class Controller { 61 | @RequestMapping("/skip") 62 | public String skip() { 63 | return "skip"; 64 | } 65 | @RequestMapping("/hello") 66 | public String hello() { 67 | return "hello"; 68 | } 69 | } 70 | 71 | @Autowired 72 | private TestRestTemplate testRestTemplate; 73 | @Autowired 74 | private MockTracer mockTracer; 75 | 76 | @Test 77 | public void testSkipPattern() { 78 | testRestTemplate.getForEntity("/skip", String.class); 79 | List mockSpans = mockTracer.finishedSpans(); 80 | assertEquals(0, mockSpans.size()); 81 | testRestTemplate.getForEntity("/hello", String.class); 82 | await().until(() -> mockTracer.finishedSpans().size() == 1); 83 | mockSpans = mockTracer.finishedSpans(); 84 | assertEquals(1, mockSpans.size()); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/WebClientTracingAutoConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.mock.MockTracer; 17 | import io.opentracing.util.ThreadLocalScopeManager; 18 | import org.junit.Assert; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 24 | import org.springframework.boot.test.context.SpringBootTest; 25 | import org.springframework.context.annotation.Bean; 26 | import org.springframework.context.annotation.Configuration; 27 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 28 | import org.springframework.web.reactive.function.client.WebClient; 29 | 30 | import java.net.URI; 31 | 32 | /** 33 | * @author Csaba Kos 34 | */ 35 | @SpringBootTest( 36 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 37 | classes = {WebClientTracingAutoConfigurationTest.SpringConfiguration.class}) 38 | @RunWith(SpringJUnit4ClassRunner.class) 39 | public class WebClientTracingAutoConfigurationTest extends AutoConfigurationBaseTest { 40 | 41 | @Configuration 42 | @EnableAutoConfiguration 43 | public static class SpringConfiguration { 44 | @Bean 45 | public MockTracer tracer() { 46 | return new MockTracer(new ThreadLocalScopeManager()); 47 | } 48 | 49 | @Bean 50 | public WebClient webClient() { 51 | return WebClient.create(); 52 | } 53 | 54 | @Bean 55 | public WebClient.Builder webClientBuilder() { 56 | return WebClient.builder(); 57 | } 58 | } 59 | 60 | @Autowired 61 | private MockTracer mockTracer; 62 | 63 | @Autowired 64 | private WebClient webClient; 65 | 66 | @Autowired 67 | private WebClient.Builder webClientBuilder; 68 | 69 | @Before 70 | public void setUp() { 71 | mockTracer.reset(); 72 | } 73 | 74 | @Test 75 | public void testWebClientAutoConfiguration() { 76 | webClient.get() 77 | .uri(URI.create("http://example.com")) 78 | .retrieve() 79 | .bodyToMono(String.class) 80 | .block(); 81 | 82 | Assert.assertEquals(1, mockTracer.finishedSpans().size()); 83 | } 84 | 85 | @Test 86 | public void testWebClientBuilderAutoConfiguration() { 87 | webClientBuilder 88 | .build() 89 | .get() 90 | .uri(URI.create("http://example.com")) 91 | .retrieve() 92 | .bodyToMono(String.class) 93 | .block(); 94 | 95 | Assert.assertEquals(1, mockTracer.finishedSpans().size()); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/main/java/io/opentracing/contrib/spring/web/starter/WebFluxTracingAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.List; 17 | import java.util.regex.Pattern; 18 | 19 | import org.springframework.beans.factory.ObjectProvider; 20 | import org.springframework.beans.factory.annotation.Qualifier; 21 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 26 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | 30 | import io.opentracing.Tracer; 31 | import io.opentracing.contrib.spring.tracer.configuration.TracerAutoConfiguration; 32 | import io.opentracing.contrib.spring.web.webfilter.TracingWebFilter; 33 | import io.opentracing.contrib.spring.web.webfilter.WebFluxSpanDecorator; 34 | 35 | /** 36 | * Instrumentation of WebFlux. 37 | * 38 | * @author Csaba Kos 39 | * @author Gilles Robert 40 | */ 41 | @Configuration 42 | @ConditionalOnBean(Tracer.class) 43 | @AutoConfigureAfter({TracerAutoConfiguration.class, SkipPatternAutoConfiguration.class}) 44 | @EnableConfigurationProperties(WebTracingProperties.class) 45 | @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) 46 | @ConditionalOnProperty(name = WebTracingProperties.CONFIGURATION_PREFIX + ".enabled", havingValue = "true", matchIfMissing = true) 47 | public class WebFluxTracingAutoConfiguration { 48 | 49 | @ConditionalOnMissingBean(WebFluxSpanDecorator.class) 50 | @Configuration 51 | static class DefaultWebFluxSpanDecorators { 52 | @Bean 53 | WebFluxSpanDecorator standardTagsWebFluxSpanDecorator() { 54 | return new WebFluxSpanDecorator.StandardTags(); 55 | } 56 | 57 | @Bean 58 | WebFluxSpanDecorator webFluxTagsWebFluxSpanDecorator() { 59 | return new WebFluxSpanDecorator.WebFluxTags(); 60 | } 61 | } 62 | 63 | @Bean 64 | @ConditionalOnMissingBean(TracingWebFilter.class) 65 | public TracingWebFilter traceFilter( 66 | final Tracer tracer, 67 | final WebTracingProperties webTracingProperties, 68 | final ObjectProvider> webFilterSpanDecorators, 69 | final @Qualifier("skipPattern") Pattern skipPattern 70 | ) { 71 | return new TracingWebFilter( 72 | tracer, 73 | webTracingProperties.getOrder(), 74 | skipPattern, 75 | webTracingProperties.getUrlPatterns(), 76 | webFilterSpanDecorators.getObject() 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/mvc/src/test/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 21 | OpenTracing Spring Interceptor tests 22 | 23 | 24 | 25 | dispatcher 26 | org.springframework.web.servlet.DispatcherServlet 27 | 28 | contextClass 29 | org.springframework.web.context.support.AnnotationConfigWebApplicationContext 30 | 31 | 32 | contextConfigLocation 33 | io.opentracing.contrib.spring.web.interceptor.itest.mvc.SpringMVCConfiguration 34 | 35 | 1 36 | true 37 | 38 | 39 | dispatcher 40 | /* 41 | 42 | 43 | 44 | 45 | io.opentracing.contrib.spring.web.interceptor.itest.mvc.SpringMVCConfiguration 46 | 47 | 48 | 49 | 50 | tracingFilter 51 | io.opentracing.contrib.web.servlet.filter.TracingFilter 52 | true 53 | 54 | 55 | tracingFilter 56 | /* 57 | 58 | 59 | 60 | 61 | exceptionFilter 62 | io.opentracing.contrib.spring.web.interceptor.itest.common.app.ExceptionFilter 63 | true 64 | 65 | 66 | exceptionFilter 67 | /* 68 | 69 | 70 | 71 | 72 | spanCheckerFilter 73 | io.opentracing.contrib.spring.web.interceptor.itest.common.app.SpanCheckerFilter 74 | true 75 | 76 | 77 | spanCheckerFilter 78 | /* 79 | 80 | 81 | 82 | 83 | springSecurityFilterChain 84 | org.springframework.web.filter.DelegatingFilterProxy 85 | true 86 | 87 | 88 | springSecurityFilterChain 89 | /* 90 | 91 | 92 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/TracingSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2020 the original author or authors. Copyright 2020 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.webfilter; 17 | 18 | import io.opentracing.Span; 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.reactivestreams.Subscription; 22 | import org.springframework.web.server.ServerWebExchange; 23 | import reactor.core.CoreSubscriber; 24 | import reactor.util.context.Context; 25 | 26 | import java.util.List; 27 | 28 | /** 29 | * Similar to {@code WebFilterTraceSubscriber} from spring-could-sleuth-core. 30 | * 31 | * @author Csaba Kos 32 | */ 33 | class TracingSubscriber implements CoreSubscriber { 34 | private static final Log LOG = LogFactory.getLog(TracingSubscriber.class); 35 | 36 | private final CoreSubscriber subscriber; 37 | private final ServerWebExchange exchange; 38 | private final Context context; 39 | private final Span span; 40 | private final List spanDecorators; 41 | 42 | TracingSubscriber( 43 | final CoreSubscriber subscriber, 44 | final ServerWebExchange exchange, 45 | final Context context, 46 | final Span span, 47 | final List spanDecorators 48 | ) { 49 | this.subscriber = subscriber; 50 | this.exchange = exchange; 51 | this.context = context.put(Span.class, span); 52 | this.span = span; 53 | this.spanDecorators = spanDecorators; 54 | } 55 | 56 | @Override 57 | public void onSubscribe(final Subscription subscription) { 58 | subscriber.onSubscribe(new Subscription() { 59 | @Override 60 | public void request(long n) { 61 | spanDecorators.forEach(spanDecorator -> safelyCall(() -> spanDecorator.onRequest(exchange, span))); 62 | subscription.request(n); 63 | } 64 | 65 | @Override 66 | public void cancel() { 67 | span.finish(); 68 | exchange.getAttributes().remove(TracingWebFilter.SERVER_SPAN_CONTEXT); 69 | subscription.cancel(); 70 | } 71 | }); 72 | } 73 | 74 | @Override 75 | public void onNext(final Void aVoid) { 76 | // Never called 77 | subscriber.onNext(aVoid); 78 | } 79 | 80 | @Override 81 | public void onError(final Throwable throwable) { 82 | spanDecorators.forEach(spanDecorator -> safelyCall(() -> spanDecorator.onError(exchange, throwable, span))); 83 | span.finish(); 84 | exchange.getAttributes().remove(TracingWebFilter.SERVER_SPAN_CONTEXT); 85 | subscriber.onError(throwable); 86 | } 87 | 88 | @Override 89 | public void onComplete() { 90 | spanDecorators.forEach(spanDecorator -> safelyCall(() -> spanDecorator.onResponse(exchange, span))); 91 | span.finish(); 92 | exchange.getAttributes().remove(TracingWebFilter.SERVER_SPAN_CONTEXT); 93 | subscriber.onComplete(); 94 | } 95 | 96 | @Override 97 | public Context currentContext() { 98 | return context; 99 | } 100 | 101 | private void safelyCall(final Runnable runnable) { 102 | try { 103 | runnable.run(); 104 | } catch (final RuntimeException e) { 105 | LOG.error("Exception during decorating span", e); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/AsyncRestTemplatePostProcessingConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.mock.MockTracer; 17 | import io.opentracing.util.ThreadLocalScopeManager; 18 | import org.awaitility.Awaitility; 19 | import org.hamcrest.core.IsEqual; 20 | import org.junit.Assert; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.beans.factory.annotation.Qualifier; 26 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 27 | import org.springframework.boot.test.context.SpringBootTest; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.context.annotation.Configuration; 30 | import org.springframework.http.ResponseEntity; 31 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 32 | import org.springframework.util.concurrent.ListenableFuture; 33 | import org.springframework.util.concurrent.ListenableFutureCallback; 34 | import org.springframework.web.client.AsyncRestTemplate; 35 | 36 | import java.util.concurrent.TimeUnit; 37 | import java.util.concurrent.atomic.AtomicBoolean; 38 | 39 | /** 40 | * @author Pavol Loffay 41 | */ 42 | @SpringBootTest( 43 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 44 | classes = {AsyncRestTemplatePostProcessingConfigurationTest.SpringConfiguration.class}) 45 | @RunWith(SpringJUnit4ClassRunner.class) 46 | public class AsyncRestTemplatePostProcessingConfigurationTest extends AutoConfigurationBaseTest { 47 | 48 | @Configuration 49 | @EnableAutoConfiguration 50 | public static class SpringConfiguration { 51 | @Bean 52 | public MockTracer tracer() { 53 | return new MockTracer(new ThreadLocalScopeManager()); 54 | } 55 | 56 | @Bean 57 | @Qualifier("foo") 58 | public AsyncRestTemplate restTemplateFoo() { 59 | return new AsyncRestTemplate(); 60 | } 61 | 62 | @Bean 63 | @Qualifier("bar") 64 | public AsyncRestTemplate restTemplateBar() { 65 | return new AsyncRestTemplate(); 66 | } 67 | } 68 | 69 | @Autowired 70 | private MockTracer mockTracer; 71 | 72 | @Autowired 73 | @Qualifier("bar") 74 | private AsyncRestTemplate asyncRestTemplate; 75 | 76 | @Before 77 | public void setUp() { 78 | mockTracer.reset(); 79 | } 80 | 81 | @Test 82 | public void testTracingAsyncRequest() { 83 | ListenableFuture> future = asyncRestTemplate.getForEntity("http://example.com", String.class); 84 | 85 | AtomicBoolean done = addDoneCallback(future); 86 | Awaitility.await().atMost(3000, TimeUnit.MILLISECONDS).untilAtomic(done, IsEqual.equalTo(true)); 87 | 88 | Assert.assertEquals(1, mockTracer.finishedSpans().size()); 89 | } 90 | 91 | public static AtomicBoolean addDoneCallback(ListenableFuture> future) { 92 | final AtomicBoolean done = new AtomicBoolean(); 93 | 94 | future.addCallback(new ListenableFutureCallback>() { 95 | @Override 96 | public void onSuccess(ResponseEntity result) { 97 | done.set(true); 98 | } 99 | 100 | @Override 101 | public void onFailure(Throwable ex) { 102 | done.set(true); 103 | } 104 | }); 105 | 106 | return done; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | io.opentracing.contrib 21 | opentracing-spring-web-parent 22 | 4.1.1-SNAPSHOT 23 | 24 | 25 | opentracing-spring-web-starter 26 | 27 | 28 | ${project.basedir}/.. 29 | 30 | 31 | 32 | 33 | ${project.groupId} 34 | opentracing-spring-web 35 | 36 | 37 | javax.servlet 38 | javax.servlet-api 39 | provided 40 | 41 | 42 | org.springframework 43 | spring-webmvc 44 | provided 45 | 46 | 47 | org.springframework 48 | spring-webflux 49 | true 50 | 51 | 52 | 53 | io.opentracing.contrib 54 | opentracing-tracerresolver 55 | ${version.io.opentracing.contrib-opentracing-tracerresolver} 56 | 57 | 58 | io.opentracing.contrib 59 | opentracing-spring-tracer-configuration-starter 60 | ${version.io.opentracing.contrib-opentracing-spring-tracer-configuration-starter} 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-autoconfigure 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-configuration-processor 71 | true 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-starter-actuator 77 | true 78 | 79 | 80 | 81 | io.opentracing 82 | opentracing-mock 83 | test 84 | 85 | 86 | org.awaitility 87 | awaitility 88 | ${version.org.awaitility-awaitility} 89 | test 90 | 91 | 92 | org.springframework.boot 93 | spring-boot-starter-test 94 | test 95 | 96 | 97 | org.springframework.boot 98 | spring-boot-starter-web 99 | test 100 | 101 | 102 | org.springframework.boot 103 | spring-boot-starter-webflux 104 | test 105 | 106 | 107 | io.projectreactor.netty 108 | reactor-netty 109 | ${version.io.projectreactor.netty-reactor-netty} 110 | test 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/WebClientSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import io.opentracing.Span; 17 | import io.opentracing.tag.Tags; 18 | import org.springframework.web.reactive.function.client.ClientRequest; 19 | import org.springframework.web.reactive.function.client.ClientResponse; 20 | 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * Decorate span by adding tags/logs or operation name change. 26 | * 27 | *

Do not finish span (otherwise some tags/logs might be missing)! 28 | * 29 | * @author Csaba Kos 30 | */ 31 | public interface WebClientSpanDecorator { 32 | 33 | /** 34 | * Decorate span before before request is executed, e.g. before {@code .onSubscribe()} is called. 35 | * 36 | * @param clientRequest request 37 | * @param span client span 38 | */ 39 | void onRequest(ClientRequest clientRequest, Span span); 40 | 41 | /** 42 | * Decorate span after the clientRequest is done, e.g. after {@code .onNext()} is called. 43 | * 44 | * @param clientRequest clientRequest 45 | * @param clientResponse clientResponse 46 | * @param span span 47 | */ 48 | void onResponse(ClientRequest clientRequest, ClientResponse clientResponse, Span span); 49 | 50 | /** 51 | * Decorate span when exception is thrown during clientRequest processing, e.g. when {@code .onError()} is called. 52 | * 53 | * @param clientRequest clientRequest 54 | * @param throwable exception 55 | * @param span span 56 | */ 57 | void onError(ClientRequest clientRequest, Throwable throwable, Span span); 58 | 59 | /** 60 | * Decorate span when the subscription is cancelled. 61 | * 62 | * @param clientRequest clientRequest 63 | * @param span span 64 | */ 65 | void onCancel(ClientRequest clientRequest, Span span); 66 | 67 | /** 68 | * This decorator adds set of standard tags to the span. 69 | */ 70 | class StandardTags implements WebClientSpanDecorator { 71 | static final String COMPONENT_NAME = "java-spring-webclient"; 72 | 73 | @Override 74 | public void onRequest(final ClientRequest clientRequest, final Span span) { 75 | Tags.COMPONENT.set(span, COMPONENT_NAME); 76 | Tags.HTTP_URL.set(span, clientRequest.url().toString()); 77 | Tags.HTTP_METHOD.set(span, clientRequest.method().toString()); 78 | 79 | if (clientRequest.url().getPort() != -1) { 80 | Tags.PEER_PORT.set(span, clientRequest.url().getPort()); 81 | } 82 | } 83 | 84 | @Override 85 | public void onResponse(final ClientRequest clientRequest, final ClientResponse clientResponse, final Span span) { 86 | Tags.HTTP_STATUS.set(span, clientResponse.rawStatusCode()); 87 | } 88 | 89 | @Override 90 | public void onError(final ClientRequest clientRequest, final Throwable throwable, final Span span) { 91 | Tags.ERROR.set(span, Boolean.TRUE); 92 | span.log(errorLogs(throwable)); 93 | } 94 | 95 | @Override 96 | public void onCancel(final ClientRequest httpRequest, final Span span) { 97 | final Map logs = new HashMap<>(2); 98 | logs.put("event", "cancelled"); 99 | logs.put("message", "The subscription was cancelled"); 100 | span.log(logs); 101 | } 102 | 103 | static Map errorLogs(final Throwable throwable) { 104 | final Map errorLogs = new HashMap<>(2); 105 | errorLogs.put("event", Tags.ERROR.getKey()); 106 | errorLogs.put("error.object", throwable); 107 | return errorLogs; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/RestTemplateSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import java.io.IOException; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import org.apache.commons.logging.Log; 21 | import org.apache.commons.logging.LogFactory; 22 | import org.springframework.http.HttpRequest; 23 | import org.springframework.http.client.ClientHttpRequestExecution; 24 | import org.springframework.http.client.ClientHttpResponse; 25 | 26 | import io.opentracing.Span; 27 | import io.opentracing.tag.Tags; 28 | 29 | /** 30 | * Decorate span by adding tags/logs or operation name change. 31 | * 32 | *

Do not finish span or throw any exceptions! 33 | * 34 | * @author Pavol Loffay 35 | */ 36 | public interface RestTemplateSpanDecorator { 37 | 38 | /** 39 | * Decorate span before before request is executed, e.g. before 40 | * {@link org.springframework.http.client.ClientHttpRequestInterceptor#intercept(HttpRequest, byte[], ClientHttpRequestExecution)} 41 | * is called. 42 | * 43 | * @param request request 44 | * @param span client span 45 | */ 46 | void onRequest(HttpRequest request, Span span); 47 | 48 | /** 49 | * Decorate span after request is done, e.g. after 50 | * {@link org.springframework.http.client.ClientHttpRequestInterceptor#intercept(HttpRequest, byte[], ClientHttpRequestExecution)} 51 | * is called 52 | * 53 | * @param request request 54 | * @param response response 55 | * @param span span 56 | */ 57 | void onResponse(HttpRequest request, ClientHttpResponse response, Span span); 58 | 59 | /** 60 | * Decorate span when exception is thrown during request processing, e.g. during 61 | * {@link org.springframework.http.client.ClientHttpRequestInterceptor#intercept(HttpRequest, byte[], ClientHttpRequestExecution)} 62 | * is processing. 63 | * 64 | * @param request request 65 | * @param ex exception 66 | * @param span span 67 | */ 68 | void onError(HttpRequest request, Throwable ex, Span span); 69 | 70 | /** 71 | * This decorator adds set of standard tags to the span. 72 | */ 73 | class StandardTags implements RestTemplateSpanDecorator { 74 | private static final Log log = LogFactory.getLog(StandardTags.class); 75 | 76 | public static final String COMPONENT_NAME = "java-spring-rest-template"; 77 | 78 | @Override 79 | public void onRequest(HttpRequest request, Span span) { 80 | Tags.COMPONENT.set(span, COMPONENT_NAME); 81 | // this can be sometimes only path e.g. "/foo" 82 | Tags.HTTP_URL.set(span, request.getURI().toString()); 83 | Tags.HTTP_METHOD.set(span, request.getMethod().toString()); 84 | 85 | if (request.getURI().getPort() != -1) { 86 | Tags.PEER_PORT.set(span, request.getURI().getPort()); 87 | } 88 | } 89 | 90 | @Override 91 | public void onResponse(HttpRequest httpRequest, ClientHttpResponse response, Span span) { 92 | try { 93 | Tags.HTTP_STATUS.set(span, response.getRawStatusCode()); 94 | } catch (IOException e) { 95 | log.error("Could not get HTTP status code"); 96 | } 97 | } 98 | 99 | @Override 100 | public void onError(HttpRequest httpRequest, Throwable ex, Span span) { 101 | Tags.ERROR.set(span, Boolean.TRUE); 102 | span.log(errorLogs(ex)); 103 | } 104 | 105 | public static Map errorLogs(Throwable ex) { 106 | Map errorLogs = new HashMap<>(2); 107 | errorLogs.put("event", Tags.ERROR.getKey()); 108 | errorLogs.put("error.object", ex); 109 | return errorLogs; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | 4 | language: java 5 | jdk: 6 | - oraclejdk8 7 | 8 | cache: 9 | directories: 10 | - $HOME/.m2/repository 11 | 12 | before_install: 13 | # allocate commits to CI, not the owner of the deploy key 14 | - git config user.name "opentracingci" 15 | - git config user.email "opentracingci+opentracing@googlegroups.com" 16 | 17 | # setup https authentication credentials, used by ./mvnw release:prepare 18 | - git config credential.helper "store --file=.git/credentials" 19 | - echo "https://$GH_TOKEN:@github.com" > .git/credentials 20 | 21 | install: 22 | # Override default travis to use the maven wrapper 23 | - ./mvnw install -DskipTests=true -Dmaven.javadoc.skip=true -B -V 24 | 25 | script: 26 | - ./travis/publish.sh 27 | 28 | branches: 29 | except: 30 | - /^[0-9]/ 31 | 32 | env: 33 | global: 34 | # travis encrypt -r org/repo GH_TOKEN=XXX-https://github.com/settings/tokens-XXX 35 | - secure: "PLgIwcMbz0wNQAvWgJm6YnRlajidWw7LklhIZ/ywUrt/IbKTicMGnMyRuUZ+Z3ASK6XM3RKeyF8UgTxczhB+jXO+SNkvMgCwTiQlzlnFG4Iz9d/Esu6zLddUk3HEiBvrCdfqEtFbJJN+BpiOzOip/99CuppjhxUZZuwAVK4hJXBlEjzb0VUo6XS4nwqglp56vqLBexDM+AsyUo3MHsrB+xRiLSp+gvVFZtZXnF7vgY+3SPFEY0qDIcdcpdvyHrACvGiIRI57xZjE0ak4t4wsbGMCNXNebRuluwqwA7bCCCy0PGzZDLM6Vhc6U2gFSEfl3SU6Sp+zfYswHeDZvFaIQF1m7i2jMXNc/ywIqWt9QMFHVAgOMh2bMewJLjyIKa7pFhjIGO152aPgYeHlStyQYuNELAl+hByiR7nLP4IRx0PTtg8DB/uHhT9D2iB5MbOonNYQrvjrvsu5o2Nr9FD2Vac0hHRTxF6TW27nY3Th6/AIW8INf24NejaRgZrf1KsyMlMVzdjkAGe7SOdzIfjiGibD/+3U0lSrmZ72FvXop+K/7VhMEk+rkACneH45Py85O74sf0pBa9fOWZQmi11B9IR/HXOfl/gM1Dl7ZcYFQxR6OaQX2ITZW9xJB79QJLbeoKu1CoDczi5a9f3c0aOZ0mtO+XZpXXVjU3242n8Rfb8=" 36 | # travis encrypt -r org/repo SONATYPE_USER=your_sonatype_account 37 | - secure: "IneY58q340X2QUJI3SJj6T51S5HPCfRIzao0IYEdn0+uPunr1RqOLG3lWrsWyPGQ/otYzPcXK/KCrSpqgf5FatpBvsaWrf/JC5XBYt3pr3tvXAFjMDX5LO5/j7Q4sRZQbHzh57N6oobiVJawKGmxQEmvuuGml7VpWTDRG7IqBxr6B/voxBPpjrkU6rTE1Lk8xyJN1kCBUoN7a2LoyUs4Gwy9nXxdHO/xRJs+9zhGlpwb5KMyqOcbXMIsRMjAXSOIa0rx//Hz2qzWqtMHDC5ORv9PdlWWN/AvCCIOTqjl5LpbEd4JfazszN33fYj7HqzicSMtEHhkX27zraHT1SgvWJOUoMoypj9cN/k8o4TdYHQUs4fSiCKSY6oEwhJNzrhQlTHCBUBnsTNhkU+hn2+GSm/zlxg24Z+LcvJk36v/wjL2+sxuNauDINOgQWJ60rt3UMW+6VXFjxt88J7DHgblVNhZ3aUusJlDYmJO6a9NfkSb6rfwh8/ZcUi8I2xJcc+GL3gW0877FAEPsNJqNHYDVZDM8LUZkUEaFKABoRvxVWwMIwojc4glNS0IxVUdHbj1VPuB74TnEGBvWEy/BrCaokdJZX5o1B5DkH2tpjmPkhRn2mt12OIjsUtuOwFx+cs3xqHZOE/eGX506LJqOV3wYei3YgT5hQJ7HJQtHLH1wQo=" 38 | # travis encrypt -r org/repo SONATYPE_PASSWORD=your_sonatype_password 39 | - secure: "YScD3XfVqhsb8W1PnZNTP5vN7CzJyO82D7ipoQMvZAkuoP4OUwEhElPUd39tPKXok0wCBFnrcdCV1Ku2xD/xCCQl1Aa58NW6GG9008ndQNxWUXTDrQ9gz33vDNMVh5gsBUyQ860q9V8tf8KyMoqbs/QDGyFWL/4DF3Phv5DlUPrIkv2cg1C9eETdpSD7/97k/YMyLjQ9+jjh/j8jaMH2VYXSu7wpi/akjowAAzQLE0HWD3tgvrWf+Ec/tPZ7hrjU1g5nm4oT2d4NS0h4xaxTqqohRpccv1MQ3WspLP41gYE487mpYS6Uqh4vWK5BCdqpd6SCu7WEBq6zfNXEIVQ0Tg+hn5ClKzx91+yrOmA5j1dwOSM8GxgTt1nut/sgQYzlyOiWKBtm7kXjyRp1KKRTHG0k6kJt1AF7hrkTz3KG0qVNNX2ZrpgSmwrt0/YgfZ+RV6Tk2tEeo0/LeWPn9W/BKlNS7QaxOjgmNYhE0SERfLkg5C0OGFrUUPeHtjjK204I6NuaVa9/EZziNCNXbWSGi1UExrk/zW1+6G4q/Zh65BkfjG1kiXEJhwrZpc2Y4iLQkwe+Y3rPverp+wEWvO55fKrX3fZN+GbCUF4kuAMWwA796+GnDSLFpGR+UMUerTcsPVXurvr/DXrYy27xFogkHkz9/iFqM/8MQE9GhvySMXk=" 40 | # travis encrypt -r org/repo BINTRAY_USER=your_github_account 41 | - secure: "MT+N6Ejska5ZtHHg4JU9i0lpKXxVFWUmJP796mC8YV8vGJ1yIpiGFKRuBrkbZ88pG3s/ZjtlWo7mffpPxdHhpt65crPxUJGzj9M7PDSu4e4QocTkxAydPHReQtFeMujNcpK5fqh37x8YXJIzs5n056Y11cPtWti8xdoR+SJ7HoOI8ojB19nPYOpmXl2KtkI8xEsAT7oTooter8m8p9VorbtlgTGIdkvawNqXBRxSQTnTlhBGhS7rgwLn4gqmrSTmLKAXRuH2WXQ0MDFx2lhkS2/MxZvIzive1f5LINrKqgdVLpHrC2sExBB/j0Si3QBHdxuk1WeIDWaf2yT15Bxx9YMC+UxLGTO6SQzdzDbBisAzMDq/9ayt3JUAOzS9JvUfOrOFZVeEbOAs6NMF+BPtdgVGszVdUnoqbI6eg2gSFSKy5HMn7WYD6b7IHEGC5Swi/GU/HgZpbA6UdZ2w0tEXrFCCExeuyme/rRzbdDBUGJBFGF2UOcliYrrSWAJL6G1BAYu5qpb/do3KEKz2kph7yNlLfHjluZ78QKpWrUoFdOeZX80gaspRbX8/9KYFIJ9X/DzEVBueX2UeSdiY0+ZhnzacsFMem0/tQj2l4oBSnL33DnGk7icvKF86uEEegwFCuaI0TVnXDPqdy0QDZiZWX8Lk7+bvMgZepLFPfsy8Sqc=" 42 | # travis encrypt -r org/repo BINTRAY_KEY=xxx-https://bintray.com/profile/edit-xxx 43 | - secure: "jfR+YEf/x9ROKUvK8dotSDi7EYdsABBgsIVvmj9yq/86OXHid7MW3qt+HiQEDhEXkzvWcmfTltYSI4p8wGcVlmoP733u2m9gnweq0qIL2ovF9Ttfdi8XFG157WFbth4w/NSaliS68taFF/P89LUJXinKTWX4A4dcYljtNvWafbouaVpt2Pb+lDzVkXqWJT2Fttces+D3lk85hjsEjgufkS160G9WLy995PjgZsPir4CO6LqzuWKKTn/2MqFK3hlziVxqGKIwwDJOPQm7kUfvcks+0lHCuBPY2z9VPK4SarvWjd/9EtgFwAVOt00jTtLNiQdH9fmscq1lLB3DAjX7/1+pIsClqhmB4uY4qSMRpa0TU7gMV7PzefcrLqnTzZpc9FhNSO0+fRQgHAXSWHltVE0C+Gx3FSOqMniEAjIT5VodrX3X06+I6gpuq9PvgxATAsVM4gn6goNtoBxzC4OndOQvyjcih/9qClsVL+vwluMBW3my9ysClS6IjALz7w+cDWRqssuxw61qehz03golJiOQQbruIp8wtCRahP9EQMulPcAwpAQhOc+PQzJuh+j0MOdQbGMUq60fpkl/qn+f+euQMj4h05nGRLlEZ3OL6i3BvfZwXz53vUMMYLjO2fwwdOUJoVOqzt3W1t2uEIvASjKIz56hvtpyvDn9eDR8IUs=" 44 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/boot/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/boot/SpringBootConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.boot; 15 | 16 | import java.util.Collections; 17 | import java.util.List; 18 | import java.util.regex.Pattern; 19 | 20 | import javax.servlet.Filter; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 24 | import org.springframework.boot.web.client.RestTemplateBuilder; 25 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.context.annotation.Configuration; 28 | import org.springframework.context.annotation.Import; 29 | import org.springframework.http.HttpStatus; 30 | import org.springframework.scheduling.annotation.EnableAsync; 31 | import org.springframework.web.client.RestTemplate; 32 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 33 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 34 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 35 | 36 | import io.opentracing.Tracer; 37 | import io.opentracing.contrib.spring.web.client.TracingRestTemplateInterceptor; 38 | import io.opentracing.contrib.spring.web.interceptor.HandlerInterceptorSpanDecorator; 39 | import io.opentracing.contrib.spring.web.interceptor.TracingHandlerInterceptor; 40 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.ExceptionFilter; 41 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.TestController; 42 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.TracingBeansConfiguration; 43 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.WebSecurityConfig; 44 | import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator; 45 | import io.opentracing.contrib.web.servlet.filter.TracingFilter; 46 | 47 | 48 | /** 49 | * @author Pavol Loffay 50 | */ 51 | @Configuration 52 | @EnableAsync 53 | @EnableAutoConfiguration 54 | @Import({TracingBeansConfiguration.class, 55 | WebSecurityConfig.class, 56 | TestController.class, 57 | }) 58 | public class SpringBootConfiguration extends WebMvcConfigurerAdapter { 59 | 60 | @Autowired 61 | private List spanDecorators; 62 | 63 | @Autowired 64 | private Tracer tracer; 65 | 66 | @Bean 67 | public Filter exceptionFilter() { 68 | return new ExceptionFilter(); 69 | } 70 | 71 | @Bean 72 | public RestTemplate restTemplate(RestTemplateBuilder builder, Tracer tracer) { 73 | return builder.additionalInterceptors(new TracingRestTemplateInterceptor(tracer)) 74 | .build(); 75 | } 76 | 77 | @Override 78 | public void addInterceptors(InterceptorRegistry registry) { 79 | registry.addInterceptor(new TracingHandlerInterceptor(tracer, spanDecorators)); 80 | } 81 | 82 | @Override 83 | public void addViewControllers(ViewControllerRegistry registry) { 84 | registry.addViewController("/controllerView") 85 | .setStatusCode(HttpStatus.OK) 86 | .setViewName("staticView"); 87 | } 88 | 89 | @Bean 90 | public FilterRegistrationBean tracingFilter() { 91 | TracingFilter tracingFilter = new TracingFilter(tracer, 92 | Collections.singletonList(ServletFilterSpanDecorator.STANDARD_TAGS), Pattern.compile("/health")); 93 | 94 | FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(tracingFilter); 95 | filterRegistrationBean.addUrlPatterns("/*"); 96 | filterRegistrationBean.setOrder(Integer.MIN_VALUE); 97 | filterRegistrationBean.setAsyncSupported(true); 98 | 99 | return filterRegistrationBean; 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/RestTemplatePostProcessingConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.mock.MockTracer; 17 | import io.opentracing.util.ThreadLocalScopeManager; 18 | import org.assertj.core.api.Assertions; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.beans.factory.annotation.Qualifier; 24 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 25 | import org.springframework.boot.test.context.SpringBootTest; 26 | import org.springframework.boot.web.client.RestTemplateBuilder; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 30 | import org.springframework.web.client.ResourceAccessException; 31 | import org.springframework.web.client.RestTemplate; 32 | 33 | /** 34 | * @author Pavol Loffay 35 | */ 36 | @SpringBootTest( 37 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 38 | classes = {RestTemplatePostProcessingConfigurationTest.SpringConfiguration.class}) 39 | @RunWith(SpringJUnit4ClassRunner.class) 40 | public class RestTemplatePostProcessingConfigurationTest extends AutoConfigurationBaseTest { 41 | 42 | @Configuration 43 | @EnableAutoConfiguration 44 | public static class SpringConfiguration { 45 | @Bean 46 | public MockTracer tracer() { 47 | return new MockTracer(new ThreadLocalScopeManager()); 48 | } 49 | 50 | @Bean 51 | @Qualifier("foo") 52 | public RestTemplate restTemplateFoo() { 53 | return new RestTemplate(); 54 | } 55 | 56 | @Bean 57 | @Qualifier("bar") 58 | public RestTemplate restTemplateBar(RestTemplateBuilder builder) { 59 | return builder.build(); 60 | } 61 | } 62 | 63 | @Autowired 64 | private MockTracer mockTracer; 65 | 66 | @Autowired 67 | @Qualifier("foo") 68 | private RestTemplate fooRestTemplate; 69 | @Autowired 70 | @Qualifier("bar") 71 | private RestTemplate barRestTemplate; 72 | @Autowired 73 | private RestTemplateBuilder restTemplateBuilder; 74 | 75 | @Before 76 | public void setUp() { 77 | mockTracer.reset(); 78 | } 79 | 80 | @Test 81 | public void testTracingRequestCustom() { 82 | try { 83 | fooRestTemplate.getForEntity("http://nonexisting.example.com", String.class); 84 | } catch (ResourceAccessException ex) { 85 | //ok UnknownHostException 86 | } 87 | 88 | Assertions.assertThat(mockTracer.finishedSpans()).hasSize(1); 89 | } 90 | 91 | @Test 92 | public void testTracingRequestBean() { 93 | try { 94 | barRestTemplate.getForEntity("http://nonexisting.example.com", String.class); 95 | } catch (ResourceAccessException ex) { 96 | //ok UnknownHostException 97 | } 98 | 99 | // Note: Even that Builder has interceptor and AutoConfig tries to add another one, 100 | // we still must have only one in the end 101 | Assertions.assertThat(mockTracer.finishedSpans()).hasSize(1); 102 | } 103 | 104 | @Test 105 | public void testTracingFromBuilder() { 106 | try { 107 | restTemplateBuilder.build().getForEntity("http://nonexisting.example.com", String.class); 108 | } catch (ResourceAccessException ex) { 109 | //ok UnknownHostException 110 | } 111 | 112 | // Note: Even that Builder has interceptor and AutoConfig tries to add another one, 113 | // we still must have only one in the end 114 | Assertions.assertThat(mockTracer.finishedSpans()).hasSize(1); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/TracingClientResponseSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2019 the original author or authors. Copyright 2019 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.client; 17 | 18 | import io.opentracing.Span; 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.reactivestreams.Subscription; 22 | import org.springframework.core.io.buffer.DataBuffer; 23 | import org.springframework.web.reactive.function.client.ClientRequest; 24 | import org.springframework.web.reactive.function.client.ClientResponse; 25 | import reactor.core.CoreSubscriber; 26 | import reactor.util.context.Context; 27 | 28 | import java.util.List; 29 | 30 | /** 31 | * Similar to {@code WebClientTracerSubscriber} from spring-cloud-sleuth-core. 32 | * 33 | * @author Csaba Kos 34 | */ 35 | class TracingClientResponseSubscriber implements CoreSubscriber { 36 | private static final Log LOG = LogFactory.getLog(TracingClientResponseSubscriber.class); 37 | 38 | private final CoreSubscriber subscriber; 39 | private final ClientRequest clientRequest; 40 | private final Context context; 41 | private final Span span; 42 | private final List spanDecorators; 43 | 44 | TracingClientResponseSubscriber( 45 | final CoreSubscriber subscriber, 46 | final ClientRequest clientRequest, 47 | final Context context, 48 | final Span span, 49 | final List spanDecorators 50 | ) { 51 | this.subscriber = subscriber; 52 | this.clientRequest = clientRequest; 53 | this.context = context.put(Span.class, span); 54 | this.span = span; 55 | this.spanDecorators = spanDecorators; 56 | } 57 | 58 | @Override 59 | public void onSubscribe(final Subscription subscription) { 60 | spanDecorators.forEach(spanDecorator -> safelyCall(() -> spanDecorator.onRequest(clientRequest, span))); 61 | 62 | subscriber.onSubscribe(new Subscription() { 63 | @Override 64 | public void request(final long n) { 65 | subscription.request(n); 66 | } 67 | 68 | @Override 69 | public void cancel() { 70 | spanDecorators.forEach(spanDecorator -> safelyCall(() -> spanDecorator.onCancel(clientRequest, span))); 71 | subscription.cancel(); 72 | span.finish(); 73 | } 74 | }); 75 | } 76 | 77 | @Override 78 | public void onNext(final ClientResponse clientResponse) { 79 | try { 80 | // decorate response body 81 | subscriber.onNext(ClientResponse.from(clientResponse) 82 | .body(clientResponse.bodyToFlux(DataBuffer.class).subscriberContext(context)) 83 | .build()); 84 | } finally { 85 | spanDecorators.forEach(spanDecorator -> 86 | safelyCall(() -> spanDecorator.onResponse(clientRequest, clientResponse, span))); 87 | } 88 | } 89 | 90 | @Override 91 | public void onError(final Throwable throwable) { 92 | try { 93 | subscriber.onError(throwable); 94 | } finally { 95 | spanDecorators.forEach(spanDecorator -> safelyCall(() -> spanDecorator.onError(clientRequest, throwable, span))); 96 | span.finish(); 97 | } 98 | } 99 | 100 | @Override 101 | public void onComplete() { 102 | try { 103 | subscriber.onComplete(); 104 | } finally { 105 | span.finish(); 106 | } 107 | } 108 | 109 | @Override 110 | public Context currentContext() { 111 | return context; 112 | } 113 | 114 | private void safelyCall(final Runnable runnable) { 115 | try { 116 | runnable.run(); 117 | } catch (final RuntimeException e) { 118 | LOG.error("Exception during decorating span", e); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/TracingRestTemplateInterceptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import io.opentracing.Span; 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | import org.apache.commons.logging.Log; 23 | import org.apache.commons.logging.LogFactory; 24 | import org.springframework.http.HttpRequest; 25 | import org.springframework.http.client.ClientHttpRequestExecution; 26 | import org.springframework.http.client.ClientHttpRequestInterceptor; 27 | import org.springframework.http.client.ClientHttpResponse; 28 | 29 | import io.opentracing.Scope; 30 | import io.opentracing.Tracer; 31 | import io.opentracing.propagation.Format; 32 | import io.opentracing.tag.Tags; 33 | import io.opentracing.util.GlobalTracer; 34 | 35 | /** 36 | * OpenTracing Spring RestTemplate integration. 37 | * This interceptor creates tracing data for all outgoing requests. 38 | * 39 | * @author Pavol Loffay 40 | */ 41 | public class TracingRestTemplateInterceptor implements ClientHttpRequestInterceptor { 42 | private static final Log log = LogFactory.getLog(TracingRestTemplateInterceptor.class); 43 | 44 | private Tracer tracer; 45 | private List spanDecorators; 46 | 47 | public TracingRestTemplateInterceptor() { 48 | this(GlobalTracer.get(), Collections.singletonList( 49 | new RestTemplateSpanDecorator.StandardTags())); 50 | } 51 | 52 | /** 53 | * @param tracer tracer 54 | */ 55 | public TracingRestTemplateInterceptor(Tracer tracer) { 56 | this(tracer, Collections.singletonList( 57 | new RestTemplateSpanDecorator.StandardTags())); 58 | } 59 | 60 | /** 61 | * @param tracer tracer 62 | * @param spanDecorators list of decorators 63 | */ 64 | public TracingRestTemplateInterceptor(Tracer tracer, List spanDecorators) { 65 | this.tracer = tracer; 66 | this.spanDecorators = new ArrayList<>(spanDecorators); 67 | } 68 | 69 | @Override 70 | public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body, 71 | ClientHttpRequestExecution execution) throws IOException { 72 | ClientHttpResponse httpResponse; 73 | 74 | Span span = tracer.buildSpan(httpRequest.getMethod().toString()) 75 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) 76 | .start(); 77 | tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, 78 | new HttpHeadersCarrier(httpRequest.getHeaders())); 79 | 80 | for (RestTemplateSpanDecorator spanDecorator : spanDecorators) { 81 | try { 82 | spanDecorator.onRequest(httpRequest, span); 83 | } catch (RuntimeException exDecorator) { 84 | log.error("Exception during decorating span", exDecorator); 85 | } 86 | } 87 | 88 | try (Scope scope = tracer.activateSpan(span)) { 89 | httpResponse = execution.execute(httpRequest, body); 90 | for (RestTemplateSpanDecorator spanDecorator : spanDecorators) { 91 | try { 92 | spanDecorator.onResponse(httpRequest, httpResponse, span); 93 | } catch (RuntimeException exDecorator) { 94 | log.error("Exception during decorating span", exDecorator); 95 | } 96 | } 97 | } catch (Exception ex) { 98 | for (RestTemplateSpanDecorator spanDecorator : spanDecorators) { 99 | try { 100 | spanDecorator.onError(httpRequest, ex, span); 101 | } catch (RuntimeException exDecorator) { 102 | log.error("Exception during decorating span", exDecorator); 103 | } 104 | } 105 | throw ex; 106 | } finally { 107 | span.finish(); 108 | } 109 | 110 | return httpResponse; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/WebFluxTracingAutoConfigurationDefaultsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.concurrent.Callable; 17 | import java.util.concurrent.CountDownLatch; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.beans.factory.annotation.Qualifier; 21 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 22 | import org.springframework.boot.test.context.SpringBootTest; 23 | import org.springframework.boot.test.mock.mockito.MockBean; 24 | import org.springframework.boot.test.web.client.TestRestTemplate; 25 | import org.springframework.context.annotation.Bean; 26 | import org.springframework.context.annotation.Configuration; 27 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 28 | import org.springframework.web.bind.annotation.RequestMapping; 29 | import org.springframework.web.bind.annotation.RestController; 30 | 31 | import io.opentracing.contrib.spring.web.webfilter.WebFluxSpanDecorator; 32 | import io.opentracing.mock.MockTracer; 33 | import org.awaitility.Awaitility; 34 | import org.hamcrest.core.IsEqual; 35 | import org.junit.After; 36 | import org.junit.Test; 37 | import org.junit.runner.RunWith; 38 | import org.mockito.Mockito; 39 | 40 | import static org.assertj.core.api.Assertions.assertThat; 41 | 42 | /** 43 | * @author Csaba Kos 44 | * @author Gilles Robert 45 | * 46 | * Test that the default settings in {@link WebTracingProperties} work as expected. 47 | */ 48 | @SpringBootTest( 49 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 50 | classes = {WebFluxTracingAutoConfigurationDefaultsTest.SpringConfiguration.class}, 51 | properties = {"opentracing.spring.web.client.enabled=false", "spring.main.web-application-type=reactive"}) 52 | @RunWith(SpringJUnit4ClassRunner.class) 53 | public class WebFluxTracingAutoConfigurationDefaultsTest extends AutoConfigurationBaseTest { 54 | 55 | private static CountDownLatch infoCountDownLatch = new CountDownLatch(1); 56 | 57 | @RestController 58 | @Configuration 59 | @EnableAutoConfiguration 60 | public static class SpringConfiguration { 61 | @Bean 62 | public MockTracer tracer() { 63 | return new MockTracer(); 64 | } 65 | 66 | @RequestMapping("/hello") 67 | public void hello() { 68 | } 69 | 70 | @RequestMapping("/hello/nested") 71 | public void nestedHello() { 72 | } 73 | 74 | @RequestMapping("/info") 75 | public void info() { 76 | infoCountDownLatch.countDown(); 77 | } 78 | } 79 | 80 | @Autowired 81 | private TestRestTemplate testRestTemplate; 82 | 83 | @Autowired 84 | private MockTracer mockTracer; 85 | 86 | @MockBean 87 | @Qualifier("mockDecorator1") 88 | private WebFluxSpanDecorator mockDecorator1; 89 | @MockBean 90 | @Qualifier("mockDecorator2") 91 | private WebFluxSpanDecorator mockDecorator2; 92 | 93 | // Test that top level paths are traced by default 94 | @Test 95 | public void testRequestIsTraced() { 96 | testRestTemplate.getForEntity("/hello", String.class); 97 | Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1)); 98 | assertThat(mockTracer.finishedSpans()).hasSize(1); 99 | } 100 | 101 | // Test that lower level paths are traced by default as well 102 | @Test 103 | public void testNestedRequestIsTraced() { 104 | testRestTemplate.getForEntity("/hello/nested", String.class); 105 | Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1)); 106 | assertThat(mockTracer.finishedSpans()).hasSize(1); 107 | } 108 | 109 | // Test that /info is excluded due to the default skipPattern 110 | @Test 111 | public void testExcluded() { 112 | testRestTemplate.getForEntity("/actuator/info", String.class); 113 | 114 | assertThat(mockTracer.finishedSpans()).hasSize(0); 115 | assertThat(Mockito.mockingDetails(mockDecorator1).getInvocations()).hasSize(0); 116 | assertThat(Mockito.mockingDetails(mockDecorator2).getInvocations()).hasSize(0); 117 | } 118 | 119 | public Callable reportedSpansSize() { 120 | return () -> mockTracer.finishedSpans().size(); 121 | } 122 | 123 | @After() 124 | public void reset() { 125 | mockTracer.reset(); 126 | infoCountDownLatch = new CountDownLatch(1); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/client/TracingAsyncRestTemplateInterceptor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.Collections; 19 | import java.util.List; 20 | 21 | import org.apache.commons.logging.Log; 22 | import org.apache.commons.logging.LogFactory; 23 | import org.springframework.http.HttpRequest; 24 | import org.springframework.http.client.AsyncClientHttpRequestExecution; 25 | import org.springframework.http.client.AsyncClientHttpRequestInterceptor; 26 | import org.springframework.http.client.ClientHttpResponse; 27 | import org.springframework.util.concurrent.ListenableFuture; 28 | import org.springframework.util.concurrent.ListenableFutureCallback; 29 | 30 | import io.opentracing.Scope; 31 | import io.opentracing.Span; 32 | import io.opentracing.Tracer; 33 | import io.opentracing.propagation.Format; 34 | import io.opentracing.tag.Tags; 35 | import io.opentracing.util.GlobalTracer; 36 | 37 | /** 38 | * Note: From Spring Framework 5, {@link org.springframework.web.client.AsyncRestTemplate} is deprecated. 39 | * 40 | * @author Pavol Loffay 41 | */ 42 | public class TracingAsyncRestTemplateInterceptor implements AsyncClientHttpRequestInterceptor { 43 | private static final Log log = LogFactory.getLog(TracingAsyncRestTemplateInterceptor.class); 44 | 45 | private Tracer tracer; 46 | private List spanDecorators; 47 | 48 | public TracingAsyncRestTemplateInterceptor() { 49 | this(GlobalTracer.get()); 50 | } 51 | 52 | public TracingAsyncRestTemplateInterceptor(Tracer tracer) { 53 | this.tracer = tracer; 54 | this.spanDecorators = Collections.singletonList(new RestTemplateSpanDecorator.StandardTags()); 55 | } 56 | 57 | public TracingAsyncRestTemplateInterceptor(Tracer tracer, List spanDecorators) { 58 | this.tracer = tracer; 59 | this.spanDecorators = new ArrayList<>(spanDecorators); 60 | } 61 | 62 | @Override 63 | public ListenableFuture intercept(final HttpRequest httpRequest, 64 | byte[] body, 65 | AsyncClientHttpRequestExecution execution) throws IOException { 66 | 67 | final Span span = tracer.buildSpan(httpRequest.getMethod().toString()) 68 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT) 69 | .start(); 70 | tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new HttpHeadersCarrier(httpRequest.getHeaders())); 71 | 72 | for (RestTemplateSpanDecorator spanDecorator : spanDecorators) { 73 | try { 74 | spanDecorator.onRequest(httpRequest, span); 75 | } catch (RuntimeException exDecorator) { 76 | log.error("Exception during decorating span", exDecorator); 77 | } 78 | } 79 | 80 | try (Scope scope = tracer.activateSpan(span)) { 81 | ListenableFuture future = execution.executeAsync(httpRequest, body); 82 | future.addCallback(new ListenableFutureCallback() { 83 | @Override 84 | public void onSuccess(ClientHttpResponse httpResponse) { 85 | for (RestTemplateSpanDecorator spanDecorator: spanDecorators) { 86 | try { 87 | spanDecorator.onResponse(httpRequest, httpResponse, span); 88 | } catch (RuntimeException exDecorator) { 89 | log.error("Exception during decorating span", exDecorator); 90 | } 91 | } 92 | span.finish(); 93 | } 94 | 95 | @Override 96 | public void onFailure(Throwable ex) { 97 | for (RestTemplateSpanDecorator spanDecorator: spanDecorators) { 98 | try { 99 | spanDecorator.onError(httpRequest, ex, span); 100 | } catch (RuntimeException exDecorator) { 101 | log.error("Exception during decorating span", exDecorator); 102 | } 103 | } 104 | span.finish(); 105 | } 106 | }); 107 | return future; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/SkipEndPointsWithoutContextPathAndWithoutBasePathTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.Callable; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.boot.test.web.client.TestRestTemplate; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | import org.springframework.web.bind.annotation.RestController; 28 | 29 | import io.opentracing.mock.MockSpan; 30 | import io.opentracing.mock.MockTracer; 31 | import org.junit.After; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | 35 | import static org.awaitility.Awaitility.await; 36 | import static org.hamcrest.Matchers.equalTo; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | /** 40 | * @author Gilles Robert 41 | */ 42 | @SpringBootTest( 43 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 44 | classes = SkipEndPointsWithoutContextPathAndWithoutBasePathTest.SpringConfiguration.class, 45 | properties = { 46 | "management.endpoints.web.exposure.include:*", 47 | "opentracing.spring.web.client.enabled=false", 48 | "management.endpoints.web.base-path:/" 49 | }) 50 | @RunWith(SpringJUnit4ClassRunner.class) 51 | public class SkipEndPointsWithoutContextPathAndWithoutBasePathTest { 52 | 53 | private static final String HELLO = "/hello"; 54 | private static final String HEALTHCARE = "/healthcare"; 55 | private static final String HEALTH = "/health"; 56 | private static final String INFO = "/info"; 57 | private static final String AUDIT_EVENTS = "/auditevents"; 58 | private static final String METRICS = "/metrics"; 59 | 60 | @Configuration 61 | @EnableAutoConfiguration 62 | public static class SpringConfiguration { 63 | 64 | @Bean 65 | public MockTracer tracer() { 66 | return new MockTracer(); 67 | } 68 | 69 | @RestController 70 | public static class Controller { 71 | 72 | @RequestMapping(HEALTH) 73 | public String health() { 74 | return "health"; 75 | } 76 | 77 | @RequestMapping(AUDIT_EVENTS) 78 | public String auditEvents() { 79 | return "audit events"; 80 | } 81 | 82 | @RequestMapping(HELLO) 83 | public String hello() { 84 | return "hello"; 85 | } 86 | 87 | @RequestMapping(HEALTHCARE) 88 | public String healthCare() { 89 | return "health care"; 90 | } 91 | 92 | @RequestMapping(INFO) 93 | public String info() { 94 | return "info"; 95 | } 96 | } 97 | } 98 | 99 | @Autowired 100 | private TestRestTemplate testRestTemplate; 101 | @Autowired 102 | private MockTracer mockTracer; 103 | 104 | @Test 105 | public void testSkipHealthEndpoint() { 106 | invokeEndpoint(HEALTH); 107 | assertNoSpans(); 108 | } 109 | 110 | @Test 111 | public void testSkipInfoEndpoint() { 112 | invokeEndpoint(INFO); 113 | assertNoSpans(); 114 | } 115 | 116 | @Test 117 | public void testSkipMetricsEndpoint() { 118 | invokeEndpoint(METRICS + "?abc"); 119 | assertNoSpans(); 120 | } 121 | 122 | @Test 123 | public void testTraceHelloEndpoint() { 124 | invokeEndpoint(HELLO); 125 | assertOneSpan(); 126 | } 127 | 128 | @Test 129 | public void testTraceHealthCareEndpoint() { 130 | invokeEndpoint(HEALTHCARE); 131 | assertOneSpan(); 132 | } 133 | 134 | @After 135 | public void reset() { 136 | mockTracer.reset(); 137 | } 138 | 139 | private void invokeEndpoint(String endpoint) { 140 | testRestTemplate.getForEntity(endpoint, String.class); 141 | } 142 | 143 | private void assertNoSpans() { 144 | List mockSpans = mockTracer.finishedSpans(); 145 | assertEquals(0, mockSpans.size()); 146 | } 147 | 148 | private void assertOneSpan() { 149 | await().until(reportedSpansSize(), equalTo(1)); 150 | List mockSpans = mockTracer.finishedSpans(); 151 | assertEquals(1, mockSpans.size()); 152 | } 153 | 154 | private Callable reportedSpansSize() { 155 | return () -> mockTracer.finishedSpans().size(); 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/mvc/src/test/java/io/opentracing/contrib/spring/web/interceptor/itest/mvc/SpringMVCConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.interceptor.itest.mvc; 15 | 16 | import java.util.Collections; 17 | import java.util.List; 18 | import java.util.regex.Pattern; 19 | 20 | import javax.servlet.ServletContextEvent; 21 | import javax.servlet.ServletContextListener; 22 | 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.context.annotation.Bean; 25 | import org.springframework.context.annotation.Configuration; 26 | import org.springframework.context.annotation.Import; 27 | import org.springframework.http.HttpStatus; 28 | import org.springframework.http.client.ClientHttpRequestInterceptor; 29 | import org.springframework.web.client.RestTemplate; 30 | import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; 31 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 32 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 33 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 34 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 35 | import org.springframework.web.servlet.view.InternalResourceViewResolver; 36 | 37 | import io.opentracing.Tracer; 38 | import io.opentracing.contrib.spring.web.client.TracingRestTemplateInterceptor; 39 | import io.opentracing.contrib.spring.web.interceptor.HandlerInterceptorSpanDecorator; 40 | import io.opentracing.contrib.spring.web.interceptor.TracingHandlerInterceptor; 41 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.TestController; 42 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.TestInterceptor; 43 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.TracingBeansConfiguration; 44 | import io.opentracing.contrib.spring.web.interceptor.itest.common.app.WebSecurityConfig; 45 | import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator; 46 | import io.opentracing.contrib.web.servlet.filter.TracingFilter; 47 | import io.opentracing.util.GlobalTracer; 48 | 49 | /** 50 | * @author Pavol Loffay 51 | */ 52 | @EnableWebMvc 53 | @Configuration 54 | @Import({WebSecurityConfig.class, 55 | TracingBeansConfiguration.class, 56 | TestController.class}) 57 | public class SpringMVCConfiguration extends WebMvcConfigurerAdapter implements ServletContextListener { 58 | 59 | @Autowired 60 | private List spanDecorators; 61 | 62 | @Autowired 63 | private Tracer tracer; 64 | 65 | 66 | @Override 67 | public void addInterceptors(InterceptorRegistry registry) { 68 | GlobalTracer.register(tracer); 69 | registry.addInterceptor(new TracingHandlerInterceptor(tracer, spanDecorators)); 70 | registry.addInterceptor(new TestInterceptor()); 71 | } 72 | 73 | @Override 74 | public void addViewControllers(ViewControllerRegistry registry) { 75 | registry.addViewController("/controllerView") 76 | .setStatusCode(HttpStatus.OK) 77 | .setViewName("staticView"); 78 | } 79 | 80 | @Override 81 | public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 82 | configurer.enable(); 83 | } 84 | 85 | /** 86 | * Basic setup for JSP views. 87 | */ 88 | @Bean 89 | public InternalResourceViewResolver configureInternalResourceViewResolver() { 90 | InternalResourceViewResolver resolver = 91 | new InternalResourceViewResolver(); 92 | resolver.setPrefix("/WEB-INF/jsp/"); 93 | resolver.setSuffix(".jsp"); 94 | return resolver; 95 | } 96 | 97 | @Bean 98 | public RestTemplate restTemplate(Tracer tracer) { 99 | RestTemplate restTemplate = new RestTemplate(); 100 | restTemplate.setInterceptors(Collections.singletonList( 101 | new TracingRestTemplateInterceptor(tracer))); 102 | return restTemplate; 103 | } 104 | 105 | @Override 106 | public void contextInitialized(ServletContextEvent sce) { 107 | sce.getServletContext().setAttribute(TracingFilter.SPAN_DECORATORS, 108 | Collections.singletonList(ServletFilterSpanDecorator.STANDARD_TAGS)); 109 | sce.getServletContext().setAttribute(TracingFilter.SKIP_PATTERN, Pattern.compile("/health")); 110 | } 111 | 112 | @Override 113 | public void contextDestroyed(ServletContextEvent sce) {} 114 | } 115 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/SkipEndPointsWithContextPathWithoutBasePathTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.Callable; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.boot.test.web.client.TestRestTemplate; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | import org.springframework.web.bind.annotation.RestController; 28 | 29 | import io.opentracing.mock.MockSpan; 30 | import io.opentracing.mock.MockTracer; 31 | import org.junit.After; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | 35 | import static org.awaitility.Awaitility.await; 36 | import static org.hamcrest.Matchers.equalTo; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | /** 40 | * @author Gilles Robert 41 | */ 42 | @SpringBootTest( 43 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 44 | classes = SkipEndPointsWithContextPathWithoutBasePathTest.SpringConfiguration.class, 45 | properties = { 46 | "management.endpoints.web.exposure.include:*", 47 | "server.servlet.context-path:/myapp", 48 | "management.endpoints.web.base-path:/", 49 | "opentracing.spring.web.client.enabled=false" 50 | }) 51 | @RunWith(SpringJUnit4ClassRunner.class) 52 | public class SkipEndPointsWithContextPathWithoutBasePathTest { 53 | 54 | private static final String ACTUATOR_PATH = "/"; 55 | private static final String HEALTH_PATH = "/health"; 56 | private static final String AUDIT_EVENTS_PATH = "/auditevents"; 57 | private static final String HELLO = "/hello"; 58 | private static final String HEALTHCARE = "/healthcare"; 59 | private static final String INFO_PATH = "/info"; 60 | private static final String HEALTH = ACTUATOR_PATH + HEALTH_PATH; 61 | private static final String INFO = ACTUATOR_PATH + INFO_PATH; 62 | private static final String AUDIT_EVENTS = ACTUATOR_PATH + AUDIT_EVENTS_PATH; 63 | 64 | @Configuration 65 | @EnableAutoConfiguration 66 | public static class SpringConfiguration { 67 | 68 | @Bean 69 | public MockTracer tracer() { 70 | return new MockTracer(); 71 | } 72 | 73 | @RestController 74 | public static class Controller { 75 | 76 | @RequestMapping(HEALTH) 77 | public String health() { 78 | return "health"; 79 | } 80 | 81 | @RequestMapping(AUDIT_EVENTS) 82 | public String auditEvents() { 83 | return "audit events"; 84 | } 85 | 86 | @RequestMapping(HELLO) 87 | public String hello() { 88 | return "hello"; 89 | } 90 | 91 | @RequestMapping(HEALTHCARE) 92 | public String healthCare() { 93 | return "health care"; 94 | } 95 | 96 | @RequestMapping(INFO) 97 | public String info() { 98 | return "info"; 99 | } 100 | } 101 | } 102 | 103 | @Autowired 104 | private TestRestTemplate testRestTemplate; 105 | @Autowired 106 | private MockTracer mockTracer; 107 | 108 | @Test 109 | public void testSkipHealthEndpoint() { 110 | invokeEndpoint(HEALTH); 111 | assertNoSpans(); 112 | } 113 | 114 | @Test 115 | public void testSkipInfoEndpoint() { 116 | invokeEndpoint(INFO); 117 | assertNoSpans(); 118 | } 119 | 120 | @Test 121 | public void testTraceHelloEndpoint() { 122 | invokeEndpoint(HELLO); 123 | assertOneSpan(); 124 | } 125 | 126 | @Test 127 | public void testTraceHealthCareEndpoint() { 128 | invokeEndpoint(HEALTHCARE); 129 | assertOneSpan(); 130 | } 131 | 132 | @After 133 | public void reset() { 134 | mockTracer.reset(); 135 | } 136 | 137 | private void invokeEndpoint(String endpoint) { 138 | testRestTemplate.getForEntity(endpoint, String.class); 139 | } 140 | 141 | private void assertNoSpans() { 142 | List mockSpans = mockTracer.finishedSpans(); 143 | assertEquals(0, mockSpans.size()); 144 | } 145 | 146 | private void assertOneSpan() { 147 | await().until(reportedSpansSize(), equalTo(1)); 148 | List mockSpans = mockTracer.finishedSpans(); 149 | assertEquals(1, mockSpans.size()); 150 | } 151 | 152 | private Callable reportedSpansSize() { 153 | return () -> mockTracer.finishedSpans().size(); 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/ServerTracingAutoConfigurationDefaultsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.concurrent.Callable; 17 | import java.util.concurrent.CountDownLatch; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.beans.factory.annotation.Qualifier; 21 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 22 | import org.springframework.boot.test.context.SpringBootTest; 23 | import org.springframework.boot.test.mock.mockito.MockBean; 24 | import org.springframework.boot.test.web.client.TestRestTemplate; 25 | import org.springframework.context.annotation.Bean; 26 | import org.springframework.context.annotation.Configuration; 27 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 28 | import org.springframework.web.bind.annotation.RequestMapping; 29 | import org.springframework.web.bind.annotation.RestController; 30 | 31 | import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator; 32 | import io.opentracing.mock.MockTracer; 33 | import org.awaitility.Awaitility; 34 | import org.hamcrest.core.IsEqual; 35 | import org.junit.After; 36 | import org.junit.Test; 37 | import org.junit.runner.RunWith; 38 | import org.mockito.Mockito; 39 | 40 | import static org.assertj.core.api.Assertions.assertThat; 41 | 42 | /** 43 | * @author Pavol Loffay 44 | * 45 | * Test that the default settings in {@link WebTracingProperties} work as expected. 46 | */ 47 | @SpringBootTest( 48 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 49 | classes = {ServerTracingAutoConfigurationDefaultsTest.SpringConfiguration.class}, 50 | properties = "opentracing.spring.web.client.enabled=false") 51 | @RunWith(SpringJUnit4ClassRunner.class) 52 | public class ServerTracingAutoConfigurationDefaultsTest extends AutoConfigurationBaseTest { 53 | 54 | private static CountDownLatch infoCountDownLatch = new CountDownLatch(1); 55 | 56 | private static CountDownLatch actuatorInfoCountDownLatch = new CountDownLatch(1); 57 | 58 | @RestController 59 | @Configuration 60 | @EnableAutoConfiguration 61 | public static class SpringConfiguration { 62 | @Bean 63 | public MockTracer tracer() { 64 | return new MockTracer(); 65 | } 66 | 67 | @RequestMapping("/hello") 68 | public void hello() { 69 | } 70 | 71 | @RequestMapping("/hello/nested") 72 | public void nestedHello() { 73 | } 74 | 75 | @RequestMapping("/info") 76 | public void info() { 77 | infoCountDownLatch.countDown(); 78 | } 79 | 80 | @RequestMapping("/actuator/info") 81 | public void actuatorInfo() { 82 | actuatorInfoCountDownLatch.countDown(); 83 | } 84 | } 85 | 86 | @Autowired 87 | private TestRestTemplate testRestTemplate; 88 | 89 | @Autowired 90 | private MockTracer mockTracer; 91 | 92 | @MockBean 93 | @Qualifier("mockDecorator1") 94 | private ServletFilterSpanDecorator mockDecorator1; 95 | @MockBean 96 | @Qualifier("mockDecorator2") 97 | private ServletFilterSpanDecorator mockDecorator2; 98 | 99 | // Test that top level paths are traced by default 100 | @Test 101 | public void testRequestIsTraced() { 102 | testRestTemplate.getForEntity("/hello", String.class); 103 | Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1)); 104 | assertThat(mockTracer.finishedSpans()).hasSize(1); 105 | } 106 | 107 | // Test that lower level paths are traced by default as well 108 | @Test 109 | public void testNestedRequestIsTraced() { 110 | testRestTemplate.getForEntity("/hello/nested", String.class); 111 | Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1)); 112 | assertThat(mockTracer.finishedSpans()).hasSize(1); 113 | } 114 | 115 | // Test that /actuator/info is excluded due to the default skipPattern 116 | @Test 117 | public void testActuatorExcluded() { 118 | testRestTemplate.getForEntity("/actuator/info", String.class); 119 | 120 | assertThat(mockTracer.finishedSpans()).hasSize(0); 121 | assertThat(Mockito.mockingDetails(mockDecorator1).getInvocations()).hasSize(0); 122 | assertThat(Mockito.mockingDetails(mockDecorator2).getInvocations()).hasSize(0); 123 | } 124 | 125 | public Callable reportedSpansSize() { 126 | return () -> mockTracer.finishedSpans().size(); 127 | } 128 | 129 | @After() 130 | public void reset() { 131 | mockTracer.reset(); 132 | infoCountDownLatch = new CountDownLatch(1); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/TracingWebFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2020 the original author or authors. Copyright 2019 The OpenTracing Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.opentracing.contrib.spring.web.webfilter; 17 | 18 | import io.opentracing.Tracer; 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | import org.springframework.core.Ordered; 22 | import org.springframework.http.server.PathContainer; 23 | import org.springframework.http.server.reactive.ServerHttpRequest; 24 | import org.springframework.lang.Nullable; 25 | import org.springframework.util.StringUtils; 26 | import org.springframework.web.server.ServerWebExchange; 27 | import org.springframework.web.server.WebFilter; 28 | import org.springframework.web.server.WebFilterChain; 29 | import org.springframework.web.util.pattern.PathPattern; 30 | import org.springframework.web.util.pattern.PathPatternParser; 31 | import reactor.core.publisher.Mono; 32 | 33 | import java.util.List; 34 | import java.util.Set; 35 | import java.util.regex.Pattern; 36 | import java.util.stream.Collectors; 37 | 38 | /** 39 | * Tracing {@link WebFilter} for Spring WebFlux. 40 | * 41 | * Current server span context is accessible via {@link ServerWebExchange#getAttribute(String)} with name 42 | * {@link TracingWebFilter#SERVER_SPAN_CONTEXT}. 43 | * 44 | * Based on {@code TraceWebFilter} from spring-cloud-sleuth-core. 45 | * 46 | * @author Csaba Kos 47 | */ 48 | public class TracingWebFilter implements WebFilter, Ordered { 49 | private static final Log LOG = LogFactory.getLog(TracingWebFilter.class); 50 | 51 | /** 52 | * Used as a key of {@link ServerWebExchange#getAttributes()}} to inject server span context 53 | */ 54 | static final String SERVER_SPAN_CONTEXT = TracingWebFilter.class.getName() + ".activeSpanContext"; 55 | 56 | private final Tracer tracer; 57 | private final int order; 58 | @Nullable 59 | private final Pattern skipPattern; 60 | private final Set urlPatterns; 61 | private final List spanDecorators; 62 | 63 | public TracingWebFilter( 64 | final Tracer tracer, 65 | final int order, 66 | final Pattern skipPattern, 67 | final List urlPatterns, 68 | final List spanDecorators 69 | ) { 70 | this.tracer = tracer; 71 | this.order = order; 72 | this.skipPattern = (skipPattern != null && StringUtils.hasText(skipPattern.pattern())) ? skipPattern : null; 73 | final PathPatternParser pathPatternParser = new PathPatternParser(); 74 | this.urlPatterns = urlPatterns.stream().map(pathPatternParser::parse).collect(Collectors.toSet()); 75 | this.spanDecorators = spanDecorators; 76 | } 77 | 78 | @Override 79 | public Mono filter(final ServerWebExchange exchange, final WebFilterChain chain) { 80 | final ServerHttpRequest request = exchange.getRequest(); 81 | 82 | if (!shouldBeTraced(request)) { 83 | return chain.filter(exchange); 84 | } 85 | 86 | if (exchange.getAttribute(SERVER_SPAN_CONTEXT) != null) { 87 | if (LOG.isTraceEnabled()) { 88 | LOG.trace("Not tracing request " + request + " because it is already being traced"); 89 | } 90 | return chain.filter(exchange); 91 | } 92 | 93 | return new TracingOperator(chain.filter(exchange), exchange, tracer, spanDecorators); 94 | } 95 | 96 | /** 97 | * It checks whether a request should be traced or not. 98 | * 99 | * @return whether request should be traced or not 100 | */ 101 | protected boolean shouldBeTraced(final ServerHttpRequest request) { 102 | final PathContainer pathWithinApplication = request.getPath().pathWithinApplication(); 103 | // skip URLs matching skip pattern 104 | // e.g. pattern is defined as '/health|/status' then URL 'http://localhost:5000/context/health' won't be traced 105 | if (skipPattern != null) { 106 | final String url = pathWithinApplication.value(); 107 | if (skipPattern.matcher(url).matches()) { 108 | if (LOG.isTraceEnabled()) { 109 | LOG.trace("Not tracing request " + request + " because it matches skip pattern: " + skipPattern); 110 | } 111 | return false; 112 | } 113 | } 114 | if (!urlPatterns.isEmpty() && urlPatterns.stream().noneMatch(urlPattern -> urlPattern.matches(pathWithinApplication))) { 115 | if (LOG.isTraceEnabled()) { 116 | LOG.trace("Not tracing request " + request + " because it does not match any URL pattern: " + urlPatterns); 117 | } 118 | return false; 119 | } 120 | return true; 121 | } 122 | 123 | @Override 124 | public int getOrder() { 125 | return order; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/client/TracingWebClientTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import io.opentracing.Scope; 17 | import io.opentracing.Span; 18 | import io.opentracing.mock.MockSpan; 19 | import io.opentracing.tag.Tags; 20 | import org.junit.Assert; 21 | import org.junit.Test; 22 | import org.springframework.http.ResponseEntity; 23 | import org.springframework.web.reactive.function.client.WebClient; 24 | import reactor.core.publisher.Mono; 25 | 26 | import java.net.URI; 27 | import java.util.ArrayList; 28 | import java.util.Collections; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.concurrent.ExecutionException; 33 | import java.util.concurrent.ExecutorService; 34 | import java.util.concurrent.Executors; 35 | import java.util.concurrent.Future; 36 | import java.util.concurrent.TimeUnit; 37 | 38 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 39 | import static com.github.tomakehurst.wiremock.client.WireMock.get; 40 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; 41 | import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; 42 | 43 | /** 44 | * @author Csaba Kos 45 | */ 46 | public class TracingWebClientTest extends AbstractTracingClientTest { 47 | 48 | public TracingWebClientTest() { 49 | super(tracer -> { 50 | final WebClient webClient = WebClient.builder() 51 | .filter(new TracingExchangeFilterFunction(tracer, 52 | Collections.singletonList(new WebClientSpanDecorator.StandardTags()))) 53 | .build(); 54 | return new Client() { 55 | @Override 56 | public ResponseEntity getForEntity(String url, Class clazz) { 57 | Mono> forEntity = webClient.get() 58 | .uri(URI.create(url)) 59 | .exchange() 60 | .flatMap(clientResponse -> clientResponse.toEntity(clazz)); 61 | return forEntity.block(); 62 | } 63 | }; 64 | }, WebClientSpanDecorator.StandardTags.COMPONENT_NAME); 65 | } 66 | 67 | @Test 68 | public void testMultipleRequests() throws InterruptedException, ExecutionException { 69 | final String url = wireMockRule.url("/foo/"); 70 | int numberOfCalls = 1000; 71 | 72 | stubFor(get(urlPathMatching(".*/foo/.*")) 73 | .willReturn(aResponse().withStatus(200))); 74 | 75 | ExecutorService executorService = Executors.newFixedThreadPool(100); 76 | List> futures = new ArrayList<>(numberOfCalls); 77 | for (int i = 0; i < numberOfCalls; i++) { 78 | final String requestUrl = url + i; 79 | 80 | Span parentSpan = mockTracer.buildSpan("foo") 81 | .withTag("request-url", requestUrl) 82 | .start(); 83 | futures.add(executorService.submit(() -> { 84 | try (final Scope span = mockTracer.scopeManager().activate(parentSpan)) { 85 | client.getForEntity(requestUrl, String.class); 86 | } finally { 87 | parentSpan.finish(); 88 | } 89 | })); 90 | } 91 | 92 | // wait to finish all calls 93 | for (Future future: futures) { 94 | future.get(); 95 | } 96 | 97 | executorService.awaitTermination(1, TimeUnit.SECONDS); 98 | executorService.shutdown(); 99 | 100 | List mockSpans = mockTracer.finishedSpans(); 101 | Assert.assertEquals(numberOfCalls * 2, mockSpans.size()); 102 | 103 | final List parentSpans = new ArrayList<>(); 104 | final Map childSpans = new HashMap<>(); 105 | 106 | for (MockSpan mockSpan: mockSpans) { 107 | if (mockSpan.tags().containsKey("request-url")) { 108 | parentSpans.add(mockSpan); 109 | } else { 110 | childSpans.put(mockSpan.parentId(), mockSpan); 111 | } 112 | 113 | } 114 | 115 | Assert.assertEquals(numberOfCalls, parentSpans.size()); 116 | Assert.assertEquals(numberOfCalls, childSpans.size()); 117 | 118 | for (MockSpan parentSpan: parentSpans) { 119 | MockSpan childSpan = childSpans.get(parentSpan.context().spanId()); 120 | Assert.assertEquals(parentSpan.tags().get("request-url"), childSpan.tags().get(Tags.HTTP_URL.getKey())); 121 | 122 | Assert.assertEquals(parentSpan.context().traceId(), childSpan.context().traceId()); 123 | Assert.assertEquals(parentSpan.context().spanId(), childSpan.parentId()); 124 | Assert.assertEquals(0, childSpan.generatedErrors().size()); 125 | Assert.assertEquals(0, parentSpan.generatedErrors().size()); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /opentracing-spring-web-itest/webflux/src/test/java/io/opentracing/contrib/spring/webflux/webfilter/itest/webflux/WebFluxJettyMinimalIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.webflux.webfilter.itest.webflux; 15 | 16 | import io.opentracing.contrib.spring.web.webfilter.TracingWebFilter; 17 | import io.opentracing.contrib.spring.web.webfilter.WebFluxSpanDecorator; 18 | import io.opentracing.mock.MockSpan; 19 | import io.opentracing.mock.MockTracer; 20 | import io.opentracing.tag.Tags; 21 | import io.opentracing.util.ThreadLocalScopeManager; 22 | import org.junit.AfterClass; 23 | import org.junit.Assert; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.mockito.Mockito; 27 | import org.springframework.boot.test.web.client.TestRestTemplate; 28 | import org.springframework.boot.web.client.RestTemplateBuilder; 29 | import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory; 30 | import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext; 31 | import org.springframework.core.io.buffer.DefaultDataBufferFactory; 32 | import org.springframework.http.HttpStatus; 33 | import org.springframework.http.server.reactive.HttpHandler; 34 | import org.springframework.http.server.reactive.ServerHttpResponse; 35 | import org.springframework.web.server.ServerWebExchange; 36 | import org.springframework.web.server.WebHandler; 37 | import org.springframework.web.server.adapter.WebHttpHandlerBuilder; 38 | import reactor.core.publisher.Mono; 39 | 40 | import java.util.Arrays; 41 | import java.util.Collections; 42 | import java.util.List; 43 | import java.util.regex.Pattern; 44 | 45 | /** 46 | * @author Csaba Kos 47 | */ 48 | public class WebFluxJettyMinimalIntegrationTest { 49 | 50 | private static final ReactiveWebServerApplicationContext APPLICATION_CONTEXT = new ReactiveWebServerApplicationContext(); 51 | private static final MockTracer MOCK_TRACER = Mockito.spy(new MockTracer(new ThreadLocalScopeManager(), 52 | MockTracer.Propagator.TEXT_MAP)); 53 | private final static TracingWebFilter TRACING_WEB_FILTER = new TracingWebFilter( 54 | MOCK_TRACER, 55 | Integer.MIN_VALUE, 56 | Pattern.compile(""), 57 | Collections.singletonList("/*"), 58 | Arrays.asList(new WebFluxSpanDecorator.StandardTags(), new WebFluxSpanDecorator.WebFluxTags()) 59 | ); 60 | private static final int SERVER_PORT; 61 | private static final TestRestTemplate TEST_REST_TEMPLATE; 62 | 63 | static { 64 | APPLICATION_CONTEXT.registerBean("jettyReactiveWebServerFactory", JettyReactiveWebServerFactory.class, () -> 65 | new JettyReactiveWebServerFactory(0)); 66 | APPLICATION_CONTEXT.registerBean("webHandler", WebHandler.class, () -> 67 | serverWebExchange -> TRACING_WEB_FILTER.filter(serverWebExchange, WebFluxJettyMinimalIntegrationTest::handler)); 68 | APPLICATION_CONTEXT.registerBean("httpHandler", HttpHandler.class, () -> 69 | WebHttpHandlerBuilder.applicationContext(APPLICATION_CONTEXT).build()); 70 | APPLICATION_CONTEXT.refresh(); 71 | SERVER_PORT = APPLICATION_CONTEXT.getWebServer().getPort(); 72 | TEST_REST_TEMPLATE = new TestRestTemplate(new RestTemplateBuilder() 73 | .rootUri("http://127.0.0.1:" + SERVER_PORT)); 74 | } 75 | 76 | private static Mono handler(final ServerWebExchange serverWebExchange) { 77 | final ServerHttpResponse response = serverWebExchange.getResponse(); 78 | response.setStatusCode(HttpStatus.OK); 79 | return response.writeWith(Mono.just(new DefaultDataBufferFactory().wrap("Hello World!\n".getBytes()))); 80 | } 81 | 82 | @AfterClass 83 | public static void afterClass() { 84 | APPLICATION_CONTEXT.close(); 85 | } 86 | 87 | @Before 88 | public void beforeTest() { 89 | MOCK_TRACER.reset(); 90 | Mockito.reset(MOCK_TRACER); 91 | } 92 | 93 | @Test 94 | public void testGet() { 95 | TEST_REST_TEMPLATE.getForEntity("/", String.class); 96 | 97 | final List mockSpans = MOCK_TRACER.finishedSpans(); 98 | Assert.assertEquals(1, mockSpans.size()); 99 | 100 | final MockSpan span = mockSpans.get(0); 101 | Assert.assertEquals("GET", span.operationName()); 102 | 103 | Assert.assertEquals(8, span.tags().size()); 104 | Assert.assertEquals(Tags.SPAN_KIND_SERVER, span.tags().get(Tags.SPAN_KIND.getKey())); 105 | Assert.assertEquals("GET", span.tags().get(Tags.HTTP_METHOD.getKey())); 106 | Assert.assertEquals(TEST_REST_TEMPLATE.getRootUri() + "/", span.tags().get(Tags.HTTP_URL.getKey())); 107 | Assert.assertEquals(200, span.tags().get(Tags.HTTP_STATUS.getKey())); 108 | Assert.assertEquals("java-spring-webflux", span.tags().get(Tags.COMPONENT.getKey())); 109 | Assert.assertNotNull(span.tags().get(Tags.PEER_PORT.getKey())); 110 | Assert.assertEquals("127.0.0.1", span.tags().get(Tags.PEER_HOST_IPV4.getKey())); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/DisabledRestTemplateTracingAutoConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import io.opentracing.contrib.spring.web.client.TracingRestTemplateInterceptor; 17 | import io.opentracing.mock.MockTracer; 18 | import io.opentracing.util.ThreadLocalScopeManager; 19 | import org.awaitility.Awaitility; 20 | import org.hamcrest.core.IsEqual; 21 | import org.junit.Assert; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 27 | import org.springframework.boot.test.context.SpringBootTest; 28 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 29 | import org.springframework.context.annotation.Bean; 30 | import org.springframework.context.annotation.Configuration; 31 | import org.springframework.http.ResponseEntity; 32 | import org.springframework.http.client.AsyncClientHttpRequestInterceptor; 33 | import org.springframework.http.client.ClientHttpRequestInterceptor; 34 | import org.springframework.test.context.ActiveProfiles; 35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 36 | import org.springframework.util.concurrent.ListenableFuture; 37 | import org.springframework.web.client.AsyncRestTemplate; 38 | import org.springframework.web.client.ResourceAccessException; 39 | import org.springframework.web.client.RestTemplate; 40 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 41 | 42 | import java.util.concurrent.TimeUnit; 43 | import java.util.concurrent.atomic.AtomicBoolean; 44 | 45 | import static org.assertj.core.api.Assertions.assertThat; 46 | import static org.junit.Assert.assertNotNull; 47 | 48 | 49 | /** 50 | * @author Michal Dvorak 51 | */ 52 | @SpringBootTest( 53 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 54 | classes = {DisabledRestTemplateTracingAutoConfigurationTest.SpringConfiguration.class}, 55 | properties = {"opentracing.spring.web.client.enabled=false"}) 56 | @RunWith(SpringJUnit4ClassRunner.class) 57 | @ActiveProfiles("test") 58 | public class DisabledRestTemplateTracingAutoConfigurationTest extends AutoConfigurationBaseTest { 59 | 60 | @Configuration 61 | @EnableAutoConfiguration 62 | public static class SpringConfiguration { 63 | 64 | @Bean 65 | public MockTracer tracer() { 66 | return new MockTracer(new ThreadLocalScopeManager()); 67 | } 68 | 69 | @Bean 70 | public RestTemplate restTemplate() { 71 | return new RestTemplate(); 72 | } 73 | 74 | @Bean 75 | public AsyncRestTemplate asyncRestTemplate() { 76 | return new AsyncRestTemplate(); 77 | } 78 | } 79 | 80 | @Autowired(required = false) 81 | private FilterRegistrationBean tracingFilter; 82 | @Autowired(required = false) 83 | private WebMvcConfigurer tracingHandlerInterceptor; 84 | @Autowired 85 | private MockTracer mockTracer; 86 | @Autowired 87 | private RestTemplate restTemplate; 88 | @Autowired 89 | private AsyncRestTemplate asyncRestTemplate; 90 | 91 | @Before 92 | public void setUp() { 93 | mockTracer.reset(); 94 | } 95 | 96 | @Test 97 | public void testWebConfigurationEnabled() { 98 | assertNotNull(tracingFilter); 99 | assertNotNull(tracingHandlerInterceptor); 100 | } 101 | 102 | @Test 103 | public void testInterceptorNotRegistered() { 104 | for (ClientHttpRequestInterceptor interceptor : restTemplate.getInterceptors()) { 105 | assertThat(interceptor).isNotInstanceOf(TracingRestTemplateInterceptor.class); 106 | } 107 | } 108 | 109 | @Test 110 | public void testAsyncInterceptorNotRegistered() { 111 | for (AsyncClientHttpRequestInterceptor interceptor : asyncRestTemplate.getInterceptors()) { 112 | assertThat(interceptor).isNotInstanceOf(TracingRestTemplateInterceptor.class); 113 | } 114 | } 115 | 116 | @Test 117 | public void testRestClientNotTracing() { 118 | try { 119 | restTemplate.getForEntity("http://nonexisting.example.com", String.class); 120 | } catch (ResourceAccessException ex) { 121 | //ok UnknownHostException 122 | } 123 | Assert.assertEquals(0, mockTracer.finishedSpans().size()); 124 | } 125 | 126 | @Test 127 | public void testAsyncRestClientNotTracing() { 128 | ListenableFuture> future = asyncRestTemplate.getForEntity("http://nonexisting.example.com", String.class); 129 | 130 | AtomicBoolean done = AsyncRestTemplatePostProcessingConfigurationTest.addDoneCallback(future); 131 | Awaitility.await().atMost(500, TimeUnit.MILLISECONDS).untilAtomic(done, IsEqual.equalTo(true)); 132 | 133 | Assert.assertEquals(0, mockTracer.finishedSpans().size()); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/SkipEndPointsWithoutContextPathAndBasePathTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.Callable; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.boot.test.web.client.TestRestTemplate; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | import org.springframework.web.bind.annotation.RestController; 28 | 29 | import io.opentracing.mock.MockSpan; 30 | import io.opentracing.mock.MockTracer; 31 | import org.junit.After; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | 35 | import static org.awaitility.Awaitility.await; 36 | import static org.hamcrest.Matchers.equalTo; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | /** 40 | * @author Gilles Robert 41 | */ 42 | @SpringBootTest( 43 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 44 | classes = SkipEndPointsWithoutContextPathAndBasePathTest.SpringConfiguration.class, 45 | properties = { 46 | "management.endpoints.web.exposure.include:*", 47 | "opentracing.spring.web.client.enabled=false" 48 | }) 49 | @RunWith(SpringJUnit4ClassRunner.class) 50 | public class SkipEndPointsWithoutContextPathAndBasePathTest { 51 | 52 | private static final String ACTUATOR_PATH = "/actuator"; 53 | private static final String HEALTH_PATH = "/health"; 54 | private static final String AUDIT_EVENTS_PATH = "/auditevents"; 55 | private static final String HELLO = "/hello"; 56 | private static final String HEALTHCARE = "/healthcare"; 57 | private static final String INFO_PATH = "/info"; 58 | private static final String METRICS_PATH = "/metrics"; 59 | private static final String INFO = INFO_PATH; 60 | private static final String HEALTH = ACTUATOR_PATH + HEALTH_PATH; 61 | private static final String INFO_ACTUATOR = ACTUATOR_PATH + INFO_PATH; 62 | private static final String AUDIT_EVENTS = ACTUATOR_PATH + AUDIT_EVENTS_PATH; 63 | private static final String METRICS = ACTUATOR_PATH + METRICS_PATH; 64 | 65 | @Configuration 66 | @EnableAutoConfiguration 67 | public static class SpringConfiguration { 68 | 69 | @Bean 70 | public MockTracer tracer() { 71 | return new MockTracer(); 72 | } 73 | 74 | @RestController 75 | public static class Controller { 76 | 77 | @RequestMapping(HEALTH) 78 | public String health() { 79 | return "health"; 80 | } 81 | 82 | @RequestMapping(AUDIT_EVENTS) 83 | public String auditEvents() { 84 | return "audit events"; 85 | } 86 | 87 | @RequestMapping(HELLO) 88 | public String hello() { 89 | return "hello"; 90 | } 91 | 92 | @RequestMapping(HEALTHCARE) 93 | public String healthCare() { 94 | return "health care"; 95 | } 96 | 97 | @RequestMapping(INFO) 98 | public String info() { 99 | return "info"; 100 | } 101 | } 102 | } 103 | 104 | @Autowired 105 | private TestRestTemplate testRestTemplate; 106 | @Autowired 107 | private MockTracer mockTracer; 108 | 109 | @Test 110 | public void testSkipHealthEndpoint() { 111 | invokeEndpoint(HEALTH); 112 | assertNoSpans(); 113 | } 114 | 115 | @Test 116 | public void testSkipInfoEndpoint() { 117 | invokeEndpoint(INFO_ACTUATOR); 118 | assertNoSpans(); 119 | } 120 | 121 | @Test 122 | public void testSkipMetricsEndpoint() { 123 | invokeEndpoint(METRICS + "?abc"); 124 | assertNoSpans(); 125 | } 126 | 127 | @Test 128 | public void testTraceHelloEndpoint() { 129 | invokeEndpoint(HELLO); 130 | assertOneSpan(); 131 | } 132 | 133 | @Test 134 | public void testTraceHealthCareEndpoint() { 135 | invokeEndpoint(HEALTHCARE); 136 | assertOneSpan(); 137 | } 138 | 139 | @Test 140 | public void testTraceInfoNonActuatorEndpoint() { 141 | invokeEndpoint(INFO); 142 | assertOneSpan(); 143 | } 144 | 145 | @After 146 | public void reset() { 147 | mockTracer.reset(); 148 | } 149 | 150 | private void invokeEndpoint(String endpoint) { 151 | testRestTemplate.getForEntity(endpoint, String.class); 152 | } 153 | 154 | private void assertNoSpans() { 155 | List mockSpans = mockTracer.finishedSpans(); 156 | assertEquals(0, mockSpans.size()); 157 | } 158 | 159 | private void assertOneSpan() { 160 | await().until(reportedSpansSize(), equalTo(1)); 161 | List mockSpans = mockTracer.finishedSpans(); 162 | assertEquals(1, mockSpans.size()); 163 | } 164 | 165 | private Callable reportedSpansSize() { 166 | return () -> mockTracer.finishedSpans().size(); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /opentracing-spring-web-starter/src/test/java/io/opentracing/contrib/spring/web/starter/SkipEndPointsWithContextPathAndBasePathTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.starter; 15 | 16 | import java.util.List; 17 | import java.util.concurrent.Callable; 18 | 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.boot.test.web.client.TestRestTemplate; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | import org.springframework.web.bind.annotation.RestController; 28 | 29 | import io.opentracing.mock.MockSpan; 30 | import io.opentracing.mock.MockTracer; 31 | import org.junit.After; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | 35 | import static org.awaitility.Awaitility.await; 36 | import static org.hamcrest.Matchers.equalTo; 37 | import static org.junit.Assert.assertEquals; 38 | 39 | /** 40 | * @author Gilles Robert 41 | */ 42 | @SpringBootTest( 43 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 44 | classes = SkipEndPointsWithContextPathAndBasePathTest.SpringConfiguration.class, 45 | properties = { 46 | "management.endpoints.web.exposure.include:*", 47 | "server.servlet.context-path:/myapp", 48 | "opentracing.spring.web.client.enabled=false" 49 | }) 50 | @RunWith(SpringJUnit4ClassRunner.class) 51 | public class SkipEndPointsWithContextPathAndBasePathTest { 52 | 53 | private static final String ACTUATOR_PATH = "/actuator"; 54 | private static final String HEALTH_PATH = "/health"; 55 | private static final String AUDIT_EVENTS_PATH = "/auditevents"; 56 | private static final String HELLO = "/hello"; 57 | private static final String HEALTHCARE = "/healthcare"; 58 | private static final String INFO_PATH = "/info"; 59 | private static final String METRICS_PATH = "/metrics"; 60 | private static final String INFO = INFO_PATH; 61 | private static final String HEALTH = ACTUATOR_PATH + HEALTH_PATH; 62 | private static final String INFO_ACTUATOR = ACTUATOR_PATH + INFO_PATH; 63 | private static final String AUDIT_EVENTS = ACTUATOR_PATH + AUDIT_EVENTS_PATH; 64 | private static final String METRICS = ACTUATOR_PATH + METRICS_PATH; 65 | 66 | @Configuration 67 | @EnableAutoConfiguration 68 | public static class SpringConfiguration { 69 | 70 | @Bean 71 | public MockTracer tracer() { 72 | return new MockTracer(); 73 | } 74 | 75 | @RestController 76 | public static class Controller { 77 | 78 | @RequestMapping(HEALTH) 79 | public String health() { 80 | return "health"; 81 | } 82 | 83 | @RequestMapping(AUDIT_EVENTS) 84 | public String auditEvents() { 85 | return "audit events"; 86 | } 87 | 88 | @RequestMapping(HELLO) 89 | public String hello() { 90 | return "hello"; 91 | } 92 | 93 | @RequestMapping(HEALTHCARE) 94 | public String healthCare() { 95 | return "health care"; 96 | } 97 | 98 | @RequestMapping(INFO) 99 | public String info() { 100 | return "info"; 101 | } 102 | } 103 | } 104 | 105 | @Autowired 106 | private TestRestTemplate testRestTemplate; 107 | @Autowired 108 | private MockTracer mockTracer; 109 | 110 | @Test 111 | public void testSkipHealthEndpoint() { 112 | invokeEndpoint(HEALTH); 113 | assertNoSpans(); 114 | } 115 | 116 | @Test 117 | public void testSkipInfoEndpoint() { 118 | invokeEndpoint(INFO_ACTUATOR); 119 | assertNoSpans(); 120 | } 121 | 122 | @Test 123 | public void testSkipMetricsEndpoint() { 124 | invokeEndpoint(METRICS+ "?abc"); 125 | assertNoSpans(); 126 | } 127 | 128 | @Test 129 | public void testTraceHelloEndpoint() { 130 | invokeEndpoint(HELLO); 131 | assertOneSpan(); 132 | } 133 | 134 | @Test 135 | public void testTraceHealthCareEndpoint() { 136 | invokeEndpoint(HEALTHCARE); 137 | assertOneSpan(); 138 | } 139 | 140 | @Test 141 | public void testTraceInfoNonActuatorEndpoint() { 142 | invokeEndpoint(INFO); 143 | assertOneSpan(); 144 | } 145 | 146 | @After 147 | public void reset() { 148 | mockTracer.reset(); 149 | } 150 | 151 | private void invokeEndpoint(String endpoint) { 152 | testRestTemplate.getForEntity(endpoint, String.class); 153 | } 154 | 155 | private void assertNoSpans() { 156 | List mockSpans = mockTracer.finishedSpans(); 157 | assertEquals(0, mockSpans.size()); 158 | } 159 | 160 | private void assertOneSpan() { 161 | await().until(reportedSpansSize(), equalTo(1)); 162 | List mockSpans = mockTracer.finishedSpans(); 163 | assertEquals(1, mockSpans.size()); 164 | } 165 | 166 | private Callable reportedSpansSize() { 167 | return () -> mockTracer.finishedSpans().size(); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /travis/publish.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-2017 The OpenTracing Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the License 10 | # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | # or implied. See the License for the specific language governing permissions and limitations under 12 | # the License. 13 | # 14 | 15 | set -euo pipefail 16 | set -x 17 | 18 | build_started_by_tag() { 19 | if [ "${TRAVIS_TAG}" == "" ]; then 20 | echo "[Publishing] This build was not started by a tag, publishing snapshot" 21 | return 1 22 | else 23 | echo "[Publishing] This build was started by the tag ${TRAVIS_TAG}, publishing release" 24 | return 0 25 | fi 26 | } 27 | 28 | is_pull_request() { 29 | if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then 30 | echo "[Not Publishing] This is a Pull Request" 31 | return 0 32 | else 33 | echo "[Publishing] This is not a Pull Request" 34 | return 1 35 | fi 36 | } 37 | 38 | is_travis_branch_master_or_release() { 39 | if [[ "${TRAVIS_BRANCH}" == "master" || "${TRAVIS_BRANCH}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 40 | echo "[Publishing] Travis branch is ${TRAVIS_BRANCH}" 41 | return 0 42 | else 43 | echo "[Not Publishing] Travis branch is not master or v0.0.0" 44 | return 1 45 | fi 46 | } 47 | 48 | check_travis_branch_equals_travis_tag() { 49 | #Weird comparison comparing branch to tag because when you 'git push --tags' 50 | #the branch somehow becomes the tag value 51 | #github issue: https://github.com/travis-ci/travis-ci/issues/1675 52 | if [ "${TRAVIS_BRANCH}" != "${TRAVIS_TAG}" ]; then 53 | echo "Travis branch does not equal Travis tag, which it should, bailing out." 54 | echo " github issue: https://github.com/travis-ci/travis-ci/issues/1675" 55 | exit 1 56 | else 57 | echo "[Publishing] Branch (${TRAVIS_BRANCH}) same as Tag (${TRAVIS_TAG})" 58 | fi 59 | } 60 | 61 | check_release_tag() { 62 | tag="${TRAVIS_TAG}" 63 | if [[ "$tag" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then 64 | echo "Build started by version tag $tag. During the release process tags like this" 65 | echo "are created by the 'release' Maven plugin. Nothing to do here." 66 | exit 0 67 | elif [[ ! "$tag" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then 68 | echo "You must specify a tag of the format 'release-0.0.0' or 'release-0.0.0-RC0' to release this project." 69 | echo "The provided tag ${tag} doesn't match that. Aborting." 70 | exit 1 71 | fi 72 | } 73 | 74 | is_release_commit() { 75 | project_version=$(./mvnw help:evaluate -N -Dexpression=project.version|sed -n '/^[0-9]/p') 76 | if [[ "$project_version" =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(\-RC[[:digit:]]+)?$ ]]; then 77 | echo "Build started by release commit $project_version. Will synchronize to maven central." 78 | return 0 79 | else 80 | return 1 81 | fi 82 | } 83 | 84 | release_version() { 85 | echo "${TRAVIS_TAG}" | sed 's/^release-//' 86 | } 87 | 88 | safe_checkout_remote_branch() { 89 | # We need to be on a branch for release:perform to be able to create commits, 90 | # and we want that branch to be master or v0.0.0 (for RCs). which has been checked before. 91 | # But we also want to make sure that we build and release exactly the tagged version, 92 | # so we verify that the remote branch is where our tag is. 93 | checkoutBranch=master 94 | if [[ "${TRAVIS_BRANCH}" =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\-RC[[:digit:]]+$ ]]; then 95 | checkoutBranch=v`release_version | sed 's/-RC[[:digit:]]\+//'` 96 | fi 97 | git checkout -B "${checkoutBranch}" 98 | git fetch origin "${checkoutBranch}":origin/"${checkoutBranch}" 99 | commit_local="$(git show --pretty='format:%H' ${checkoutBranch})" 100 | commit_remote="$(git show --pretty='format:%H' origin/${checkoutBranch})" 101 | if [ "$commit_local" != "$commit_remote" ]; then 102 | echo "${checkoutBranch} on remote 'origin' has commits since the version under release, aborting" 103 | exit 1 104 | fi 105 | } 106 | 107 | #---------------------- 108 | # MAIN 109 | #---------------------- 110 | 111 | if ! is_pull_request && build_started_by_tag; then 112 | check_travis_branch_equals_travis_tag 113 | check_release_tag 114 | fi 115 | 116 | ./mvnw install -nsu 117 | 118 | # If we are on a pull request, our only job is to run tests, which happened above via ./mvnw install 119 | if is_pull_request; then 120 | true 121 | # If we are on master, we will deploy the latest snapshot or release version 122 | # - If a release commit fails to deploy for a transient reason, delete the broken version from bintray and click rebuild 123 | elif is_travis_branch_master_or_release; then 124 | ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DskipTests deploy 125 | 126 | # If the deployment succeeded, sync it to Maven Central. Note: this needs to be done once per project, not module, hence -N 127 | if is_release_commit; then 128 | ./mvnw --batch-mode -s ./.settings.xml -nsu -N io.zipkin.centralsync-maven-plugin:centralsync-maven-plugin:sync 129 | fi 130 | 131 | # If we are on a release tag, the following will update any version references and push a version tag for deployment. 132 | elif build_started_by_tag; then 133 | safe_checkout_remote_branch 134 | ./mvnw --batch-mode -s ./.settings.xml -Prelease -nsu -DreleaseVersion="$(release_version)" -Darguments="-DskipTests" release:prepare 135 | fi 136 | 137 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | # avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in %* 125 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 126 | if ERRORLEVEL 1 goto error 127 | goto end 128 | 129 | :error 130 | set ERROR_CODE=1 131 | 132 | :end 133 | @endlocal & set ERROR_CODE=%ERROR_CODE% 134 | 135 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 136 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 137 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 138 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 139 | :skipRcPost 140 | 141 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 142 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 143 | 144 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 145 | 146 | exit /B %ERROR_CODE% 147 | -------------------------------------------------------------------------------- /opentracing-spring-web/src/test/java/io/opentracing/contrib/spring/web/client/TracingAsyncRestTemplateTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016-2019 The OpenTracing Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package io.opentracing.contrib.spring.web.client; 15 | 16 | import io.opentracing.Scope; 17 | import io.opentracing.Span; 18 | import io.opentracing.mock.MockSpan; 19 | import io.opentracing.tag.Tags; 20 | import org.junit.Assert; 21 | import org.junit.Test; 22 | import org.springframework.http.ResponseEntity; 23 | import org.springframework.util.concurrent.ListenableFuture; 24 | import org.springframework.web.client.AsyncRestTemplate; 25 | 26 | import java.util.ArrayList; 27 | import java.util.Collections; 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | import java.util.concurrent.ExecutionException; 32 | import java.util.concurrent.ExecutorService; 33 | import java.util.concurrent.Executors; 34 | import java.util.concurrent.Future; 35 | import java.util.concurrent.TimeUnit; 36 | 37 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 38 | import static com.github.tomakehurst.wiremock.client.WireMock.get; 39 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; 40 | import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; 41 | 42 | /** 43 | * @author Pavol Loffay 44 | */ 45 | public class TracingAsyncRestTemplateTest extends AbstractTracingClientTest { 46 | 47 | public TracingAsyncRestTemplateTest() { 48 | super(tracer -> { 49 | final AsyncRestTemplate restTemplate = new AsyncRestTemplate(); 50 | restTemplate.setInterceptors(Collections.singletonList( 51 | new TracingAsyncRestTemplateInterceptor(tracer, 52 | Collections.singletonList(new RestTemplateSpanDecorator.StandardTags())))); 53 | 54 | return new Client() { 55 | @Override 56 | public ResponseEntity getForEntity(String url, Class clazz) { 57 | ListenableFuture> forEntity = restTemplate.getForEntity(url, clazz); 58 | try { 59 | // By converting to CompletableFuture<>, we ensure that the callbacks are finished even in 60 | // case of exception 61 | return forEntity.completable().get(); 62 | } catch (final ExecutionException e) { 63 | throw new RuntimeException(e.getCause()); 64 | } catch (final InterruptedException e) { 65 | e.printStackTrace(); 66 | Assert.fail(); 67 | return null; 68 | } 69 | } 70 | }; 71 | }, RestTemplateSpanDecorator.StandardTags.COMPONENT_NAME); 72 | } 73 | 74 | @Test 75 | public void testMultipleRequests() throws InterruptedException, ExecutionException { 76 | final String url = wireMockRule.url("/foo/"); 77 | int numberOfCalls = 1000; 78 | stubFor(get(urlPathMatching(".*/foo/.*")) 79 | .willReturn(aResponse().withStatus(200))); 80 | 81 | ExecutorService executorService = Executors.newFixedThreadPool(100); 82 | List> futures = new ArrayList<>(numberOfCalls); 83 | for (int i = 0; i < numberOfCalls; i++) { 84 | final String requestUrl = url + i; 85 | 86 | Span parentSpan = mockTracer.buildSpan("foo") 87 | .withTag("request-url", requestUrl) 88 | .start() ; 89 | futures.add(executorService.submit(() -> { 90 | try (final Scope span = mockTracer.activateSpan(parentSpan)) { 91 | client.getForEntity(requestUrl, String.class); 92 | } finally { 93 | parentSpan.finish(); 94 | } 95 | })); 96 | } 97 | 98 | // wait to finish all calls 99 | for (Future future: futures) { 100 | future.get(); 101 | } 102 | 103 | executorService.awaitTermination(1, TimeUnit.SECONDS); 104 | executorService.shutdown(); 105 | 106 | List mockSpans = mockTracer.finishedSpans(); 107 | Assert.assertEquals(numberOfCalls * 2, mockSpans.size()); 108 | 109 | final List parentSpans = new ArrayList<>(); 110 | final Map childSpans = new HashMap<>(); 111 | 112 | for (MockSpan mockSpan: mockSpans) { 113 | if (mockSpan.tags().containsKey("request-url")) { 114 | parentSpans.add(mockSpan); 115 | } else { 116 | childSpans.put(mockSpan.parentId(), mockSpan); 117 | } 118 | 119 | } 120 | 121 | Assert.assertEquals(numberOfCalls, parentSpans.size()); 122 | Assert.assertEquals(numberOfCalls, childSpans.size()); 123 | 124 | for (MockSpan parentSpan: parentSpans) { 125 | MockSpan childSpan = childSpans.get(parentSpan.context().spanId()); 126 | Assert.assertEquals(parentSpan.tags().get("request-url"), childSpan.tags().get(Tags.HTTP_URL.getKey())); 127 | 128 | Assert.assertEquals(parentSpan.context().traceId(), childSpan.context().traceId()); 129 | Assert.assertEquals(parentSpan.context().spanId(), childSpan.parentId()); 130 | Assert.assertEquals(0, childSpan.generatedErrors().size()); 131 | Assert.assertEquals(0, parentSpan.generatedErrors().size()); 132 | } 133 | } 134 | } 135 | --------------------------------------------------------------------------------