starting to wire some metrics
diff --git a/pom.xml b/pom.xml
index f85ac1f..e5889f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,213 +18,214 @@
   ~  under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache</groupId>
-        <artifactId>apache</artifactId>
-        <version>18</version>
-    </parent>
-    <groupId>org.apache.geronimo.safeguard</groupId>
-    <artifactId>safeguard-parent</artifactId>
-    <version>1.1-SNAPSHOT</version>
-    <packaging>pom</packaging>
-    <name>Apache Safeguard</name>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>18</version>
+  </parent>
+  <groupId>org.apache.geronimo.safeguard</groupId>
+  <artifactId>safeguard-parent</artifactId>
+  <version>1.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <name>Apache Safeguard</name>
 
-    <modules>
-        <module>safeguard-impl</module>
-    </modules>
+  <modules>
+    <module>safeguard-impl</module>
+  </modules>
 
-    <licenses>
-        <license>
-            <name>Apache License, Version 2.0</name>
-            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
-            <distribution>repo</distribution>
-        </license>
-    </licenses>
+  <licenses>
+    <license>
+      <name>Apache License, Version 2.0</name>
+      <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
 
-    <scm>
-        <connection>scm:git:https://git-wip-us.apache.org/repos/asf/geronimo-safeguard.git</connection>
-        <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/geronimo-safeguard.git</developerConnection>
-        <url>https://git-wip-us.apache.org/repos/asf/geronimo-safeguard.git</url>
-        <tag>HEAD</tag>
-    </scm>
+  <scm>
+    <connection>scm:git:https://git-wip-us.apache.org/repos/asf/geronimo-safeguard.git</connection>
+    <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/geronimo-safeguard.git</developerConnection>
+    <url>https://git-wip-us.apache.org/repos/asf/geronimo-safeguard.git</url>
+    <tag>HEAD</tag>
+  </scm>
 
-    <organization>
-        <name>The Apache Software Foundation</name>
-        <url>http://www.apache.org/</url>
-    </organization>
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://www.apache.org/</url>
+  </organization>
 
-    <inceptionYear>2017</inceptionYear>
+  <inceptionYear>2017</inceptionYear>
 
-    <developers>
-        <developer>
-            <name>Apache Geronimo Community</name>
-            <url>https://geronimo.apache.org</url>
-            <organization>Apache</organization>
-        </developer>
-    </developers>
+  <developers>
+    <developer>
+      <name>Apache Geronimo Community</name>
+      <url>https://geronimo.apache.org</url>
+      <organization>Apache</organization>
+    </developer>
+  </developers>
 
-    <issueManagement>
-        <system>ASF JIRA</system>
-        <url>https://issues.apache.org/jira/browse/GERONIMO</url>
-    </issueManagement>
+  <issueManagement>
+    <system>ASF JIRA</system>
+    <url>https://issues.apache.org/jira/browse/GERONIMO</url>
+  </issueManagement>
 
-    <properties>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
-        <microprofile-fault-tolerance.version>1.1.3</microprofile-fault-tolerance.version>
-        <owb.version>2.0.1</owb.version>
-        <arquillian.version>1.1.14.Final</arquillian.version>
-        <arquillian-weld-embedded.version>2.0.0.Final</arquillian-weld-embedded.version>
-        <cdi2-api.version>2.0</cdi2-api.version>
-        <weld.version>3.0.1.Final</weld.version>
-        <geronimo-config-impl.version>1.2</geronimo-config-impl.version>
-        <microprofile-config-api.version>1.2</microprofile-config-api.version>
-    </properties>
+  <properties>
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+    <microprofile-fault-tolerance.version>1.1.3</microprofile-fault-tolerance.version>
+    <owb.version>2.0.1</owb.version>
+    <arquillian.version>1.1.14.Final</arquillian.version>
+    <arquillian-weld-embedded.version>2.0.0.Final</arquillian-weld-embedded.version>
+    <cdi2-api.version>2.0</cdi2-api.version>
+    <weld.version>3.0.1.Final</weld.version>
+    <geronimo-config-impl.version>1.2</geronimo-config-impl.version>
+    <microprofile-config-api.version>1.2</microprofile-config-api.version>
+  </properties>
 
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.apache.geronimo.specs</groupId>
-                <artifactId>geronimo-jcdi_2.0_spec</artifactId>
-                <version>1.0.1</version>
-                <scope>provided</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.geronimo.specs</groupId>
-                <artifactId>geronimo-annotation_1.3_spec</artifactId>
-                <version>1.0</version>
-                <scope>provided</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.geronimo.specs</groupId>
-                <artifactId>geronimo-atinject_1.0_spec</artifactId>
-                <version>1.0</version>
-                <scope>provided</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.microprofile.config</groupId>
-                <artifactId>microprofile-config-api</artifactId>
-                <version>${microprofile-config-api.version}</version>
-                <optional>true</optional>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.geronimo.config</groupId>
-                <artifactId>geronimo-config-impl</artifactId>
-                <version>${geronimo-config-impl.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
-                <artifactId>microprofile-fault-tolerance-api</artifactId>
-                <version>${microprofile-fault-tolerance.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
-                <artifactId>microprofile-fault-tolerance-tck</artifactId>
-                <version>${microprofile-fault-tolerance.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.geronimo.specs</groupId>
-                <artifactId>geronimo-interceptor_1.2_spec</artifactId>
-                <version>1.0</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.geronimo.specs</groupId>
-                <artifactId>geronimo-el_2.2_spec</artifactId>
-                <version>1.0.2</version>
-                <scope>provided</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.openwebbeans</groupId>
-                <artifactId>openwebbeans-spi</artifactId>
-                <version>${owb.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.openwebbeans</groupId>
-                <artifactId>openwebbeans-impl</artifactId>
-                <version>${owb.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.openwebbeans.arquillian</groupId>
-                <artifactId>owb-arquillian-standalone</artifactId>
-                <version>${owb.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.testng</groupId>
-                <artifactId>testng</artifactId>
-                <version>6.9.9</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.assertj</groupId>
-                <artifactId>assertj-core</artifactId>
-                <version>3.8.0</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.jboss.weld.se</groupId>
-                <artifactId>weld-se-shaded</artifactId>
-                <version>${weld.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.jboss.arquillian.container</groupId>
-                <artifactId>arquillian-weld-embedded</artifactId>
-                <version>${arquillian-weld-embedded.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.jboss.arquillian.testng</groupId>
-                <artifactId>arquillian-testng-container</artifactId>
-                <version>${arquillian.version}</version>
-                <scope>test</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-jcdi_2.0_spec</artifactId>
+        <version>1.0.1</version>
+        <scope>provided</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-annotation_1.3_spec</artifactId>
+        <version>1.0</version>
+        <scope>provided</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-atinject_1.0_spec</artifactId>
+        <version>1.0</version>
+        <scope>provided</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.eclipse.microprofile.config</groupId>
+        <artifactId>microprofile-config-api</artifactId>
+        <version>${microprofile-config-api.version}</version>
+        <optional>true</optional>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.config</groupId>
+        <artifactId>geronimo-config-impl</artifactId>
+        <version>${geronimo-config-impl.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
+        <artifactId>microprofile-fault-tolerance-api</artifactId>
+        <version>${microprofile-fault-tolerance.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
+        <artifactId>microprofile-fault-tolerance-tck</artifactId>
+        <version>${microprofile-fault-tolerance.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-interceptor_1.2_spec</artifactId>
+        <version>1.0</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-el_2.2_spec</artifactId>
+        <version>1.0.2</version>
+        <scope>provided</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.openwebbeans</groupId>
+        <artifactId>openwebbeans-spi</artifactId>
+        <version>${owb.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.openwebbeans</groupId>
+        <artifactId>openwebbeans-impl</artifactId>
+        <version>${owb.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.openwebbeans.arquillian</groupId>
+        <artifactId>owb-arquillian-standalone</artifactId>
+        <version>${owb.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.testng</groupId>
+        <artifactId>testng</artifactId>
+        <version>6.9.9</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.assertj</groupId>
+        <artifactId>assertj-core</artifactId>
+        <version>3.8.0</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.weld.se</groupId>
+        <artifactId>weld-se-shaded</artifactId>
+        <version>${weld.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.arquillian.container</groupId>
+        <artifactId>arquillian-weld-embedded</artifactId>
+        <version>${arquillian-weld-embedded.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.arquillian.testng</groupId>
+        <artifactId>arquillian-testng-container</artifactId>
+        <version>${arquillian.version}</version>
+        <scope>test</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
 
-    <profiles>
-        <profile>
-            <id>OWB2</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.apache.geronimo.specs</groupId>
-                    <artifactId>geronimo-el_2.2_spec</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.openwebbeans</groupId>
-                    <artifactId>openwebbeans-spi</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.openwebbeans</groupId>
-                    <artifactId>openwebbeans-impl</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.apache.openwebbeans.arquillian</groupId>
-                    <artifactId>owb-arquillian-standalone</artifactId>
-                </dependency>
-            </dependencies>
-        </profile>
-        <profile>
-            <id>Weld3</id>
-            <dependencies>
-                <dependency>
-                    <groupId>org.jboss.weld.se</groupId>
-                    <artifactId>weld-se-shaded</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>org.jboss.arquillian.container</groupId>
-                    <artifactId>arquillian-weld-embedded</artifactId>
-                </dependency>
-            </dependencies>
-        </profile>
-    </profiles>
+  <profiles>
+    <profile>
+      <id>OWB2</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.geronimo.specs</groupId>
+          <artifactId>geronimo-el_2.2_spec</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.openwebbeans</groupId>
+          <artifactId>openwebbeans-spi</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.openwebbeans</groupId>
+          <artifactId>openwebbeans-impl</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.openwebbeans.arquillian</groupId>
+          <artifactId>owb-arquillian-standalone</artifactId>
+        </dependency>
+      </dependencies>
+    </profile>
+    <profile>
+      <id>Weld3</id>
+      <dependencies>
+        <dependency>
+          <groupId>org.jboss.weld.se</groupId>
+          <artifactId>weld-se-shaded</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.jboss.arquillian.container</groupId>
+          <artifactId>arquillian-weld-embedded</artifactId>
+        </dependency>
+      </dependencies>
+    </profile>
+  </profiles>
 </project>
\ No newline at end of file
diff --git a/safeguard-impl/pom.xml b/safeguard-impl/pom.xml
index 9022b62..7d4cf7b 100644
--- a/safeguard-impl/pom.xml
+++ b/safeguard-impl/pom.xml
@@ -18,96 +18,103 @@
   ~  under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>safeguard-parent</artifactId>
-        <groupId>org.apache.geronimo.safeguard</groupId>
-        <version>1.1-SNAPSHOT</version>
-    </parent>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>safeguard-parent</artifactId>
+    <groupId>org.apache.geronimo.safeguard</groupId>
+    <version>1.1-SNAPSHOT</version>
+  </parent>
 
-    <modelVersion>4.0.0</modelVersion>
+  <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>safeguard-impl</artifactId>
-    <name>Apache Safeguard :: Implementation</name>
+  <artifactId>safeguard-impl</artifactId>
+  <name>Apache Safeguard :: Implementation</name>
 
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
-            <artifactId>microprofile-fault-tolerance-api</artifactId>
-            <version>${microprofile-fault-tolerance.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.microprofile.metrics</groupId>
-            <artifactId>microprofile-metrics-api</artifactId>
-            <version>1.1.1</version>
-            <scope>provided</scope>
-        </dependency>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
+      <artifactId>microprofile-fault-tolerance-api</artifactId>
+      <version>${microprofile-fault-tolerance.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.microprofile.metrics</groupId>
+      <artifactId>microprofile-metrics-api</artifactId>
+      <version>1.1.1</version>
+      <scope>provided</scope>
+    </dependency>
 
-        <dependency>
-            <groupId>org.jboss.arquillian.testng</groupId>
-            <artifactId>arquillian-testng-container</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-jcdi_2.0_spec</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-atinject_1.0_spec</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-annotation_1.3_spec</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-interceptor_1.2_spec</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.microprofile.config</groupId>
-            <artifactId>microprofile-config-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.testng</groupId>
-            <artifactId>testng</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo.config</groupId>
-            <artifactId>geronimo-config-impl</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
-            <artifactId>microprofile-fault-tolerance-tck</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.geronimo</groupId>
-            <artifactId>geronimo-metrics</artifactId>
-            <version>1.0.0</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
+    <dependency>
+      <groupId>org.jboss.arquillian.testng</groupId>
+      <artifactId>arquillian-testng-container</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jcdi_2.0_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-atinject_1.0_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-annotation_1.3_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-interceptor_1.2_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.microprofile.config</groupId>
+      <artifactId>microprofile-config-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest-all</artifactId>
+      <version>1.3</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.testng</groupId>
+      <artifactId>testng</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.config</groupId>
+      <artifactId>geronimo-config-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
+      <artifactId>microprofile-fault-tolerance-tck</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo</groupId>
+      <artifactId>geronimo-metrics</artifactId>
+      <version>1.0.0</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>3.0.0-M1</version>
-                <configuration>
-                    <dependenciesToScan>
-                        <dependency>org.eclipse.microprofile.fault-tolerance:microprofile-fault-tolerance-tck</dependency>
-                    </dependenciesToScan>
-                    <excludes>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.ConfigTest</exclude>
-                    </excludes>
-                    <trimStackTrace>false</trimStackTrace>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>3.0.0-M1</version>
+        <configuration>
+          <dependenciesToScan>
+            <dependency>org.eclipse.microprofile.fault-tolerance:microprofile-fault-tolerance-tck</dependency>
+          </dependenciesToScan>
+          <excludes>
+            <exclude>org.eclipse.microprofile.fault.tolerance.tck.ConfigTest</exclude>
+          </excludes>
+          <trimStackTrace>false</trimStackTrace>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>
\ No newline at end of file
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java
index db68832..e85871e 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java
@@ -32,6 +32,7 @@
 import javax.interceptor.AroundInvoke;
 import javax.interceptor.InvocationContext;
 
+import org.apache.safeguard.impl.interceptor.IdGeneratorInterceptor;
 import org.eclipse.microprofile.faulttolerance.Asynchronous;
 import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
 
@@ -39,11 +40,13 @@
     protected abstract Executor getExecutor(InvocationContext context);
 
     protected Object around(final InvocationContext context) throws Exception {
-        if (context.getContextData().get(Asynchronous.class.getName()) != null) { // bulkhead or so handling threading
+        final String key = Asynchronous.class.getName() +
+                context.getContextData().get(IdGeneratorInterceptor.class.getName());
+        if (context.getContextData().get(key) != null) { // bulkhead or so handling threading
             return context.proceed();
         }
 
-        context.getContextData().put(Asynchronous.class.getName(), "true");
+        context.getContextData().put(key, "true");
 
         final Class<?> returnType = context.getMethod().getReturnType();
         if (CompletionStage.class.isAssignableFrom(returnType)) {
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java
index 6bdb6f7..b7f5799 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java
@@ -25,10 +25,10 @@
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.ThreadPoolExecutor;
 
+import javax.annotation.PreDestroy;
 import javax.annotation.Priority;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
@@ -38,11 +38,13 @@
 
 import org.apache.safeguard.impl.annotation.AnnotationFinder;
 import org.apache.safeguard.impl.asynchronous.BaseAsynchronousInterceptor;
+import org.apache.safeguard.impl.interceptor.IdGeneratorInterceptor;
 import org.eclipse.microprofile.faulttolerance.Asynchronous;
 import org.eclipse.microprofile.faulttolerance.Bulkhead;
 import org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException;
 import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
 
+// todo: metrics
 @Bulkhead
 @Interceptor
 @Priority(Interceptor.Priority.PLATFORM_AFTER + 5)
@@ -64,7 +66,8 @@
             }
         }
         if (model.useThreads) {
-            context.getContextData().put(EXECUTOR_KEY, model.pool);
+            context.getContextData().put(
+                    EXECUTOR_KEY + context.getContextData().get(IdGeneratorInterceptor.class.getName()), model.pool);
             return around(context);
         } else {
             if (!model.semaphore.tryAcquire()) {
@@ -80,14 +83,15 @@
 
     @Override
     protected Executor getExecutor(final InvocationContext context) {
-        return Executor.class.cast(context.getContextData().get(EXECUTOR_KEY));
+        return Executor.class.cast(context.getContextData()
+                  .get(EXECUTOR_KEY + context.getContextData().get(IdGeneratorInterceptor.class.getName())));
     }
 
     static class Model {
         private final int value;
         private final int waitingQueue;
         private final boolean useThreads;
-        private final ExecutorService pool;
+        private final ThreadPoolExecutor pool;
         private final Semaphore semaphore;
 
         private Model(final Bulkhead bulkhead, final boolean useThreads) {
@@ -104,6 +108,9 @@
             this.useThreads = useThreads;
             if (this.useThreads) {
                 this.pool = new ThreadPoolExecutor(value, value, 0L, MILLISECONDS, new ArrayBlockingQueue<>(waitingQueue));
+                this.pool.setRejectedExecutionHandler((r, executor) -> {
+                    throw new BulkheadException("Can't accept task " + r);
+                });
                 this.semaphore = null;
             } else {
                 this.pool = null;
@@ -119,6 +126,11 @@
         @Inject
         private AnnotationFinder finder;
 
+        @PreDestroy
+        private void destroy() {
+            models.values().stream().filter(m -> m.pool != null).forEach(m -> m.pool.shutdownNow());
+        }
+
         public Map<Method, Model> getModels() {
             return models;
         }
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardEnabled.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardEnabled.java
new file mode 100644
index 0000000..9755681
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardEnabled.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.safeguard.impl.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.Retention;
+import java.lang.annotation.Target;
+
+import javax.enterprise.util.AnnotationLiteral;
+import javax.interceptor.InterceptorBinding;
+
+@InterceptorBinding
+@Target({TYPE, METHOD})
+@Retention(RUNTIME)
+public @interface SafeguardEnabled {
+    class Literal extends AnnotationLiteral<SafeguardEnabled> implements SafeguardEnabled {
+        public static final SafeguardEnabled.Literal INSTANCE = new SafeguardEnabled.Literal();
+
+        private static final long serialVersionUID = 1L;
+    }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
index e16294b..38e0fea 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
@@ -1,22 +1,38 @@
 package org.apache.safeguard.impl.cdi;
 
+import static java.util.stream.Collectors.toList;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+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.Extension;
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
 import javax.enterprise.inject.spi.ProcessBean;
+import javax.enterprise.inject.spi.WithAnnotations;
 
 import org.apache.safeguard.impl.config.GeronimoFaultToleranceConfig;
 import org.apache.safeguard.impl.customizable.Safeguard;
 import org.apache.safeguard.impl.fallback.FallbackInterceptor;
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
+import org.eclipse.microprofile.faulttolerance.Asynchronous;
+import org.eclipse.microprofile.faulttolerance.Bulkhead;
+import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
+import org.eclipse.microprofile.faulttolerance.Fallback;
+import org.eclipse.microprofile.faulttolerance.Retry;
+import org.eclipse.microprofile.faulttolerance.Timeout;
 
 // todo: mp.fault.tolerance.interceptor.priority handling
 public class SafeguardExtension implements Extension {
@@ -26,6 +42,26 @@
         processAnnotatedType.configureAnnotatedType().add(new FallbackBinding());
     }
 
+    void activateSafeguard(@Observes @WithAnnotations({
+            /*Asynchronous.class, */
+            Bulkhead.class, CircuitBreaker.class,
+            Fallback.class, Retry.class, Timeout.class
+    }) final ProcessAnnotatedType<?> processAnnotatedType) {
+        if (processAnnotatedType.getAnnotatedType().getJavaClass().getName().startsWith("org.apache.safeguard.impl")) {
+            return;
+        }
+        if (faultToleranceAnnotations().anyMatch(it -> processAnnotatedType.getAnnotatedType().isAnnotationPresent(it))) {
+            processAnnotatedType.configureAnnotatedType().add(SafeguardEnabled.Literal.INSTANCE);
+        } else {
+            final List<Method> methods = processAnnotatedType.getAnnotatedType().getMethods().stream()
+                    .filter(it -> faultToleranceAnnotations().anyMatch(it::isAnnotationPresent))
+                    .map(AnnotatedMethod::getJavaMember).collect(toList());
+            processAnnotatedType.configureAnnotatedType()
+                    .filterMethods(it -> methods.contains(it.getJavaMember()))
+                    .forEach(m -> m.add(SafeguardEnabled.Literal.INSTANCE));
+        }
+    }
+
     void onBean(@Observes final ProcessBean<?> bean) {
         if (bean.getBean().getQualifiers().stream().anyMatch(it -> it.annotationType() == Safeguard.class)
             && bean.getBean().getTypes().stream().anyMatch(it -> Executor.class.isAssignableFrom(toClass(it)))) {
@@ -40,8 +76,17 @@
                 .types(GeronimoFaultToleranceConfig.class, Object.class)
                 .beanClass(GeronimoFaultToleranceConfig.class)
                 .qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
+                .scope(ApplicationScoped.class)
                 .createWith(c -> config);
 
+        afterBeanDiscovery.addBean()
+                .id("geronimo_safeguard#metrics")
+                .types(FaultToleranceMetrics.class, Object.class)
+                .beanClass(FaultToleranceMetrics.class)
+                .qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
+                .scope(ApplicationScoped.class)
+                .createWith(c -> FaultToleranceMetrics.create());
+
         if (!foundExecutor) {
             afterBeanDiscovery.addBean()
                     .id("geronimo_safeguard#executor")
@@ -49,6 +94,7 @@
                     .beanClass(Executor.class)
                     .qualifiers(Safeguard.Literal.INSTANCE, Any.Literal.INSTANCE)
                     .createWith(c -> Executors.newCachedThreadPool())
+                    .scope(ApplicationScoped.class)
                     .destroyWith((e, c) -> ExecutorService.class.cast(e).shutdownNow());
         }
     }
@@ -69,4 +115,9 @@
         }
         return Object.class; // will not match any of our test
     }
+
+    private Stream<Class<? extends Annotation>> faultToleranceAnnotations() {
+        return Stream.of(Asynchronous.class, Bulkhead.class, CircuitBreaker.class,
+                Fallback.class, Retry.class, Timeout.class);
+    }
 }
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java
index eecb8e3..f7c54a8 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java
@@ -23,6 +23,7 @@
 import java.util.EnumMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Stream;
 
@@ -35,6 +36,7 @@
 
 import org.apache.safeguard.impl.annotation.AnnotationFinder;
 import org.apache.safeguard.impl.config.ConfigurationMapper;
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
 import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
 import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException;
 import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
@@ -58,14 +60,20 @@
             }
         }
         if (!circuitBreaker.checkState()) {
+            circuitBreaker.callsPrevented.inc();
             throw new CircuitBreakerOpenException(context.getMethod() + " circuit breaker is open");
         }
         try {
-            return context.proceed();
+            final Object result = context.proceed();
+            circuitBreaker.callsSucceeded.inc();
+            return result;
         } catch (final Exception e) {
             if (circuitBreaker.failOn.length > 0 &&
                     Stream.of(circuitBreaker.failOn).anyMatch(it -> it.isInstance(e) || it.isInstance(e.getCause()))) {
+                circuitBreaker.callsFailed.inc();
                 circuitBreaker.incrementAndCheckState(1);
+            } else {
+                circuitBreaker.callsSucceeded.inc();
             }
             throw e;
         }
@@ -105,6 +113,9 @@
         @Inject
         private ConfigurationMapper mapper;
 
+        @Inject
+        private FaultToleranceMetrics metrics;
+
         public Map<Method, CircuitBreakerImpl> getCircuitBreakers() {
             return circuitBreakers;
         }
@@ -133,7 +144,26 @@
             if (successThreshold < 0) {
                 throw new FaultToleranceDefinitionException("CircuitBreaker success threshold can't be < 0");
             }
-            return new CircuitBreakerImpl(volumeThreshold, delay, successThreshold, delay, failOn, failureRatio);
+
+            final String metricsNameBase = "ft." + context.getMethod().getDeclaringClass().getCanonicalName() + "."
+                    + context.getMethod().getName() + ".circuitbreaker.";
+
+            final CircuitBreakerImpl circuitBreaker = new CircuitBreakerImpl(volumeThreshold, delay, successThreshold,
+                    delay, failOn, failureRatio, metrics.counter(metricsNameBase + "callsSucceeded.total",
+                    "Number of calls allowed to run by the circuit breaker that returned successfully"),
+                    metrics.counter(metricsNameBase + "callsFailed.total",
+                            "Number of calls allowed to run by the circuit breaker that then failed"),
+                    metrics.counter(metricsNameBase + "callsPrevented.total",
+                            "Number of calls prevented from running by an open circuit breaker"),
+                    metrics.counter(metricsNameBase + "opened.total",
+                            "Number of times the circuit breaker has moved from closed state to open state"));
+            metrics.gauge(metricsNameBase + "open.total", "Amount of time the circuit breaker has spent in open state", "nanoseconds",
+                    circuitBreaker.openDuration::get);
+            metrics.gauge(metricsNameBase + "halfOpen.total", "Amount of time the circuit breaker has spent in half-open state", "nanoseconds",
+                    circuitBreaker.halfOpenDuration::get);
+            metrics.gauge(metricsNameBase + "closed.total", "Amount of time the circuit breaker has spent in closed state", "nanoseconds",
+                    circuitBreaker.closedDuration::get);
+            return circuitBreaker;
         }
     }
 
@@ -150,10 +180,21 @@
         private final double failureRatio;
         private final Class<? extends Throwable>[] failOn;
 
-        private CircuitBreakerImpl(final int openingThreshold, final long openingInterval,
-                                   final int closingThreshold, final long closingInterval,
-                                   final Class<? extends Throwable>[] failOn,
-                                   final double failureRatio) {
+        private final AtomicLong openDuration = new AtomicLong();
+        private final FaultToleranceMetrics.Counter callsSucceeded;
+        private final FaultToleranceMetrics.Counter callsFailed;
+        private final FaultToleranceMetrics.Counter callsPrevented;
+        private final AtomicLong halfOpenDuration = new AtomicLong();
+        private final AtomicLong closedDuration = new AtomicLong();
+        private final FaultToleranceMetrics.Counter opened;
+
+        CircuitBreakerImpl(final int openingThreshold, final long openingInterval, final int closingThreshold,
+                           final long closingInterval, final Class<? extends Throwable>[] failOn,
+                           final double failureRatio,
+                           final FaultToleranceMetrics.Counter callsSucceeded,
+                           final FaultToleranceMetrics.Counter callsFailed,
+                           final FaultToleranceMetrics.Counter callsPrevented,
+                           final FaultToleranceMetrics.Counter opened) {
             this.checkIntervalData = new AtomicReference<>(new CheckIntervalData(0, 0));
             this.openingThreshold = openingThreshold;
             this.openingInterval = openingInterval;
@@ -161,6 +202,10 @@
             this.closingInterval = closingInterval;
             this.failOn = failOn;
             this.failureRatio = failureRatio;
+            this.callsSucceeded = callsSucceeded;
+            this.callsFailed = callsFailed;
+            this.callsPrevented = callsPrevented;
+            this.opened = opened;
         }
 
         protected static boolean isOpen(final State state) {
@@ -191,6 +236,9 @@
             } while (!updateCheckIntervalData(currentData, nextData));
             if (stateStrategy(currentState).isStateTransition(this, currentData, nextData)) {
                 currentState = currentState.oppositeState();
+                if (currentState == State.OPEN) {
+                    opened.inc();
+                }
                 changeStateAndStartNewCheckInterval(currentState);
             }
             return !isOpen(currentState);
@@ -264,8 +312,12 @@
             public boolean isStateTransition(final CircuitBreakerImpl breaker,
                                              final CheckIntervalData currentData, final CheckIntervalData nextData) {
                 final long now = now();
-                return nextData.eventCount > breaker.openingThreshold ||
-                        (now != currentData.checkIntervalStart && (currentData.eventCount / (now - currentData.checkIntervalStart)) > breaker.failureRatio);
+                final boolean result =
+                        nextData.eventCount >= breaker.openingThreshold || (now != currentData.checkIntervalStart && (currentData.eventCount / (now - currentData.checkIntervalStart)) > breaker.failureRatio);
+                if (!result) {
+                    breaker.closedDuration.set(now - currentData.checkIntervalStart);
+                }
+                return result;
             }
 
             @Override
@@ -278,8 +330,12 @@
             @Override
             public boolean isStateTransition(final CircuitBreakerImpl breaker,
                                              final CheckIntervalData currentData, final CheckIntervalData nextData) {
-                return nextData.checkIntervalStart != currentData.checkIntervalStart
-                        && currentData.eventCount < breaker.closingThreshold;
+                final boolean result =
+                        nextData.checkIntervalStart != currentData.checkIntervalStart && currentData.eventCount <= breaker.closingThreshold;
+                if (!result) {
+                    breaker.openDuration.set(now() - currentData.checkIntervalStart);
+                }
+                return result;
             }
 
             @Override
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java
index bd9ee46..77f0d2d 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java
@@ -49,8 +49,8 @@
     private <T extends Annotation> Object findConfiguredValue(final T instance, final Class<T> api,
                                                               final Method sourceMethod,
                                                               final Method proxyMethod, final Object[] args) {
-        return ofNullable(ofNullable(findDefaultConfiguration(proxyMethod))
-                .orElseGet(() -> ofNullable(findMethodConfiguration(api, sourceMethod, proxyMethod))
+        return ofNullable(ofNullable(findMethodConfiguration(api, sourceMethod, proxyMethod))
+                .orElseGet(() -> ofNullable(findDefaultConfiguration(proxyMethod))
                         .orElseGet(() -> ofNullable(findClassConfiguration(api, sourceMethod, proxyMethod)).orElse(null))))
                 .map(v -> coerce(v, proxyMethod.getReturnType()))
                 .orElseGet(() -> {
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java
index e3e8a61..c939059 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java
@@ -43,6 +43,7 @@
 
 import org.apache.safeguard.impl.annotation.AnnotationFinder;
 import org.apache.safeguard.impl.cdi.SafeguardExtension;
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
 import org.eclipse.microprofile.faulttolerance.ExecutionContext;
 import org.eclipse.microprofile.faulttolerance.Fallback;
 import org.eclipse.microprofile.faulttolerance.FallbackHandler;
@@ -103,6 +104,9 @@
         @Inject
         private BeanManager beanManager;
 
+        @Inject
+        private FaultToleranceMetrics metrics;
+
         private final Collection<CreationalContext<?>> contexts = new ArrayList<>();
 
         @PreDestroy
@@ -121,6 +125,8 @@
             if (!method.isEmpty() && value != Fallback.DEFAULT.class) {
                 throw new FaultToleranceDefinitionException("You can't set a method and handler as fallback on " + context.getMethod());
             }
+
+            FallbackHandler<?> handler;
             if (value != Fallback.DEFAULT.class) {
                 Stream.of(value.getInterfaces()).filter(it -> it == FallbackHandler.class)
                         .findFirst()
@@ -134,29 +140,48 @@
                 if (!beanManager.isNormalScope(handlerBean.getScope())) {
                     contexts.add(creationalContext);
                 }
-                return FallbackHandler.class.cast(beanManager.getReference(handlerBean, FallbackHandler.class, creationalContext));
-            }
-            try {
-                final Method fallbackMethod = context.getTarget().getClass().getMethod(method);
-                if (!extension.toClass(context.getMethod().getReturnType()).isAssignableFrom(extension.toClass(fallbackMethod.getReturnType())) ||
-                        !Arrays.equals(context.getMethod().getParameterTypes(), fallbackMethod.getParameterTypes())) {
-                    throw new FaultToleranceDefinitionException("handler method does not match method: " + context.getMethod());
-                }
-                if (!fallbackMethod.isAccessible()) {
-                    fallbackMethod.setAccessible(true);
-                }
-                return (FallbackHandler<Object>) context1 -> {
-                    try {
-                        return fallbackMethod.invoke(EnrichedExecutionContext.class.cast(context1).getTarget(), context1.getParameters());
-                    } catch (final IllegalAccessException e) {
-                        throw new IllegalStateException(e);
-                    } catch (final InvocationTargetException e) {
-                        throw new IllegalStateException(e.getTargetException());
+                final FallbackHandler fallbackHandler = FallbackHandler.class.cast(
+                        beanManager.getReference(handlerBean, FallbackHandler.class, creationalContext));
+                handler = fallbackHandler;
+            } else {
+                try {
+                    final Method fallbackMethod = context.getTarget()
+                                                         .getClass()
+                                                         .getMethod(method);
+                    if (!extension.toClass(context.getMethod()
+                                                  .getReturnType())
+                                  .isAssignableFrom(extension.toClass(fallbackMethod.getReturnType())) || !Arrays.equals(
+                            context.getMethod()
+                                   .getParameterTypes(), fallbackMethod.getParameterTypes())) {
+                        throw new FaultToleranceDefinitionException("handler method does not match method: " + context.getMethod());
                     }
-                };
-            } catch (final NoSuchMethodException e) {
-                throw new FaultToleranceDefinitionException("No method " + method + " in " + context.getTarget());
+                    if (!fallbackMethod.isAccessible()) {
+                        fallbackMethod.setAccessible(true);
+                    }
+                    handler = (FallbackHandler<Object>) context1 -> {
+                        try {
+                            return fallbackMethod.invoke(EnrichedExecutionContext.class.cast(context1)
+                                                                                       .getTarget(),
+                                    context1.getParameters());
+                        } catch (final IllegalAccessException e) {
+                            throw new IllegalStateException(e);
+                        } catch (final InvocationTargetException e) {
+                            throw new IllegalStateException(e.getTargetException());
+                        }
+                    };
+                } catch (final NoSuchMethodException e) {
+                    throw new FaultToleranceDefinitionException("No method " + method + " in " + context.getTarget());
+                }
             }
+
+            final String metricsName = "ft." + context.getMethod().getDeclaringClass().getCanonicalName() + "."
+                    + context.getMethod().getName() + ".fallback.calls.total";
+            final FaultToleranceMetrics.Counter counter = metrics.counter(metricsName,
+                    "Number of times the fallback handler or method was called");
+            return (FallbackHandler<Object>) context12 -> {
+                counter.inc();
+                return handler.handle(context12);
+            };
         }
     }
 
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/interceptor/IdGeneratorInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/interceptor/IdGeneratorInterceptor.java
new file mode 100644
index 0000000..58dd561
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/interceptor/IdGeneratorInterceptor.java
@@ -0,0 +1,111 @@
+/*
+ *  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.safeguard.impl.interceptor;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.cdi.SafeguardEnabled;
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
+
+// simple way to ensure we use a single key in the interceptor context by call
+// and avoids to manage a stack
+@Interceptor
+@SafeguardEnabled
+@Priority(Interceptor.Priority.PLATFORM_BEFORE)
+public class IdGeneratorInterceptor implements Serializable {
+    private static final String KEY = IdGeneratorInterceptor.class.getName();
+
+    private final AtomicLong idGenerator = new AtomicLong();
+
+    @Inject
+    private Cache cache;
+
+    @AroundInvoke
+    public Object generateId(final InvocationContext context) throws Exception {
+        final Object old = context.getContextData().get(KEY);
+        context.getContextData().put(IdGeneratorInterceptor.class.getName(), idGenerator.incrementAndGet());
+
+        final Map<Method, Counters> counters = cache.getCounters();
+        Counters methodCounters = counters.get(context.getMethod());
+        if (methodCounters == null) {
+            methodCounters = cache.create(context.getMethod());
+            final Counters existing = counters.putIfAbsent(context.getMethod(), methodCounters);
+            if (existing != null) {
+                methodCounters = existing;
+            }
+        }
+
+        methodCounters.total.inc();
+        try {
+            return context.proceed();
+        } catch (final Exception | Error e) {
+            methodCounters.failed.inc();
+            throw e;
+        } finally {
+            if (old != null) {
+                context.getContextData().put(IdGeneratorInterceptor.class.getName(), old);
+            } else {
+                context.getContextData().remove(IdGeneratorInterceptor.class.getName());
+            }
+        }
+    }
+
+    private static class Counters {
+        private final FaultToleranceMetrics.Counter total;
+        private final FaultToleranceMetrics.Counter failed;
+
+        private Counters(final FaultToleranceMetrics.Counter total, final FaultToleranceMetrics.Counter failed) {
+            this.total = total;
+            this.failed = failed;
+        }
+    }
+
+    @ApplicationScoped
+    public static class Cache {
+        private final Map<Method, Counters> counters = new ConcurrentHashMap<>();
+
+        @Inject
+        private FaultToleranceMetrics metrics;
+
+        public Map<Method, Counters> getCounters() {
+            return counters;
+        }
+
+        public Counters create(final Method method) {
+            //ft.org.eclipse.microprofile.fault.tolerance.tck.metrics.RetryMetricBean.failSeveralTimes.invocations.total
+            final String metricsNameBase = "ft." + method.getDeclaringClass().getCanonicalName() + "." + method.getName() + ".invocations.";
+            return new Counters(
+                    metrics.counter(metricsNameBase + "total",
+                            "The number of times the method was called"),
+                    metrics.counter(metricsNameBase + "failed.total",
+                            "The number of times the method was called and, after all Fault Tolerance actions had been processed, threw a Throwable"));
+        }
+    }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java
index ec888d3..7edb886 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java
@@ -23,16 +23,27 @@
 
 import java.util.Optional;
 import java.util.ServiceLoader;
+import java.util.function.Supplier;
 import java.util.stream.StreamSupport;
 
 import javax.annotation.Priority;
 import javax.enterprise.inject.spi.CDI;
 
-// todo
 public interface FaultToleranceMetrics {
+    Counter counter(String name, String description);
+    void gauge(String name, String description, String unit, Supplier<Long> supplier);
+    Histogram histogram(String name, String description);
 
-    void inc(String value);
-    void dec(String value);
+
+    interface Histogram {
+        void update(long duration);
+    }
+    interface Counter {
+        void inc();
+        void dec();
+    }
+    interface Gauge extends Supplier<Long> {
+    }
 
     static FaultToleranceMetrics create() {
         try {
@@ -46,17 +57,7 @@
         } catch (final Exception e) {
             // no-op
         }
-        return new FaultToleranceMetrics() {
-            @Override
-            public void inc(final String value) {
-                // no-op
-            }
-
-            @Override
-            public void dec(final String value) {
-                // no-op
-            }
-        };
+        return new NoMetrics();
     }
 }
 
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java
index 9bdf74d..0a2fa9f 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java
@@ -18,8 +18,15 @@
  */
 package org.apache.safeguard.impl.metrics;
 
+import static org.eclipse.microprofile.metrics.MetricType.COUNTER;
+import static org.eclipse.microprofile.metrics.MetricType.GAUGE;
+import static org.eclipse.microprofile.metrics.MetricType.HISTOGRAM;
+
+import java.util.function.Supplier;
+
 import javax.enterprise.inject.Vetoed;
 
+import org.eclipse.microprofile.metrics.Metadata;
 import org.eclipse.microprofile.metrics.MetricRegistry;
 
 @Vetoed
@@ -31,12 +38,33 @@
     }
 
     @Override
-    public void inc(final String value) {
-        registry.counter(value).inc();
+    public Counter counter(final String name, final String description) {
+        final org.eclipse.microprofile.metrics.Counter delegate = registry.counter(
+                new Metadata(name, name, description, COUNTER, "none"));
+        return new Counter() {
+            @Override
+            public void inc() {
+                delegate.inc();
+            }
+
+            @Override
+            public void dec() {
+                delegate.dec();
+            }
+        };
     }
 
     @Override
-    public void dec(final String value) {
-        registry.counter(value).dec();
+    public void gauge(final String name, final String description, final String unit,
+                       final Supplier<Long> supplier) {
+        registry.register(new Metadata(name, name, description, GAUGE, unit),
+                (org.eclipse.microprofile.metrics.Gauge<Long>) supplier::get);
+    }
+
+    @Override
+    public Histogram histogram(final String name, final String description) {
+        final org.eclipse.microprofile.metrics.Histogram histogram = registry.histogram(
+                new Metadata(name, name, description, HISTOGRAM, "none"));
+        return histogram::update;
     }
 }
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/NoMetrics.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/NoMetrics.java
new file mode 100644
index 0000000..d8a4beb
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/NoMetrics.java
@@ -0,0 +1,54 @@
+/*
+ *  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.safeguard.impl.metrics;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+
+@Vetoed
+class NoMetrics implements FaultToleranceMetrics {
+    @Override
+    public Counter counter(final String name, final String description) {
+        return new Counter() {
+            @Override
+            public void inc() {
+                // no-op
+            }
+
+            @Override
+            public void dec() {
+                // no-op
+            }
+        };
+    }
+
+    @Override
+    public void gauge(final String name, final String description, final String unit,
+                      final Supplier<Long> supplier) {
+        // no-op
+    }
+
+    @Override
+    public Histogram histogram(final String name, final String description) {
+        return value -> {
+            // no-op
+        };
+    }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java
index 03d7d13..141f2dc 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java
@@ -18,13 +18,22 @@
  */
 package org.apache.safeguard.impl.retry;
 
+import java.util.Map;
+
 import javax.annotation.Priority;
 import javax.interceptor.Interceptor;
 
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
 import org.eclipse.microprofile.faulttolerance.Retry;
 
 @Retry
 @Interceptor
 @Priority(Interceptor.Priority.PLATFORM_AFTER + 10)
 public class AfterRetryInterceptor extends BaseRetryInterceptor {
+    @Override
+    protected void executeFinalCounterAction(final Map<String, Object> contextData, final String counterActionKey,
+                                             final FaultToleranceMetrics.Counter counter) {
+        // can be used to push it back to the before interceptor:
+        // contextData.put(counterActionKey, (Runnable) counter::inc);
+    }
 }
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java
index dcfc848..89acc9f 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java
@@ -1,20 +1,20 @@
 /*
- *  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
+ * 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
+ * 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.
+ * 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.safeguard.impl.retry;
 
@@ -27,6 +27,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Stream;
 
 import javax.enterprise.context.ApplicationScoped;
@@ -36,10 +37,13 @@
 
 import org.apache.safeguard.impl.annotation.AnnotationFinder;
 import org.apache.safeguard.impl.config.ConfigurationMapper;
+import org.apache.safeguard.impl.interceptor.IdGeneratorInterceptor;
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
 import org.eclipse.microprofile.faulttolerance.Retry;
 import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceException;
 
-public class BaseRetryInterceptor implements Serializable {
+public abstract class BaseRetryInterceptor implements Serializable {
+
     @Inject
     private Cache cache;
 
@@ -51,63 +55,107 @@
             model = cache.create(context);
             models.putIfAbsent(context.getMethod(), model);
         }
-        for (int i = 0; i < model.maxRetries + 1; i++) {
+
+        final Map<String, Object> contextData = context.getContextData();
+        final String counterKey = BaseRetryInterceptor.class.getName() + ".counter_"
+                + contextData.get(IdGeneratorInterceptor.class.getName());
+        final String counterActionKey = BaseRetryInterceptor.class.getName() + ".counterAction_"
+                + contextData.get(IdGeneratorInterceptor.class.getName());
+        AtomicInteger counter = AtomicInteger.class.cast(contextData.get(counterKey));
+        if (counter == null) {
+            counter = new AtomicInteger(model.maxRetries);
+            contextData.put(counterKey, counter);
+        }
+
+        while (counter.get() >= 0) {
             try {
-                return context.proceed();
-            } catch (final RuntimeException re) {
-                if (model.abortOn(re)) {
-                    throw new FaultToleranceException(re);
+                final Object proceed = context.proceed();
+                if (counter.get() == model.maxRetries) {
+                    executeFinalCounterAction(contextData, counterActionKey, model.callsSucceededNotRetried);
+                } else {
+                    executeFinalCounterAction(contextData, counterActionKey, model.callsSucceededRetried);
                 }
-                if (model.maxRetries == i) {
+                return proceed;
+            } catch (final Exception re) {
+                // refresh the counter from the other interceptors
+                counter = AtomicInteger.class.cast(contextData.get(counterKey));
+
+                if (model.abortOn(re) || counter.decrementAndGet() < 0) {
+                    executeFinalCounterAction(contextData, counterActionKey, model.callsFailed);
                     throw re;
                 }
-                if (model.retryOn(re)) {
-                    Thread.sleep(model.nextPause());
+                if (!model.retryOn(re)) {
+                    throw re;
                 }
+                model.retries.inc();
+                Thread.sleep(model.nextPause());
             }
         }
-        throw new IllegalStateException("Inaccessible but needed to compile");
+        throw new FaultToleranceException("Inaccessible normally, here for compilation");
     }
 
+    protected abstract void executeFinalCounterAction(Map<String, Object> contextData, String counterActionKey,
+            FaultToleranceMetrics.Counter counter);
+
     static class Model {
+
         private final Class<? extends Throwable>[] abortOn;
+
         private final Class<? extends Throwable>[] retryOn;
+
         private final long maxDuration;
+
         private final int maxRetries;
+
         private final long delay;
+
         private final long jitter;
 
-        private Model(final Retry retry) {
-            abortOn = retry.abortOn();
-            retryOn = retry.retryOn();
-            maxDuration = retry.delayUnit().getDuration().toNanos() * retry.maxDuration();
-            maxRetries = retry.maxRetries();
-            delay = retry.delayUnit().getDuration().toNanos() * retry.delay();
-            jitter = retry.jitterDelayUnit().getDuration().toNanos() * retry.jitter();
+        private final FaultToleranceMetrics.Counter callsSucceededNotRetried;
+
+        private final FaultToleranceMetrics.Counter callsSucceededRetried;
+
+        private final FaultToleranceMetrics.Counter callsFailed;
+
+        private final FaultToleranceMetrics.Counter retries;
+
+        private Model(final Retry retry, final FaultToleranceMetrics.Counter callsSucceededNotRetried,
+                final FaultToleranceMetrics.Counter callsSucceededRetried, final FaultToleranceMetrics.Counter callsFailed,
+                final FaultToleranceMetrics.Counter retries) {
+            this.abortOn = retry.abortOn();
+            this.retryOn = retry.retryOn();
+            this.maxDuration = retry.delayUnit().getDuration().toNanos() * retry.maxDuration();
+            this.maxRetries = retry.maxRetries();
+            this.delay = retry.delayUnit().getDuration().toNanos() * retry.delay();
+            this.jitter = retry.jitterDelayUnit().getDuration().toNanos() * retry.jitter();
+            this.callsSucceededNotRetried = callsSucceededNotRetried;
+            this.callsSucceededRetried = callsSucceededRetried;
+            this.callsFailed = callsFailed;
+            this.retries = retries;
         }
 
-        private boolean abortOn(final RuntimeException re) {
+        private boolean abortOn(final Exception re) {
             return matches(abortOn, re);
         }
 
-        private boolean retryOn(final RuntimeException re) {
+        private boolean retryOn(final Exception re) {
             return matches(retryOn, re);
         }
 
-        private boolean matches(final Class<? extends Throwable>[] list, final RuntimeException re) {
-            return list.length > 0 &&
-                    Stream.of(list).anyMatch(it -> it.isInstance(re) || it.isInstance(re.getCause()));
+        private boolean matches(final Class<? extends Throwable>[] list, final Exception re) {
+            return list.length > 0 && Stream.of(list).anyMatch(it -> it.isInstance(re) || it.isInstance(re.getCause()));
         }
 
         private long nextPause() {
             final ThreadLocalRandom random = ThreadLocalRandom.current();
-            return TimeUnit.NANOSECONDS.toMillis(
-                    min(maxDuration, max(0, ((random.nextBoolean() ? 1 : -1) * delay) + random.nextLong(jitter))));
+            return TimeUnit.NANOSECONDS
+                    .toMillis(min(maxDuration, max(0, ((random.nextBoolean() ? 1 : -1) * delay) + random.nextLong(jitter))));
         }
     }
 
     @ApplicationScoped
     public static class Cache {
+
         private final Map<Method, Model> models = new ConcurrentHashMap<>();
 
         @Inject
@@ -116,6 +164,9 @@
         @Inject
         private ConfigurationMapper configurationMapper;
 
+        @Inject
+        private FaultToleranceMetrics metrics;
+
         public Map<Method, Model> getModels() {
             return models;
         }
@@ -123,7 +174,16 @@
         public Model create(final InvocationContext context) {
             final Retry retry = finder.findAnnotation(Retry.class, context);
             final Retry configuredRetry = configurationMapper.map(retry, context.getMethod(), Retry.class);
-            return new Model(configuredRetry);
+            final String metricsNameBase = "ft." + context.getMethod().getDeclaringClass().getCanonicalName() + "."
+                    + context.getMethod().getName() + ".retry.";
+            return new Model(configuredRetry,
+                    metrics.counter(metricsNameBase + "callsSucceededNotRetried.total",
+                            "The number of times the method was called and succeeded without retrying"),
+                    metrics.counter(metricsNameBase + "callsSucceededRetried.total",
+                            "The number of times the method was called and succeeded after retrying at least once"),
+                    metrics.counter(metricsNameBase + "callsFailed.total",
+                            "The number of times the method was called and ultimately failed after retrying"),
+                    metrics.counter(metricsNameBase + "retries.total", "The total number of times the method was retried"));
         }
     }
 }
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java
index 257c85b..cf8884c 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java
@@ -18,13 +18,22 @@
  */
 package org.apache.safeguard.impl.retry;
 
+import java.util.Map;
+
 import javax.annotation.Priority;
 import javax.interceptor.Interceptor;
 
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
 import org.eclipse.microprofile.faulttolerance.Retry;
 
 @Retry
 @Interceptor
 @Priority(Interceptor.Priority.PLATFORM_AFTER)
 public class BeforeRetryInterceptor extends BaseRetryInterceptor {
+    @Override
+    protected void executeFinalCounterAction(final Map<String, Object> contextData,
+                                             final String counterActionKey,
+                                             final FaultToleranceMetrics.Counter counter) {
+        counter.inc();
+    }
 }
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java
index f90f93a..9c7ef0f 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java
@@ -38,6 +38,7 @@
 
 import org.apache.safeguard.impl.annotation.AnnotationFinder;
 import org.apache.safeguard.impl.customizable.Safeguard;
+import org.apache.safeguard.impl.metrics.FaultToleranceMetrics;
 import org.eclipse.microprofile.faulttolerance.Timeout;
 import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
 
@@ -54,22 +55,29 @@
 
     @AroundInvoke
     public Object withTimeout(final InvocationContext context) throws Exception {
-        final Map<Method, Long> timeouts = cache.getTimeouts();
-        Long duration = timeouts.get(context.getMethod());
-        if (duration == null) {
-            duration = cache.create(context);
-            timeouts.putIfAbsent(context.getMethod(), duration);
+        final Map<Method, Model> timeouts = cache.getTimeouts();
+        Model model = timeouts.get(context.getMethod());
+        if (model == null) {
+            model = cache.create(context);
+            timeouts.putIfAbsent(context.getMethod(), model);
         }
         final FutureTask<Object> task = new FutureTask<>(context::proceed);
+        final long start = System.nanoTime();
         executor.execute(task);
         try {
-            return task.get(duration, NANOSECONDS);
+            final Object result = task.get(model.timeout, NANOSECONDS);
+            model.successes.inc();
+            return result;
         } catch (final ExecutionException ee) {
             cancel(task);
             throw toCause(ee);
         } catch (final TimeoutException te) {
+            model.timeouts.inc();
             cancel(task);
             throw new org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException(te);
+        } finally {
+            final long end = System.nanoTime();
+            model.executionDuration.update(end - start);
         }
     }
 
@@ -90,23 +98,47 @@
         throw te;
     }
 
+    private static class Model {
+        private final long timeout;
+        private final FaultToleranceMetrics.Histogram executionDuration;
+        private final FaultToleranceMetrics.Counter timeouts;
+        private final FaultToleranceMetrics.Counter successes;
+
+        private Model(final long timeout, final FaultToleranceMetrics.Histogram executionDuration,
+                      final FaultToleranceMetrics.Counter timeouts, final FaultToleranceMetrics.Counter successes) {
+            this.timeout = timeout;
+            this.executionDuration = executionDuration;
+            this.timeouts = timeouts;
+            this.successes = successes;
+        }
+    }
+
     @ApplicationScoped
     public static class Cache {
-        private final Map<Method, Long> timeouts = new ConcurrentHashMap<>();
+        private final Map<Method, Model> timeouts = new ConcurrentHashMap<>();
 
         @Inject
         private AnnotationFinder finder;
 
-        public Map<Method, Long> getTimeouts() {
+        @Inject
+        private FaultToleranceMetrics metrics;
+
+        public Map<Method, Model> getTimeouts() {
             return timeouts;
         }
 
-        public long create(final InvocationContext context) {
+        public Model create(final InvocationContext context) {
             final Timeout timeout = finder.findAnnotation(Timeout.class, context);
             if (timeout.value() < 0) {
                 throw new FaultToleranceDefinitionException("Timeout can't be < 0: " + context.getMethod());
             }
-            return timeout.unit().getDuration().toNanos() * timeout.value();
+            final String metricsNameBase = "ft." + context.getMethod().getDeclaringClass().getCanonicalName() + "." +
+                    context.getMethod().getName() + ".timeout.";
+            return new Model(
+                    timeout.unit().getDuration().toNanos() * timeout.value(),
+                    metrics.histogram(metricsNameBase + "executionDuration", "Histogram of execution times for the method"),
+                    metrics.counter(metricsNameBase + "callsTimedOut.total", "The number of times the method timed out"),
+                    metrics.counter(metricsNameBase + "callsNotTimedOut.total", "The number of times the method completed without timing out"));
         }
     }
 }
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/IDERunner.java b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/IDERunner.java
deleted file mode 100644
index d7d1c0c..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/IDERunner.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.apache.safeguard.ft.tck;
-
-import org.eclipse.microprofile.fault.tolerance.tck.circuitbreaker.CircuitBreakerConfigOnMethodTest;
-
-public class IDERunner extends CircuitBreakerConfigOnMethodTest {
-}
diff --git a/safeguard-impl/src/test/resources/dev.xml b/safeguard-impl/src/test/resources/dev.xml
new file mode 100644
index 0000000..7c7c780
--- /dev/null
+++ b/safeguard-impl/src/test/resources/dev.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
+<suite name="Dev Manual Test Run" verbose="2" configfailurepolicy="continue" >
+  <test name="Manual Run">
+    <classes>
+      <!--
+      <class name="org.eclipse.microprofile.fault.tolerance.tck.config.ConfigPropertyGlobalVsClassVsMethodTest">
+      </class>
+      <class name="org.eclipse.microprofile.fault.tolerance.tck.metrics.RetryMetricTest">
+        <methods>
+          <include name="testRetryMetricUnsuccessful" />
+        </methods>
+      </class>
+      <class name="org.eclipse.microprofile.fault.tolerance.tck.bulkhead.BulkheadSynchRetryTest">
+        <methods>
+          <include name="testIgnoreWaitingTaskQueueBulkhead"/>
+        </methods>
+      </class>
+      -->
+    </classes>
+  </test>
+</suite>
+