├── contrib ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── beans.xml │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── opentracing │ │ └── contrib │ │ ├── resolver │ │ ├── TracerFactory.java │ │ ├── TracerConverter.java │ │ ├── PriorityComparator.java │ │ └── TracerResolver.java │ │ ├── jaxrs2 │ │ ├── internal │ │ │ ├── CastUtils.java │ │ │ ├── SpanWrapper.java │ │ │ └── URIUtils.java │ │ ├── client │ │ │ ├── ClientHeadersInjectTextMap.java │ │ │ ├── TracingProperties.java │ │ │ ├── ClientTracingInterceptor.java │ │ │ ├── ClientSpanDecorator.java │ │ │ ├── ClientTracingFilter.java │ │ │ └── ClientTracingFeature.java │ │ ├── server │ │ │ ├── ServerHeadersExtractTextMap.java │ │ │ ├── ServerTracingInterceptor.java │ │ │ ├── ServerSpanDecorator.java │ │ │ ├── SpanFinishingFilter.java │ │ │ ├── OperationNameProvider.java │ │ │ ├── ServerTracingFilter.java │ │ │ └── ServerTracingDynamicFeature.java │ │ └── serialization │ │ │ ├── InterceptorSpanDecorator.java │ │ │ └── TracingInterceptor.java │ │ ├── web │ │ └── servlet │ │ │ └── filter │ │ │ ├── HttpServletRequestExtractAdapter.java │ │ │ ├── decorator │ │ │ └── ServletFilterHeaderSpanDecorator.java │ │ │ ├── ServletFilterSpanDecorator.java │ │ │ └── TracingFilter.java │ │ └── interceptor │ │ └── OpenTracingInterceptor.java └── pom.xml ├── CODEOWNERS ├── .github ├── project.yml ├── dependabot.yml └── workflows │ └── build.yml ├── tck ├── src │ └── test │ │ ├── resources │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── org.jboss.arquillian.core.spi.LoadableExtension │ │ └── arquillian.xml │ │ ├── tck-suite.xml │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── opentracing │ │ └── tck │ │ ├── ArquillianExtension.java │ │ ├── TracerProducer.java │ │ ├── ExceptionMapper.java │ │ ├── DeploymentProcessor.java │ │ ├── ResteasyClientTracingRegistrarProvider.java │ │ ├── ServletContextTracingInstaller.java │ │ └── TestApplication.java └── pom.xml ├── implementation ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ └── org.eclipse.microprofile.rest.client.spi.RestClientListener │ │ └── java │ │ └── io │ │ └── smallrye │ │ └── opentracing │ │ ├── SmallRyeLogging.java │ │ ├── OpenTracingAsyncInterceptorFactory.java │ │ ├── SmallRyeClientTracingFeature.java │ │ ├── SmallRyeRestClientListener.java │ │ ├── OpenTracingAsyncInterceptor.java │ │ └── SmallRyeTracingDynamicFeature.java └── pom.xml ├── .gitignore ├── release └── pom.xml ├── README.adoc ├── pom.xml └── LICENSE.md /contrib/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | .github @smallrye/opentracing-opentelemetry 2 | -------------------------------------------------------------------------------- /.github/project.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye OpenTracing 2 | release: 3 | current-version: 3.0.3 4 | next-version: 3.0.4-SNAPSHOT 5 | -------------------------------------------------------------------------------- /tck/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension: -------------------------------------------------------------------------------- 1 | io.smallrye.opentracing.tck.ArquillianExtension 2 | -------------------------------------------------------------------------------- /implementation/src/main/resources/META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientListener: -------------------------------------------------------------------------------- 1 | io.smallrye.opentracing.SmallRyeRestClientListener 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /tck/src/test/tck-suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/ArquillianExtension.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 4 | import org.jboss.arquillian.core.spi.LoadableExtension; 5 | 6 | /** 7 | * @author Pavol Loffay 8 | */ 9 | public class ArquillianExtension implements LoadableExtension { 10 | 11 | @Override 12 | public void register(ExtensionBuilder extensionBuilder) { 13 | extensionBuilder.service(ApplicationArchiveProcessor.class, DeploymentProcessor.class); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | !.mvn/wrapper/maven-wrapper.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | target 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | # Eclipse 27 | .project 28 | .classpath 29 | .settings 30 | 31 | .gitkeep 32 | .editorconfig 33 | 34 | # Intellij Idea 35 | *.iml 36 | .idea/ 37 | 38 | # formatter cache directories 39 | .cache 40 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/TracerProducer.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import jakarta.enterprise.context.ApplicationScoped; 4 | import jakarta.enterprise.inject.Default; 5 | import jakarta.enterprise.inject.Produces; 6 | import jakarta.inject.Singleton; 7 | 8 | import io.opentracing.Tracer; 9 | import io.opentracing.mock.MockTracer; 10 | 11 | /** 12 | * @author Pavol Loffay 13 | */ 14 | @ApplicationScoped 15 | public class TracerProducer { 16 | 17 | @Default 18 | @Produces 19 | @Singleton 20 | public Tracer tracer() { 21 | return new MockTracer(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tck/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/ExceptionMapper.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import jakarta.ws.rs.core.Response; 4 | import jakarta.ws.rs.core.Response.Status; 5 | import jakarta.ws.rs.ext.Provider; 6 | 7 | /** 8 | * Temporal fix to catch exceptions thrown in JAX-RS endpoints 9 | * See https://issues.jboss.org/browse/RESTEASY-1758 10 | * 11 | * @author Pavol Loffay 12 | */ 13 | @Provider 14 | public class ExceptionMapper implements jakarta.ws.rs.ext.ExceptionMapper { 15 | 16 | @Override 17 | public Response toResponse(RuntimeException exception) { 18 | return Response.status(Status.INTERNAL_SERVER_ERROR).entity(exception.getMessage()).build(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/opentracing/SmallRyeLogging.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing; 2 | 3 | import org.jboss.logging.Logger; 4 | import org.jboss.logging.annotations.LogMessage; 5 | import org.jboss.logging.annotations.Message; 6 | import org.jboss.logging.annotations.MessageLogger; 7 | 8 | @MessageLogger(projectCode = "SROPT", length = 5) 9 | public interface SmallRyeLogging { 10 | 11 | SmallRyeLogging log = Logger.getMessageLogger(SmallRyeLogging.class, SmallRyeLogging.class.getPackage().getName()); 12 | 13 | @LogMessage(level = Logger.Level.WARN) 14 | @Message(id = 1000, value = "Provided operation name does not match http-path or class-method. Using default class-method.") 15 | void operationNameNotMatch(); 16 | } 17 | -------------------------------------------------------------------------------- /release/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.smallrye 7 | smallrye-opentracing-parent 8 | 3.1.4-SNAPSHOT 9 | 10 | 11 | smallrye-opentracing-release 12 | 13 | Empty Release Project to Avoid Maven Bug 14 | Empty Release Project to Avoid Maven Bug 15 | 16 | pom 17 | 18 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/opentracing/OpenTracingAsyncInterceptorFactory.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing; 2 | 3 | import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptor; 4 | import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptorFactory; 5 | 6 | import io.opentracing.Tracer; 7 | 8 | /** 9 | * @author Pavol Loffay 10 | */ 11 | public class OpenTracingAsyncInterceptorFactory implements AsyncInvocationInterceptorFactory { 12 | 13 | private Tracer tracer; 14 | 15 | public OpenTracingAsyncInterceptorFactory(Tracer tracer) { 16 | this.tracer = tracer; 17 | } 18 | 19 | @Override 20 | public AsyncInvocationInterceptor newInterceptor() { 21 | return new OpenTracingAsyncInterceptor(tracer); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/opentracing/SmallRyeClientTracingFeature.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing; 2 | 3 | import jakarta.ws.rs.core.Feature; 4 | import jakarta.ws.rs.core.FeatureContext; 5 | 6 | import io.opentracing.Tracer; 7 | import io.smallrye.opentracing.contrib.jaxrs2.client.ClientTracingFeature; 8 | 9 | /** 10 | * @author Pavol Loffay 11 | */ 12 | public class SmallRyeClientTracingFeature implements Feature { 13 | 14 | private final ClientTracingFeature delegate; 15 | 16 | public SmallRyeClientTracingFeature(Tracer tracer) { 17 | this.delegate = new ClientTracingFeature.Builder(tracer) 18 | .withTraceSerialization(false) 19 | .build(); 20 | } 21 | 22 | @Override 23 | public boolean configure(FeatureContext context) { 24 | return this.delegate.configure(context); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/DeploymentProcessor.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import org.eclipse.microprofile.opentracing.ClientTracingRegistrarProvider; 4 | import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; 5 | import org.jboss.arquillian.test.spi.TestClass; 6 | import org.jboss.shrinkwrap.api.Archive; 7 | import org.jboss.shrinkwrap.api.spec.WebArchive; 8 | 9 | /** 10 | * @author Pavol Loffay 11 | */ 12 | public class DeploymentProcessor implements ApplicationArchiveProcessor { 13 | @Override 14 | public void process(Archive archive, TestClass testClass) { 15 | if (archive instanceof WebArchive) { 16 | WebArchive war = (WebArchive) archive; 17 | war.addClass(ServletContextTracingInstaller.class); 18 | war.addClass(TracerProducer.class); 19 | war.addAsServiceProvider(ClientTracingRegistrarProvider.class, ResteasyClientTracingRegistrarProvider.class); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/opentracing/SmallRyeRestClientListener.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing; 2 | 3 | import jakarta.enterprise.inject.spi.CDI; 4 | 5 | import org.eclipse.microprofile.opentracing.Traced; 6 | import org.eclipse.microprofile.rest.client.RestClientBuilder; 7 | import org.eclipse.microprofile.rest.client.spi.RestClientListener; 8 | 9 | import io.opentracing.Tracer; 10 | 11 | /** 12 | * @author Pavol Loffay 13 | */ 14 | public class SmallRyeRestClientListener implements RestClientListener { 15 | 16 | @Override 17 | public void onNewClient(Class clientInterface, RestClientBuilder restClientBuilder) { 18 | Traced traced = clientInterface.getAnnotation(Traced.class); 19 | if (traced != null && !traced.value()) { 20 | // tracing is disabled 21 | return; 22 | } 23 | 24 | Tracer tracer = CDI.current().select(Tracer.class).get(); 25 | restClientBuilder.register(new SmallRyeClientTracingFeature(tracer)); 26 | restClientBuilder.register(new OpenTracingAsyncInterceptorFactory(tracer)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/ResteasyClientTracingRegistrarProvider.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | import jakarta.enterprise.inject.spi.CDI; 7 | import jakarta.ws.rs.client.ClientBuilder; 8 | 9 | import org.eclipse.microprofile.opentracing.ClientTracingRegistrarProvider; 10 | 11 | import io.opentracing.Tracer; 12 | import io.opentracing.contrib.concurrent.TracedExecutorService; 13 | import io.smallrye.opentracing.SmallRyeClientTracingFeature; 14 | 15 | /** 16 | * @author Pavol Loffay 17 | */ 18 | public class ResteasyClientTracingRegistrarProvider implements ClientTracingRegistrarProvider { 19 | 20 | public ClientBuilder configure(ClientBuilder clientBuilder) { 21 | return configure(clientBuilder, Executors.newFixedThreadPool(10)); 22 | } 23 | 24 | public ClientBuilder configure(ClientBuilder clientBuilder, ExecutorService executorService) { 25 | Tracer tracer = CDI.current().select(Tracer.class).get(); 26 | return clientBuilder.executorService(new TracedExecutorService(executorService, tracer)) 27 | .register(new SmallRyeClientTracingFeature(tracer)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/opentracing/OpenTracingAsyncInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptor; 6 | 7 | import io.opentracing.Scope; 8 | import io.opentracing.Span; 9 | import io.opentracing.Tracer; 10 | 11 | /** 12 | * @author Pavol Loffay 13 | */ 14 | public class OpenTracingAsyncInterceptor implements AsyncInvocationInterceptor { 15 | 16 | private final Tracer tracer; 17 | private final CountDownLatch countDownLatch = new CountDownLatch(1); 18 | private Span span; 19 | private Scope scope; 20 | 21 | public OpenTracingAsyncInterceptor(Tracer tracer) { 22 | this.tracer = tracer; 23 | } 24 | 25 | @Override 26 | public void prepareContext() { 27 | span = tracer.activeSpan(); 28 | countDownLatch.countDown(); 29 | } 30 | 31 | @Override 32 | public void applyContext() { 33 | try { 34 | countDownLatch.await(); 35 | } catch (InterruptedException e) { 36 | } 37 | if (span != null) { 38 | scope = tracer.scopeManager().activate(span); 39 | } 40 | } 41 | 42 | @Override 43 | public void removeContext() { 44 | if (scope != null) { 45 | scope.close(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/resolver/TracerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2018 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-tracerresolver 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package io.smallrye.opentracing.contrib.resolver; 19 | 20 | import java.util.ServiceLoader; 21 | 22 | import io.opentracing.Tracer; 23 | 24 | /** 25 | * Represents a class that knows how to select and build an appropriate tracer. The factory is usually used in 26 | * conjunction with the {@link TracerResolver}, but other resolver implementations can also load factories via 27 | * Java's {@link ServiceLoader} 28 | */ 29 | public interface TracerFactory { 30 | 31 | /** 32 | * Returns the concrete tracer implementation. 33 | * 34 | * @return the tracer instance 35 | */ 36 | Tracer getTracer(); 37 | } 38 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/ServletContextTracingInstaller.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import java.util.EnumSet; 4 | 5 | import jakarta.servlet.DispatcherType; 6 | import jakarta.servlet.FilterRegistration.Dynamic; 7 | import jakarta.servlet.ServletContext; 8 | import jakarta.servlet.ServletContextEvent; 9 | import jakarta.servlet.ServletContextListener; 10 | import jakarta.servlet.annotation.WebListener; 11 | 12 | import io.smallrye.opentracing.SmallRyeTracingDynamicFeature; 13 | import io.smallrye.opentracing.contrib.jaxrs2.server.SpanFinishingFilter; 14 | 15 | /** 16 | * @author Pavol Loffay 17 | */ 18 | @WebListener 19 | public class ServletContextTracingInstaller implements ServletContextListener { 20 | 21 | @Override 22 | public void contextInitialized(ServletContextEvent servletContextEvent) { 23 | ServletContext servletContext = servletContextEvent.getServletContext(); 24 | servletContext.setInitParameter("resteasy.providers", 25 | SmallRyeTracingDynamicFeature.class.getName() + "," + ExceptionMapper.class.getName()); 26 | 27 | // Span finishing filter 28 | Dynamic filterRegistration = servletContext.addFilter("tracingFilter", new SpanFinishingFilter()); 29 | filterRegistration.setAsyncSupported(true); 30 | filterRegistration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "*"); 31 | } 32 | 33 | @Override 34 | public void contextDestroyed(ServletContextEvent servletContextEvent) { 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/internal/CastUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.internal; 17 | 18 | import java.util.logging.Logger; 19 | 20 | /** 21 | * @author Pavol Loffay 22 | */ 23 | public class CastUtils { 24 | private static final Logger log = Logger.getLogger(CastUtils.class.getName()); 25 | 26 | private CastUtils() { 27 | } 28 | 29 | /** 30 | * Casts given object to the given class. 31 | * 32 | * @param object 33 | * @param clazz 34 | * @param 35 | * @return casted object, or null if there is any error 36 | */ 37 | public static T cast(Object object, Class clazz) { 38 | if (object == null || clazz == null) { 39 | return null; 40 | } 41 | 42 | try { 43 | return clazz.cast(object); 44 | } catch (ClassCastException ex) { 45 | log.severe("Cannot cast to " + clazz.getName()); 46 | return null; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/client/ClientHeadersInjectTextMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.client; 17 | 18 | import java.util.Iterator; 19 | import java.util.Map; 20 | 21 | import jakarta.ws.rs.core.MultivaluedMap; 22 | 23 | import io.opentracing.propagation.TextMap; 24 | 25 | /** 26 | * Helper class used to add carrier data to HTTP headers. 27 | * 28 | * @author Pavol Loffay 29 | */ 30 | public class ClientHeadersInjectTextMap implements TextMap { 31 | 32 | private final MultivaluedMap headers; 33 | 34 | public ClientHeadersInjectTextMap(MultivaluedMap headers) { 35 | this.headers = headers; 36 | } 37 | 38 | @Override 39 | public Iterator> iterator() { 40 | throw new UnsupportedOperationException( 41 | ClientHeadersInjectTextMap.class.getName() + " should only be used with Tracer.inject()"); 42 | } 43 | 44 | @Override 45 | public void put(String key, String value) { 46 | headers.add(key, value); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: SmallRye Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - '.gitignore' 9 | - 'CODEOWNERS' 10 | - 'LICENSE' 11 | - 'NOTICE' 12 | - 'README*' 13 | pull_request: 14 | paths-ignore: 15 | - '.gitignore' 16 | - 'CODEOWNERS' 17 | - 'LICENSE' 18 | - 'NOTICE' 19 | - 'README*' 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | java: [11, 17] 27 | name: build with jdk ${{matrix.java}} 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | name: checkout 32 | 33 | - uses: actions/setup-java@v4 34 | name: set up jdk ${{matrix.java}} 35 | with: 36 | distribution: 'temurin' 37 | java-version: ${{matrix.java}} 38 | cache: 'maven' 39 | cache-dependency-path: '**/pom.xml' 40 | 41 | - name: build with maven 42 | run: mvn -B formatter:validate verify --file pom.xml 43 | 44 | - uses: actions/upload-artifact@v4 45 | name: tck-report 46 | with: 47 | name: tck-report-java-${{matrix.java}} 48 | path: tck/target/surefire-reports 49 | 50 | build-windows: 51 | runs-on: windows-latest 52 | strategy: 53 | matrix: 54 | java: [11, 17] 55 | name: build with jdk ${{matrix.java}} windows 56 | 57 | steps: 58 | - uses: actions/checkout@v4 59 | name: checkout 60 | 61 | - uses: actions/setup-java@v4 62 | name: set up jdk ${{matrix.java}} 63 | with: 64 | distribution: 'temurin' 65 | java-version: ${{matrix.java}} 66 | cache: 'maven' 67 | cache-dependency-path: '**/pom.xml' 68 | 69 | - name: build with maven 70 | run: mvn -B formatter:validate verify --file pom.xml -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/client/TracingProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.client; 17 | 18 | import io.opentracing.References; 19 | 20 | /** 21 | * @author Pavol Loffay 22 | */ 23 | public class TracingProperties { 24 | 25 | private TracingProperties() { 26 | } 27 | 28 | /** 29 | * Denotes a parent span context {@link References#CHILD_OF}. 30 | * If it is not specified a new trace will be started. 31 | * Set on {@link jakarta.ws.rs.client.Invocation#property(String, Object)}. 32 | */ 33 | public static final String CHILD_OF = ClientTracingFilter.class.getName() + "." + References.CHILD_OF; 34 | 35 | /** 36 | * Indicates whether request should be traced or not. If it is not 37 | * present and client is correctly configured request will be traced. 38 | * Value should be a boolean (trace disabled/enabled). 39 | * Set on {@link jakarta.ws.rs.client.Invocation#property(String, Object)}. 40 | */ 41 | public static final String TRACING_DISABLED = ClientTracingFilter.class.getName() + ".tracingDisabled"; 42 | } 43 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/internal/SpanWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.internal; 17 | 18 | import java.util.concurrent.atomic.AtomicBoolean; 19 | 20 | import io.opentracing.Scope; 21 | import io.opentracing.Span; 22 | 23 | /** 24 | * Wrapper class used for exchanging span between filters. 25 | * 26 | * @author Pavol Loffay 27 | */ 28 | public class SpanWrapper { 29 | 30 | public static final String PROPERTY_NAME = SpanWrapper.class.getName() + ".activeSpanWrapper"; 31 | 32 | private Scope scope; 33 | private Span span; 34 | private AtomicBoolean finished = new AtomicBoolean(); 35 | 36 | public SpanWrapper(Span span, Scope scope) { 37 | this.span = span; 38 | this.scope = scope; 39 | 40 | } 41 | 42 | public Span get() { 43 | return span; 44 | } 45 | 46 | public Scope getScope() { 47 | return scope; 48 | } 49 | 50 | public synchronized void finish() { 51 | if (!finished.get()) { 52 | finished.set(true); 53 | span.finish(); 54 | } 55 | } 56 | 57 | public boolean isFinished() { 58 | return finished.get(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/client/ClientTracingInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.client; 17 | 18 | import static io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper.PROPERTY_NAME; 19 | 20 | import java.util.List; 21 | 22 | import jakarta.annotation.Priority; 23 | import jakarta.ws.rs.Priorities; 24 | import jakarta.ws.rs.ext.InterceptorContext; 25 | 26 | import io.opentracing.Tracer; 27 | import io.smallrye.opentracing.contrib.jaxrs2.internal.CastUtils; 28 | import io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper; 29 | import io.smallrye.opentracing.contrib.jaxrs2.serialization.InterceptorSpanDecorator; 30 | import io.smallrye.opentracing.contrib.jaxrs2.serialization.TracingInterceptor; 31 | 32 | @Priority(Priorities.ENTITY_CODER) 33 | public class ClientTracingInterceptor extends TracingInterceptor { 34 | 35 | public ClientTracingInterceptor(Tracer tracer, List spanDecorators) { 36 | super(tracer, spanDecorators); 37 | } 38 | 39 | @Override 40 | protected SpanWrapper findSpan(InterceptorContext context) { 41 | return CastUtils.cast(context.getProperty(PROPERTY_NAME), SpanWrapper.class); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/ServerHeadersExtractTextMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import java.util.Iterator; 19 | import java.util.Map; 20 | 21 | import jakarta.ws.rs.core.MultivaluedMap; 22 | 23 | import io.opentracing.propagation.TextMap; 24 | import io.smallrye.opentracing.contrib.web.servlet.filter.HttpServletRequestExtractAdapter; 25 | 26 | /** 27 | * Helper class used to iterate over HTTP headers. 28 | * 29 | * @author Pavol Loffay 30 | */ 31 | public class ServerHeadersExtractTextMap implements TextMap { 32 | 33 | private final MultivaluedMap headers; 34 | 35 | public ServerHeadersExtractTextMap(MultivaluedMap headers) { 36 | this.headers = headers; 37 | } 38 | 39 | @Override 40 | public Iterator> iterator() { 41 | return new HttpServletRequestExtractAdapter.MultivaluedMapFlatIterator<>(headers.entrySet()); 42 | } 43 | 44 | @Override 45 | public void put(String key, String value) { 46 | throw new UnsupportedOperationException( 47 | ServerHeadersExtractTextMap.class.getName() + " should only be used with Tracer.extract()"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/internal/URIUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.internal; 17 | 18 | import java.net.MalformedURLException; 19 | import java.net.URI; 20 | import java.net.URL; 21 | 22 | /** 23 | * @author Pavol Loffay 24 | */ 25 | public class URIUtils { 26 | private URIUtils() { 27 | } 28 | 29 | /** 30 | * Returns path of given URI. If the first character of path is '/' then it is removed. 31 | * 32 | * @param uri 33 | * @return path or null 34 | */ 35 | public static String path(URI uri) { 36 | String path = uri.getPath(); 37 | if (path != null && path.startsWith("/")) { 38 | path = path.substring(1); 39 | } 40 | 41 | return path; 42 | } 43 | 44 | /** 45 | * Returns string representation of supplied URL. 46 | * 47 | * @param uri 48 | * @return string URL or null 49 | */ 50 | public static String url(URI uri) { 51 | String urlStr = null; 52 | try { 53 | URL url = uri.toURL(); 54 | urlStr = url.toString(); 55 | } catch (MalformedURLException e) { 56 | // ignoring returning null 57 | } 58 | 59 | return urlStr; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/serialization/InterceptorSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.serialization; 17 | 18 | import jakarta.ws.rs.ext.InterceptorContext; 19 | 20 | import io.opentracing.Span; 21 | 22 | public interface InterceptorSpanDecorator { 23 | 24 | /** 25 | * Decorate spans by outgoing object. 26 | * 27 | * @param context 28 | * @param span 29 | */ 30 | void decorateRead(InterceptorContext context, Span span); 31 | 32 | /** 33 | * Decorate spans by outgoing object. 34 | * 35 | * @param context 36 | * @param span 37 | */ 38 | void decorateWrite(InterceptorContext context, Span span); 39 | 40 | /** 41 | * Adds tags: \"media.type\", \"entity.type\" 42 | */ 43 | InterceptorSpanDecorator STANDARD_TAGS = new InterceptorSpanDecorator() { 44 | @Override 45 | public void decorateRead(InterceptorContext context, Span span) { 46 | span.setTag("media.type", context.getMediaType().toString()); 47 | span.setTag("entity.type", context.getType().getName()); 48 | } 49 | 50 | @Override 51 | public void decorateWrite(InterceptorContext context, Span span) { 52 | decorateRead(context, span); 53 | } 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /contrib/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.smallrye 6 | smallrye-opentracing-parent 7 | 3.1.4-SNAPSHOT 8 | 9 | 10 | smallrye-opentracing-contrib 11 | SmallRye: MicroProfile OpenTracing Contrib 12 | Fork of io.opentracing.contrib projects 13 | 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-javadoc-plugin 19 | 20 | false 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | jakarta.enterprise 29 | jakarta.enterprise.cdi-api 30 | provided 31 | 32 | 33 | jakarta.ws.rs 34 | jakarta.ws.rs-api 35 | provided 36 | 37 | 38 | jakarta.servlet 39 | jakarta.servlet-api 40 | 41 | 42 | io.opentracing 43 | opentracing-api 44 | 45 | 46 | io.opentracing 47 | opentracing-noop 48 | 49 | 50 | io.opentracing 51 | opentracing-util 52 | 53 | 54 | io.opentracing.contrib 55 | opentracing-concurrent 56 | 57 | 58 | org.eclipse.microprofile.opentracing 59 | microprofile-opentracing-api 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/resolver/TracerConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-tracerresolver 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package io.smallrye.opentracing.contrib.resolver; 19 | 20 | import io.opentracing.Tracer; 21 | 22 | /** 23 | * Function converting an existing {@link Tracer}. 24 | *

25 | * This can be useful for wrapping tracers: 26 | * 27 | *

28 |  * 
29 |  * public final class FooWrapperConverter implements TracerConverter {
30 |  *     public Tracer convert(Tracer existingTracer) {
31 |  *         return new FooTracerWrapper(existingTracer);
32 |  *     }
33 |  * }
34 |  * 
35 |  * 
36 | *

37 | * If there are multiple {@linkplain TracerConverter} implementations resolved, 38 | * they will be applied in the order of their {@literal @}Priority annotation: 39 | *

    40 | *
  1. First, non-negative priority is applied in natural order (e.g. {@code 0}, {@code 1}, {@code 2}, ...).
  2. 41 | *
  3. Next, objects without {@literal @}Priority annotation are applied 42 | * by assigning a default priority of {@link Integer#MAX_VALUE}.
  4. 43 | *
  5. Finally, negative priority is applied in reverse-natural order (e.g. {@code -1}, {@code -2}, {@code -3}, ...).
  6. 44 | *
45 | *

46 | * The order of objects with equal (implicit) priority is undefined. 47 | * 48 | * @author Sjoerd Talsma 49 | */ 50 | public interface TracerConverter { 51 | 52 | /** 53 | * Function that converts a {@link Tracer}. 54 | *

55 | * It may either manipulate the tracer or return an entirely new {@linkplain Tracer} instance. 56 | * 57 | * @param existingTracer The existing tracer to be converted. 58 | * @return The converted tracer. 59 | */ 60 | Tracer convert(Tracer existingTracer); 61 | 62 | } 63 | -------------------------------------------------------------------------------- /implementation/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.smallrye 6 | smallrye-opentracing-parent 7 | 3.1.4-SNAPSHOT 8 | 9 | 10 | smallrye-opentracing 11 | SmallRye: MicroProfile OpenTracing Implementation 12 | 13 | 14 | 15 | org.eclipse.microprofile.opentracing 16 | microprofile-opentracing-api 17 | 18 | 19 | org.eclipse.microprofile.config 20 | microprofile-config-api 21 | 22 | 23 | org.eclipse.microprofile.rest.client 24 | microprofile-rest-client-api 25 | 26 | 27 | 28 | io.smallrye 29 | smallrye-opentracing-contrib 30 | 31 | 32 | 33 | jakarta.enterprise 34 | jakarta.enterprise.cdi-api 35 | provided 36 | 37 | 38 | jakarta.ws.rs 39 | jakarta.ws.rs-api 40 | provided 41 | 42 | 43 | 44 | org.jboss.logging 45 | jboss-logging 46 | 47 | 48 | org.jboss.logging 49 | jboss-logging-annotations 50 | 51 | 52 | org.jboss.logging 53 | jboss-logging-processor 54 | 55 | 56 | 57 | 58 | 59 | coverage 60 | 61 | @{jacocoArgLine} 62 | 63 | 64 | 65 | 66 | org.jacoco 67 | jacoco-maven-plugin 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /implementation/src/main/java/io/smallrye/opentracing/SmallRyeTracingDynamicFeature.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing; 2 | 3 | import java.util.Optional; 4 | 5 | import jakarta.enterprise.inject.Instance; 6 | import jakarta.enterprise.inject.spi.CDI; 7 | import jakarta.ws.rs.container.DynamicFeature; 8 | import jakarta.ws.rs.container.ResourceInfo; 9 | import jakarta.ws.rs.core.FeatureContext; 10 | import jakarta.ws.rs.ext.Provider; 11 | 12 | import org.eclipse.microprofile.config.Config; 13 | import org.eclipse.microprofile.config.ConfigProvider; 14 | 15 | import io.opentracing.Tracer; 16 | import io.smallrye.opentracing.contrib.jaxrs2.server.OperationNameProvider.ClassNameOperationName; 17 | import io.smallrye.opentracing.contrib.jaxrs2.server.OperationNameProvider.WildcardOperationName; 18 | import io.smallrye.opentracing.contrib.jaxrs2.server.ServerTracingDynamicFeature; 19 | import io.smallrye.opentracing.contrib.jaxrs2.server.ServerTracingDynamicFeature.Builder; 20 | 21 | /** 22 | * @author Pavol Loffay 23 | */ 24 | @Provider 25 | public class SmallRyeTracingDynamicFeature implements DynamicFeature { 26 | 27 | private final ServerTracingDynamicFeature delegate; 28 | 29 | public SmallRyeTracingDynamicFeature() { 30 | Instance tracerInstance = CDI.current().select(Tracer.class); 31 | Config config = ConfigProvider.getConfig(); 32 | Optional skipPattern = config.getOptionalValue("mp.opentracing.server.skip-pattern", String.class); 33 | Optional operationNameProvider = config.getOptionalValue("mp.opentracing.server.operation-name-provider", 34 | String.class); 35 | 36 | Builder builder = new Builder(tracerInstance.get()) 37 | .withOperationNameProvider(ClassNameOperationName.newBuilder()) 38 | .withTraceSerialization(false); 39 | if (skipPattern.isPresent()) { 40 | builder.withSkipPattern(skipPattern.get()); 41 | } 42 | if (operationNameProvider.isPresent()) { 43 | if ("http-path".equalsIgnoreCase(operationNameProvider.get())) { 44 | builder.withOperationNameProvider(WildcardOperationName.newBuilder()); 45 | } else if (!"class-method".equalsIgnoreCase(operationNameProvider.get())) { 46 | SmallRyeLogging.log.operationNameNotMatch(); 47 | } 48 | } 49 | this.delegate = builder.build(); 50 | } 51 | 52 | @Override 53 | public void configure(ResourceInfo resourceInfo, FeatureContext context) { 54 | this.delegate.configure(resourceInfo, context); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/ServerTracingInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import static io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper.PROPERTY_NAME; 19 | 20 | import java.util.List; 21 | 22 | import jakarta.annotation.Priority; 23 | import jakarta.servlet.http.HttpServletRequest; 24 | import jakarta.ws.rs.Priorities; 25 | import jakarta.ws.rs.core.Context; 26 | import jakarta.ws.rs.ext.InterceptorContext; 27 | 28 | import io.opentracing.Tracer; 29 | import io.smallrye.opentracing.contrib.jaxrs2.internal.CastUtils; 30 | import io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper; 31 | import io.smallrye.opentracing.contrib.jaxrs2.serialization.InterceptorSpanDecorator; 32 | import io.smallrye.opentracing.contrib.jaxrs2.serialization.TracingInterceptor; 33 | 34 | @Priority(Priorities.ENTITY_CODER) 35 | public class ServerTracingInterceptor extends TracingInterceptor { 36 | /** 37 | * Apache CFX does not seem to publish the PROPERTY_NAME into the Interceptor context. 38 | * Use the current HttpServletRequest to lookup the current span wrapper. 39 | */ 40 | @Context 41 | private HttpServletRequest servletReq; 42 | 43 | public ServerTracingInterceptor(Tracer tracer, List spanDecorators) { 44 | super(tracer, spanDecorators); 45 | } 46 | 47 | @Override 48 | protected SpanWrapper findSpan(InterceptorContext context) { 49 | SpanWrapper spanWrapper = CastUtils.cast(context.getProperty(PROPERTY_NAME), SpanWrapper.class); 50 | if (spanWrapper == null && servletReq != null) { 51 | spanWrapper = CastUtils 52 | .cast(servletReq.getAttribute(PROPERTY_NAME), SpanWrapper.class); 53 | } 54 | return spanWrapper; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/ServerSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import jakarta.ws.rs.container.ContainerRequestContext; 19 | import jakarta.ws.rs.container.ContainerResponseContext; 20 | 21 | import io.opentracing.Span; 22 | import io.opentracing.tag.Tags; 23 | import io.smallrye.opentracing.contrib.jaxrs2.internal.URIUtils; 24 | 25 | /** 26 | * @author Pavol Loffay 27 | */ 28 | public interface ServerSpanDecorator { 29 | 30 | /** 31 | * Decorate span by incoming object. 32 | * 33 | * @param requestContext 34 | * @param span 35 | */ 36 | void decorateRequest(ContainerRequestContext requestContext, Span span); 37 | 38 | /** 39 | * Decorate spans by outgoing object. 40 | * 41 | * @param responseContext 42 | * @param span 43 | */ 44 | void decorateResponse(ContainerResponseContext responseContext, Span span); 45 | 46 | /** 47 | * Adds standard tags: {@link Tags#SPAN_KIND}, 48 | * {@link Tags#HTTP_METHOD}, {@link Tags#HTTP_URL} and 49 | * {@link Tags#HTTP_STATUS} 50 | */ 51 | ServerSpanDecorator STANDARD_TAGS = new ServerSpanDecorator() { 52 | @Override 53 | public void decorateRequest(ContainerRequestContext requestContext, Span span) { 54 | Tags.COMPONENT.set(span, "jaxrs"); 55 | Tags.HTTP_METHOD.set(span, requestContext.getMethod()); 56 | 57 | String url = URIUtils.url(requestContext.getUriInfo().getRequestUri()); 58 | if (url != null) { 59 | Tags.HTTP_URL.set(span, url); 60 | } 61 | } 62 | 63 | @Override 64 | public void decorateResponse(ContainerResponseContext responseContext, Span span) { 65 | Tags.HTTP_STATUS.set(span, responseContext.getStatus()); 66 | } 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/client/ClientSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.client; 17 | 18 | import jakarta.ws.rs.client.ClientRequestContext; 19 | import jakarta.ws.rs.client.ClientResponseContext; 20 | 21 | import io.opentracing.Span; 22 | import io.opentracing.tag.Tags; 23 | import io.smallrye.opentracing.contrib.jaxrs2.internal.URIUtils; 24 | 25 | /** 26 | * @author Pavol Loffay 27 | */ 28 | public interface ClientSpanDecorator { 29 | 30 | /** 31 | * Decorate get by incoming object. 32 | * 33 | * @param requestContext 34 | * @param span 35 | */ 36 | void decorateRequest(ClientRequestContext requestContext, Span span); 37 | 38 | /** 39 | * Decorate spans by outgoing object. 40 | * 41 | * @param responseContext 42 | * @param span 43 | */ 44 | void decorateResponse(ClientResponseContext responseContext, Span span); 45 | 46 | /** 47 | * Adds standard tags: {@link Tags#SPAN_KIND}, 48 | * {@link Tags#PEER_HOSTNAME}, {@link Tags#PEER_PORT}, 49 | * {@link Tags#HTTP_METHOD}, {@link Tags#HTTP_URL} and 50 | * {@link Tags#HTTP_STATUS} 51 | */ 52 | ClientSpanDecorator STANDARD_TAGS = new ClientSpanDecorator() { 53 | @Override 54 | public void decorateRequest(ClientRequestContext requestContext, Span span) { 55 | Tags.COMPONENT.set(span, "jaxrs"); 56 | Tags.PEER_HOSTNAME.set(span, requestContext.getUri().getHost()); 57 | Tags.PEER_PORT.set(span, requestContext.getUri().getPort()); 58 | 59 | Tags.HTTP_METHOD.set(span, requestContext.getMethod()); 60 | 61 | String url = URIUtils.url(requestContext.getUri()); 62 | if (url != null) { 63 | Tags.HTTP_URL.set(span, url); 64 | } 65 | } 66 | 67 | @Override 68 | public void decorateResponse(ClientResponseContext responseContext, Span span) { 69 | Tags.HTTP_STATUS.set(span, responseContext.getStatus()); 70 | } 71 | }; 72 | 73 | /** 74 | * As operation name provides HTTP path. If there are path parameters used in URL then 75 | * spans for the same requests would have different operation names, therefore use carefully. 76 | */ 77 | ClientSpanDecorator HTTP_PATH_OPERATION_NAME = new ClientSpanDecorator() { 78 | @Override 79 | public void decorateRequest(ClientRequestContext clientRequestContext, Span span) { 80 | span.setOperationName(URIUtils.path(clientRequestContext.getUri())); 81 | } 82 | 83 | @Override 84 | public void decorateResponse(ClientResponseContext response, Span span) { 85 | } 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :ci: https://github.com/smallrye/smallrye-opentracing/actions/workflows/build.yml/ 2 | 3 | image:https://github.com/smallrye/smallrye-opentracing/actions/workflows/build.yml/badge.svg?branch=main[link={ci}] 4 | image:https://img.shields.io/github/license/smallrye/smallrye-opentracing.svg["License", link="http://www.apache.org/licenses/LICENSE-2.0"] 5 | image:https://img.shields.io/maven-central/v/io.smallrye/smallrye-opentracing?color=green[] 6 | 7 | = SmallRye OpenTracing (Deprecated) 8 | 9 | OpenTracing is no longer under development and was replaced by OpenTelemetry Tracing. In the future, 10 | please refer to SmallRye OpenTelemetry: https://github.com/smallrye/smallrye-opentelemetry 11 | 12 | ___ 13 | 14 | SmallRye OpenTracing is an implementation of https://github.com/eclipse/microprofile-opentracing meant 15 | to be reusable for different vendors. 16 | 17 | == How to use 18 | 19 | The following components have to be added to deployment to pass `microprofile-opentracing-tck`: 20 | 21 | === Server side JAX-RS 22 | 23 | Server side JAX-RS tracing integration is provided by JAX-RS `SmallRyeTracingDynamicFeature` and 24 | servlet filter `SpanFinishingFilter` which finishes the span started in JAX-RS filter. 25 | 26 | The installation is JAX-RS and server implementation specific. 27 | For example in RestEasy `DynamicFeature` it can be enabled by specifying 28 | `resteasy.providers` in servlet context init parameters. The following code snippet demonstrates 29 | possible installation. 30 | 31 | ```java 32 | public class ServletContextTracingInstaller implements ServletContextListener { 33 | 34 | @Override 35 | public void contextInitialized(ServletContextEvent servletContextEvent) { 36 | ServletContext servletContext = servletContextEvent.getServletContext(); 37 | servletContext.setInitParameter("resteasy.providers", SmallRyeTracingDynamicFeature.class.getName()); 38 | 39 | Dynamic filterRegistration = servletContext.addFilter("tracingFilter", new SpanFinishingFilter()); 40 | filterRegistration.setAsyncSupported(true); 41 | filterRegistration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "*"); 42 | } 43 | } 44 | ``` 45 | 46 | === Client side JAX-RS 47 | 48 | Vendor has to implement `ClientTracingRegistrarProvider` and specify it in 49 | `META-INF/services/org.eclipse.microprofile.opentracing.ClientTracingRegistrarProvider`. 50 | 51 | This project provides `SmallRyeClientTracingFeature` with tracing integration. The feature 52 | has to be registered to `ClientBuilder` in vendor specific implementation of `ClientTracingRegistrarProvider`. 53 | Client side tracing usually requires more components, for example OpenTracing-aware `AsyncExecutor`. 54 | 55 | === MicroProfile Rest Client 56 | The Rest Client instrumentation is provided in `SmallRyeRestClientListener` which has to be registered 57 | in `META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientListener`. 58 | 59 | === CDI 60 | 61 | The `@Traced` aspects of the specification is provided by the `OpenTracingInterceptor`, from the 62 | link:https://github.com/opentracing-contrib/java-interceptors[OpenTracing Contrib Java Interceptors] project. 63 | 64 | === Tracer producer 65 | 66 | Vendor has to provide CDI tracer producer. It is not provided by this library as the 67 | tracer resolution is not defined by MicroProfile specification. 68 | 69 | == Develop 70 | 71 | ```bash 72 | mvn clean install 73 | ``` 74 | 75 | === Debug 76 | 77 | Debug of the deployment can be enabled in `arquillian.xml` configuration file. 78 | 79 | Run the following to debug tests on port `8788`. 80 | ```bash 81 | mvn -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8788 -Xnoagent -Djava.compiler=NONE" test 82 | ``` 83 | -------------------------------------------------------------------------------- /tck/src/test/java/io/smallrye/opentracing/tck/TestApplication.java: -------------------------------------------------------------------------------- 1 | package io.smallrye.opentracing.tck; 2 | 3 | import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; 4 | 5 | import java.io.IOException; 6 | import java.net.HttpURLConnection; 7 | import java.net.URL; 8 | 9 | import jakarta.enterprise.context.ApplicationScoped; 10 | import jakarta.enterprise.context.RequestScoped; 11 | import jakarta.enterprise.inject.spi.CDI; 12 | import jakarta.inject.Inject; 13 | import jakarta.servlet.annotation.WebServlet; 14 | import jakarta.servlet.http.HttpServlet; 15 | import jakarta.servlet.http.HttpServletRequest; 16 | import jakarta.servlet.http.HttpServletResponse; 17 | import jakarta.ws.rs.ApplicationPath; 18 | import jakarta.ws.rs.GET; 19 | import jakarta.ws.rs.Path; 20 | import jakarta.ws.rs.client.ClientBuilder; 21 | import jakarta.ws.rs.client.WebTarget; 22 | import jakarta.ws.rs.core.Response; 23 | 24 | import org.jboss.arquillian.container.test.api.Deployment; 25 | import org.jboss.arquillian.container.test.api.RunAsClient; 26 | import org.jboss.arquillian.test.api.ArquillianResource; 27 | import org.jboss.arquillian.testng.Arquillian; 28 | import org.jboss.shrinkwrap.api.ArchivePaths; 29 | import org.jboss.shrinkwrap.api.ShrinkWrap; 30 | import org.jboss.shrinkwrap.api.asset.EmptyAsset; 31 | import org.jboss.shrinkwrap.api.spec.WebArchive; 32 | import org.testng.Assert; 33 | import org.testng.annotations.Test; 34 | 35 | public class TestApplication extends Arquillian { 36 | /** 37 | * The base URL for the container under test 38 | */ 39 | @ArquillianResource 40 | private URL baseURL; 41 | 42 | @Deployment 43 | public static WebArchive createDeployment() { 44 | return ShrinkWrap 45 | .create(WebArchive.class) 46 | .addClass(TestServlet.class) 47 | .addClass(RestApplication.class) 48 | .addClass(TestEndpoint.class) 49 | .addAsWebInfResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml")); 50 | } 51 | 52 | @Test 53 | @RunAsClient 54 | public void servlet() { 55 | String uri = baseURL.toExternalForm() + "servlet"; 56 | System.out.println("uri = " + uri); 57 | WebTarget echoEndpointTarget = ClientBuilder.newClient().target(uri); 58 | Response response = echoEndpointTarget.request(TEXT_PLAIN).get(); 59 | Assert.assertEquals(response.getStatus(), HttpURLConnection.HTTP_OK); 60 | } 61 | 62 | @Test 63 | @RunAsClient 64 | public void rest() { 65 | String uri = baseURL.toExternalForm() + "rest"; 66 | System.out.println("uri = " + uri); 67 | WebTarget echoEndpointTarget = ClientBuilder.newClient().target(uri); 68 | Response response = echoEndpointTarget.request(TEXT_PLAIN).get(); 69 | Assert.assertEquals(response.getStatus(), HttpURLConnection.HTTP_OK); 70 | } 71 | 72 | @WebServlet(urlPatterns = "/servlet") 73 | public static class TestServlet extends HttpServlet { 74 | @Override 75 | protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException { 76 | resp.getWriter().write(CDI.current().select(HelloBean.class).get().hello()); 77 | } 78 | } 79 | 80 | @ApplicationPath("/rest") 81 | public static class RestApplication extends jakarta.ws.rs.core.Application { 82 | 83 | } 84 | 85 | @RequestScoped 86 | @Path("/") 87 | public static class TestEndpoint { 88 | @Inject 89 | HelloBean helloBean; 90 | 91 | @GET 92 | public String hello() { 93 | return helloBean.hello(); 94 | } 95 | } 96 | 97 | @ApplicationScoped 98 | public static class HelloBean { 99 | public String hello() { 100 | return "hello"; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/resolver/PriorityComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-tracerresolver 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package io.smallrye.opentracing.contrib.resolver; 19 | 20 | import static java.lang.Math.abs; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.Comparator; 25 | 26 | /** 27 | * Comparator for classes that may or may not contain a {@literal @}Priority annotation 28 | * on their class or superclasses. 29 | *

30 | * The priority is applied as follows: 31 | *

    32 | *
  1. First, non-negative priority is applied in natural order (e.g. {@code 0}, {@code 1}, {@code 2}, ...).
  2. 33 | *
  3. Next, objects without {@literal @}Priority annotation are applied 34 | * by assigning a {@link #UNDEFINED_PRIORITY default priority} of {@link Integer#MAX_VALUE}.
  4. 35 | *
  5. Finally, negative priority is applied in reverse-natural order (e.g. {@code -1}, {@code -2}, {@code -3}, ...).
  6. 36 | *
37 | *

38 | * The order of objects with equal (implicit) priority is undefined. 39 | * 40 | * @author Sjoerd Talsma 41 | */ 42 | final class PriorityComparator implements Comparator { 43 | private static final int UNDEFINED_PRIORITY = Integer.MAX_VALUE; 44 | private static final boolean PRIORITY_AVAILABLE = isPriorityAnnotationAvailable(); 45 | 46 | private static final PriorityComparator INSTANCE = new PriorityComparator(); 47 | 48 | private PriorityComparator() { 49 | } 50 | 51 | static Iterable prioritize(Iterable iterable) { 52 | if (!PRIORITY_AVAILABLE) 53 | return iterable; 54 | ArrayList list = new ArrayList(); 55 | for (T value : iterable) 56 | list.add(value); 57 | Collections.sort(list, INSTANCE); 58 | return list; 59 | } 60 | 61 | @Override 62 | public int compare(Object value1, Object value2) { 63 | return comparePriority(priorityOf(value1), priorityOf(value2)); 64 | } 65 | 66 | private static int comparePriority(int prio1, int prio2) { 67 | return prio1 == prio2 ? 0 68 | : prio1 < 0 ? (prio2 < 0 ? comparePriority(abs(prio1), abs(prio2)) : 1) 69 | : prio2 < 0 ? -1 70 | : prio1 < prio2 ? -1 : 1; 71 | } 72 | 73 | private static int priorityOf(Object value) { 74 | if (value == null) 75 | return UNDEFINED_PRIORITY; 76 | Class type = value instanceof Class ? (Class) value : value.getClass(); 77 | // Don't import Priority. Loading the PriorityComparator class would fail if Priority isn't there at runtime! 78 | jakarta.annotation.Priority priority = type.getAnnotation(jakarta.annotation.Priority.class); 79 | return priority != null ? priority.value() : priorityOf(type.getSuperclass()); 80 | } 81 | 82 | private static boolean isPriorityAnnotationAvailable() { 83 | try { 84 | return Class.forName("jakarta.annotation.Priority") != null; 85 | } catch (ClassNotFoundException cnfe) { 86 | return false; 87 | } catch (LinkageError le) { 88 | return false; 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/web/servlet/filter/HttpServletRequestExtractAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-web-servlet-filter 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.web.servlet.filter; 17 | 18 | import java.util.AbstractMap; 19 | import java.util.ArrayList; 20 | import java.util.Enumeration; 21 | import java.util.HashMap; 22 | import java.util.Iterator; 23 | import java.util.List; 24 | import java.util.Map; 25 | import java.util.Set; 26 | 27 | import jakarta.servlet.http.HttpServletRequest; 28 | 29 | import io.opentracing.propagation.TextMap; 30 | 31 | /** 32 | * Tracer extract adapter for {@link HttpServletRequest}. 33 | * 34 | * @author Pavol Loffay 35 | */ 36 | public class HttpServletRequestExtractAdapter implements TextMap { 37 | 38 | private Map> headers; 39 | 40 | public HttpServletRequestExtractAdapter(HttpServletRequest httpServletRequest) { 41 | headers = servletHeadersToMultiMap(httpServletRequest); 42 | } 43 | 44 | @Override 45 | public Iterator> iterator() { 46 | return new MultivaluedMapFlatIterator<>(headers.entrySet()); 47 | } 48 | 49 | @Override 50 | public void put(String key, String value) { 51 | throw new UnsupportedOperationException("This class should be used only with Tracer.inject()!"); 52 | } 53 | 54 | protected Map> servletHeadersToMultiMap(HttpServletRequest httpServletRequest) { 55 | Map> headersResult = new HashMap<>(); 56 | 57 | Enumeration headerNamesIt = httpServletRequest.getHeaderNames(); 58 | while (headerNamesIt.hasMoreElements()) { 59 | String headerName = headerNamesIt.nextElement(); 60 | 61 | Enumeration valuesIt = httpServletRequest.getHeaders(headerName); 62 | List valuesList = new ArrayList<>(1); 63 | while (valuesIt.hasMoreElements()) { 64 | valuesList.add(valuesIt.nextElement()); 65 | } 66 | 67 | headersResult.put(headerName, valuesList); 68 | } 69 | 70 | return headersResult; 71 | } 72 | 73 | public static final class MultivaluedMapFlatIterator implements Iterator> { 74 | 75 | private final Iterator>> mapIterator; 76 | private Map.Entry> mapEntry; 77 | private Iterator listIterator; 78 | 79 | public MultivaluedMapFlatIterator(Set>> multiValuesEntrySet) { 80 | this.mapIterator = multiValuesEntrySet.iterator(); 81 | } 82 | 83 | @Override 84 | public boolean hasNext() { 85 | if (listIterator != null && listIterator.hasNext()) { 86 | return true; 87 | } 88 | 89 | return mapIterator.hasNext(); 90 | } 91 | 92 | @Override 93 | public Map.Entry next() { 94 | if (mapEntry == null || (!listIterator.hasNext() && mapIterator.hasNext())) { 95 | mapEntry = mapIterator.next(); 96 | listIterator = mapEntry.getValue().iterator(); 97 | } 98 | 99 | if (listIterator.hasNext()) { 100 | return new AbstractMap.SimpleImmutableEntry<>(mapEntry.getKey(), listIterator.next()); 101 | } else { 102 | return new AbstractMap.SimpleImmutableEntry<>(mapEntry.getKey(), null); 103 | } 104 | } 105 | 106 | @Override 107 | public void remove() { 108 | throw new UnsupportedOperationException(); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/web/servlet/filter/decorator/ServletFilterHeaderSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-web-servlet-filter 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.web.servlet.filter.decorator; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import jakarta.servlet.http.HttpServletRequest; 22 | import jakarta.servlet.http.HttpServletResponse; 23 | 24 | import io.opentracing.Span; 25 | import io.opentracing.tag.StringTag; 26 | import io.smallrye.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator; 27 | 28 | /** 29 | * ServletFilterHeaderSpanDecorator will decorate the span based on incoming HTTP headers. 30 | * Incoming are compared to the list of {@link #allowedHeaders}, if the header is part of the provided list, 31 | * they will be added as {@link StringTag}. 32 | * The tag format will be a concatenation of {@link #prefix} and {@link HeaderEntry#tag} 33 | */ 34 | public class ServletFilterHeaderSpanDecorator implements ServletFilterSpanDecorator { 35 | 36 | private final String prefix; 37 | private final List allowedHeaders; 38 | 39 | /** 40 | * Constructor of ServletFilterHeaderSpanDecorator with a default prefix of "http.header." 41 | * 42 | * @param allowedHeaders list of {@link HeaderEntry} to extract from the incoming request 43 | */ 44 | public ServletFilterHeaderSpanDecorator(List allowedHeaders) { 45 | this(allowedHeaders, "http.header."); 46 | } 47 | 48 | /** 49 | * Constructor of ServletFilterHeaderSpanDecorator 50 | * 51 | * @param allowedHeaders list of {@link HeaderEntry} to extract from the incoming request 52 | * @param prefix the prefix to prepend on each @{@link StringTag}. Can be null is not prefix is desired 53 | */ 54 | public ServletFilterHeaderSpanDecorator(List allowedHeaders, String prefix) { 55 | this.allowedHeaders = new ArrayList<>(allowedHeaders); 56 | this.prefix = (prefix != null && !prefix.isEmpty()) ? prefix : null; 57 | } 58 | 59 | @Override 60 | public void onRequest(HttpServletRequest httpServletRequest, Span span) { 61 | for (HeaderEntry headerEntry : allowedHeaders) { 62 | String headerValue = httpServletRequest.getHeader(headerEntry.getHeader()); 63 | if (headerValue != null && !headerValue.isEmpty()) { 64 | buildTag(headerEntry.getTag()).set(span, headerValue); 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | public void onResponse(HttpServletRequest httpServletRequest, 71 | HttpServletResponse httpServletResponse, Span span) { 72 | } 73 | 74 | @Override 75 | public void onError(HttpServletRequest httpServletRequest, 76 | HttpServletResponse httpServletResponse, Throwable exception, Span span) { 77 | } 78 | 79 | @Override 80 | public void onTimeout(HttpServletRequest httpServletRequest, 81 | HttpServletResponse httpServletResponse, long timeout, Span span) { 82 | } 83 | 84 | private StringTag buildTag(String tag) { 85 | if (prefix == null) { 86 | return new StringTag(tag); 87 | } 88 | return new StringTag(prefix + tag); 89 | } 90 | 91 | public String getPrefix() { 92 | return this.prefix; 93 | } 94 | 95 | public List getAllowedHeaders() { 96 | return this.allowedHeaders; 97 | } 98 | 99 | /** 100 | * HeaderEntry is used to configure {@link ServletFilterHeaderSpanDecorator} 101 | * {@link #header} is used to check if the header exists using {@link HttpServletRequest#getHeader(String)} 102 | * {@link #tag} will be used as a {@link StringTag} if {@link #header} is found on the incoming request 103 | */ 104 | public static class HeaderEntry { 105 | private final String header; 106 | private final String tag; 107 | 108 | /** 109 | * @param header Header on the {@link HttpServletRequest} 110 | * @param tag Tag to be used if {@link #header} is found 111 | */ 112 | public HeaderEntry(String header, String tag) { 113 | this.header = header; 114 | this.tag = tag; 115 | } 116 | 117 | public String getHeader() { 118 | return this.header; 119 | } 120 | 121 | public String getTag() { 122 | return this.tag; 123 | } 124 | 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/SpanFinishingFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import java.io.IOException; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | import jakarta.servlet.AsyncEvent; 23 | import jakarta.servlet.AsyncListener; 24 | import jakarta.servlet.Filter; 25 | import jakarta.servlet.FilterChain; 26 | import jakarta.servlet.FilterConfig; 27 | import jakarta.servlet.ServletException; 28 | import jakarta.servlet.ServletRequest; 29 | import jakarta.servlet.ServletResponse; 30 | import jakarta.servlet.http.HttpServletRequest; 31 | import jakarta.servlet.http.HttpServletResponse; 32 | 33 | import io.opentracing.Span; 34 | import io.opentracing.Tracer; 35 | import io.opentracing.tag.Tags; 36 | import io.smallrye.opentracing.contrib.jaxrs2.internal.CastUtils; 37 | import io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper; 38 | 39 | /** 40 | * Filter which finishes span after server processing. It is required to be registered. 41 | * 42 | * @author Pavol Loffay 43 | */ 44 | public class SpanFinishingFilter implements Filter { 45 | 46 | public SpanFinishingFilter() { 47 | } 48 | 49 | /** 50 | * @param tracer 51 | * @deprecated use no-args constructor 52 | */ 53 | @Deprecated 54 | public SpanFinishingFilter(Tracer tracer) { 55 | } 56 | 57 | @Override 58 | public void init(FilterConfig filterConfig) { 59 | } 60 | 61 | @Override 62 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 63 | throws IOException, ServletException { 64 | 65 | HttpServletResponse httpResponse = (HttpServletResponse) response; 66 | HttpServletRequest httpRequest = (HttpServletRequest) request; 67 | 68 | try { 69 | chain.doFilter(request, response); 70 | } catch (Exception ex) { 71 | SpanWrapper spanWrapper = getSpanWrapper(httpRequest); 72 | if (spanWrapper != null) { 73 | Tags.HTTP_STATUS.set(spanWrapper.get(), httpResponse.getStatus()); 74 | addExceptionLogs(spanWrapper.get(), ex); 75 | } 76 | throw ex; 77 | } finally { 78 | SpanWrapper spanWrapper = getSpanWrapper(httpRequest); 79 | if (spanWrapper != null) { 80 | spanWrapper.getScope().close(); 81 | if (request.isAsyncStarted()) { 82 | request.getAsyncContext().addListener(new SpanFinisher(spanWrapper), request, response); 83 | } else { 84 | spanWrapper.finish(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | private SpanWrapper getSpanWrapper(HttpServletRequest request) { 91 | return CastUtils.cast(request.getAttribute(SpanWrapper.PROPERTY_NAME), SpanWrapper.class); 92 | } 93 | 94 | @Override 95 | public void destroy() { 96 | } 97 | 98 | static class SpanFinisher implements AsyncListener { 99 | private SpanWrapper spanWrapper; 100 | 101 | SpanFinisher(SpanWrapper spanWrapper) { 102 | this.spanWrapper = spanWrapper; 103 | } 104 | 105 | @Override 106 | public void onComplete(AsyncEvent event) throws IOException { 107 | HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse(); 108 | if (httpResponse.getStatus() >= 500) { 109 | addExceptionLogs(spanWrapper.get(), event.getThrowable()); 110 | } 111 | Tags.HTTP_STATUS.set(spanWrapper.get(), httpResponse.getStatus()); 112 | spanWrapper.finish(); 113 | } 114 | 115 | @Override 116 | public void onTimeout(AsyncEvent event) throws IOException { 117 | } 118 | 119 | @Override 120 | public void onError(AsyncEvent event) throws IOException { 121 | // this handler is called when exception is thrown in async handler 122 | // note that exception logs are added in filter not here 123 | } 124 | 125 | @Override 126 | public void onStartAsync(AsyncEvent event) throws IOException { 127 | } 128 | } 129 | 130 | private static void addExceptionLogs(Span span, Throwable throwable) { 131 | Tags.ERROR.set(span, true); 132 | if (throwable != null) { 133 | Map errorLogs = new HashMap<>(2); 134 | errorLogs.put("event", Tags.ERROR.getKey()); 135 | errorLogs.put("error.object", throwable); 136 | span.log(errorLogs); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.smallrye 5 | smallrye-parent 6 | 39 7 | 8 | 9 | smallrye-opentracing-parent 10 | 3.1.4-SNAPSHOT 11 | pom 12 | SmallRye: MicroProfile OpenTracing Parent 13 | http://smallrye.io 14 | 15 | 16 | 3.0 17 | 3.0 18 | 3.0 19 | 6.0.0 20 | 21 | 0.33.0 22 | 0.4.0 23 | 24 | 25 | 26 | 27 | Apache License, Version 2.0 28 | http://www.apache.org/licenses/LICENSE-2.0.txt 29 | 30 | 31 | 32 | 33 | GitHub 34 | https://github.com/smallrye/smallrye-opentracing/issues 35 | 36 | 37 | 38 | scm:git:git@github.com:smallrye/smallrye-opentracing 39 | scm:git:git@github.com:smallrye/smallrye-opentracing 40 | https://github.com/smallrye/smallrye-opentracing/ 41 | HEAD 42 | 43 | 44 | 45 | 46 | 47 | io.smallrye 48 | smallrye-opentracing-contrib 49 | ${project.version} 50 | 51 | 52 | io.smallrye 53 | smallrye-opentracing 54 | ${project.version} 55 | 56 | 57 | jakarta.servlet 58 | jakarta.servlet-api 59 | ${version.jakarta.servlet} 60 | provided 61 | 62 | 63 | io.opentracing 64 | opentracing-api 65 | ${version.opentracing} 66 | 67 | 68 | io.opentracing 69 | opentracing-noop 70 | ${version.opentracing} 71 | 72 | 73 | io.opentracing 74 | opentracing-util 75 | ${version.opentracing} 76 | 77 | 78 | io.opentracing.contrib 79 | opentracing-concurrent 80 | ${version.opentracing.concurrent} 81 | 82 | 83 | 84 | org.eclipse.microprofile.opentracing 85 | microprofile-opentracing-api 86 | ${version.microprofile.opentracing} 87 | 88 | 89 | org.eclipse.microprofile.config 90 | microprofile-config-api 91 | ${version.microprofile.config} 92 | 93 | 94 | org.eclipse.microprofile.rest.client 95 | microprofile-rest-client-api 96 | ${version.microprofile.restclient} 97 | 98 | 99 | javax.inject 100 | javax.inject 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | contrib 109 | implementation 110 | tck 111 | 112 | 113 | 114 | 115 | release 116 | 117 | 118 | !release.maven.bug.always.be.active 119 | 120 | 121 | 122 | release 123 | 124 | 125 | 126 | coverage 127 | 128 | @{jacocoArgLine} 129 | 130 | 131 | ${maven.multiModuleProjectDirectory}/tck/target/site/jacoco-aggregate/jacoco.xml 132 | 133 | 134 | 135 | 136 | 137 | org.jacoco 138 | jacoco-maven-plugin 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/serialization/TracingInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.serialization; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.List; 22 | import java.util.Objects; 23 | 24 | import jakarta.ws.rs.WebApplicationException; 25 | import jakarta.ws.rs.ext.InterceptorContext; 26 | import jakarta.ws.rs.ext.ReaderInterceptor; 27 | import jakarta.ws.rs.ext.ReaderInterceptorContext; 28 | import jakarta.ws.rs.ext.WriterInterceptor; 29 | import jakarta.ws.rs.ext.WriterInterceptorContext; 30 | 31 | import io.opentracing.References; 32 | import io.opentracing.Scope; 33 | import io.opentracing.Span; 34 | import io.opentracing.Tracer; 35 | import io.opentracing.noop.NoopSpan; 36 | import io.opentracing.tag.Tags; 37 | import io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper; 38 | 39 | public abstract class TracingInterceptor implements WriterInterceptor, ReaderInterceptor { 40 | private final Tracer tracer; 41 | private final Collection spanDecorators; 42 | 43 | public TracingInterceptor(Tracer tracer, 44 | List spanDecorators) { 45 | Objects.requireNonNull(tracer); 46 | Objects.requireNonNull(spanDecorators); 47 | this.tracer = tracer; 48 | this.spanDecorators = new ArrayList<>(spanDecorators); 49 | } 50 | 51 | @Override 52 | public Object aroundReadFrom(ReaderInterceptorContext context) 53 | throws IOException, WebApplicationException { 54 | Span span = buildSpan(context, "deserialize"); 55 | try (Scope scope = tracer.activateSpan(span)) { 56 | decorateRead(context, span); 57 | try { 58 | return context.proceed(); 59 | } catch (Exception e) { 60 | //TODO add exception logs in case they are not added by the filter. 61 | Tags.ERROR.set(span, true); 62 | throw e; 63 | } 64 | } finally { 65 | span.finish(); 66 | } 67 | } 68 | 69 | @Override 70 | public void aroundWriteTo(WriterInterceptorContext context) 71 | throws IOException, WebApplicationException { 72 | Span span = buildSpan(context, "serialize"); 73 | try (Scope scope = tracer.activateSpan(span)) { 74 | decorateWrite(context, span); 75 | context.proceed(); 76 | } catch (Exception e) { 77 | Tags.ERROR.set(span, true); 78 | throw e; 79 | } finally { 80 | span.finish(); 81 | } 82 | } 83 | 84 | /** 85 | * Client requests : 86 | *
    87 | *
  • Serialization of request body happens between the tracing filter invocation so we can use child_of.
  • 88 | *
  • Deserialization happens after the request is processed by the client filter therefore we can use follows_from 89 | * only.
  • 90 | *
91 | * Server requests : 92 | *
    93 | *
  • Deserialization happens between the span in the server filter is started and finished so we can use child_of.
  • 94 | *
  • Serialization of response entity happens after the server span if finished so we can use only follows_from.
  • 95 | *
96 | * 97 | * @param context Used to retrieve the current span wrapper created by the jax-rs request filter. 98 | * @param operationName "serialize" or "deserialize" depending on the context 99 | * @return a noop span is no span context is registered in the context. Otherwise a new span related to the current on 100 | * retrieved from the context. 101 | */ 102 | private Span buildSpan(InterceptorContext context, String operationName) { 103 | final SpanWrapper spanWrapper = findSpan(context); 104 | if (spanWrapper == null) { 105 | return NoopSpan.INSTANCE; 106 | } 107 | final Tracer.SpanBuilder spanBuilder = tracer.buildSpan(operationName); 108 | if (spanWrapper.isFinished()) { 109 | spanBuilder.addReference(References.FOLLOWS_FROM, spanWrapper.get().context()); 110 | } else { 111 | spanBuilder.asChildOf(spanWrapper.get()); 112 | } 113 | return spanBuilder.start(); 114 | } 115 | 116 | protected abstract SpanWrapper findSpan(InterceptorContext context); 117 | 118 | private void decorateRead(InterceptorContext context, Span span) { 119 | for (InterceptorSpanDecorator decorator : spanDecorators) { 120 | decorator.decorateRead(context, span); 121 | } 122 | } 123 | 124 | private void decorateWrite(InterceptorContext context, Span span) { 125 | for (InterceptorSpanDecorator decorator : spanDecorators) { 126 | decorator.decorateWrite(context, span); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/client/ClientTracingFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.client; 17 | 18 | import static io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper.PROPERTY_NAME; 19 | 20 | import java.io.IOException; 21 | import java.lang.reflect.Method; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | 27 | import jakarta.annotation.Priority; 28 | import jakarta.ws.rs.Priorities; 29 | import jakarta.ws.rs.client.ClientRequestContext; 30 | import jakarta.ws.rs.client.ClientRequestFilter; 31 | import jakarta.ws.rs.client.ClientResponseContext; 32 | import jakarta.ws.rs.client.ClientResponseFilter; 33 | 34 | import org.eclipse.microprofile.opentracing.Traced; 35 | 36 | import io.opentracing.Span; 37 | import io.opentracing.SpanContext; 38 | import io.opentracing.Tracer; 39 | import io.opentracing.noop.NoopScopeManager.NoopScope; 40 | import io.opentracing.propagation.Format; 41 | import io.opentracing.tag.Tags; 42 | import io.smallrye.opentracing.contrib.jaxrs2.internal.CastUtils; 43 | import io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper; 44 | 45 | /** 46 | * @author Pavol Loffay 47 | */ 48 | @Priority(Priorities.HEADER_DECORATOR) 49 | public class ClientTracingFilter implements ClientRequestFilter, ClientResponseFilter { 50 | 51 | private static final Logger log = Logger.getLogger( 52 | ClientTracingFilter.class.getName()); 53 | 54 | private Tracer tracer; 55 | private List spanDecorators; 56 | 57 | public ClientTracingFilter(Tracer tracer, List spanDecorators) { 58 | this.tracer = tracer; 59 | this.spanDecorators = new ArrayList<>(spanDecorators); 60 | } 61 | 62 | @Override 63 | public void filter(ClientRequestContext requestContext) { 64 | if (tracingDisabled(requestContext)) { 65 | log.finest("Client tracing disabled"); 66 | return; 67 | } 68 | 69 | // in case filter is registered twice 70 | if (requestContext.getProperty(PROPERTY_NAME) != null) { 71 | return; 72 | } 73 | 74 | Tracer.SpanBuilder spanBuilder = tracer.buildSpan(requestContext.getMethod()) 75 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT); 76 | 77 | SpanContext parentSpanContext = CastUtils.cast(requestContext.getProperty(TracingProperties.CHILD_OF), 78 | SpanContext.class); 79 | if (parentSpanContext != null) { 80 | spanBuilder.ignoreActiveSpan() 81 | .asChildOf(parentSpanContext); 82 | } 83 | 84 | /** 85 | * Do not create Scope - there is no way to deactivate it on UnknownHostException 86 | */ 87 | final Span span = spanBuilder.start(); 88 | 89 | if (spanDecorators != null) { 90 | for (ClientSpanDecorator decorator : spanDecorators) { 91 | decorator.decorateRequest(requestContext, span); 92 | } 93 | } 94 | 95 | if (log.isLoggable(Level.FINEST)) { 96 | log.finest("Starting client span"); 97 | } 98 | 99 | tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new ClientHeadersInjectTextMap(requestContext.getHeaders())); 100 | requestContext.setProperty(PROPERTY_NAME, new SpanWrapper(span, new NoopScope() { 101 | @Override 102 | public void close() { 103 | } 104 | })); 105 | } 106 | 107 | @Override 108 | public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { 109 | SpanWrapper spanWrapper = CastUtils 110 | .cast(requestContext.getProperty(PROPERTY_NAME), SpanWrapper.class); 111 | if (spanWrapper != null && !spanWrapper.isFinished()) { 112 | log.finest("Finishing client span"); 113 | 114 | if (spanDecorators != null) { 115 | for (ClientSpanDecorator decorator : spanDecorators) { 116 | decorator.decorateResponse(responseContext, spanWrapper.get()); 117 | } 118 | } 119 | 120 | spanWrapper.finish(); 121 | } 122 | } 123 | 124 | private boolean tracingDisabled(ClientRequestContext clientRequestContext) { 125 | Boolean tracingDisabled = CastUtils.cast(clientRequestContext.getProperty(TracingProperties.TRACING_DISABLED), 126 | Boolean.class); 127 | if (tracingDisabled != null && tracingDisabled) { 128 | return true; 129 | } 130 | 131 | Object invokedMethod = clientRequestContext.getProperty("org.eclipse.microprofile.rest.client.invokedMethod"); 132 | if (invokedMethod == null) { 133 | return false; 134 | } 135 | 136 | Method method = (Method) invokedMethod; 137 | Traced traced = method.getAnnotation(Traced.class); 138 | if (traced != null && !traced.value()) { 139 | return true; 140 | } 141 | return false; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/OperationNameProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import java.lang.reflect.AnnotatedElement; 19 | import java.lang.reflect.Method; 20 | import java.util.Arrays; 21 | 22 | import jakarta.ws.rs.Path; 23 | import jakarta.ws.rs.container.ContainerRequestContext; 24 | 25 | /** 26 | * @author Pavol Loffay 27 | */ 28 | public interface OperationNameProvider { 29 | interface Builder { 30 | OperationNameProvider build(Class clazz, Method method); 31 | } 32 | 33 | String operationName(ContainerRequestContext requestContext); 34 | 35 | /** 36 | * Returns HTTP method as operation name 37 | */ 38 | class HTTPMethodOperationName implements OperationNameProvider { 39 | static class Builder implements OperationNameProvider.Builder { 40 | @Override 41 | public OperationNameProvider build(Class clazz, Method method) { 42 | return new HTTPMethodOperationName(); 43 | } 44 | } 45 | 46 | HTTPMethodOperationName() { 47 | } 48 | 49 | @Override 50 | public String operationName(ContainerRequestContext requestContext) { 51 | return requestContext.getMethod(); 52 | } 53 | 54 | public static Builder newBuilder() { 55 | return new Builder(); 56 | } 57 | } 58 | 59 | /** 60 | * Default Microprofile operation name :.. 61 | */ 62 | class ClassNameOperationName implements OperationNameProvider { 63 | static class Builder implements OperationNameProvider.Builder { 64 | @Override 65 | public OperationNameProvider build(Class clazz, Method method) { 66 | return new ClassNameOperationName(clazz, method); 67 | } 68 | } 69 | 70 | private String classMethod; 71 | 72 | ClassNameOperationName(Class clazz, Method method) { 73 | this.classMethod = String.format("%s.%s", clazz.getName(), method.getName()); 74 | } 75 | 76 | @Override 77 | public String operationName(ContainerRequestContext requestContext) { 78 | return String.format("%s:%s", requestContext.getMethod(), classMethod); 79 | } 80 | 81 | public static Builder newBuilder() { 82 | return new Builder(); 83 | } 84 | } 85 | 86 | /** 87 | * As operation name provides "wildcard" HTTP path e.g: 88 | * 89 | * resource method annotated with @Path("/foo/bar/{name: \\w+}") produces "/foo/bar/{name: \\w+}" 90 | * 91 | */ 92 | class WildcardOperationName implements OperationNameProvider { 93 | static class Builder implements OperationNameProvider.Builder { 94 | @Override 95 | public OperationNameProvider build(Class clazz, Method method) { 96 | String classPath = extractPath(clazz); 97 | String methodPath = extractPath(method); 98 | if (classPath == null || methodPath == null) { 99 | for (Class i : clazz.getInterfaces()) { 100 | if (classPath == null) { 101 | String intfPath = extractPath(i); 102 | if (intfPath != null) { 103 | classPath = intfPath; 104 | } 105 | } 106 | if (methodPath == null) { 107 | for (Method m : i.getMethods()) { 108 | if (m.getName() == method.getName() 109 | && Arrays.deepEquals(m.getParameterTypes(), method.getParameterTypes())) { 110 | methodPath = extractPath(m); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | return new WildcardOperationName(classPath == null ? "" : classPath, methodPath == null ? "" : methodPath); 117 | } 118 | 119 | private static String extractPath(AnnotatedElement element) { 120 | Path path = element.getAnnotation(Path.class); 121 | if (path != null) { 122 | return path.value(); 123 | } 124 | return null; 125 | } 126 | } 127 | 128 | private final String path; 129 | 130 | WildcardOperationName(String clazz, String method) { 131 | if (clazz.isEmpty() || clazz.charAt(0) != '/') { 132 | clazz = "/" + clazz; 133 | } 134 | if (clazz.endsWith("/")) { 135 | clazz = clazz.substring(0, clazz.length() - 1); 136 | } 137 | if (method.isEmpty() || method.charAt(0) != '/') { 138 | method = "/" + method; 139 | } 140 | this.path = clazz + method; 141 | } 142 | 143 | @Override 144 | public String operationName(ContainerRequestContext requestContext) { 145 | return requestContext.getMethod() + ":" + path; 146 | } 147 | 148 | public static Builder newBuilder() { 149 | return new Builder(); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/client/ClientTracingFeature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.client; 17 | 18 | import java.util.Arrays; 19 | import java.util.Collections; 20 | import java.util.List; 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | import jakarta.ws.rs.Priorities; 25 | import jakarta.ws.rs.client.Client; 26 | import jakarta.ws.rs.core.Feature; 27 | import jakarta.ws.rs.core.FeatureContext; 28 | 29 | import io.opentracing.Tracer; 30 | import io.opentracing.util.GlobalTracer; 31 | import io.smallrye.opentracing.contrib.jaxrs2.serialization.InterceptorSpanDecorator; 32 | 33 | /** 34 | * @author Pavol Loffay 35 | */ 36 | public class ClientTracingFeature implements Feature { 37 | private static final Logger log = Logger.getLogger( 38 | ClientTracingFeature.class.getName()); 39 | 40 | private Builder builder; 41 | 42 | /** 43 | * When using this constructor application has to call {@link GlobalTracer#registerIfAbsent(Tracer)} to register 44 | * tracer instance. 45 | * 46 | * For a custom configuration use {@link Builder#build()}. 47 | */ 48 | public ClientTracingFeature() { 49 | this(new Builder(GlobalTracer.get())); 50 | } 51 | 52 | private ClientTracingFeature(Builder builder) { 53 | this.builder = builder; 54 | } 55 | 56 | @Override 57 | public boolean configure(FeatureContext context) { 58 | if (log.isLoggable(Level.FINE)) { 59 | log.fine("Registering client OpenTracing, with configuration:" + builder.toString()); 60 | } 61 | context.register(new ClientTracingFilter(builder.tracer, builder.spanDecorators), 62 | builder.priority); 63 | 64 | if (builder.traceSerialization) { 65 | context.register( 66 | new ClientTracingInterceptor(builder.tracer, builder.serializationSpanDecorators), 67 | builder.serializationPriority); 68 | } 69 | return true; 70 | } 71 | 72 | /** 73 | * Builder for configuring {@link Client} to trace outgoing requests. 74 | * 75 | * By default get's operation name is HTTP method and get is decorated with 76 | * {@link ClientSpanDecorator#STANDARD_TAGS} which adds set of standard tags. 77 | */ 78 | public static class Builder { 79 | private Tracer tracer; 80 | private List spanDecorators; 81 | private List serializationSpanDecorators; 82 | private int priority; 83 | private int serializationPriority; 84 | private boolean traceSerialization; 85 | 86 | public Builder(Tracer tracer) { 87 | this.tracer = tracer; 88 | this.spanDecorators = Collections.singletonList(ClientSpanDecorator.STANDARD_TAGS); 89 | this.serializationSpanDecorators = Arrays.asList(InterceptorSpanDecorator.STANDARD_TAGS); 90 | // by default do not use Priorities.AUTHENTICATION due to security concerns 91 | this.priority = Priorities.HEADER_DECORATOR; 92 | this.serializationPriority = Priorities.ENTITY_CODER; 93 | this.traceSerialization = true; 94 | } 95 | 96 | /** 97 | * Set span decorators. 98 | * 99 | * @return builder 100 | */ 101 | public Builder withDecorators(List spanDecorators) { 102 | this.spanDecorators = spanDecorators; 103 | return this; 104 | } 105 | 106 | /** 107 | * Set serialization span decorators. 108 | * 109 | * @return builder 110 | */ 111 | public Builder withSerializationDecorators(List spanDecorators) { 112 | this.serializationSpanDecorators = spanDecorators; 113 | return this; 114 | } 115 | 116 | /** 117 | * @param priority the overriding priority for the registered component. 118 | * Default is {@link Priorities#HEADER_DECORATOR} 119 | * @return builder 120 | * 121 | * @see Priorities 122 | */ 123 | public Builder withPriority(int priority) { 124 | this.priority = priority; 125 | return this; 126 | } 127 | 128 | /** 129 | * @param serializationPriority the overriding priority for the registered component. 130 | * Default is {@link Priorities#ENTITY_CODER} 131 | * @return builder 132 | * 133 | * @see Priorities 134 | */ 135 | public Builder withSerializationPriority(int serializationPriority) { 136 | this.serializationPriority = serializationPriority; 137 | return this; 138 | } 139 | 140 | /** 141 | * @param traceSerialization whether to trace serialization 142 | * @return builder 143 | */ 144 | public Builder withTraceSerialization(boolean traceSerialization) { 145 | this.traceSerialization = traceSerialization; 146 | return this; 147 | } 148 | 149 | /** 150 | * @return client tracing feature. This feature should be manually registered to {@link Client} 151 | */ 152 | public ClientTracingFeature build() { 153 | return new ClientTracingFeature(this); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tck/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | io.smallrye 6 | smallrye-opentracing-parent 7 | 3.1.4-SNAPSHOT 8 | 9 | 10 | smallrye-opentracing-tck 11 | SmallRye: MicroProfile OpenTracing TCK 12 | 13 | 14 | 2.3.0 15 | 3.1.1 16 | 6.2.2.Final 17 | 18 | org.jboss.resteasy.microprofile 19 | microprofile-rest-client 20 | 2.0.0.Final 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.eclipse.microprofile.opentracing 28 | microprofile-opentracing-tck 29 | ${version.microprofile.opentracing} 30 | test 31 | 32 | 33 | org.eclipse.microprofile.opentracing 34 | microprofile-opentracing-tck-rest-client 35 | ${version.microprofile.opentracing} 36 | test 37 | 38 | 39 | io.opentracing 40 | opentracing-mock 41 | ${version.opentracing} 42 | test 43 | 44 | 45 | io.smallrye.testing 46 | smallrye-testing-bom-tck 47 | ${version.smallrye.testing} 48 | pom 49 | import 50 | 51 | 52 | io.smallrye.config 53 | smallrye-config 54 | ${version.smallrye.config} 55 | test 56 | 57 | 58 | org.jboss.resteasy 59 | resteasy-bom 60 | ${version.resteasy} 61 | pom 62 | import 63 | 64 | 65 | 66 | 67 | 68 | 69 | io.smallrye 70 | smallrye-opentracing 71 | 72 | 73 | org.eclipse.microprofile.opentracing 74 | microprofile-opentracing-tck 75 | 76 | 77 | org.eclipse.microprofile.opentracing 78 | microprofile-opentracing-tck-rest-client 79 | 80 | 81 | io.opentracing 82 | opentracing-mock 83 | 84 | 85 | 86 | 87 | io.smallrye.testing 88 | smallrye-testing-tck-jetty 89 | 90 | 91 | io.smallrye.config 92 | smallrye-config 93 | 94 | 95 | ${groupId.resteasy.client} 96 | ${artifactId.resteasy.client} 97 | ${version.resteasy.client} 98 | test 99 | 100 | 101 | 102 | 103 | 104 | 105 | org.apache.maven.plugins 106 | maven-surefire-plugin 107 | 108 | 109 | src/test/tck-suite.xml 110 | 111 | 112 | org.eclipse.microprofile.opentracing:microprofile-opentracing-tck 113 | org.eclipse.microprofile.opentracing:microprofile-opentracing-tck-rest-client 114 | 115 | 116 | 117 | 118 | org.apache.maven.surefire 119 | surefire-testng 120 | ${version.surefire.plugin} 121 | 122 | 123 | 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-install-plugin 128 | 129 | true 130 | 131 | 132 | 133 | 134 | org.sonatype.plugins 135 | nexus-staging-maven-plugin 136 | 137 | true 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | coverage 146 | 147 | @{jacocoArgLine} 148 | 149 | 150 | 151 | 152 | org.jacoco 153 | jacoco-maven-plugin 154 | 155 | 156 | report-aggregate 157 | verify 158 | 159 | report-aggregate 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/web/servlet/filter/ServletFilterSpanDecorator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-web-servlet-filter 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.web.servlet.filter; 17 | 18 | import java.io.PrintWriter; 19 | import java.io.StringWriter; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import jakarta.servlet.AsyncEvent; 24 | import jakarta.servlet.FilterChain; 25 | import jakarta.servlet.ServletRequest; 26 | import jakarta.servlet.ServletResponse; 27 | import jakarta.servlet.http.HttpServletRequest; 28 | import jakarta.servlet.http.HttpServletResponse; 29 | 30 | import io.opentracing.Span; 31 | import io.opentracing.tag.Tags; 32 | 33 | /** 34 | * SpanDecorator to decorate span at different stages in filter processing (before filterChain.doFilter(), after and 35 | * if exception is thrown). 36 | * 37 | * @author Pavol Loffay 38 | */ 39 | public interface ServletFilterSpanDecorator { 40 | 41 | /** 42 | * Decorate span before {@link jakarta.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)} is 43 | * called. This is called right after span in created. Span is already present in request attributes with name 44 | * {@link TracingFilter#SERVER_SPAN_CONTEXT}. 45 | * 46 | * @param httpServletRequest request 47 | * @param span span to decorate 48 | */ 49 | void onRequest(HttpServletRequest httpServletRequest, Span span); 50 | 51 | /** 52 | * Decorate span after {@link jakarta.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}. When it 53 | * is an async request this will be called in {@link jakarta.servlet.AsyncListener#onComplete(AsyncEvent)}. 54 | * 55 | * @param httpServletRequest request 56 | * @param httpServletResponse response 57 | * @param span span to decorate 58 | */ 59 | void onResponse(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Span span); 60 | 61 | /** 62 | * Decorate span when an exception is thrown during processing in 63 | * {@link jakarta.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}. This is 64 | * also called in {@link jakarta.servlet.AsyncListener#onError(AsyncEvent)}. 65 | * 66 | * @param httpServletRequest request 67 | * @param exception exception 68 | * @param span span to decorate 69 | */ 70 | void onError(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, 71 | Throwable exception, Span span); 72 | 73 | /** 74 | * Decorate span on asynchronous request timeout. It is called in 75 | * {@link jakarta.servlet.AsyncListener#onTimeout(AsyncEvent)}. 76 | * 77 | * @param httpServletRequest request 78 | * @param httpServletResponse response 79 | * @param timeout timeout 80 | * @param span span to decorate 81 | */ 82 | void onTimeout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, 83 | long timeout, Span span); 84 | 85 | /** 86 | * Adds standard tags to span. {@link Tags#HTTP_URL}, {@link Tags#HTTP_STATUS}, {@link Tags#HTTP_METHOD} and 87 | * {@link Tags#COMPONENT}. If an exception during 88 | * {@link jakarta.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)} is thrown tag 89 | * {@link Tags#ERROR} is added and {@link Tags#HTTP_STATUS} not because at this point it is not known. 90 | */ 91 | ServletFilterSpanDecorator STANDARD_TAGS = new ServletFilterSpanDecorator() { 92 | @Override 93 | public void onRequest(HttpServletRequest httpServletRequest, Span span) { 94 | Tags.COMPONENT.set(span, "java-web-servlet"); 95 | 96 | Tags.HTTP_METHOD.set(span, httpServletRequest.getMethod()); 97 | //without query params 98 | Tags.HTTP_URL.set(span, httpServletRequest.getRequestURL().toString()); 99 | } 100 | 101 | @Override 102 | public void onResponse(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, 103 | Span span) { 104 | Tags.HTTP_STATUS.set(span, httpServletResponse.getStatus()); 105 | } 106 | 107 | @Override 108 | public void onError(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, 109 | Throwable exception, Span span) { 110 | Tags.ERROR.set(span, Boolean.TRUE); 111 | span.log(logsForException(exception)); 112 | 113 | if (httpServletResponse.getStatus() == HttpServletResponse.SC_OK) { 114 | // exception is thrown in filter chain, but status code is incorrect 115 | Tags.HTTP_STATUS.set(span, 500); 116 | } 117 | } 118 | 119 | @Override 120 | public void onTimeout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, 121 | long timeout, Span span) { 122 | Map timeoutLogs = new HashMap<>(2); 123 | timeoutLogs.put("event", "timeout"); 124 | timeoutLogs.put("timeout", timeout); 125 | span.log(timeoutLogs); 126 | } 127 | 128 | private Map logsForException(Throwable throwable) { 129 | Map errorLog = new HashMap<>(3); 130 | errorLog.put("event", Tags.ERROR.getKey()); 131 | 132 | String message = throwable.getCause() != null ? throwable.getCause().getMessage() : throwable.getMessage(); 133 | if (message != null) { 134 | errorLog.put("message", message); 135 | } 136 | StringWriter sw = new StringWriter(); 137 | throwable.printStackTrace(new PrintWriter(sw)); 138 | errorLog.put("stack", sw.toString()); 139 | 140 | return errorLog; 141 | } 142 | }; 143 | } 144 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/ServerTracingFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import static io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper.PROPERTY_NAME; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.logging.Level; 23 | import java.util.logging.Logger; 24 | import java.util.regex.Pattern; 25 | 26 | import jakarta.annotation.Priority; 27 | import jakarta.servlet.http.HttpServletRequest; 28 | import jakarta.ws.rs.Priorities; 29 | import jakarta.ws.rs.container.ContainerRequestContext; 30 | import jakarta.ws.rs.container.ContainerRequestFilter; 31 | import jakarta.ws.rs.container.ContainerResponseContext; 32 | import jakarta.ws.rs.container.ContainerResponseFilter; 33 | import jakarta.ws.rs.core.Context; 34 | 35 | import io.opentracing.Span; 36 | import io.opentracing.SpanContext; 37 | import io.opentracing.Tracer; 38 | import io.opentracing.propagation.Format; 39 | import io.opentracing.tag.Tags; 40 | import io.smallrye.opentracing.contrib.jaxrs2.internal.CastUtils; 41 | import io.smallrye.opentracing.contrib.jaxrs2.internal.SpanWrapper; 42 | 43 | /** 44 | * @author Pavol Loffay 45 | */ 46 | @Priority(Priorities.HEADER_DECORATOR) 47 | public class ServerTracingFilter implements ContainerRequestFilter, ContainerResponseFilter { 48 | private static final Logger log = Logger.getLogger( 49 | ServerTracingFilter.class.getName()); 50 | 51 | private Tracer tracer; 52 | private List spanDecorators; 53 | private String operationName; 54 | private OperationNameProvider operationNameProvider; 55 | private Pattern skipPattern; 56 | private final boolean joinExistingActiveSpan; 57 | 58 | protected ServerTracingFilter( 59 | Tracer tracer, 60 | String operationName, 61 | List spanDecorators, 62 | OperationNameProvider operationNameProvider, 63 | Pattern skipPattern, 64 | boolean joinExistingActiveSpan) { 65 | this.tracer = tracer; 66 | this.operationName = operationName; 67 | this.spanDecorators = new ArrayList<>(spanDecorators); 68 | this.operationNameProvider = operationNameProvider; 69 | this.skipPattern = skipPattern; 70 | this.joinExistingActiveSpan = joinExistingActiveSpan; 71 | } 72 | 73 | @Context 74 | private HttpServletRequest httpServletRequest; 75 | 76 | @Override 77 | public void filter(ContainerRequestContext requestContext) { 78 | // return in case filter if registered twice 79 | if (requestContext.getProperty(PROPERTY_NAME) != null || matchesSkipPattern(requestContext)) { 80 | return; 81 | } 82 | 83 | if (tracer != null) { 84 | 85 | SpanContext parentSpanContext = parentSpanContext(requestContext); 86 | Span span = tracer.buildSpan(operationNameProvider.operationName(requestContext)) 87 | .ignoreActiveSpan() 88 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) 89 | .asChildOf(parentSpanContext) 90 | .start(); 91 | 92 | if (spanDecorators != null) { 93 | for (ServerSpanDecorator decorator : spanDecorators) { 94 | decorator.decorateRequest(requestContext, span); 95 | } 96 | } 97 | 98 | // override operation name set by @Traced 99 | if (this.operationName != null) { 100 | span.setOperationName(operationName); 101 | } 102 | 103 | if (log.isLoggable(Level.FINEST)) { 104 | log.finest("Creating server span: " + operationName); 105 | } 106 | 107 | requestContext.setProperty(PROPERTY_NAME, new SpanWrapper(span, tracer.activateSpan(span))); 108 | } 109 | } 110 | 111 | /** 112 | * Returns a parent for a span created by this filter (jax-rs span). 113 | * The context from the active span takes precedence over context in the request, 114 | * but only if joinExistingActiveSpan has been set. 115 | * The current active span should be child-of extracted context and for example 116 | * created at a lower level e.g. jersey filter. 117 | */ 118 | private SpanContext parentSpanContext(ContainerRequestContext requestContext) { 119 | Span activeSpan = tracer.activeSpan(); 120 | if (activeSpan != null && this.joinExistingActiveSpan) { 121 | return activeSpan.context(); 122 | } else { 123 | return tracer.extract( 124 | Format.Builtin.HTTP_HEADERS, 125 | new ServerHeadersExtractTextMap(requestContext.getHeaders())); 126 | } 127 | } 128 | 129 | @Override 130 | public void filter(ContainerRequestContext requestContext, 131 | ContainerResponseContext responseContext) { 132 | SpanWrapper spanWrapper = CastUtils.cast(requestContext.getProperty(PROPERTY_NAME), SpanWrapper.class); 133 | if (spanWrapper == null) { 134 | return; 135 | } 136 | 137 | if (spanDecorators != null) { 138 | for (ServerSpanDecorator decorator : spanDecorators) { 139 | decorator.decorateResponse(responseContext, spanWrapper.get()); 140 | } 141 | } 142 | } 143 | 144 | private boolean matchesSkipPattern(ContainerRequestContext requestContext) { 145 | // skip URLs matching skip pattern 146 | // e.g. pattern is defined as '/health|/status' then URL 'http://localhost:5000/context/health' won't be traced 147 | String path = requestContext.getUriInfo().getPath(); 148 | if (skipPattern != null && path != null) { 149 | if (path.length() > 0 && path.charAt(0) != '/') { 150 | path = "/" + path; 151 | } 152 | return skipPattern.matcher(path).matches(); 153 | } 154 | return false; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/interceptor/OpenTracingInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-interceptors 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.interceptor; 17 | 18 | import java.lang.reflect.Method; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | import java.util.logging.Logger; 22 | 23 | import jakarta.annotation.Priority; 24 | import jakarta.enterprise.inject.Instance; 25 | import jakarta.inject.Inject; 26 | import jakarta.interceptor.AroundInvoke; 27 | import jakarta.interceptor.Interceptor; 28 | import jakarta.interceptor.InvocationContext; 29 | import jakarta.ws.rs.Path; 30 | 31 | import org.eclipse.microprofile.opentracing.Traced; 32 | 33 | import io.opentracing.Scope; 34 | import io.opentracing.Span; 35 | import io.opentracing.SpanContext; 36 | import io.opentracing.Tracer; 37 | import io.opentracing.tag.Tags; 38 | import io.smallrye.opentracing.contrib.resolver.TracerResolver; 39 | 40 | @Traced 41 | @Interceptor 42 | @Priority(value = Interceptor.Priority.LIBRARY_BEFORE + 1) 43 | public class OpenTracingInterceptor { 44 | public static final String SPAN_CONTEXT = "__opentracing_span_context"; 45 | private static final Logger log = Logger.getLogger(OpenTracingInterceptor.class.getName()); 46 | 47 | @Inject 48 | Instance tracerInstance; 49 | 50 | private volatile Tracer tracer = null; 51 | 52 | @AroundInvoke 53 | public Object wrap(InvocationContext ctx) throws Exception { 54 | if (skipJaxRs(ctx.getMethod())) { 55 | return ctx.proceed(); 56 | } 57 | 58 | if (!traced(ctx.getMethod())) { 59 | return ctx.proceed(); 60 | } 61 | 62 | Tracer tracer = getTracer(); 63 | Tracer.SpanBuilder spanBuilder = tracer.buildSpan(getOperationName(ctx.getMethod())); 64 | 65 | int contextParameterIndex = -1; 66 | for (int i = 0; i < ctx.getParameters().length; i++) { 67 | Object parameter = ctx.getParameters()[i]; 68 | if (parameter instanceof SpanContext) { 69 | log.fine("Found parameter as span context. Using it as the parent of this new span"); 70 | spanBuilder.asChildOf((SpanContext) parameter); 71 | contextParameterIndex = i; 72 | break; 73 | } 74 | 75 | if (parameter instanceof Span) { 76 | log.fine("Found parameter as span. Using it as the parent of this new span"); 77 | spanBuilder.asChildOf((Span) parameter); 78 | contextParameterIndex = i; 79 | break; 80 | } 81 | } 82 | 83 | if (contextParameterIndex < 0) { 84 | log.fine("No parent found. Trying to get span context from context data"); 85 | Object ctxParentSpan = ctx.getContextData().get(SPAN_CONTEXT); 86 | if (ctxParentSpan instanceof SpanContext) { 87 | log.fine("Found span context from context data."); 88 | SpanContext parentSpan = (SpanContext) ctxParentSpan; 89 | spanBuilder.asChildOf(parentSpan); 90 | } 91 | } 92 | 93 | Span span = spanBuilder.start(); 94 | Scope scope = tracer.activateSpan(span); 95 | try { 96 | log.fine("Adding span context into the invocation context."); 97 | ctx.getContextData().put(SPAN_CONTEXT, span.context()); 98 | 99 | if (contextParameterIndex >= 0) { 100 | log.fine("Overriding the original span context with our new context."); 101 | for (int i = 0; i < ctx.getParameters().length; i++) { 102 | if (ctx.getParameters()[contextParameterIndex] instanceof Span) { 103 | ctx.getParameters()[contextParameterIndex] = span; 104 | } 105 | 106 | if (ctx.getParameters()[contextParameterIndex] instanceof SpanContext) { 107 | ctx.getParameters()[contextParameterIndex] = span.context(); 108 | } 109 | } 110 | } 111 | 112 | return ctx.proceed(); 113 | } catch (Exception e) { 114 | logException(span, e); 115 | throw e; 116 | } finally { 117 | span.finish(); 118 | scope.close(); 119 | } 120 | } 121 | 122 | // uses volatile read and synchronized block to avoid possible duplicate creation of Tracer in multi-threaded env 123 | public Tracer getTracer() { 124 | Tracer val = tracer; 125 | if (val != null) { 126 | return val; 127 | } 128 | synchronized (this) { 129 | if (tracer == null) { 130 | if (null != tracerInstance && !tracerInstance.isUnsatisfied()) { 131 | tracer = this.tracerInstance.get(); 132 | } else { 133 | tracer = TracerResolver.resolveTracer(); 134 | } 135 | } 136 | return tracer; 137 | } 138 | } 139 | 140 | private boolean traced(Method method) { 141 | Traced classTraced = method.getDeclaringClass().getAnnotation(Traced.class); 142 | Traced methodTraced = method.getAnnotation(Traced.class); 143 | if (methodTraced != null) { 144 | return methodTraced.value(); 145 | } 146 | return classTraced != null && classTraced.value(); 147 | } 148 | 149 | private boolean skipJaxRs(Method method) { 150 | return method.getAnnotation(Path.class) != null || 151 | method.getDeclaringClass().getAnnotation(Path.class) != null; 152 | } 153 | 154 | private String getOperationName(Method method) { 155 | Traced classTraced = method.getDeclaringClass().getAnnotation(Traced.class); 156 | Traced methodTraced = method.getAnnotation(Traced.class); 157 | if (methodTraced != null && methodTraced.operationName().length() > 0) { 158 | return methodTraced.operationName(); 159 | } else if (classTraced != null && classTraced.operationName().length() > 0) { 160 | return classTraced.operationName(); 161 | } 162 | 163 | // use a StringBuilder with predefined capacity to compute the operation name for performance reason 164 | String className = method.getDeclaringClass().getName(); 165 | String methodName = method.getName(); 166 | int capacity = className.length() + methodName.length() + 1; 167 | StringBuilder builder = new StringBuilder(capacity); 168 | builder.append(className).append('.').append(methodName); 169 | return builder.toString(); 170 | } 171 | 172 | private void logException(Span span, Exception e) { 173 | Map errorLogs = new HashMap(2); 174 | errorLogs.put("event", Tags.ERROR.getKey()); 175 | errorLogs.put("error.object", e); 176 | span.log(errorLogs); 177 | Tags.ERROR.set(span, true); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/jaxrs2/server/ServerTracingDynamicFeature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-jaxrs 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.jaxrs2.server; 17 | 18 | import java.util.Collections; 19 | import java.util.List; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | import java.util.regex.Pattern; 23 | 24 | import jakarta.ws.rs.Priorities; 25 | import jakarta.ws.rs.container.DynamicFeature; 26 | import jakarta.ws.rs.container.ResourceInfo; 27 | import jakarta.ws.rs.core.FeatureContext; 28 | 29 | import org.eclipse.microprofile.opentracing.Traced; 30 | 31 | import io.opentracing.Tracer; 32 | import io.opentracing.util.GlobalTracer; 33 | import io.smallrye.opentracing.contrib.jaxrs2.serialization.InterceptorSpanDecorator; 34 | import io.smallrye.opentracing.contrib.jaxrs2.server.OperationNameProvider.WildcardOperationName; 35 | 36 | /** 37 | * This class has to be registered as JAX-RS provider to enable tracing of server requests. It also 38 | * requires {@link SpanFinishingFilter} for correct functionality. Spans are created in JAX-RS filter 39 | * and finished in servlet filter. 40 | * 41 | * @author Pavol Loffay 42 | */ 43 | public class ServerTracingDynamicFeature implements DynamicFeature { 44 | private static final Logger log = Logger.getLogger( 45 | ServerTracingDynamicFeature.class.getName()); 46 | 47 | private final Builder builder; 48 | 49 | /** 50 | * When using this constructor application has to call {@link GlobalTracer#register} to register 51 | * tracer instance. Ideally it should be called in {@link jakarta.servlet.ServletContextListener}. 52 | * 53 | * For a custom configuration use {@link Builder#build()}. 54 | */ 55 | public ServerTracingDynamicFeature() { 56 | this(new Builder(GlobalTracer.get())); 57 | } 58 | 59 | private ServerTracingDynamicFeature(Builder builder) { 60 | this.builder = builder; 61 | } 62 | 63 | @Override 64 | public void configure(ResourceInfo resourceInfo, FeatureContext context) { 65 | // TODO why it is called twice for the same endpoint 66 | if (!tracingDisabled(resourceInfo)) { 67 | log(resourceInfo); 68 | context.register(new ServerTracingFilter( 69 | builder.tracer, 70 | operationName(resourceInfo), 71 | builder.spanDecorators, 72 | builder.operationNameBuilder.build(resourceInfo.getResourceClass(), resourceInfo.getResourceMethod()), 73 | builder.skipPattern != null ? Pattern.compile(builder.skipPattern) : null, 74 | builder.joinExistingActiveSpan), 75 | builder.priority); 76 | 77 | if (builder.traceSerialization) { 78 | context.register(new ServerTracingInterceptor(builder.tracer, 79 | builder.serializationSpanDecorators), builder.serializationPriority); 80 | } 81 | } 82 | } 83 | 84 | private void log(ResourceInfo resourceInfo) { 85 | if (log.isLoggable(Level.FINE)) { 86 | log.fine(String.format("Registering tracing on %s#%s...", 87 | resourceInfo.getResourceClass().getCanonicalName(), 88 | resourceInfo.getResourceMethod().getName())); 89 | } 90 | } 91 | 92 | protected Traced closestTracedAnnotation(ResourceInfo resourceInfo) { 93 | Traced tracedAnnotation = resourceInfo.getResourceMethod().getAnnotation(Traced.class); 94 | if (tracedAnnotation == null) { 95 | tracedAnnotation = resourceInfo.getResourceClass().getAnnotation(Traced.class); 96 | } 97 | 98 | return tracedAnnotation; 99 | } 100 | 101 | protected boolean tracingDisabled(ResourceInfo resourceInfo) { 102 | Traced traced = closestTracedAnnotation(resourceInfo); 103 | return traced == null ? !builder.allTraced : !traced.value(); 104 | } 105 | 106 | protected String operationName(ResourceInfo resourceInfo) { 107 | Traced traced = closestTracedAnnotation(resourceInfo); 108 | return traced != null && !traced.operationName().isEmpty() ? traced.operationName() : null; 109 | } 110 | 111 | /** 112 | * Builder for creating JAX-RS dynamic feature for tracing server requests. 113 | * 114 | * By default span's operation name is HTTP method and span is decorated with 115 | * {@link ServerSpanDecorator#STANDARD_TAGS} which adds standard tags. 116 | * If you want to set different span name provide custom span decorator {@link ServerSpanDecorator}. 117 | */ 118 | public static class Builder { 119 | private final Tracer tracer; 120 | private boolean allTraced; 121 | private List spanDecorators; 122 | private List serializationSpanDecorators; 123 | private int priority; 124 | private int serializationPriority; 125 | private OperationNameProvider.Builder operationNameBuilder; 126 | private boolean traceSerialization; 127 | private String skipPattern; 128 | private boolean joinExistingActiveSpan; 129 | 130 | public Builder(Tracer tracer) { 131 | this.tracer = tracer; 132 | this.spanDecorators = Collections.singletonList(ServerSpanDecorator.STANDARD_TAGS); 133 | this.serializationSpanDecorators = Collections.singletonList(InterceptorSpanDecorator.STANDARD_TAGS); 134 | // by default do not use Priorities.AUTHENTICATION due to security concerns 135 | this.priority = Priorities.HEADER_DECORATOR; 136 | this.serializationPriority = Priorities.ENTITY_CODER; 137 | this.allTraced = true; 138 | this.operationNameBuilder = WildcardOperationName.newBuilder(); 139 | this.traceSerialization = true; 140 | this.joinExistingActiveSpan = false; 141 | } 142 | 143 | /** 144 | * Only resources annotated with {@link Traced} will be traced. 145 | * 146 | * @return builder 147 | */ 148 | public Builder withTraceNothing() { 149 | allTraced = false; 150 | return this; 151 | } 152 | 153 | /** 154 | * Set span decorators. 155 | * 156 | * @param spanDecorators span decorator 157 | * @return builder 158 | */ 159 | public Builder withDecorators(List spanDecorators) { 160 | this.spanDecorators = spanDecorators; 161 | return this; 162 | } 163 | 164 | /** 165 | * Set serialization span decorators. 166 | * 167 | * @return builder 168 | */ 169 | public Builder withSerializationDecorators(List spanDecorators) { 170 | this.serializationSpanDecorators = spanDecorators; 171 | return this; 172 | } 173 | 174 | /** 175 | * @param priority the overriding priority for the registered component. 176 | * Default is {@link Priorities#HEADER_DECORATOR} 177 | * @return builder 178 | * 179 | * @see Priorities 180 | */ 181 | public Builder withPriority(int priority) { 182 | this.priority = priority; 183 | return this; 184 | } 185 | 186 | /** 187 | * @param serializationPriority the overriding priority for the registered component. 188 | * Default is {@link Priorities#ENTITY_CODER} 189 | * @return builder 190 | * 191 | * @see Priorities 192 | */ 193 | public Builder withSerializationPriority(int serializationPriority) { 194 | this.serializationPriority = serializationPriority; 195 | return this; 196 | } 197 | 198 | /** 199 | * @param builder the builder for operation name provider 200 | * @return 201 | */ 202 | public Builder withOperationNameProvider(OperationNameProvider.Builder builder) { 203 | this.operationNameBuilder = builder; 204 | return this; 205 | } 206 | 207 | /** 208 | * @param traceSerialization whether to trace serialization 209 | * @return builder 210 | */ 211 | public Builder withTraceSerialization(boolean traceSerialization) { 212 | this.traceSerialization = traceSerialization; 213 | return this; 214 | } 215 | 216 | /** 217 | * @param skipPattern skip pattern e.g. /health|/status 218 | * @return builder 219 | */ 220 | public Builder withSkipPattern(String skipPattern) { 221 | this.skipPattern = skipPattern; 222 | return this; 223 | } 224 | 225 | /** 226 | * @param joinExistingActiveSpan If true, any active span on the on the current thread will 227 | * be used as a parent span. If false, parent span will be 228 | * extracted from HTTP headers. 229 | * This feature can be used when chaining spans from lower 230 | * instrumentation layers e.g. servlet instrumentation. 231 | * Default is false. 232 | * @return builder 233 | */ 234 | public Builder withJoinExistingActiveSpan(boolean joinExistingActiveSpan) { 235 | this.joinExistingActiveSpan = joinExistingActiveSpan; 236 | return this; 237 | } 238 | 239 | /** 240 | * @return server tracing dynamic feature. This feature should be manually registered to 241 | * {@link jakarta.ws.rs.core.Application} 242 | */ 243 | public ServerTracingDynamicFeature build() { 244 | return new ServerTracingDynamicFeature(this); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/resolver/TracerResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2019 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-tracerresolver 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package io.smallrye.opentracing.contrib.resolver; 19 | 20 | import static io.smallrye.opentracing.contrib.resolver.PriorityComparator.prioritize; 21 | 22 | import java.util.ServiceLoader; 23 | import java.util.logging.Level; 24 | import java.util.logging.Logger; 25 | 26 | import io.opentracing.Tracer; 27 | 28 | /** 29 | * {@code TracerResolver} API definition looks for one or more registered {@link TracerResolver} implementations 30 | * using the {@link ServiceLoader}. 31 | *

32 | * If no {@link TracerResolver} implementations are found, the {@link #resolveTracer()} method will fallback to 33 | * {@link ServiceLoader} lookup of the {@link Tracer} service itself. 34 | *

35 | * Available {@link TracerConverter} implementations are applied to the resolved {@link Tracer} instance. 36 | *

37 | * None of this happens if there is an existing {@code GlobalTracer} explicit registration. 38 | * That will always be returned (as-is) by the resolver, if available. 39 | * 40 | * @author Sjoerd Talsma 41 | */ 42 | public abstract class TracerResolver { 43 | private static final Logger LOGGER = Logger.getLogger(TracerResolver.class.getName()); 44 | 45 | /** 46 | * Resolves the {@link Tracer} implementation. 47 | * 48 | * @return The resolved Tracer or {@code null} if none was resolved. 49 | * @deprecated Tracers are encouraged to use the {@link TracerFactory} interface to provide tracers 50 | */ 51 | @Deprecated 52 | protected abstract Tracer resolve(); 53 | 54 | /** 55 | * Attempts to resolve a Tracer via {@link ServiceLoader} using a variety of mechanisms, from the most recommended 56 | * to the least recommended: 57 | *

58 | *

    59 | *
  • based on the available {@link TracerFactory}
  • 60 | *
  • based on subclasses of {@link TracerResolver}
  • 61 | *
  • based on classes of {@link Tracer}
  • 62 | *
63 | * 64 | *

65 | * Whenever a Tracer can be resolved by any of the methods above, the resolution stops. It means that if a Factory 66 | * is found, no Resolvers are attempted to be loaded. 67 | * 68 | *

69 | * If a {@code GlobalTracer} has been previously registered, it will be returned before attempting to resolve 70 | * a {@linkplain Tracer} on our own. 71 | * 72 | *

73 | * If more than one {@link TracerFactory} or {@link TracerResolver} is found, the one with the highest priority is 74 | * returned. Note that if a {@link TracerResolver} has a higher priority than all available {@link TracerFactory}, 75 | * the factory still wins. 76 | * 77 | * @return The resolved Tracer or {@code null} if none was resolved. 78 | */ 79 | public static Tracer resolveTracer() { 80 | return resolveTracer(null); 81 | } 82 | 83 | /** 84 | * Attempts to resolve a Tracer via {@link ServiceLoader} using a variety of mechanisms, from the most recommended 85 | * to the least recommended: 86 | *

87 | *

    88 | *
  • based on the available {@link TracerFactory}
  • 89 | *
  • based on subclasses of {@link TracerResolver}
  • 90 | *
  • based on classes of {@link Tracer}
  • 91 | *
92 | * 93 | *

94 | * Whenever a Tracer can be resolved by any of the methods above, the resolution stops. It means that if a Factory 95 | * is found, no Resolvers are attempted to be loaded. 96 | * 97 | *

98 | * If a {@code GlobalTracer} has been previously registered, it will be returned before attempting to resolve 99 | * a {@linkplain Tracer} on our own. 100 | * 101 | *

102 | * If more than one {@link TracerFactory} or {@link TracerResolver} is found, the one with the highest priority is 103 | * returned. Note that if a {@link TracerResolver} has a higher priority than all available {@link TracerFactory}, 104 | * the factory still wins. 105 | * 106 | * @param classloader The class loader to be used to load provider-configuration files 107 | * and provider classes, or null if the thread context class loader to be used. 108 | * @return The resolved Tracer or {@code null} if none was resolved. 109 | */ 110 | public static Tracer resolveTracer(ClassLoader classloader) { 111 | try { // Take care NOT to import GlobalTracer as it is an optional dependency and may not be on the classpath. 112 | if (io.opentracing.util.GlobalTracer.isRegistered()) { 113 | return logResolved(io.opentracing.util.GlobalTracer.get()); 114 | } 115 | } catch (NoClassDefFoundError globalTracerNotInClasspath) { 116 | LOGGER.finest("GlobalTracer is not found on the classpath."); 117 | } 118 | 119 | Tracer tracer = null; 120 | if (!TracerResolver.isDisabled()) { 121 | if (classloader == null) { 122 | classloader = Thread.currentThread().getContextClassLoader(); 123 | } 124 | tracer = getFromFactory(classloader); 125 | if (null == tracer) { 126 | tracer = getFromResolver(classloader); 127 | } 128 | 129 | if (null == tracer) { 130 | tracer = getFromServiceLoader(classloader); 131 | } 132 | } 133 | 134 | return tracer; 135 | } 136 | 137 | /** 138 | * Reloads the lazily found {@linkplain TracerResolver resolvers} and the fallback resolver. 139 | * 140 | * @deprecated This method is now no-op. It's safe to just remove this method call, as there's no caching anymore. 141 | */ 142 | @Deprecated 143 | public static void reload() { 144 | LOGGER.log(Level.FINER, "No-op for this implementation."); 145 | } 146 | 147 | /** 148 | * There are two ways to globally disable the tracer resolver: 149 | *

    150 | *
  • Setting a {@code "tracerresolver.disabled"} system property to {@code true}
  • 151 | *
  • Setting the environment variable {@code TRACERRESOLVER_DISABLED} to {@code true}
  • 152 | *
153 | * 154 | * @return Whether the tracer resolver mechanism is disabled ({@code false} by default). 155 | */ 156 | private static boolean isDisabled() { 157 | String prop = System.getProperty("tracerresolver.disabled", System.getenv("TRACERRESOLVER_DISABLED")); 158 | return prop != null && (prop.equals("1") || prop.equalsIgnoreCase("true")); 159 | } 160 | 161 | private static Tracer convert(Tracer resolved) { 162 | if (resolved != null) { 163 | for (TracerConverter converter : prioritize(ServiceLoader.load(TracerConverter.class))) { 164 | try { 165 | Tracer converted = converter.convert(resolved); 166 | LOGGER.log(Level.FINEST, "Converted {0} using {1}: {2}.", new Object[] { resolved, converter, converted }); 167 | resolved = converted; 168 | } catch (RuntimeException rte) { 169 | LOGGER.log(Level.WARNING, "Error converting " + resolved + " with " + converter + ": " + rte.getMessage(), 170 | rte); 171 | } 172 | if (resolved == null) 173 | break; 174 | } 175 | } 176 | return resolved; 177 | } 178 | 179 | private static Tracer logResolved(Tracer resolvedTracer) { 180 | LOGGER.log(Level.FINER, "Resolved tracer: {0}.", resolvedTracer); 181 | return resolvedTracer; 182 | } 183 | 184 | /** 185 | * Attempts to load a Tracer based on the {@link TracerFactory} interface. This is the preferred way to load a tracer 186 | * 187 | * @param classloader The class loader to be used to load provider-configuration files 188 | * and provider classes 189 | * @return a tracer as resolved by the classpath's TracerFactory, or null 190 | */ 191 | private static Tracer getFromFactory(ClassLoader classloader) { 192 | for (TracerFactory factory : prioritize(ServiceLoader.load(TracerFactory.class, classloader))) { 193 | try { 194 | Tracer tracer = convert(factory.getTracer()); 195 | if (tracer != null) { 196 | return logResolved(tracer); 197 | } 198 | } catch (RuntimeException rte) { 199 | LOGGER.log(Level.WARNING, "Error getting tracer using " + factory + ": " + rte.getMessage(), rte); 200 | } 201 | } 202 | 203 | return null; 204 | } 205 | 206 | /** 207 | * Attempts to load a Tracer based on the TracerResolver class. This is the deprecated behavior and is kept here 208 | * for backwards compatibility reasons. 209 | * 210 | * @param classloader The class loader to be used to load provider-configuration files 211 | * and provider classes 212 | * @return a tracer from {@link #resolve()}, or null 213 | */ 214 | private static Tracer getFromResolver(ClassLoader classloader) { 215 | for (TracerResolver resolver : prioritize(ServiceLoader.load(TracerResolver.class, classloader))) { 216 | try { 217 | Tracer tracer = convert(resolver.resolve()); 218 | if (tracer != null) { 219 | return logResolved(tracer); 220 | } 221 | } catch (RuntimeException rte) { 222 | LOGGER.log(Level.WARNING, "Error resolving tracer using " + resolver + ": " + rte.getMessage(), rte); 223 | } 224 | } 225 | 226 | return null; 227 | } 228 | 229 | /** 230 | * Attempts to load a Tracer directly from the ServiceLoader. 231 | * 232 | * @param classloader The class loader to be used to load provider-configuration files 233 | * and provider classes 234 | * @return a tracer as resolved directly by the service loader, or null 235 | */ 236 | private static Tracer getFromServiceLoader(ClassLoader classloader) { 237 | for (Tracer tracer : prioritize(ServiceLoader.load(Tracer.class, classloader))) { 238 | tracer = convert(tracer); 239 | if (tracer != null) { 240 | return logResolved(tracer); 241 | } 242 | } 243 | 244 | return null; 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /contrib/src/main/java/io/smallrye/opentracing/contrib/web/servlet/filter/TracingFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 The OpenTracing Authors 3 | * Copied from https://github.com/opentracing-contrib/java-web-servlet-filter 4 | * Intended only for Jakarta namespace migration 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package io.smallrye.opentracing.contrib.web.servlet.filter; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.Collections; 22 | import java.util.List; 23 | import java.util.logging.Logger; 24 | import java.util.regex.Pattern; 25 | 26 | import jakarta.servlet.AsyncEvent; 27 | import jakarta.servlet.AsyncListener; 28 | import jakarta.servlet.Filter; 29 | import jakarta.servlet.FilterChain; 30 | import jakarta.servlet.FilterConfig; 31 | import jakarta.servlet.ServletContext; 32 | import jakarta.servlet.ServletException; 33 | import jakarta.servlet.ServletRequest; 34 | import jakarta.servlet.ServletResponse; 35 | import jakarta.servlet.http.HttpServletRequest; 36 | import jakarta.servlet.http.HttpServletResponse; 37 | 38 | import io.opentracing.Scope; 39 | import io.opentracing.Span; 40 | import io.opentracing.SpanContext; 41 | import io.opentracing.Tracer; 42 | import io.opentracing.propagation.Format; 43 | import io.opentracing.tag.Tags; 44 | import io.opentracing.util.GlobalTracer; 45 | 46 | /** 47 | * Tracing servlet filter. 48 | * 49 | * Filter can be programmatically added to {@link ServletContext} or initialized via web.xml. 50 | * 51 | * Following code examples show possible initialization: 52 | * 53 | *
 54 |  * {
 55 |  *     @code
 56 |  *     TracingFilter filter = new TracingFilter(tracer);
 57 |  *     servletContext.addFilter("tracingFilter", filter);
 58 |  * }
 59 |  * 
60 | * 61 | * Or include filter in web.xml and: 62 | * 63 | *
 64 |  * {@code
 65 |  *  GlobalTracer.register(tracer);
 66 |  *  servletContext.setAttribute({@link TracingFilter#SPAN_DECORATORS}, listOfDecorators); // optional, if no present ServletFilterSpanDecorator.STANDARD_TAGS is applied
 67 |  * }
 68 |  * 
69 | * 70 | * Current server span context is accessible via {@link HttpServletRequest#getAttribute(String)} with name 71 | * {@link TracingFilter#SERVER_SPAN_CONTEXT}. 72 | * 73 | * @author Pavol Loffay 74 | */ 75 | public class TracingFilter implements Filter { 76 | private static final Logger log = Logger.getLogger( 77 | TracingFilter.class.getName()); 78 | 79 | /** 80 | * Use as a key of {@link ServletContext#setAttribute(String, Object)} to set span decorators 81 | */ 82 | public static final String SPAN_DECORATORS = TracingFilter.class.getName() + ".spanDecorators"; 83 | /** 84 | * Use as a key of {@link ServletContext#setAttribute(String, Object)} to skip pattern 85 | */ 86 | public static final String SKIP_PATTERN = TracingFilter.class.getName() + ".skipPattern"; 87 | 88 | /** 89 | * Used as a key of {@link HttpServletRequest#setAttribute(String, Object)} to inject server span context 90 | */ 91 | public static final String SERVER_SPAN_CONTEXT = TracingFilter.class.getName() + ".activeSpanContext"; 92 | 93 | private FilterConfig filterConfig; 94 | 95 | protected Tracer tracer; 96 | private List spanDecorators; 97 | private Pattern skipPattern; 98 | 99 | /** 100 | * Tracer instance has to be registered with {@link GlobalTracer#register(Tracer)}. 101 | */ 102 | public TracingFilter() { 103 | this(GlobalTracer.get()); 104 | } 105 | 106 | /** 107 | * @param tracer 108 | */ 109 | public TracingFilter(Tracer tracer) { 110 | this(tracer, Collections.singletonList(ServletFilterSpanDecorator.STANDARD_TAGS), null); 111 | } 112 | 113 | /** 114 | * 115 | * @param tracer tracer 116 | * @param spanDecorators decorators 117 | * @param skipPattern null or pattern to exclude certain paths from tracing e.g. "/health" 118 | */ 119 | public TracingFilter(Tracer tracer, List spanDecorators, Pattern skipPattern) { 120 | this.tracer = tracer; 121 | this.spanDecorators = new ArrayList<>(spanDecorators); 122 | this.spanDecorators.removeAll(Collections.singleton(null)); 123 | this.skipPattern = skipPattern; 124 | } 125 | 126 | @Override 127 | public void init(FilterConfig filterConfig) throws ServletException { 128 | this.filterConfig = filterConfig; 129 | ServletContext servletContext = filterConfig.getServletContext(); 130 | 131 | // Check whether the servlet context provides a tracer 132 | Object tracerObj = servletContext.getAttribute(Tracer.class.getName()); 133 | if (tracerObj instanceof Tracer) { 134 | tracer = (Tracer) tracerObj; 135 | } else { 136 | // Add current tracer to servlet context, so available to webapp 137 | servletContext.setAttribute(Tracer.class.getName(), tracer); 138 | } 139 | 140 | // use decorators from context attributes 141 | Object contextAttribute = servletContext.getAttribute(SPAN_DECORATORS); 142 | if (contextAttribute instanceof Collection) { 143 | List decorators = new ArrayList<>(); 144 | for (Object decorator : (Collection) contextAttribute) { 145 | if (decorator instanceof ServletFilterSpanDecorator) { 146 | decorators.add((ServletFilterSpanDecorator) decorator); 147 | } else { 148 | log.severe(decorator + " is not an instance of " + ServletFilterSpanDecorator.class); 149 | } 150 | } 151 | this.spanDecorators = decorators.size() > 0 ? decorators : this.spanDecorators; 152 | } 153 | 154 | contextAttribute = servletContext.getAttribute(SKIP_PATTERN); 155 | if (contextAttribute instanceof Pattern) { 156 | skipPattern = (Pattern) contextAttribute; 157 | } 158 | } 159 | 160 | @Override 161 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) 162 | throws IOException, ServletException { 163 | 164 | HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; 165 | HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; 166 | 167 | if (!isTraced(httpRequest, httpResponse)) { 168 | chain.doFilter(httpRequest, httpResponse); 169 | return; 170 | } 171 | 172 | /** 173 | * If request is traced then do not start new span. 174 | */ 175 | if (servletRequest.getAttribute(SERVER_SPAN_CONTEXT) != null) { 176 | chain.doFilter(servletRequest, servletResponse); 177 | } else { 178 | SpanContext extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS, 179 | new HttpServletRequestExtractAdapter(httpRequest)); 180 | 181 | final Span span = tracer.buildSpan(httpRequest.getMethod()) 182 | .asChildOf(extractedContext) 183 | .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER) 184 | .start(); 185 | 186 | httpRequest.setAttribute(SERVER_SPAN_CONTEXT, span.context()); 187 | 188 | for (ServletFilterSpanDecorator spanDecorator : spanDecorators) { 189 | spanDecorator.onRequest(httpRequest, span); 190 | } 191 | 192 | try (Scope scope = tracer.activateSpan(span)) { 193 | chain.doFilter(servletRequest, servletResponse); 194 | if (!httpRequest.isAsyncStarted()) { 195 | for (ServletFilterSpanDecorator spanDecorator : spanDecorators) { 196 | spanDecorator.onResponse(httpRequest, httpResponse, span); 197 | } 198 | } 199 | // catch all exceptions (e.g. RuntimeException, ServletException...) 200 | } catch (Throwable ex) { 201 | for (ServletFilterSpanDecorator spanDecorator : spanDecorators) { 202 | spanDecorator.onError(httpRequest, httpResponse, ex, span); 203 | } 204 | throw ex; 205 | } finally { 206 | if (httpRequest.isAsyncStarted()) { 207 | // what if async is already finished? This would not be called 208 | httpRequest.getAsyncContext() 209 | .addListener(new AsyncListener() { 210 | @Override 211 | public void onComplete(AsyncEvent event) throws IOException { 212 | HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest(); 213 | HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse(); 214 | for (ServletFilterSpanDecorator spanDecorator : spanDecorators) { 215 | spanDecorator.onResponse(httpRequest, 216 | httpResponse, 217 | span); 218 | } 219 | span.finish(); 220 | } 221 | 222 | @Override 223 | public void onTimeout(AsyncEvent event) throws IOException { 224 | HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest(); 225 | HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse(); 226 | for (ServletFilterSpanDecorator spanDecorator : spanDecorators) { 227 | spanDecorator.onTimeout(httpRequest, 228 | httpResponse, 229 | event.getAsyncContext().getTimeout(), 230 | span); 231 | } 232 | } 233 | 234 | @Override 235 | public void onError(AsyncEvent event) throws IOException { 236 | HttpServletRequest httpRequest = (HttpServletRequest) event.getSuppliedRequest(); 237 | HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse(); 238 | for (ServletFilterSpanDecorator spanDecorator : spanDecorators) { 239 | spanDecorator.onError(httpRequest, 240 | httpResponse, 241 | event.getThrowable(), 242 | span); 243 | } 244 | } 245 | 246 | @Override 247 | public void onStartAsync(AsyncEvent event) throws IOException { 248 | } 249 | }); 250 | } else { 251 | // If not async, then need to explicitly finish the span associated with the scope. 252 | // This is necessary, as we don't know whether this request is being handled 253 | // asynchronously until after the scope has already been started. 254 | span.finish(); 255 | } 256 | } 257 | } 258 | } 259 | 260 | @Override 261 | public void destroy() { 262 | this.filterConfig = null; 263 | } 264 | 265 | /** 266 | * It checks whether a request should be traced or not. 267 | * 268 | * @param httpServletRequest request 269 | * @param httpServletResponse response 270 | * @return whether request should be traced or not 271 | */ 272 | protected boolean isTraced(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { 273 | // skip URLs matching skip pattern 274 | // e.g. pattern is defined as '/health|/status' then URL 'http://localhost:5000/context/health' won't be traced 275 | if (skipPattern != null) { 276 | String url = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length()); 277 | return !skipPattern.matcher(url).matches(); 278 | } 279 | 280 | return true; 281 | } 282 | 283 | /** 284 | * Get context of server span. 285 | * 286 | * @param servletRequest request 287 | * @return server span context 288 | */ 289 | public static SpanContext serverSpanContext(ServletRequest servletRequest) { 290 | return (SpanContext) servletRequest.getAttribute(SERVER_SPAN_CONTEXT); 291 | } 292 | } 293 | --------------------------------------------------------------------------------