moving configuration to [config]
diff --git a/README.adoc b/README.adoc
new file mode 100644
index 0000000..e14611b
--- /dev/null
+++ b/README.adoc
@@ -0,0 +1,25 @@
+= Geronimo OpenTracing
+
+Geronimo OpenTracing provides an OpenTracing implementation and a Microprofile OpenTracing implementation at once.
+
+== Configuration
+
+NOTE: if you are using Microprofile Config it is used, otherwise it uses system properties.
+
+|===
+| Key | Description | Default
+|geronimo.opentracing.filter.active|Should OpenTracing be activated|true
+|geronimo.opentracing.filter.forcedTracing.urls|Urls for which the tracking should be activated automatically. The urls are actually the requets uri minus the context path.|-
+|geronimo.opentracing.filter.forcedTracing.matcherType|Type of matcher for the url, default is `prefix` which means a `startsWith` is used on the url but you can also use `regex` which compiles the url as a `Pattern`|prefix
+|geronimo.opentracing.filter.forcedTracing.skipDefaultTags|Should `HTTP_METHOD`, `HTTP_URL` not be added to tags|false
+|geronimo.opentracing.server.filter.request.skip.<endpoint class>_<endpoint method>|Should server instrumentation be ignored|false
+|geronimo.opentracing.server.filter.request.skip|Should server instrumentation be ignored (if previous is not set)|false
+|geronimo.opentracing.server.filter.request.skipDefaultTags|Should `HTTP_METHOD`, `HTTP_URL` not be added to tags|false
+|geronimo.opentracing.client.filter.request.skip|Should client instrumentation be ignored|false
+|geronimo.opentracing.client.filter.request.skipDefaultTags|Should `HTTP_METHOD`, `HTTP_URL` not be added to tags|false
+|geronimo.opentracing.client.filter.request.skipPeerTags|Should `PEER_HOSTNAME`, `PEER_PORT` not be added to tags|false
+|geronimo.opentracing.propagation.headers.spanId|Name of the header used to host the spanId value|`X-B3-SpanId`
+|geronimo.opentracing.propagation.headers.traceId|Name of the header used to host the traceId value|`X-B3-TraceId`
+|geronimo.opentracing.propagation.headers.baggagePrefix|Prefix of headers used to host the baggage values|`baggage-`
+|geronimo.opentracing.cdi.executorServices.wrappedNames|Name (as CDI names of the beans) of executor services which will get an interceptor propagating the current scope (span)|-
+|===
diff --git a/geronimo-opentracing-impl/pom.xml b/geronimo-opentracing-impl/pom.xml
index cfdba21..207dba6 100644
--- a/geronimo-opentracing-impl/pom.xml
+++ b/geronimo-opentracing-impl/pom.xml
@@ -36,6 +36,13 @@
 
   <dependencies>
     <dependency>
+      <groupId>org.eclipse.microprofile.config</groupId>
+      <artifactId>microprofile-config-api</artifactId>
+      <version>1.2</version>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
       <groupId>org.apache.geronimo</groupId>
       <artifactId>geronimo-microprofile-opentracing-spec</artifactId>
       <version>${project.version}</version>
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/DefaultOpenTracingConfig.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/DefaultOpenTracingConfig.java
new file mode 100644
index 0000000..646c3a7
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/DefaultOpenTracingConfig.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.enterprise.inject.Vetoed;
+
+@Vetoed
+class DefaultOpenTracingConfig implements GeronimoOpenTracingConfig {
+    private final Map<String, String> configuration = new HashMap<>();
+
+    DefaultOpenTracingConfig() {
+        System.getProperties().stringPropertyNames()
+              .forEach(k -> configuration.put(k, System.getProperty(k)));
+        try (final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/geronimo/microprofile/opentracing.properties")) {
+            if (stream != null) {
+                final Properties properties = new Properties();
+                properties.load(stream);
+                properties.stringPropertyNames().forEach(k -> configuration.put(k, properties.getProperty(k)));
+            }
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public String read(final String value, final String def) {
+        return configuration.getOrDefault(value, def);
+    }
+}
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/GeronimoOpenTracingConfig.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/GeronimoOpenTracingConfig.java
new file mode 100644
index 0000000..d9b3677
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/GeronimoOpenTracingConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.config;
+
+@FunctionalInterface
+public interface GeronimoOpenTracingConfig {
+
+    String read(String value, String def);
+
+    static GeronimoOpenTracingConfig create() {
+        try {
+            return new PrefixedConfig(new OpenTracingConfigMpConfigImpl());
+        } catch (final NoClassDefFoundError | ExceptionInInitializerError cnfe) {
+            return new PrefixedConfig(new DefaultOpenTracingConfig());
+        }
+    }
+}
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/OpenTracingConfigMpConfigImpl.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/OpenTracingConfigMpConfigImpl.java
new file mode 100644
index 0000000..7c54bd0
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/OpenTracingConfigMpConfigImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.config;
+
+import javax.enterprise.inject.Vetoed;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+
+@Vetoed
+class OpenTracingConfigMpConfigImpl implements GeronimoOpenTracingConfig {
+    private final Config config;
+
+    OpenTracingConfigMpConfigImpl() {
+        config = ConfigProvider.getConfig();
+    }
+
+    @Override
+    public String read(final String key, final String def) {
+        return config.getOptionalValue(key, String.class).orElse(def);
+    }
+}
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/PrefixedConfig.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/PrefixedConfig.java
new file mode 100644
index 0000000..5575786
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/config/PrefixedConfig.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.config;
+
+import javax.enterprise.inject.Vetoed;
+
+@Vetoed
+class PrefixedConfig implements GeronimoOpenTracingConfig {
+    private final GeronimoOpenTracingConfig delegate;
+
+    PrefixedConfig(final GeronimoOpenTracingConfig geronimoOpenTracingConfig) {
+        this.delegate = geronimoOpenTracingConfig;
+    }
+
+    @Override
+    public String read(final String value, final String def) {
+        return delegate.read("geronimo.opentracing." + value, def);
+    }
+}
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/GeronimoTracer.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/GeronimoTracer.java
index 791144e..ff9d47b 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/GeronimoTracer.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/GeronimoTracer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.geronimo.microprofile.opentracing.impl;
 
+import static java.util.Collections.list;
 import static java.util.Optional.ofNullable;
 import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.toMap;
@@ -24,9 +25,11 @@
 import java.util.Iterator;
 import java.util.Map;
 
+import javax.annotation.PostConstruct;
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.event.Event;
 import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.core.MultivaluedMap;
 
 import io.opentracing.Scope;
@@ -37,6 +40,8 @@
 import io.opentracing.propagation.Format;
 import io.opentracing.propagation.TextMap;
 
+import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
+
 @ApplicationScoped
 public class GeronimoTracer implements Tracer {
 
@@ -49,6 +54,20 @@
     @Inject
     private Event<FinishedSpan> finishedSpanEvent;
 
+    @Inject
+    private GeronimoOpenTracingConfig config;
+
+    private String spanIdHeader;
+    private String traceIdHeader;
+    private String baggageHeaderPrefix;
+
+    @PostConstruct
+    private void init() {
+        spanIdHeader = config.read("propagation.headers.spanId", "X-B3-SpanId");
+        traceIdHeader = config.read("propagation.headers.traceId", "X-B3-TraceId");
+        baggageHeaderPrefix = config.read("propagation.headers.baggagePrefix", "baggage-");
+    }
+
     @Override
     public ScopeManager scopeManager() {
         return scopeManager;
@@ -73,23 +92,33 @@
         }
         final TextMap textMap = TextMap.class.cast(carrier);
         final SpanContextImpl context = SpanContextImpl.class.cast(spanContext);
-        textMap.put("X-B3-TraceId", String.valueOf(context.getTraceId()));
-        textMap.put("X-B3-SpanId", String.valueOf(context.getSpanId()));
-        context.getBaggageItems().forEach((k, v) -> textMap.put("baggage-" + k, v));
+        textMap.put(traceIdHeader, String.valueOf(context.getTraceId()));
+        textMap.put(spanIdHeader, String.valueOf(context.getSpanId()));
+        context.getBaggageItems().forEach((k, v) -> textMap.put(baggageHeaderPrefix + k, v));
     }
 
     @Override
     public <C> SpanContext extract(final Format<C> format, final C carrier) {
-        if (HeaderTextMap.class.isInstance(carrier)) {
-            final MultivaluedMap<String, ?> map = HeaderTextMap.class.cast(carrier).getMap();
-            final String traceid = (String) map.getFirst("X-B3-TraceId");
-            final String spanid = (String) map.getFirst("X-B3-SpanId");
+        if (JaxRsHeaderTextMap.class.isInstance(carrier)) {
+            final MultivaluedMap<String, ?> map = JaxRsHeaderTextMap.class.cast(carrier).getMap();
+            final String traceid = (String) map.getFirst(traceIdHeader);
+            final String spanid = (String) map.getFirst(spanIdHeader);
             if (traceid != null && spanid != null) {
-                return newContext(traceid, spanid, map.keySet().stream().filter(it -> it.startsWith("baggage-"))
+                return newContext(traceid, spanid, map.keySet().stream().filter(it -> it.startsWith(baggageHeaderPrefix))
                         .collect(toMap(identity(), k -> String.valueOf(map.getFirst(k)))));
             }
             return null;
         }
+        if (ServletHeaderTextMap.class.isInstance(carrier)) {
+            final HttpServletRequest req = ServletHeaderTextMap.class.cast(carrier).getRequest();
+            final String traceid = req.getHeader(traceIdHeader);
+            final String spanid = req.getHeader(spanIdHeader);
+            if (traceid != null && spanid != null) {
+                return newContext(traceid, spanid, list(req.getHeaderNames()).stream().filter(it -> it.startsWith(baggageHeaderPrefix))
+                        .collect(toMap(identity(), k -> String.valueOf(req.getHeader(k)))));
+            }
+            return null;
+        }
         if (!TextMap.class.isInstance(carrier)) {
             throw new IllegalArgumentException("Only TextMap are supported");
         }
@@ -99,11 +128,11 @@
         final Map<String, String> baggages = new HashMap<>();
         while (textMap.hasNext()) {
             final Map.Entry<String, String> next = textMap.next();
-            if (next.getKey().startsWith("baggage-")) {
+            if (next.getKey().startsWith(baggageHeaderPrefix)) {
                 baggages.put(next.getKey(), next.getValue());
-            } else if ("X-B3-SpanId".equals(next.getKey())) {
+            } else if (spanIdHeader.equals(next.getKey())) {
                 spanId = next.getValue();
-            } else if ("X-B3-TracedId".equals(next.getKey())) {
+            } else if (traceIdHeader.equals(next.getKey())) {
                 traceId = next.getValue();
             }
         }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/HeaderTextMap.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/JaxRsHeaderTextMap.java
similarity index 94%
rename from geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/HeaderTextMap.java
rename to geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/JaxRsHeaderTextMap.java
index 82b1706..53d5944 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/HeaderTextMap.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/JaxRsHeaderTextMap.java
@@ -23,11 +23,11 @@
 
 import io.opentracing.propagation.TextMap;
 
-public class HeaderTextMap<T> implements TextMap {
+public class JaxRsHeaderTextMap<T> implements TextMap {
 
     private final MultivaluedMap<String, T> headers;
 
-    public HeaderTextMap(final MultivaluedMap<String, T> headers) {
+    public JaxRsHeaderTextMap(final MultivaluedMap<String, T> headers) {
         this.headers = headers;
     }
 
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ScopeManagerImpl.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ScopeManagerImpl.java
index af938a1..4ba677e 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ScopeManagerImpl.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ScopeManagerImpl.java
@@ -48,4 +48,8 @@
         }
         return scope;
     }
+
+    public void clear() {
+        current.remove();
+    }
 }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/HeaderTextMap.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ServletHeaderTextMap.java
similarity index 69%
copy from geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/HeaderTextMap.java
copy to geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ServletHeaderTextMap.java
index 82b1706..af135bc 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/HeaderTextMap.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/impl/ServletHeaderTextMap.java
@@ -16,38 +16,43 @@
  */
 package org.apache.geronimo.microprofile.opentracing.impl;
 
+import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.Map;
 
-import javax.ws.rs.core.MultivaluedMap;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import io.opentracing.propagation.TextMap;
 
-public class HeaderTextMap<T> implements TextMap {
+public class ServletHeaderTextMap implements TextMap {
 
-    private final MultivaluedMap<String, T> headers;
+    private final HttpServletRequest request;
 
-    public HeaderTextMap(final MultivaluedMap<String, T> headers) {
-        this.headers = headers;
+    private final HttpServletResponse response;
+
+    public ServletHeaderTextMap(final HttpServletRequest request, final HttpServletResponse response) {
+        this.request = request;
+        this.response = response;
     }
 
-    public MultivaluedMap<String, ?> getMap() {
-        return headers;
+    public HttpServletRequest getRequest() {
+        return request;
     }
 
     @Override
     public Iterator<Map.Entry<String, String>> iterator() {
-        final Iterator<String> iterator = headers.keySet().iterator();
+        final Enumeration<String> iterator = request.getHeaderNames();
         return new Iterator<Map.Entry<String, String>>() {
 
             @Override
             public boolean hasNext() {
-                return iterator.hasNext();
+                return iterator.hasMoreElements();
             }
 
             @Override
             public Map.Entry<String, String> next() {
-                final String next = iterator.next();
+                final String next = iterator.nextElement();
                 return new Map.Entry<String, String>() {
 
                     @Override
@@ -57,7 +62,7 @@
 
                     @Override
                     public String getValue() {
-                        return String.valueOf(headers.getFirst(next));
+                        return String.valueOf(request.getHeader(next));
                     }
 
                     @Override
@@ -71,6 +76,6 @@
 
     @Override
     public void put(final String key, final String value) {
-        this.headers.putSingle(key, (T) value);
+        this.response.setHeader(key, value);
     }
 }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/OpenTracingExtension.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/OpenTracingExtension.java
index b57b669..a36f406 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/OpenTracingExtension.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/OpenTracingExtension.java
@@ -16,9 +16,23 @@
  */
 package org.apache.geronimo.microprofile.opentracing.microprofile.cdi;
 
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toSet;
+
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Stream;
+
+import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
 import javax.enterprise.inject.spi.AnnotatedMethod;
 import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
 import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
 import javax.enterprise.inject.spi.WithAnnotations;
@@ -26,22 +40,48 @@
 import javax.ws.rs.HttpMethod;
 import javax.ws.rs.Path;
 
+import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
+import org.apache.geronimo.microprofile.opentracing.microprofile.thread.OpenTracingExecutorService;
 import org.eclipse.microprofile.opentracing.Traced;
 
 public class OpenTracingExtension implements Extension {
+
+    private GeronimoOpenTracingConfig config;
+
+    private Collection<String> instrumentedExecutorServices;
+
+    void onStart(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
+        config = GeronimoOpenTracingConfig.create();
+        instrumentedExecutorServices = ofNullable(config.read("cdi.executorServices.wrappedNames", null))
+                .map(s -> Stream.of(s.split(",")).map(String::trim).filter(it -> !it.isEmpty()).collect(toSet())).orElse(null);
+    }
+
     <T> void removeTracedFromJaxRsEndpoints(@Observes @WithAnnotations(Traced.class) final ProcessAnnotatedType<T> pat) {
         if (isJaxRs(pat.getAnnotatedType())) { // we have filters with more accurate timing
             final AnnotatedTypeConfigurator<T> configurator = pat.configureAnnotatedType();
             configurator.remove(it -> it.annotationType() == Traced.class);
-            configurator.methods().stream()
-                    .filter(m -> isJaxRs(m.getAnnotated()))
+            configurator.methods().stream().filter(m -> isJaxRs(m.getAnnotated()))
                     .forEach(m -> m.remove(it -> it.annotationType() == Traced.class));
         }
     }
 
+    <T> void instrumentExecutorServices(@Observes final ProcessAnnotatedType<T> pat) {
+        final Set<Type> typeClosure = pat.getAnnotatedType().getTypeClosure();
+        if (typeClosure.contains(ExecutorService.class) && !typeClosure.contains(OpenTracingExecutorService.class)) {
+            pat.configureAnnotatedType().add(TracedExecutorService.Literal.INSTANCE);
+        }
+    }
+
+    void addConfigAsBean(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
+        afterBeanDiscovery.addBean().id(OpenTracingExtension.class.getName() + "#" + GeronimoOpenTracingConfig.class.getName())
+                .beanClass(GeronimoOpenTracingConfig.class).types(GeronimoOpenTracingConfig.class, Object.class)
+                .qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE).scope(ApplicationScoped.class)
+                .createWith(ctx -> config);
+    }
+
     private <T> boolean isJaxRs(final AnnotatedType<T> annotatedType) {
-        return annotatedType.getAnnotations().stream().anyMatch(it -> it.annotationType() == Path.class) ||
-                annotatedType.getMethods().stream().anyMatch(this::isJaxRs);
+        return annotatedType.getAnnotations().stream().anyMatch(it -> it.annotationType() == Path.class)
+                || annotatedType.getMethods().stream().anyMatch(this::isJaxRs);
     }
 
     private <T> boolean isJaxRs(final AnnotatedMethod<? super T> m) {
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/TracedExecutorService.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/TracedExecutorService.java
new file mode 100644
index 0000000..61e511b
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/TracedExecutorService.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.opentracing.microprofile.cdi;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.interceptor.InterceptorBinding;
+
+@InterceptorBinding
+@Retention(RUNTIME)
+@Target({ TYPE, METHOD })
+public @interface TracedExecutorService {
+
+    class Literal implements TracedExecutorService {
+
+        public static final TracedExecutorService INSTANCE = new Literal();
+
+        @Override
+        public Class<? extends Annotation> annotationType() {
+            return TracedExecutorService.class;
+        }
+
+        @Override
+        public boolean equals(final Object other) {
+            return TracedExecutorService.class.isInstance(other) || (Annotation.class.isInstance(other)
+                    && Annotation.class.cast(other).annotationType() == TracedExecutorService.class);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return "@" + TracedExecutorService.class.getName();
+        }
+    }
+}
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/TracedExecutorServiceInterceptor.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/TracedExecutorServiceInterceptor.java
new file mode 100644
index 0000000..a7470f0
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/cdi/TracedExecutorServiceInterceptor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.opentracing.microprofile.cdi;
+
+import io.opentracing.Tracer;
+
+import java.io.Serializable;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.geronimo.microprofile.opentracing.microprofile.thread.ScopePropagatingCallable;
+
+@Interceptor
+@TracedExecutorService
+@Priority(Interceptor.Priority.LIBRARY_AFTER)
+public class TracedExecutorServiceInterceptor implements Serializable {
+    @Inject
+    private Tracer tracer;
+
+    public Object around(final InvocationContext context) throws Exception {
+        return new ScopePropagatingCallable<>(context::proceed, tracer).call();
+    }
+}
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/GeronimoClientTracingRegistrarProvider.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/GeronimoClientTracingRegistrarProvider.java
index cefeb30..60bc46b 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/GeronimoClientTracingRegistrarProvider.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/GeronimoClientTracingRegistrarProvider.java
@@ -21,6 +21,7 @@
 import javax.enterprise.inject.spi.CDI;
 import javax.ws.rs.client.ClientBuilder;
 
+import org.apache.geronimo.microprofile.opentracing.microprofile.thread.OpenTracingExecutorService;
 import org.eclipse.microprofile.opentracing.ClientTracingRegistrarProvider;
 
 import io.opentracing.Tracer;
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingClientRequestFilter.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingClientRequestFilter.java
index 637ab74..f550774 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingClientRequestFilter.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingClientRequestFilter.java
@@ -21,12 +21,14 @@
 
 import java.util.function.Consumer;
 
+import javax.annotation.PostConstruct;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
 import javax.ws.rs.client.ClientRequestContext;
 import javax.ws.rs.client.ClientRequestFilter;
 
-import org.apache.geronimo.microprofile.opentracing.impl.HeaderTextMap;
+import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
+import org.apache.geronimo.microprofile.opentracing.impl.JaxRsHeaderTextMap;
 
 import io.opentracing.Scope;
 import io.opentracing.Span;
@@ -41,10 +43,23 @@
     @Inject
     private Tracer tracer;
 
+    @Inject
+    private GeronimoOpenTracingConfig config;
+
+    private boolean skip;
+    private boolean skipDefaultTags;
+    private boolean skipPeerTags;
+
+    @PostConstruct
+    private void init() {
+        skip = Boolean.parseBoolean(config.read("client.filter.request.skip", "false"));
+        skipDefaultTags = Boolean.parseBoolean(config.read("client.filter.request.skipDefaultTags", "false"));
+        skipPeerTags = Boolean.parseBoolean(config.read("client.filter.request.skipPeerTags", "false"));
+    }
+
     @Override
     public void filter(final ClientRequestContext context) {
-        if (context.getProperty(OpenTracingClientRequestFilter.class.getName()) != null || "true"
-                .equalsIgnoreCase(String.valueOf(context.getProperty("org.apache.geronimo.microprofile.opentracing.skip")))) {
+        if (context.getProperty(OpenTracingClientRequestFilter.class.getName()) != null || skip) {
             return;
         }
 
@@ -57,8 +72,7 @@
 
         final Scope scope = builder.startActive(true);
         final Span span = scope.span();
-        if (!"true".equalsIgnoreCase(
-                String.valueOf(context.getProperty("org.apache.geronimo.microprofile.opentracing.client.skipDefaultSpanTags")))) {
+        if (!skipDefaultTags) {
             Tags.HTTP_METHOD.set(span, context.getMethod());
             Tags.HTTP_URL.set(span, context.getUri().toASCIIString());
         }
@@ -71,7 +85,7 @@
         ofNullable(context.getProperty("org.apache.geronimo.microprofile.opentracing.spanConsumer"))
                 .ifPresent(consumer -> Consumer.class.cast(consumer).accept(span));
 
-        tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new HeaderTextMap<>(context.getHeaders()));
+        tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new JaxRsHeaderTextMap<>(context.getHeaders()));
         context.setProperty(OpenTracingClientRequestFilter.class.getName(), scope);
 
     }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/GeronimoOpenTracingFeature.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/GeronimoOpenTracingFeature.java
index 8032163..821f14e 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/GeronimoOpenTracingFeature.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/GeronimoOpenTracingFeature.java
@@ -30,6 +30,7 @@
 import javax.ws.rs.core.FeatureContext;
 import javax.ws.rs.ext.Provider;
 
+import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
 import org.eclipse.microprofile.opentracing.Traced;
 
 import io.opentracing.Tracer;
@@ -41,10 +42,15 @@
     @Inject
     private Tracer tracer;
 
+    @Inject
+    private GeronimoOpenTracingConfig config;
+
     @Override
     public void configure(final ResourceInfo resourceInfo, final FeatureContext context) {
         if (tracer == null) { // configured instead of scanned
-            tracer = CDI.current().select(Tracer.class).get();
+            CDI<Object> cdi = CDI.current();
+            tracer = cdi.select(Tracer.class).get();
+            config = cdi.select(GeronimoOpenTracingConfig.class).get();
         }
 
         final Optional<Traced> traced = ofNullable(ofNullable(resourceInfo.getResourceMethod().getAnnotation(Traced.class))
@@ -59,6 +65,9 @@
                         .map(a -> a.annotationType().getAnnotation(HttpMethod.class).value()).orElse("") + ':'
                         + resourceInfo.getResourceClass().getName() + "." + resourceInfo.getResourceMethod().getName());
         context.register(new OpenTracingServerResponseFilter())
-                .register(new OpenTracingServerRequestFilter(operationName, tracer));
+                .register(new OpenTracingServerRequestFilter(
+                        operationName, tracer,
+                        Boolean.parseBoolean(config.read("server.filter.request.skip." + resourceInfo.getResourceClass().getName() + "_" + resourceInfo.getResourceMethod().getName(), config.read("server.filter.request.skip", "false"))),
+                        Boolean.parseBoolean(config.read("server.filter.request.skipDefaultTags", "false"))));
     }
 }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingFilter.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingFilter.java
index 9d2307e..4fae300 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingFilter.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingFilter.java
@@ -1,24 +1,37 @@
 package org.apache.geronimo.microprofile.opentracing.microprofile.server;
 
 import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
 
 import java.io.IOException;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import javax.inject.Inject;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
+import org.apache.geronimo.microprofile.opentracing.impl.ScopeManagerImpl;
+import org.apache.geronimo.microprofile.opentracing.impl.ServletHeaderTextMap;
+
 import io.opentracing.Scope;
 import io.opentracing.Span;
 import io.opentracing.Tracer;
+import io.opentracing.propagation.Format;
 import io.opentracing.tag.Tags;
 
 public class OpenTracingFilter implements Filter {
@@ -26,6 +39,39 @@
     @Inject
     private Tracer tracer;
 
+    @Inject
+    private GeronimoOpenTracingConfig config;
+
+    @Inject
+    private ScopeManagerImpl manager;
+
+    private Collection<Predicate<String>> forcedUrls;
+
+    private boolean skipDefaultTags;
+
+    @Override
+    public void init(final FilterConfig filterConfig) throws ServletException {
+        skipDefaultTags = Boolean.parseBoolean(config.read("filter.forcedTracing.skipDefaultTags", "false"));
+        forcedUrls = ofNullable(config.read("filter.forcedTracing.urls", null)).map(String::trim).filter(v -> !v.isEmpty())
+                .map(v -> {
+                    final String matchingType = config.read("filter.forcedTracing.matcherType", "prefix");
+                    final Function<String, Predicate<String>> matcherFactory;
+                    switch (matchingType) {
+                    case "regex":
+                        matcherFactory = from -> {
+                            final Pattern compiled = Pattern.compile(from);
+                            return url -> compiled.matcher(url).matches();
+                        };
+                        break;
+                    case "prefix":
+                    default:
+                        matcherFactory = from -> url -> url.startsWith(from);
+                    }
+                    return Stream.of(v.split(",")).map(String::trim).filter(it -> !it.isEmpty()).map(matcherFactory)
+                            .collect(toList());
+                }).orElse(null);
+    }
+
     @Override
     public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
             throws IOException, ServletException {
@@ -33,26 +79,50 @@
             chain.doFilter(request, response);
             return;
         }
-        // todo: implicit start for matching urls
+        if (forcedUrls != null && !forcedUrls.isEmpty()) {
+            final HttpServletRequest req = HttpServletRequest.class.cast(request);
+            final String matching = req.getRequestURI().substring(req.getContextPath().length());
+            if (forcedUrls.stream().anyMatch(p -> p.test(matching))) {
+                final Tracer.SpanBuilder builder = tracer.buildSpan(buildServletOperationName(req));
+                builder.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER);
+                builder.withTag("component", "servlet");
+
+                ofNullable(ofNullable(tracer.activeSpan()).map(Span::context)
+                        .orElseGet(() -> tracer.extract(Format.Builtin.HTTP_HEADERS,
+                                new ServletHeaderTextMap(req, HttpServletResponse.class.cast(response)))))
+                                        .ifPresent(builder::asChildOf);
+
+                final Scope scope = builder.startActive(true);
+                final Span span = scope.span();
+
+                if (!skipDefaultTags) {
+                    Tags.HTTP_METHOD.set(span, req.getMethod());
+                    Tags.HTTP_URL.set(span, req.getRequestURL().toString());
+                }
+
+                request.setAttribute(OpenTracingFilter.class.getName(), scope);
+            }
+        }
         try {
             chain.doFilter(request, response);
         } catch (final Exception ex) {
-            ofNullable(request.getAttribute(OpenTracingFilter.class.getName())).map(Scope.class::cast).ifPresent(scope -> {
-                final int status = HttpServletResponse.class.cast(response).getStatus();
-                final Span span = scope.span();
-                Tags.HTTP_STATUS.set(span, status == HttpServletResponse.SC_OK ? HttpServletResponse.SC_INTERNAL_SERVER_ERROR : status);
-                Tags.ERROR.set(span, true);
-                span.log(new HashMap<String, Object>() {
+            getCurrentScope(request).ifPresent(scope -> {
+                        final int status = HttpServletResponse.class.cast(response).getStatus();
+                        final Span span = scope.span();
+                        Tags.HTTP_STATUS.set(span,
+                                status == HttpServletResponse.SC_OK ? HttpServletResponse.SC_INTERNAL_SERVER_ERROR : status);
+                        Tags.ERROR.set(span, true);
+                        span.log(new HashMap<String, Object>() {
 
-                    {
-                        put("event", Tags.ERROR.getKey());
-                        put("event.object", ex);
-                    }
-                });
-            });
+                            {
+                                put("event", Tags.ERROR.getKey());
+                                put("event.object", ex);
+                            }
+                        });
+                    });
             throw ex;
         } finally {
-            ofNullable(request.getAttribute(OpenTracingFilter.class.getName())).map(Scope.class::cast).ifPresent(scope -> {
+            getCurrentScope(request).ifPresent(scope -> {
                 if (request.isAsyncStarted()) {
                     request.getAsyncContext().addListener(new AsyncListener() {
 
@@ -76,10 +146,20 @@
                             // no-op
                         }
                     });
+                    manager.clear();
                 } else {
                     scope.close();
                 }
             });
         }
     }
+
+    private Optional<Scope> getCurrentScope(final ServletRequest request) {
+        return ofNullable(ofNullable(request.getAttribute(OpenTracingFilter.class.getName()))
+                .orElseGet(() -> tracer.scopeManager().active())).map(Scope.class::cast);
+    }
+
+    protected String buildServletOperationName(final HttpServletRequest req) {
+        return req.getMethod() + ":" + req.getRequestURL();
+    }
 }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingServerRequestFilter.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingServerRequestFilter.java
index 7993db4..91aaed1 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingServerRequestFilter.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/OpenTracingServerRequestFilter.java
@@ -21,7 +21,7 @@
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.ContainerRequestFilter;
 
-import org.apache.geronimo.microprofile.opentracing.impl.HeaderTextMap;
+import org.apache.geronimo.microprofile.opentracing.impl.JaxRsHeaderTextMap;
 import org.apache.geronimo.microprofile.opentracing.microprofile.client.OpenTracingClientRequestFilter;
 
 import io.opentracing.Scope;
@@ -36,15 +36,21 @@
 
     private final Tracer tracer;
 
-    public OpenTracingServerRequestFilter(final String operationName, final Tracer tracer) {
+    private final boolean skip;
+
+    private final boolean skipDefaultTags;
+
+    public OpenTracingServerRequestFilter(final String operationName, final Tracer tracer,
+                                          final boolean skip, final boolean skipDefaultTags) {
         this.operationName = operationName;
         this.tracer = tracer;
+        this.skip = skip;
+        this.skipDefaultTags = skipDefaultTags;
     }
 
     @Override
     public void filter(final ContainerRequestContext context) {
-        if (context.getProperty(OpenTracingClientRequestFilter.class.getName()) != null || "true"
-                .equalsIgnoreCase(String.valueOf(context.getProperty("org.apache.geronimo.microprofile.opentracing.skip")))) {
+        if (context.getProperty(OpenTracingClientRequestFilter.class.getName()) != null || skip) {
             return;
         }
 
@@ -53,14 +59,13 @@
         builder.withTag("component", "jaxrs");
 
         ofNullable(ofNullable(tracer.activeSpan()).map(Span::context)
-                .orElseGet(() -> tracer.extract(Format.Builtin.HTTP_HEADERS, new HeaderTextMap<>(context.getHeaders()))))
+                .orElseGet(() -> tracer.extract(Format.Builtin.HTTP_HEADERS, new JaxRsHeaderTextMap<>(context.getHeaders()))))
                 .ifPresent(builder::asChildOf);
 
         final Scope scope = builder.startActive(true);
         final Span span = scope.span();
 
-        if (!"true".equalsIgnoreCase(
-                String.valueOf(context.getProperty("org.apache.geronimo.microprofile.opentracing.server.skipDefaultSpanTags")))) {
+        if (!skipDefaultTags) {
             Tags.HTTP_METHOD.set(span, context.getMethod());
             Tags.HTTP_URL.set(span, context.getUriInfo().getRequestUri().toASCIIString());
         }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/ServletTracingSetup.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/ServletTracingSetup.java
index a0e01fd..72281fd 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/ServletTracingSetup.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/server/ServletTracingSetup.java
@@ -24,9 +24,15 @@
 import javax.servlet.ServletContainerInitializer;
 import javax.servlet.ServletContext;
 
+import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
+
 public class ServletTracingSetup implements ServletContainerInitializer {
     @Override
     public void onStartup(final Set<Class<?>> c, final ServletContext ctx) {
+        final GeronimoOpenTracingConfig config  = GeronimoOpenTracingConfig.create();
+        if (!"true".equalsIgnoreCase(config.read("filter.active", "true"))) {
+            return;
+        }
         final FilterRegistration.Dynamic opentracing = ctx.addFilter("opentracing", OpenTracingFilter.class);
         opentracing.setAsyncSupported(true);
         opentracing.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingExecutorService.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/thread/OpenTracingExecutorService.java
similarity index 77%
rename from geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingExecutorService.java
rename to geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/thread/OpenTracingExecutorService.java
index 37e1059..9928fb2 100644
--- a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/client/OpenTracingExecutorService.java
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/thread/OpenTracingExecutorService.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.geronimo.microprofile.opentracing.microprofile.client;
+package org.apache.geronimo.microprofile.opentracing.microprofile.thread;
 
 import static java.util.stream.Collectors.toList;
 
@@ -27,9 +27,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import io.opentracing.Span;
 import io.opentracing.Tracer;
-import io.opentracing.tag.Tags;
 
 public class OpenTracingExecutorService implements ExecutorService {
 
@@ -42,20 +40,6 @@
         this.tracer = tracer;
     }
 
-    private Span before() {
-        return tracer.activeSpan();
-    }
-
-    private void after(final Span span, final RuntimeException error) {
-        if (span != null && error != null) {
-            Tags.ERROR.set(span, true);
-            if (error.getMessage() != null) {
-                span.setTag("errorMessage", error.getMessage());
-                span.setTag("errorType", error.getClass().getName());
-            }
-        }
-    }
-
     @Override
     public void shutdown() {
         delegate.shutdown();
@@ -124,32 +108,22 @@
     }
 
     private Runnable wrap(final Runnable task) {
+        final ScopePropagatingCallable<Void> decorator = new ScopePropagatingCallable<>(() -> {
+            task.run();
+            return null;
+        }, tracer);
         return () -> {
-            RuntimeException error = null;
-            final Span span = before();
             try {
-                task.run();
-            } catch (final RuntimeException re) {
-                error = re;
-                throw re;
-            } finally {
-                after(span, error);
+                decorator.call();
+            } catch (final RuntimeException | Error e) {
+                throw e;
+            } catch (final Exception e) { // unlikely since that's a Runnable
+                throw new IllegalStateException(e);
             }
         };
     }
 
     private <T> Callable<T> wrap(final Callable<T> task) {
-        return () -> {
-            RuntimeException error = null;
-            final Span span = before();
-            try {
-                return task.call();
-            } catch (final RuntimeException re) {
-                error = re;
-                throw re;
-            } finally {
-                after(span, error);
-            }
-        };
+        return new ScopePropagatingCallable<>(task, tracer);
     }
 }
diff --git a/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/thread/ScopePropagatingCallable.java b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/thread/ScopePropagatingCallable.java
new file mode 100644
index 0000000..bd56c7b
--- /dev/null
+++ b/geronimo-opentracing-impl/src/main/java/org/apache/geronimo/microprofile/opentracing/microprofile/thread/ScopePropagatingCallable.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.microprofile.opentracing.microprofile.thread;
+
+import java.util.concurrent.Callable;
+
+import io.opentracing.Span;
+import io.opentracing.Tracer;
+import io.opentracing.tag.Tags;
+
+public class ScopePropagatingCallable<B> implements Callable<B> {
+
+    private final Callable<B> delegate;
+
+    private final Tracer tracer;
+
+    public ScopePropagatingCallable(final Callable<B> delegate, final Tracer tracer) {
+        this.delegate = delegate;
+        this.tracer = tracer;
+    }
+
+    private Span before() {
+        return tracer.activeSpan();
+    }
+
+    private void after(final Span span, final RuntimeException error) {
+        if (span != null && error != null) {
+            Tags.ERROR.set(span, true);
+            if (error.getMessage() != null) {
+                span.setTag("errorMessage", error.getMessage());
+                span.setTag("errorType", error.getClass().getName());
+            }
+        }
+    }
+
+    @Override
+    public B call() throws Exception {
+        RuntimeException error = null;
+        final Span span = before();
+        try {
+            return delegate.call();
+        } catch (final RuntimeException re) {
+            error = re;
+            throw re;
+        } finally {
+            after(span, error);
+        }
+    }
+}