You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2019/08/22 05:37:04 UTC

[camel] branch master updated: CAMEL-13838: Add support for microprofile metrics

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new df63426  CAMEL-13838: Add support for microprofile metrics
df63426 is described below

commit df634261b919e283d0cd04e916a3b0a26d959e1b
Author: James Netherton <ja...@gmail.com>
AuthorDate: Wed Aug 21 13:13:59 2019 +0100

    CAMEL-13838: Add support for microprofile metrics
---
 apache-camel/pom.xml                               |   5 +
 apache-camel/src/main/descriptors/common-bin.xml   |   1 +
 bom/camel-bom/pom.xml                              |   5 +
 components/camel-microprofile-metrics/pom.xml      |  95 +++++
 .../main/docs/microprofile-metrics-component.adoc  | 413 +++++++++++++++++++++
 .../AbstractMicroProfileMetricsProducer.java       | 135 +++++++
 .../metrics/MicroProfileMetricsComponent.java      |  61 +++
 .../metrics/MicroProfileMetricsConstants.java      |  54 +++
 .../MicroProfileMetricsCounterProducer.java        |  49 +++
 .../metrics/MicroProfileMetricsEndpoint.java       | 210 +++++++++++
 .../metrics/MicroProfileMetricsGaugeProducer.java  |  53 +++
 .../metrics/MicroProfileMetricsHelper.java         | 118 ++++++
 .../MicroProfileMetricsHistogramProducer.java      |  47 +++
 .../MicroProfileMetricsMeteredProducer.java        |  49 +++
 .../metrics/MicroProfileMetricsService.java        |  54 +++
 .../metrics/MicroProfileMetricsTimerProducer.java  |  93 +++++
 .../microprofile/metrics/TimerAction.java          |  22 ++
 .../AbstractMicroProfileMetricsEventNotifier.java  |  83 +++++
 ...oProfileMetricsEventNotifierNamingStrategy.java |  42 +++
 .../MicroProfileMetricsEventNotifierService.java   |  24 ++
 .../MicroProfileMetricsExchangeEventNotifier.java  |  94 +++++
 ...MetricsExchangeEventNotifierNamingStrategy.java |  48 +++
 .../MicroProfileMetricsRouteEventNotifier.java     |  76 ++++
 ...ileMetricsRouteEventNotifierNamingStrategy.java |  55 +++
 .../history/MicroProfileMetricsMessageHistory.java |  52 +++
 .../MicroProfileMetricsMessageHistoryFactory.java  | 136 +++++++
 ...ProfileMetricsMessageHistoryNamingStrategy.java |  44 +++
 .../MicroProfileMetricsMessageHistoryService.java  |  26 ++
 .../policy/MicroProfileMetricsRoutePolicy.java     | 120 ++++++
 .../MicroProfileMetricsRoutePolicyFactory.java     |  53 +++
 ...croProfileMetricsRoutePolicyNamingStrategy.java |  45 +++
 .../MicroProfileMetricsRoutePolicyService.java     |  26 ++
 .../metrics/MicroProfileMetricsCounterTest.java    |  82 ++++
 .../MicroProfileMetricsCustomRegistryTest.java     |  64 ++++
 .../metrics/MicroProfileMetricsEndpointTest.java   |  79 ++++
 .../metrics/MicroProfileMetricsGaugeTest.java      |  83 +++++
 .../metrics/MicroProfileMetricsHelperTest.java     |  74 ++++
 .../metrics/MicroProfileMetricsHistogramTest.java  |  62 ++++
 .../metrics/MicroProfileMetricsMetadataTest.java   |  88 +++++
 .../metrics/MicroProfileMetricsMeterTest.java      |  72 ++++
 .../metrics/MicroProfileMetricsTagTest.java        | 109 ++++++
 .../metrics/MicroProfileMetricsTestSupport.java    |  98 +++++
 .../metrics/MicroProfileMetricsTimerTest.java      |  71 ++++
 ...croProfileMetricsExchangeEventNotifierTest.java |  82 ++++
 .../MicroProfileMetricsRouteEventNotifierTest.java |  78 ++++
 ...eMetricsExceptionInRouteMessageHistoryTest.java |  93 +++++
 .../MicroProfileMetricsMessageHistoryTest.java     | 110 ++++++
 ...ileMetricsRoutePolicyMulticastSubRouteTest.java |  74 ++++
 ...MicroProfileMetricsRoutePolicySubRouteTest.java |  70 ++++
 .../policy/MicroProfileMetricsRoutePolicyTest.java |  95 +++++
 .../src/test/resources/log4j2.properties           |  28 ++
 components/pom.xml                                 |   1 +
 components/readme.adoc                             |   5 +-
 .../MicroProfileMetricsEndpointBuilderFactory.java | 300 +++++++++++++++
 docs/components/modules/ROOT/nav.adoc              |   1 +
 .../ROOT/pages/microprofile-metrics-component.adoc | 413 +++++++++++++++++++++
 parent/pom.xml                                     |   8 +
 .../camel-spring-boot-dependencies/pom.xml         |   5 +
 .../maven/packaging/SpringBootStarterMojo.java     |   3 +-
 59 files changed, 4634 insertions(+), 2 deletions(-)

diff --git a/apache-camel/pom.xml b/apache-camel/pom.xml
index f61b9d3..75d2faa 100644
--- a/apache-camel/pom.xml
+++ b/apache-camel/pom.xml
@@ -988,6 +988,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-microprofile-metrics</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-milo</artifactId>
       <version>${project.version}</version>
     </dependency>
diff --git a/apache-camel/src/main/descriptors/common-bin.xml b/apache-camel/src/main/descriptors/common-bin.xml
index 48c86f6..5209374 100644
--- a/apache-camel/src/main/descriptors/common-bin.xml
+++ b/apache-camel/src/main/descriptors/common-bin.xml
@@ -218,6 +218,7 @@
         <include>org.apache.camel:camel-metrics</include>
         <include>org.apache.camel:camel-micrometer</include>
         <include>org.apache.camel:camel-microprofile-config</include>
+        <include>org.apache.camel:camel-microprofile-metrics</include>
         <include>org.apache.camel:camel-milo</include>
         <include>org.apache.camel:camel-mina</include>
         <include>org.apache.camel:camel-mllp</include>
diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index be58ba7..ebd4cf9 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1890,6 +1890,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-microprofile-metrics</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-milo</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/components/camel-microprofile-metrics/pom.xml b/components/camel-microprofile-metrics/pom.xml
new file mode 100644
index 0000000..fcb2217
--- /dev/null
+++ b/components/camel-microprofile-metrics/pom.xml
@@ -0,0 +1,95 @@
+<?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.
+
+-->
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"  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.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-microprofile-metrics</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Camel :: MicroProfile Metrics</name>
+    <description>Camel metrics exposed with Eclipse MicroProfile Metrics</description>
+
+    <properties>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.metrics</groupId>
+            <artifactId>microprofile-metrics-api</artifactId>
+            <version>${microprofile-metrics-version}</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.smallrye</groupId>
+            <artifactId>smallrye-metrics-2.0</artifactId>
+            <version>${smallrye-metrics-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.smallrye</groupId>
+            <artifactId>smallrye-config-1.3</artifactId>
+            <version>${smallrye-config-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/components/camel-microprofile-metrics/src/main/docs/microprofile-metrics-component.adoc b/components/camel-microprofile-metrics/src/main/docs/microprofile-metrics-component.adoc
new file mode 100644
index 0000000..d03cb35
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/docs/microprofile-metrics-component.adoc
@@ -0,0 +1,413 @@
+[[microprofile-metrics-component]]
+= MicroProfile Metrics Component
+
+*Available as of Camel version 3.0*
+
+The MircoProfile Metrics component provides the capability to expose metrics from Camel routes.
+
+Maven users need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-microprofile-metrics</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+----
+
+It is expected that the component is running in a MicroProfile environment that provides an appropriate implementation of MicroProfile Metrics 2.0. E.g https://github.com/smallrye/smallrye-metrics[SmallRye Metrics].
+
+== URI format
+
+[source]
+----
+microprofile-metrics:[ concurrent gauge | counter | gauge | histogram | meter | timer ]:metricname[?options]
+----
+
+== Options
+// component options: START
+The MicroProfile Metrics component supports 2 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *metricRegistry* (advanced) | Use a custom MetricRegistry. |  | MetricRegistry
+| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+|===
+// component options: END
+
+// endpoint options: START
+The MicroProfile Metrics endpoint is configured using URI syntax:
+
+----
+microprofile-metrics:metricsType:metricsName
+----
+
+with the following path and query parameters:
+
+=== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *metricType* | *Required* Metric type |  | MetricType
+| *metricName* | *Required* Metric name |  | String
+| *tags* | Comma delimited list of tags associated with the metric in the format tagName=tagValue |  | List
+|===
+
+
+=== Query Parameters (12 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *action* (producer) | The action to use when using the Timer metric type |  | String
+| *counterIncrement* (producer) | The amount to increment to use when using the Counter metric type |  | Long
+| *description* (producer) | Sets a description within the metric metadata |  | String
+| *displayName* (producer) | Sets a display name within the metric metadata |  | String
+| *gaugeDecrement* (producer) | Decrements a counter when using the ConcurrentGauge metric type |  | Boolean
+| *gaugeIncrement* (producer) | Increments a counter when using the ConcurrentGauge metric type |  | Boolean
+| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *mark* (producer) | The mark value to set when using the Meter metric type |  | Long
+| *metricUnit* (producer) | Sets a metric unit within the metric metadata |  | String
+| *value* (producer) | The value to set when using the Histogram metric type |  | Long
+| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+|===
+// endpoint options: END
+
+== MetricRegistry Configuration
+
+Configure a `MetricRegistry` to use either by passing it to the MicroProfileMetricsComponent.
+
+[source,java]
+----
+MicroProfileMetricsComponent component = new MicroProfileMetricsComponent();
+component.setRegistry(myMetricRegistryImpl);
+----
+
+Or by binding it to the Camel registry using the binding name 'metricRegistry' (See `MicroProfileMetricsConstants.METRIC_REGISTRY_NAME`).
+
+
+== [[MicroProfileMetrics-counter]]Counter
+
+[source]
+----
+microprofile-metrics:counter:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|counterIncrement  |- |Value to add to the counter
+|=====================================================
+
+If `counterIncrement` is not defined then counter value will be incremented by one.
+
+[source,java]
+----
+// Increment counter simple.counter by 7
+from("direct:in")
+    .to("microprofile-metrics:counter:simple.counter?counterIncrement=7")
+    .to("direct:out");
+----
+
+[source,java]
+----
+// Increment counter simple.counter by 1
+from("direct:in")
+    .to("microprofile-metrics:counter:simple.counter")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`counterIncrement` values specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsCounterIncrement  |Override increment value from the URI |Long
+|====================================================================
+
+[source,java]
+----
+// Increment counter simple.counter by 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_COUNTER_INCREMENT, constant(417))
+    .to("microprofile-metrics:counter:simple.counter?increment=7")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-concurrentGauge]]Concurrent Gauge
+
+[source]
+----
+microprofile-metrics:concurrent gauge:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|gaugeIncrement  |false |Value to add to the counter
+|gaugeDecrement  |false |Value to add to the counter
+|=====================================================
+
+If neither `gaugeIncrement` or `gaugeDecrement` are defined then no action is performed on the gauge.
+
+[source,java]
+----
+// Increment concurrent gauge simple.gauge by 1
+from("direct:in")
+    .to("microprofile-metrics:concurrent gauge:simple.gauge?gaugeIncrement=true")
+    .to("direct:out");
+----
+
+[source,java]
+----
+// Decrement concurrent gauge simple.gauge by 1
+from("direct:in")
+    .to("microprofile-metrics:concurrent gauge:simple.gauge?gaugeDecrement=true")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`gaugeIncrement` and `gaugeDecrement` values specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsGaugeIncrement  |Override gaugeIncrement value from the URI |Boolean
+|CamelMicroProfileMetricsGaugeDecrement  |Override gaugeDecrement value from the URI |Boolean
+|====================================================================
+
+[source,java]
+----
+// Increment concurrent gauge simple.gauge by 1
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_GAUGE_INCREMENT, constant(true))
+    .to("microprofile-metrics:concurrent gauge:simple.gauge")
+    .to("direct:out");
+----
+
+----
+// Decrement concurrent gauge simple.gauge by 1
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_GAUGE_DECREMENT, constant(true))
+    .to("microprofile-metrics:concurrent gauge:simple.gauge")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-histogram]]Histogram
+
+[source]
+----
+microprofile-metrics:histogram:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|value  |- |Value to set on the histogram
+|=====================================================
+
+If `value` is not defined then histogram value will not be changed.
+
+[source,java]
+----
+// Set histogram simple.histogram to 7
+from("direct:in")
+    .to("microprofile-metrics:histogram:simple.histogram?value=7")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`value` specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsHistogramValue  |Override histogram value from the URI |Long
+|====================================================================
+
+[source,java]
+----
+// Set histogram simple.histogram to 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_HISTOGRAM_VALUE, constant(417))
+    .to("microprofile-metrics:histogram:simple.histogram?value=7")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-meter]]Meter
+
+[source]
+----
+microprofile-metrics:meter:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|mark  |- |Mark value to set on the meter
+|=====================================================
+
+If `mark` is not defined then the meter will be marked with the value '1'.
+
+[source,java]
+----
+// Mark the meter simple.meter with 7
+from("direct:in")
+    .to("microprofile-metrics:meter:simple.meter?mark=7")
+    .to("direct:out");
+----
+
+[source,java]
+----
+// Mark the meter simple.meter with 1
+from("direct:in")
+    .to("microprofile-metrics:meter:simple.meter")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`value` specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsMeterMark  |Override meter mark value from the URI |Long
+|====================================================================
+
+[source,java]
+----
+// Mark the meter simple.meter with 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_METER_MARK, constant(417))
+    .to("microprofile-metrics:meter:simple.meter?value=7")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-Timer]]Timer
+
+[source]
+----
+microprofile-metrics:timer:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|action  |- |start or stop
+|=====================================================
+
+If no `action` is specified or it's an invalid value, then no timer update occurs.
+
+If the `start` action is called on an already running timer or `stop` is called on an unknown timer, then
+no timer(s) are updated.
+
+[source,java]
+----
+// Measure time spent in route `direct:calculate`
+from("direct:in")
+    .to("microprofile-metrics:timer:simple.timer?action=start")
+    .to("direct:calculate")
+    .to("microprofile-metrics:timer:simple.timer?action=stop");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`action` specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsTimerAction  |Override time action from the URI |org.apache.camel.component.microprofile.metrics.TimerAction
+|====================================================================
+
+[source,java]
+----
+// Mark the meter simple.meter with 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_TIMER_ACTION, TimerAction.START)
+    .to("microprofile-metrics:timer:simple.timer")
+    .to("direct:out");
+----
+
+
+== MicroProfileMetricsRoutePolicyFactory
+
+This factory allows to add a RoutePolicy for each
+route and exposes route utilization statistics using MicroProfile metrics.
+
+NOTE: Instead of using the MicroProfileMetricsRoutePolicyFactory you can define a
+MicroProfileMetricsRoutePolicy per route you want to instrument, in case you only
+want to instrument a few selected routes.
+
+Add the factory to the `CamelContext` as shown below:
+
+[source,java]
+----
+context.addRoutePolicyFactory(new MicroProfileMetricsRoutePolicyFactory());
+----
+
+
+== MicroProfileMetricsMessageHistoryFactory
+
+This factory captures message history performance statistics while routing messages.
+
+Add the factory to the `CamelContext` as shown below:
+
+[source,java]
+----
+context.setMessageHistoryFactory(new MicroProfileMetricsMessageHistoryFactory());
+----
+
+
+== MicroProfileMetricsExchangeEventNotifier
+
+The exchange event notifer times exchanges from creation through to completion.
+
+EventNotifiers can be added to the `CamelContext`, e.g.:
+
+[source,java]
+----
+camelContext.getManagementStrategy().addEventNotifier(new MicroProfileMetricsExchangeEventNotifier())
+----
+
+
+== MicroProfileMetricsRouteEventNotifier
+
+The route event notifer counts added and running routes within the `CamelContext`.
+
+EventNotifiers can be added to the `CamelContext`, e.g.:
+
+[source,java]
+----
+camelContext.getManagementStrategy().addEventNotifier(new MicroProfileMetricsRouteEventNotifier())
+----
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/AbstractMicroProfileMetricsProducer.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/AbstractMicroProfileMetricsProducer.java
new file mode 100644
index 0000000..55f2ad2
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/AbstractMicroProfileMetricsProducer.java
@@ -0,0 +1,135 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.support.DefaultProducer;
+import org.apache.camel.util.ObjectHelper;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.MetadataBuilder;
+import org.eclipse.microprofile.metrics.Metric;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.CAMEL_CONTEXT_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_DESCRIPTION;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_DISPLAY_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_TAGS;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_TYPE;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_UNIT;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_PREFIX;
+
+public abstract class AbstractMicroProfileMetricsProducer<T extends Metric> extends DefaultProducer {
+
+    private static final String HEADER_PATTERN = HEADER_PREFIX + "*";
+
+    public AbstractMicroProfileMetricsProducer(Endpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    public MicroProfileMetricsEndpoint getEndpoint() {
+        return (MicroProfileMetricsEndpoint) super.getEndpoint();
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        MicroProfileMetricsEndpoint endpoint = getEndpoint();
+        Message in = exchange.getIn();
+
+        String metricName = getStringHeader(in, HEADER_METRIC_NAME, endpoint.getMetricName());
+        String metricDescription = getStringHeader(in, HEADER_METRIC_DESCRIPTION, endpoint.getDescription());
+        String metricDisplayName = getStringHeader(in, HEADER_METRIC_DISPLAY_NAME, endpoint.getDisplayName());
+        String metricUnit = getStringHeader(in, HEADER_METRIC_UNIT, endpoint.getMetricUnit());
+        MetricType metricType = exchange.getIn().getHeader(HEADER_METRIC_TYPE,  endpoint.getMetricType(), MetricType.class);
+
+        List<Tag> defaultTags = endpoint.getTags();
+        String headerTags = getStringHeader(in, HEADER_METRIC_TAGS, "");
+
+        List<Tag> allTags = new ArrayList<>();
+        allTags.addAll(defaultTags);
+        allTags.addAll(MicroProfileMetricsHelper.getMetricsTag(headerTags));
+
+        List<Tag> finalTags = allTags.stream()
+            .map(tag -> MicroProfileMetricsHelper.parseTag(tag.getTagName() + "=" + tag.getTagValue()))
+            .collect(Collectors.toList());
+        finalTags.add(MicroProfileMetricsHelper.parseTag(CAMEL_CONTEXT_TAG + "=" + getEndpoint().getCamelContext().getName()));
+
+        MetadataBuilder builder = new MetadataBuilder()
+            .withName(metricName)
+            .withType(metricType);
+
+        if (metricDescription != null) {
+            builder.withDescription(metricDescription);
+        }
+
+        if (metricDisplayName != null) {
+            builder.withDisplayName(metricDisplayName);
+        }
+
+        if (metricUnit != null) {
+            builder.withUnit(metricUnit);
+        }
+
+        try {
+            doProcess(exchange, builder.build(), finalTags);
+        } catch (Exception e) {
+            exchange.setException(e);
+        } finally {
+            clearMetricsHeaders(in);
+        }
+    }
+
+    protected void doProcess(Exchange exchange, Metadata metadata, List<Tag> tags) {
+        doProcess(exchange, getEndpoint(), getOrRegisterMetric(metadata, tags));
+    }
+
+    protected T getOrRegisterMetric(Metadata metadata, List<Tag> tags) {
+        MetricRegistry metricRegistry = getEndpoint().getMetricRegistry();
+        return registerMetric(metadata, tags).apply(metricRegistry);
+    }
+
+    protected String getStringHeader(Message in, String header, String defaultValue) {
+        String headerValue = in.getHeader(header, String.class);
+        return ObjectHelper.isNotEmpty(headerValue) ? headerValue : defaultValue;
+    }
+
+    protected Long getLongHeader(Message in, String header, Long defaultValue) {
+        return in.getHeader(header, defaultValue, Long.class);
+    }
+
+    protected Boolean getBooleanHeader(Message in, String header, Boolean defaultValue) {
+        Boolean headerValue = in.getHeader(header, Boolean.class);
+        return ObjectHelper.isNotEmpty(headerValue) ? headerValue : defaultValue;
+    }
+
+    protected void clearMetricsHeaders(Message in) {
+        in.removeHeaders(HEADER_PATTERN);
+    }
+
+    protected abstract void doProcess(Exchange exchange, MicroProfileMetricsEndpoint endpoint, T meter);
+
+    protected abstract Function<MetricRegistry, T> registerMetric(Metadata metadata, List<Tag> tags);
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsComponent.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsComponent.java
new file mode 100644
index 0000000..cc19420
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsComponent.java
@@ -0,0 +1,61 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.DefaultComponent;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.eclipse.microprofile.metrics.Tag;
+
+@Component("microprofile-metrics")
+public class MicroProfileMetricsComponent extends DefaultComponent {
+
+    @Metadata(label = "advanced")
+    private MetricRegistry metricRegistry;
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        if (metricRegistry == null) {
+            metricRegistry = MicroProfileMetricsHelper.getMetricRegistry(getCamelContext());
+        }
+
+        String metricsName = MicroProfileMetricsHelper.getMetricsName(remaining);
+        MetricType metricsType = MicroProfileMetricsHelper.getMetricsType(remaining);
+
+        String rawTags = getAndRemoveParameter(parameters, "tags", String.class, "");
+        List<Tag> tags = MicroProfileMetricsHelper.getMetricsTag(rawTags);
+
+        return new MicroProfileMetricsEndpoint(uri, this, metricRegistry, metricsType, metricsName, tags);
+    }
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    /**
+     * Use a custom MetricRegistry.
+     */
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
+        this.metricRegistry = metricRegistry;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsConstants.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsConstants.java
new file mode 100644
index 0000000..720bf3a
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsConstants.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.camel.component.microprofile.metrics;
+
+public final class MicroProfileMetricsConstants {
+
+    public static final String HEADER_PREFIX = "CamelMicroProfileMetrics";
+
+    public static final String HEADER_COUNTER_INCREMENT = HEADER_PREFIX + "CounterIncrement";
+    public static final String HEADER_GAUGE_INCREMENT = HEADER_PREFIX + "GaugeIncrement";
+    public static final String HEADER_GAUGE_DECREMENT = HEADER_PREFIX + "GaugeDecrement";
+    public static final String HEADER_HISTOGRAM_VALUE = HEADER_PREFIX + "HistogramValue";
+    public static final String HEADER_METER_MARK = HEADER_PREFIX + "MeterMark";
+    public static final String HEADER_METRIC_DESCRIPTION = HEADER_PREFIX + "Description";
+    public static final String HEADER_METRIC_DISPLAY_NAME = HEADER_PREFIX + "DisplayName";
+    public static final String HEADER_METRIC_NAME = HEADER_PREFIX + "Name";
+    public static final String HEADER_METRIC_TAGS = HEADER_PREFIX + "Tags";
+    public static final String HEADER_METRIC_TYPE = HEADER_PREFIX + "Type";
+    public static final String HEADER_METRIC_UNIT = HEADER_PREFIX + "Units";
+    public static final String HEADER_TIMER_ACTION = HEADER_PREFIX + "TimerAction";
+
+    public static final String DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME = "org.apache.camel.message.history";
+    public static final String DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME = "org.apache.camel.route";
+    public static final String DEFAULT_CAMEL_EXCHANGE_EVENT_METRIC_NAME = "org.apache.camel.exchange";
+    public static final String DEFAULT_CAMEL_ROUTES_ADDED_METRIC_NAME = "org.apache.camel.route.total";
+    public static final String DEFAULT_CAMEL_ROUTES_RUNNING_METRIC_NAME = "org.apache.camel.route.running.total";
+
+    public static final String ROUTE_ID_TAG = "routeId";
+    public static final String NODE_ID_TAG = "nodeId";
+    public static final String FAILED_TAG = "failed";
+    public static final String CAMEL_CONTEXT_TAG = "camelContext";
+    public static final String EVENT_TYPE_TAG = "eventType";
+    public static final String METRIC_REGISTRY_NAME = "metricRegistry";
+
+    public static final String SERVICE_NAME = "serviceName";
+    public static final String ENDPOINT_NAME = "endpointName";
+
+    private MicroProfileMetricsConstants() {
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCounterProducer.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCounterProducer.java
new file mode 100644
index 0000000..275899c
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCounterProducer.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.camel.component.microprofile.metrics;
+
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.camel.Exchange;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_COUNTER_INCREMENT;
+
+public class MicroProfileMetricsCounterProducer extends AbstractMicroProfileMetricsProducer<Counter> {
+
+    public MicroProfileMetricsCounterProducer(MicroProfileMetricsEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    protected void doProcess(Exchange exchange, MicroProfileMetricsEndpoint endpoint, Counter counter) {
+        Long increment = getLongHeader(exchange.getIn(), HEADER_COUNTER_INCREMENT, endpoint.getCounterIncrement());
+        if (increment != null) {
+            counter.inc(increment);
+        } else {
+            counter.inc();
+        }
+    }
+
+    @Override
+    protected Function<MetricRegistry, Counter> registerMetric(Metadata metadata, List<Tag> tags) {
+        return metricRegistry -> metricRegistry.counter(metadata, tags.toArray(new Tag[0]));
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsEndpoint.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsEndpoint.java
new file mode 100644
index 0000000..d4b3f16
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsEndpoint.java
@@ -0,0 +1,210 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.List;
+
+import org.apache.camel.Component;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.support.DefaultEndpoint;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.eclipse.microprofile.metrics.Tag;
+
+@UriEndpoint(firstVersion = "3.0.0", scheme = "microprofile-metrics", title = "MicroProfile Metrics", syntax = "microprofile-metrics:metricsType:metricsName", producerOnly = true, label = "monitoring")
+public class MicroProfileMetricsEndpoint extends DefaultEndpoint {
+
+    protected final MetricRegistry metricRegistry;
+
+    @UriPath(description = "Metric type")
+    @Metadata(required = true, enums = "concurrent gauge,counter,histogram,meter,timer")
+    private final MetricType metricType;
+    @UriPath(description = "Metric name")
+    @Metadata(required = true)
+    private final String metricName;
+    @UriPath(description = "Comma delimited list of tags associated with the metric in the format tagName=tagValue")
+    private final List<Tag> tags;
+    @UriParam(description = "Action to use when using the timer type")
+    private String action;
+    @UriParam(description = "Mark value to set when using the meter type")
+    private Long mark;
+    @UriParam(description = "Value to set when using the histogram type")
+    private Long value;
+    @UriParam(description = "Increment value when using the counter type")
+    private Long counterIncrement;
+    @UriParam(description = "Increment metric value when using the concurrent gauge type")
+    private Boolean gaugeIncrement = false;
+    @UriParam(description = "Decrement metric value when using concurrent gauge type")
+    private Boolean gaugeDecrement = false;
+    @UriParam(description = "Metric description")
+    private String description;
+    @UriParam(description = "Metric display name")
+    private String displayName;
+    @UriParam(description = "Metric unit. See org.eclipse.microprofile.metrics.MetricUnits")
+    private String metricUnit;
+
+    public MicroProfileMetricsEndpoint(String uri, Component component, MetricRegistry metricRegistry, MetricType metricType, String metricsName, List<Tag> tags) {
+        super(uri, component);
+        this.metricRegistry = metricRegistry;
+        this.metricType = metricType;
+        this.metricName = metricsName;
+        this.tags = tags;
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        if (metricType.equals(MetricType.COUNTER)) {
+            return new MicroProfileMetricsCounterProducer(this);
+        } else if (metricType.equals(MetricType.GAUGE) || metricType.equals(MetricType.CONCURRENT_GAUGE)) {
+            return new MicroProfileMetricsGaugeProducer(this);
+        } else if (metricType.equals(MetricType.HISTOGRAM)) {
+            return new MicroProfileMetricsHistogramProducer(this);
+        } else if (metricType.equals(MetricType.METERED)) {
+            return new MicroProfileMetricsMeteredProducer(this);
+        } else if (metricType.equals(MetricType.TIMER)) {
+            return new MicroProfileMetricsTimerProducer(this);
+        } else {
+            throw new IllegalStateException("Unknown metric type " + metricType);
+        }
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        throw new UnsupportedOperationException("The microprofile-metrics endpoint does not support consumers");
+    }
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    public MetricType getMetricType() {
+        return metricType;
+    }
+
+    public String getMetricName() {
+        return metricName;
+    }
+
+    public List<Tag> getTags() {
+        return tags;
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    /**
+     * The action to use when using the Timer metric type
+     */
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+    public Long getMark() {
+        return mark;
+    }
+
+    /**
+     * The mark value to set when using the Meter metric type
+     */
+    public void setMark(Long mark) {
+        this.mark = mark;
+    }
+
+    public Long getValue() {
+        return value;
+    }
+
+    /**
+     * The value to set when using the Histogram metric type
+     */
+    public void setValue(Long value) {
+        this.value = value;
+    }
+
+    public Long getCounterIncrement() {
+        return counterIncrement;
+    }
+
+    /**
+     * The amount to increment to use when using the Counter metric type
+     */
+    public void setCounterIncrement(Long counterIncrement) {
+        this.counterIncrement = counterIncrement;
+    }
+
+    public Boolean getGaugeIncrement() {
+        return gaugeIncrement;
+    }
+
+    /**
+     * Increments a counter when using the ConcurrentGauge metric type
+     */
+    public void setGaugeIncrement(Boolean gaugeIncrement) {
+        this.gaugeIncrement = gaugeIncrement;
+    }
+
+    public Boolean getGaugeDecrement() {
+        return gaugeDecrement;
+    }
+
+    /**
+     * Decrements a counter when using the ConcurrentGauge metric type
+     */
+    public void setGaugeDecrement(Boolean gaugeDecrement) {
+        this.gaugeDecrement = gaugeDecrement;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Sets a description within the metric metadata
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * Sets a display name within the metric metadata
+     */
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    public String getMetricUnit() {
+        return metricUnit;
+    }
+
+    /**
+     * Sets a metric unit within the metric metadata
+     */
+    public void setMetricUnit(String metricUnit) {
+        this.metricUnit = metricUnit;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsGaugeProducer.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsGaugeProducer.java
new file mode 100644
index 0000000..b19c631
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsGaugeProducer.java
@@ -0,0 +1,53 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_GAUGE_DECREMENT;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_GAUGE_INCREMENT;
+
+public class MicroProfileMetricsGaugeProducer extends AbstractMicroProfileMetricsProducer<ConcurrentGauge> {
+
+    public MicroProfileMetricsGaugeProducer(MicroProfileMetricsEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    protected void doProcess(Exchange exchange, MicroProfileMetricsEndpoint endpoint, ConcurrentGauge gauge) {
+        Message in = exchange.getIn();
+        Boolean finalIncrement = getBooleanHeader(in, HEADER_GAUGE_INCREMENT, endpoint.getGaugeIncrement());
+        Boolean finalDecrement = getBooleanHeader(in, HEADER_GAUGE_DECREMENT, endpoint.getGaugeDecrement());
+        if (finalIncrement && !finalDecrement) {
+            gauge.inc();
+        } else if (finalDecrement) {
+            gauge.dec();
+        }
+    }
+
+    @Override
+    protected Function<MetricRegistry, ConcurrentGauge> registerMetric(Metadata metadata, List<Tag> tags) {
+        return metricRegistry -> metricRegistry.concurrentGauge(metadata, tags.toArray(new Tag[0]));
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHelper.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHelper.java
new file mode 100644
index 0000000..104567e
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHelper.java
@@ -0,0 +1,118 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.eclipse.microprofile.metrics.Metric;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.METRIC_REGISTRY_NAME;
+
+public final class MicroProfileMetricsHelper {
+
+    private static final MetricType DEFAULT_METRIC_TYPE = MetricType.COUNTER;
+
+    private MicroProfileMetricsHelper() {
+    }
+
+    public static String getMetricsName(String remaining) {
+        String name = StringHelper.after(remaining, ":");
+        return name == null ? remaining : name;
+    }
+
+    public static MetricType getMetricsType(String remaining) {
+        String type = StringHelper.before(remaining, ":");
+        return type == null ? DEFAULT_METRIC_TYPE : MetricType.from(type.toLowerCase(Locale.US));
+    }
+
+    public static List<Tag> getMetricsTag(String rawTags) {
+        if (rawTags != null && !rawTags.isEmpty()) {
+            String[] tagStrings = rawTags.split("\\s*,\\s*");
+            return Stream.of(tagStrings)
+                .map(tag -> parseTag(tag))
+                .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    public static <T extends Metric> T findMetric(MetricRegistry metricRegistry, String metricName, Class<T> metricType) {
+        return findMetric(metricRegistry, metricName, metricType, Collections.emptyList());
+    }
+
+    public static <T extends Metric> T findMetric(MetricRegistry metricRegistry, String metricName, Class<T> metricType, List<Tag> tags) {
+        Map<MetricID, Metric> metrics = metricRegistry.getMetrics();
+        for (Map.Entry<MetricID, Metric> entry : metrics.entrySet()) {
+            if (metricTypeMatches(entry.getValue(), metricType)) {
+                MetricID metricID = entry.getKey();
+                if (metricID.getName().equals(metricName)) {
+                    if (tags.isEmpty() || metricID.getTagsAsList().equals(tags)) {
+                        return metricType.cast(entry.getValue());
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public static Tag parseTag(String tagString) {
+        if (ObjectHelper.isEmpty(tagString) || !tagString.contains("=")) {
+            throw new IllegalArgumentException("Tag must be in the format: key=value");
+        }
+        String[] tagElements = tagString.split("=");
+        if (tagElements.length != 2) {
+            throw new IllegalArgumentException("Tag must be in the format: key=value");
+        }
+        return new Tag(tagElements[0], tagElements[1]);
+    }
+
+    public static Tag[] parseTagArray(String[] tagStrings) {
+        Tag[] tags = new Tag[tagStrings.length];
+        int i = 0;
+        for (String tagString : tagStrings) {
+            tags[i] = parseTag(tagString);
+            i++;
+        }
+        return tags;
+    }
+
+    public static MetricRegistry getMetricRegistry(CamelContext camelContext) {
+        Registry camelRegistry = camelContext.getRegistry();
+        MetricRegistry metricRegistry = camelRegistry.lookupByNameAndType(METRIC_REGISTRY_NAME, MetricRegistry.class);
+
+        if (metricRegistry == null) {
+            throw new IllegalStateException("No usable MetricRegistry has been configured");
+        }
+
+        return metricRegistry;
+    }
+
+    private static boolean metricTypeMatches(Metric metric, Class<? extends Metric> metricType) {
+        return metricType.isInstance(metric);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHistogramProducer.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHistogramProducer.java
new file mode 100644
index 0000000..e21c4a8
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHistogramProducer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.camel.Exchange;
+import org.eclipse.microprofile.metrics.Histogram;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_HISTOGRAM_VALUE;
+
+public class MicroProfileMetricsHistogramProducer extends AbstractMicroProfileMetricsProducer<Histogram> {
+
+    public MicroProfileMetricsHistogramProducer(MicroProfileMetricsEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    protected void doProcess(Exchange exchange, MicroProfileMetricsEndpoint endpoint, Histogram histogram) {
+        Long value = getLongHeader(exchange.getIn(), HEADER_HISTOGRAM_VALUE, endpoint.getValue());
+        if (value != null) {
+            histogram.update(value);
+        }
+    }
+
+    @Override
+    protected Function<MetricRegistry, Histogram> registerMetric(Metadata metadata, List<Tag> tags) {
+        return metricRegistry -> metricRegistry.histogram(metadata, tags.toArray(new Tag[0]));
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMeteredProducer.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMeteredProducer.java
new file mode 100644
index 0000000..b274a53
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMeteredProducer.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.camel.component.microprofile.metrics;
+
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.camel.Exchange;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.Meter;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METER_MARK;
+
+public class MicroProfileMetricsMeteredProducer extends AbstractMicroProfileMetricsProducer<Meter> {
+
+    public MicroProfileMetricsMeteredProducer(MicroProfileMetricsEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    protected void doProcess(Exchange exchange, MicroProfileMetricsEndpoint endpoint, Meter meter) {
+        Long value = getLongHeader(exchange.getIn(), HEADER_METER_MARK, endpoint.getMark());
+        if (value != null) {
+            meter.mark(value);
+        } else {
+            meter.mark();
+        }
+    }
+
+    @Override
+    protected Function<MetricRegistry, Meter> registerMetric(Metadata metadata, List<Tag> tags) {
+        return metricRegistry -> metricRegistry.meter(metadata, tags.toArray(new Tag[0]));
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsService.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsService.java
new file mode 100644
index 0000000..e82fef1
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsService.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.camel.component.microprofile.metrics;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.support.service.ServiceSupport;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+
+public class MicroProfileMetricsService extends ServiceSupport {
+
+    private CamelContext camelContext;
+    private MetricRegistry metricRegistry;
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
+        this.metricRegistry = metricRegistry;
+    }
+
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    protected void doStart() {
+        if (metricRegistry == null) {
+            metricRegistry = MicroProfileMetricsHelper.getMetricRegistry(camelContext);
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTimerProducer.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTimerProducer.java
new file mode 100644
index 0000000..70e8950
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTimerProducer.java
@@ -0,0 +1,93 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.function.Function;
+
+import org.apache.camel.Exchange;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
+import org.eclipse.microprofile.metrics.Timer.Context;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_TIMER_ACTION;
+
+public class MicroProfileMetricsTimerProducer extends AbstractMicroProfileMetricsProducer<Timer> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MicroProfileMetricsTimerProducer.class);
+
+    public MicroProfileMetricsTimerProducer(MicroProfileMetricsEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    protected void doProcess(Exchange exchange, MicroProfileMetricsEndpoint endpoint, Timer timer) {
+        String propertyName = getPropertyName(endpoint.getMetricName());
+        Context context = getTimerContextFromExchange(exchange, propertyName);
+        if (context != null) {
+            context.stop();
+        } else {
+            LOG.warn("Timer context for metric '{}' was not found", propertyName);
+        }
+        exchange.removeProperty(propertyName);
+    }
+
+    @Override
+    protected void doProcess(Exchange exchange, Metadata metadata, List<Tag> tags) {
+        String actionString = getEndpoint().getAction().toUpperCase(Locale.US);
+        TimerAction action = exchange.getIn().getHeader(HEADER_TIMER_ACTION, actionString, TimerAction.class);
+        if (action == TimerAction.START) {
+            handleStart(exchange, metadata, tags);
+        } else {
+            handleStop(exchange, metadata, tags);
+        }
+    }
+
+    @Override
+    protected Function<MetricRegistry, Timer> registerMetric(Metadata metadata, List<Tag> tags) {
+        return metricRegistry -> metricRegistry.timer(metadata, tags.toArray(new Tag[0]));
+    }
+
+    private void handleStart(Exchange exchange, Metadata metadata, List<Tag> tags) {
+        String propertyName = getPropertyName(metadata.getName());
+        Context context = getTimerContextFromExchange(exchange, propertyName);
+        if (context == null) {
+            Timer timer = getOrRegisterMetric(metadata, tags);
+            exchange.setProperty(propertyName, timer.time());
+        } else {
+            LOG.warn("Timer '{}' is already running", metadata.getName());
+        }
+    }
+
+    private void handleStop(Exchange exchange, Metadata metadata, List<Tag> tags) {
+        if (getTimerContextFromExchange(exchange, getPropertyName(metadata.getName())) != null) {
+            doProcess(exchange, getEndpoint(), getOrRegisterMetric(metadata, tags));
+        }
+    }
+
+    private String getPropertyName(String metricName) {
+        return "timer:" + metricName;
+    }
+
+    private Context getTimerContextFromExchange(Exchange exchange, String propertyName) {
+        return exchange.getProperty(propertyName, Context.class);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/TimerAction.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/TimerAction.java
new file mode 100644
index 0000000..5ee9122
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/TimerAction.java
@@ -0,0 +1,22 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+public enum TimerAction {
+    START,
+    STOP
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/AbstractMicroProfileMetricsEventNotifier.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/AbstractMicroProfileMetricsEventNotifier.java
new file mode 100644
index 0000000..007db9a
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/AbstractMicroProfileMetricsEventNotifier.java
@@ -0,0 +1,83 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.spi.CamelEvent;
+import org.apache.camel.support.EventNotifierSupport;
+import org.apache.camel.support.service.ServiceHelper;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+
+public abstract class AbstractMicroProfileMetricsEventNotifier <T extends CamelEvent> extends EventNotifierSupport implements CamelContextAware {
+
+    private final Class<T> eventType;
+
+    private CamelContext camelContext;
+    private MetricRegistry metricRegistry;
+
+    public AbstractMicroProfileMetricsEventNotifier(Class<T> eventType) {
+        super();
+        this.eventType = eventType;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
+        this.metricRegistry = metricRegistry;
+    }
+
+    @Override
+    public boolean isEnabled(CamelEvent eventObject) {
+        return eventType.isAssignableFrom(eventObject.getClass());
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        if (metricRegistry == null) {
+            metricRegistry = MicroProfileMetricsHelper.getMetricRegistry(camelContext);
+        }
+
+        try {
+            MicroProfileMetricsEventNotifierService service = camelContext.hasService(MicroProfileMetricsEventNotifierService.class);
+            if (service == null) {
+                service = new MicroProfileMetricsEventNotifierService();
+                service.setMetricRegistry(getMetricRegistry());
+                camelContext.addService(service);
+                ServiceHelper.startService(service);
+            }
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeCamelException(e);
+        }
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/MicroProfileMetricsEventNotifierNamingStrategy.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/MicroProfileMetricsEventNotifierNamingStrategy.java
new file mode 100644
index 0000000..c2f3970
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/MicroProfileMetricsEventNotifierNamingStrategy.java
@@ -0,0 +1,42 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.spi.CamelEvent.ExchangeEvent;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.ENDPOINT_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.EVENT_TYPE_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.FAILED_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.SERVICE_NAME;
+
+public interface MicroProfileMetricsEventNotifierNamingStrategy {
+
+    String getName(Exchange exchange, Endpoint endpoint);
+
+    default Tag[] getTags(ExchangeEvent event, Endpoint endpoint) {
+        String[] tags = {
+            SERVICE_NAME + "=" + MicroProfileMetricsEventNotifierService.class.getSimpleName(),
+            EVENT_TYPE_TAG + "=" + event.getClass().getSimpleName(),
+            ENDPOINT_NAME + "=" + endpoint.getEndpointUri(),
+            FAILED_TAG + "=" + event.getExchange().isFailed()
+        };
+        return MicroProfileMetricsHelper.parseTagArray(tags);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/MicroProfileMetricsEventNotifierService.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/MicroProfileMetricsEventNotifierService.java
new file mode 100644
index 0000000..e70365b
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/MicroProfileMetricsEventNotifierService.java
@@ -0,0 +1,24 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier;
+
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.StaticService;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsService;
+
+public final class MicroProfileMetricsEventNotifierService extends MicroProfileMetricsService implements CamelContextAware, StaticService {
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifier.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifier.java
new file mode 100644
index 0000000..1dd702b
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifier.java
@@ -0,0 +1,94 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier.exchange;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.microprofile.metrics.event.notifier.AbstractMicroProfileMetricsEventNotifier;
+import org.apache.camel.spi.CamelEvent;
+import org.apache.camel.spi.CamelEvent.ExchangeCompletedEvent;
+import org.apache.camel.spi.CamelEvent.ExchangeCreatedEvent;
+import org.apache.camel.spi.CamelEvent.ExchangeEvent;
+import org.apache.camel.spi.CamelEvent.ExchangeSentEvent;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
+import org.eclipse.microprofile.metrics.Timer.Context;
+
+public class MicroProfileMetricsExchangeEventNotifier extends AbstractMicroProfileMetricsEventNotifier<ExchangeEvent> {
+
+    private Predicate<Exchange> ignoreExchanges = exchange -> false;
+    private MicroProfileMetricsExchangeEventNotifierNamingStrategy namingStrategy = MicroProfileMetricsExchangeEventNotifierNamingStrategy.DEFAULT;
+
+    public MicroProfileMetricsExchangeEventNotifier() {
+        super(ExchangeEvent.class);
+    }
+
+    public Predicate<Exchange> getIgnoreExchanges() {
+        return ignoreExchanges;
+    }
+
+    public MicroProfileMetricsExchangeEventNotifierNamingStrategy getNamingStrategy() {
+        return namingStrategy;
+    }
+
+    public void setNamingStrategy(MicroProfileMetricsExchangeEventNotifierNamingStrategy namingStrategy) {
+        this.namingStrategy = namingStrategy;
+    }
+
+    @Override
+    public void notify(CamelEvent event) throws Exception {
+        if (!(getIgnoreExchanges().test(((ExchangeEvent) event).getExchange()))) {
+            if (event instanceof ExchangeSentEvent) {
+                handleSentEvent((ExchangeSentEvent) event);
+            } else if (event instanceof ExchangeCreatedEvent) {
+                handleCreatedEvent((ExchangeCreatedEvent) event);
+            } else if (event instanceof ExchangeCompletedEvent || event instanceof CamelEvent.ExchangeFailedEvent) {
+                handleDoneEvent((ExchangeEvent) event);
+            }
+        }
+    }
+
+    protected void handleCreatedEvent(ExchangeCreatedEvent createdEvent) {
+        String name = namingStrategy.getName(createdEvent.getExchange(), createdEvent.getExchange().getFromEndpoint());
+        Tag[] tags = namingStrategy.getTags(createdEvent, createdEvent.getExchange().getFromEndpoint());
+        Timer timer = getMetricRegistry().timer(name, tags);
+        createdEvent.getExchange().setProperty("eventTimer:" + name, timer);
+        createdEvent.getExchange().setProperty("eventTimerContext:" + name, timer.time());
+    }
+
+    protected void handleSentEvent(ExchangeSentEvent sentEvent) {
+        String name = namingStrategy.getName(sentEvent.getExchange(), sentEvent.getEndpoint());
+        Timer timer = sentEvent.getExchange().getProperty("eventTimer:" + name, Timer.class);
+        if (timer == null) {
+            Tag[] tags = namingStrategy.getTags(sentEvent, sentEvent.getEndpoint());
+            timer = getMetricRegistry().timer(name, tags);
+            sentEvent.getExchange().setProperty("eventTimer:" + name, timer);
+        }
+        timer.update(sentEvent.getTimeTaken(), TimeUnit.MILLISECONDS);
+    }
+
+    protected void handleDoneEvent(ExchangeEvent doneEvent) {
+        String name = namingStrategy.getName(doneEvent.getExchange(), doneEvent.getExchange().getFromEndpoint());
+        doneEvent.getExchange().removeProperty("eventTimer:" + name);
+        Context context = (Context) doneEvent.getExchange().removeProperty("eventTimerContext:" + name);
+        if (context != null) {
+            context.stop();
+        }
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifierNamingStrategy.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifierNamingStrategy.java
new file mode 100644
index 0000000..7cba4c3
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifierNamingStrategy.java
@@ -0,0 +1,48 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier.exchange;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.component.microprofile.metrics.event.notifier.MicroProfileMetricsEventNotifierService;
+import org.apache.camel.spi.CamelEvent.ExchangeEvent;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.CAMEL_CONTEXT_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_EXCHANGE_EVENT_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.ENDPOINT_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.EVENT_TYPE_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.FAILED_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.SERVICE_NAME;
+
+public interface MicroProfileMetricsExchangeEventNotifierNamingStrategy {
+
+    MicroProfileMetricsExchangeEventNotifierNamingStrategy DEFAULT = (event, endpoint) -> DEFAULT_CAMEL_EXCHANGE_EVENT_METRIC_NAME;
+
+    String getName(Exchange exchange, Endpoint endpoint);
+
+    default Tag[] getTags(ExchangeEvent event, Endpoint endpoint) {
+        String[] tags = {
+            SERVICE_NAME + "=" + MicroProfileMetricsEventNotifierService.class.getSimpleName(),
+            CAMEL_CONTEXT_TAG + "=" + event.getExchange().getContext().getName(),
+            EVENT_TYPE_TAG + "=" + event.getClass().getSimpleName(),
+            ENDPOINT_NAME + "=" + endpoint.getEndpointUri(),
+            FAILED_TAG + "=" + event.getExchange().isFailed()
+        };
+        return MicroProfileMetricsHelper.parseTagArray(tags);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifier.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifier.java
new file mode 100644
index 0000000..61dcc8e
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifier.java
@@ -0,0 +1,76 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier.route;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.microprofile.metrics.event.notifier.AbstractMicroProfileMetricsEventNotifier;
+import org.apache.camel.spi.CamelEvent;
+import org.apache.camel.spi.CamelEvent.RouteEvent;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.spi.CamelEvent.Type.RouteAdded;
+import static org.apache.camel.spi.CamelEvent.Type.RouteRemoved;
+import static org.apache.camel.spi.CamelEvent.Type.RouteStarted;
+import static org.apache.camel.spi.CamelEvent.Type.RouteStopped;
+
+public class MicroProfileMetricsRouteEventNotifier extends AbstractMicroProfileMetricsEventNotifier<RouteEvent> {
+
+    private ConcurrentGauge routesAdded;
+    private ConcurrentGauge routesRunning;
+    private MicroProfileMetricsRouteEventNotifierNamingStrategy namingStrategy = MicroProfileMetricsRouteEventNotifierNamingStrategy.DEFAULT;
+
+    public MicroProfileMetricsRouteEventNotifier() {
+        super(RouteEvent.class);
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        CamelContext camelContext = getCamelContext();
+        MetricRegistry metricRegistry = getMetricRegistry();
+        Tag[] tags = namingStrategy.getTags(camelContext);
+        routesAdded = metricRegistry.concurrentGauge(namingStrategy.getRouteAddedName(), tags);
+        routesRunning = metricRegistry.concurrentGauge(namingStrategy.getRouteRunningName(), tags);
+    }
+
+    @Override
+    public void notify(CamelEvent event) throws Exception {
+        if (routesAdded == null || routesRunning == null) {
+            return;
+        }
+
+        if (event.getType().equals(RouteAdded)) {
+            routesAdded.inc();
+        } else if (event.getType().equals(RouteRemoved)) {
+            routesAdded.dec();
+        } else if (event.getType().equals(RouteStarted)) {
+            routesRunning.inc();
+        } else if (event.getType().equals(RouteStopped)) {
+            routesRunning.dec();
+        }
+    }
+
+    public MicroProfileMetricsRouteEventNotifierNamingStrategy getNamingStrategy() {
+        return namingStrategy;
+    }
+
+    public void setNamingStrategy(MicroProfileMetricsRouteEventNotifierNamingStrategy namingStrategy) {
+        this.namingStrategy = namingStrategy;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifierNamingStrategy.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifierNamingStrategy.java
new file mode 100644
index 0000000..14dbf03
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifierNamingStrategy.java
@@ -0,0 +1,55 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier.route;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.component.microprofile.metrics.event.notifier.MicroProfileMetricsEventNotifierService;
+import org.apache.camel.spi.CamelEvent;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.CAMEL_CONTEXT_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTES_ADDED_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTES_RUNNING_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.EVENT_TYPE_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.SERVICE_NAME;
+
+public interface MicroProfileMetricsRouteEventNotifierNamingStrategy {
+
+    MicroProfileMetricsRouteEventNotifierNamingStrategy DEFAULT = new MicroProfileMetricsRouteEventNotifierNamingStrategy() {
+        @Override
+        public String getRouteAddedName() {
+            return DEFAULT_CAMEL_ROUTES_ADDED_METRIC_NAME;
+        }
+
+        @Override
+        public String getRouteRunningName() {
+            return DEFAULT_CAMEL_ROUTES_RUNNING_METRIC_NAME;
+        }
+    };
+
+    String getRouteAddedName();
+    String getRouteRunningName();
+
+    default Tag[] getTags(CamelContext camelContext) {
+        String[] tags = {
+            SERVICE_NAME + "=" + MicroProfileMetricsEventNotifierService.class.getSimpleName(),
+            CAMEL_CONTEXT_TAG + "=" + camelContext.getName(),
+            EVENT_TYPE_TAG + "=" + CamelEvent.RouteEvent.class.getSimpleName(),
+        };
+        return MicroProfileMetricsHelper.parseTagArray(tags);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistory.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistory.java
new file mode 100644
index 0000000..33e59b8
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.camel.component.microprofile.metrics.message.history;
+
+import org.apache.camel.Message;
+import org.apache.camel.NamedNode;
+import org.apache.camel.Route;
+import org.apache.camel.support.DefaultMessageHistory;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import static org.eclipse.microprofile.metrics.Timer.Context;
+
+public class MicroProfileMetricsMessageHistory extends DefaultMessageHistory {
+    private final Route route;
+    private final Context context;
+    private final MetricRegistry metricRegistry;
+    private final MicroProfileMetricsMessageHistoryNamingStrategy namingStrategy;
+
+    public MicroProfileMetricsMessageHistory(MetricRegistry metricRegistry, Route route, NamedNode namedNode,
+            MicroProfileMetricsMessageHistoryNamingStrategy namingStrategy, long timestamp, Message message) {
+        super(route.getId(), namedNode, timestamp, message);
+        this.metricRegistry = metricRegistry;
+        this.route = route;
+        this.namingStrategy = namingStrategy;
+        this.context = metricRegistry.timer(namingStrategy.getName(route, getNode()), namingStrategy.getTags(route, getNode())).time();
+    }
+
+    @Override
+    public void nodeProcessingDone() {
+        super.nodeProcessingDone();
+        context.stop();
+    }
+
+    @Override
+    public String toString() {
+        return "MicroProfileMetricsMessageHistory[routeId=" + getRouteId() + ", node=" + getNode().getId() + ']';
+    }
+
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryFactory.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryFactory.java
new file mode 100644
index 0000000..15135c9
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryFactory.java
@@ -0,0 +1,136 @@
+/*
+ * 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.camel.component.microprofile.metrics.message.history;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.MessageHistory;
+import org.apache.camel.NamedNode;
+import org.apache.camel.NonManagedService;
+import org.apache.camel.Route;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.StaticService;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.spi.MessageHistoryFactory;
+import org.apache.camel.support.PatternHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+
+public class MicroProfileMetricsMessageHistoryFactory extends ServiceSupport implements CamelContextAware, StaticService, NonManagedService, MessageHistoryFactory {
+
+    private CamelContext camelContext;
+    private MetricRegistry metricRegistry;
+    private boolean copyMessage;
+    private String nodePattern;
+    private MicroProfileMetricsMessageHistoryNamingStrategy namingStrategy = MicroProfileMetricsMessageHistoryNamingStrategy.DEFAULT;
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
+        this.metricRegistry = metricRegistry;
+    }
+
+    public MicroProfileMetricsMessageHistoryNamingStrategy getNamingStrategy() {
+        return namingStrategy;
+    }
+
+    public void setNamingStrategy(MicroProfileMetricsMessageHistoryNamingStrategy namingStrategy) {
+        this.namingStrategy = namingStrategy;
+    }
+
+    @Override
+    public boolean isCopyMessage() {
+        return copyMessage;
+    }
+
+    @Override
+    public void setCopyMessage(boolean copyMessage) {
+        this.copyMessage = copyMessage;
+    }
+
+    @Override
+    public String getNodePattern() {
+        return nodePattern;
+    }
+
+    @Override
+    public void setNodePattern(String nodePattern) {
+        this.nodePattern = nodePattern;
+    }
+
+    @Override
+    public MessageHistory newMessageHistory(String routeId, NamedNode namedNode, long timestamp, Exchange exchange) {
+        if (nodePattern != null) {
+            String name = namedNode.getShortName();
+            String[] parts = nodePattern.split(",");
+            for (String part : parts) {
+                boolean match = PatternHelper.matchPattern(name, part);
+                if (!match) {
+                    return null;
+                }
+            }
+        }
+
+        Message msg = null;
+        if (copyMessage) {
+            msg = exchange.getMessage().copy();
+        }
+
+        Route route = camelContext.getRoute(routeId);
+        if (route != null) {
+            return new MicroProfileMetricsMessageHistory(getMetricRegistry(), route, namedNode, getNamingStrategy(), timestamp, msg);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        if (metricRegistry == null) {
+            metricRegistry = MicroProfileMetricsHelper.getMetricRegistry(camelContext);
+        }
+
+        try {
+            MicroProfileMetricsMessageHistoryService service = camelContext.hasService(MicroProfileMetricsMessageHistoryService.class);
+            if (service == null) {
+                service = new MicroProfileMetricsMessageHistoryService();
+                service.setMetricRegistry(getMetricRegistry());
+                camelContext.addService(service);
+            }
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeCamelException(e);
+        }
+    }
+
+    @Override
+    protected void doStop() {
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryNamingStrategy.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryNamingStrategy.java
new file mode 100644
index 0000000..774b2f8
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryNamingStrategy.java
@@ -0,0 +1,44 @@
+/*
+ * 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.camel.component.microprofile.metrics.message.history;
+
+import org.apache.camel.NamedNode;
+import org.apache.camel.Route;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.CAMEL_CONTEXT_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.NODE_ID_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.ROUTE_ID_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.SERVICE_NAME;
+
+public interface MicroProfileMetricsMessageHistoryNamingStrategy {
+
+    MicroProfileMetricsMessageHistoryNamingStrategy DEFAULT = (route, node) -> DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME;
+
+    String getName(Route route, NamedNode node);
+
+    default Tag[] getTags(Route route, NamedNode node) {
+        String[] tags = {
+            SERVICE_NAME + "=" + MicroProfileMetricsMessageHistory.class.getSimpleName(),
+            CAMEL_CONTEXT_TAG + "=" + route.getCamelContext().getName(),
+            ROUTE_ID_TAG + "=" + route.getId(),
+            NODE_ID_TAG + "=" + node.getId(),
+        };
+        return MicroProfileMetricsHelper.parseTagArray(tags);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryService.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryService.java
new file mode 100644
index 0000000..a207611
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.camel.component.microprofile.metrics.message.history;
+
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.StaticService;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsService;
+
+@ManagedResource(description = "MicroProfileMetricsMessageHistory")
+public final class MicroProfileMetricsMessageHistoryService extends MicroProfileMetricsService implements CamelContextAware, StaticService {
+}
\ No newline at end of file
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicy.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicy.java
new file mode 100644
index 0000000..5ea3e98
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicy.java
@@ -0,0 +1,120 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.NonManagedService;
+import org.apache.camel.Route;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.support.RoutePolicySupport;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Timer;
+import org.eclipse.microprofile.metrics.Timer.Context;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME;
+
+public class MicroProfileMetricsRoutePolicy extends RoutePolicySupport implements NonManagedService {
+
+    private MetricRegistry metricRegistry;
+    private MetricsStatistics statistics;
+    private MicroProfileMetricsRoutePolicyNamingStrategy namingStrategy = MicroProfileMetricsRoutePolicyNamingStrategy.DEFAULT;
+
+    private static final class MetricsStatistics {
+        private final MetricRegistry metricRegistry;
+        private final Route route;
+        private final MicroProfileMetricsRoutePolicyNamingStrategy namingStrategy;
+
+        private MetricsStatistics(MetricRegistry metricRegistry, Route route, MicroProfileMetricsRoutePolicyNamingStrategy namingStrategy) {
+            this.metricRegistry = ObjectHelper.notNull(metricRegistry, "metricRegistry", this);
+            this.namingStrategy = ObjectHelper.notNull(namingStrategy, "MicroProfileMetricsRoutePolicyNamingStrategy", this);
+            this.route = route;
+        }
+
+        public void onExchangeBegin(Exchange exchange) {
+            namingStrategy.getName(route);
+
+            Timer timer = metricRegistry.timer(namingStrategy.getName(route), namingStrategy.getTags(route, exchange));
+            exchange.setProperty(propertyName(exchange), timer.time());
+        }
+
+        public void onExchangeDone(Exchange exchange) {
+            Context context = (Context) exchange.removeProperty(propertyName(exchange));
+            if (context != null) {
+                context.stop();
+            }
+        }
+
+        private String propertyName(Exchange exchange) {
+            return String.format("%s.%s.%s", DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME, route.getId(), exchange.getExchangeId());
+        }
+    }
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
+        this.metricRegistry = metricRegistry;
+    }
+
+    public MicroProfileMetricsRoutePolicyNamingStrategy getNamingStrategy() {
+        return namingStrategy;
+    }
+
+    public void setNamingStrategy(MicroProfileMetricsRoutePolicyNamingStrategy namingStrategy) {
+        this.namingStrategy = namingStrategy;
+    }
+
+    @Override
+    public void onInit(Route route) {
+        super.onInit(route);
+        MetricRegistry metricRegistry = getMetricRegistry();
+        if (metricRegistry == null) {
+            metricRegistry = MicroProfileMetricsHelper.getMetricRegistry(route.getCamelContext());
+        }
+
+        try {
+            MicroProfileMetricsRoutePolicyService registryService = route.getCamelContext().hasService(MicroProfileMetricsRoutePolicyService.class);
+            if (registryService == null) {
+                registryService = new MicroProfileMetricsRoutePolicyService();
+                registryService.setMetricRegistry(metricRegistry);
+                route.getCamelContext().addService(registryService);
+                ServiceHelper.startService(registryService);
+            }
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeCamelException(e);
+        }
+        statistics = new MetricsStatistics(metricRegistry, route, getNamingStrategy());
+    }
+
+
+    @Override
+    public void onExchangeBegin(Route route, Exchange exchange) {
+        if (statistics != null) {
+            statistics.onExchangeBegin(exchange);
+        }
+    }
+
+    @Override
+    public void onExchangeDone(Route route, Exchange exchange) {
+        if (statistics != null) {
+            statistics.onExchangeDone(exchange);
+        }
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyFactory.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyFactory.java
new file mode 100644
index 0000000..4a46ca2
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.NamedNode;
+import org.apache.camel.spi.RoutePolicy;
+import org.apache.camel.spi.RoutePolicyFactory;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+
+public class MicroProfileMetricsRoutePolicyFactory implements RoutePolicyFactory {
+
+    private MetricRegistry metricRegistry;
+    private MicroProfileMetricsRoutePolicyNamingStrategy namingStrategy = MicroProfileMetricsRoutePolicyNamingStrategy.DEFAULT;
+
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
+        this.metricRegistry = metricRegistry;
+    }
+
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    public MicroProfileMetricsRoutePolicyNamingStrategy getNamingStrategy() {
+        return namingStrategy;
+    }
+
+    public void setNamingStrategy(MicroProfileMetricsRoutePolicyNamingStrategy namingStrategy) {
+        this.namingStrategy = namingStrategy;
+    }
+
+    @Override
+    public RoutePolicy createRoutePolicy(CamelContext camelContext, String routeId, NamedNode routeDefinition) {
+        MicroProfileMetricsRoutePolicy answer = new MicroProfileMetricsRoutePolicy();
+        answer.setMetricRegistry(getMetricRegistry());
+        answer.setNamingStrategy(getNamingStrategy());
+        return answer;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyNamingStrategy.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyNamingStrategy.java
new file mode 100644
index 0000000..49cbda3
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyNamingStrategy.java
@@ -0,0 +1,45 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Route;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.eclipse.microprofile.metrics.Tag;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.CAMEL_CONTEXT_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.FAILED_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.ROUTE_ID_TAG;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.SERVICE_NAME;
+
+public interface MicroProfileMetricsRoutePolicyNamingStrategy {
+
+    MicroProfileMetricsRoutePolicyNamingStrategy DEFAULT = route -> DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME;
+
+    String getName(Route route);
+
+    default Tag[] getTags(Route route, Exchange exchange) {
+        String[] tags = {
+            SERVICE_NAME + "=" + MicroProfileMetricsRoutePolicyService.class.getSimpleName(),
+            CAMEL_CONTEXT_TAG + "=" + route.getCamelContext().getName(),
+            ROUTE_ID_TAG + "=" + route.getId(),
+            FAILED_TAG + "=" + exchange.isFailed(),
+        };
+        return MicroProfileMetricsHelper.parseTagArray(tags);
+    }
+
+}
diff --git a/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyService.java b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyService.java
new file mode 100644
index 0000000..279be16
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/main/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyService.java
@@ -0,0 +1,26 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.StaticService;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsService;
+
+@ManagedResource(description = "MicroProfileMetricsRoutePolicy")
+public final class MicroProfileMetricsRoutePolicyService extends MicroProfileMetricsService implements CamelContextAware, StaticService {
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCounterTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCounterTest.java
new file mode 100644
index 0000000..832deff
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCounterTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.Counter;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_COUNTER_INCREMENT;
+
+public class MicroProfileMetricsCounterTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testCounterMetric() {
+        template.sendBody("direct:increment", null);
+        Counter counter = getCounter("test-counter");
+        assertEquals(10, counter.getCount());
+    }
+
+    @Test
+    public void testCounterMetricDefaultIncrement() {
+        template.sendBody("direct:default", null);
+        Counter counter = getCounter("test-counter");
+        assertEquals(1, counter.getCount());
+    }
+
+    @Test
+    public void testCounterMetricIsDefaultType() {
+        template.sendBody("direct:defaultMetricType", null);
+        Counter counter = getCounter("test-counter");
+        assertEquals(1, counter.getCount());
+    }
+
+    @Test
+    public void testCounterMetricHeaderValueIncrement() {
+        template.sendBody("direct:incrementFromHeader", null);
+        Counter counter = getCounter("test-counter-header");
+        assertEquals(10, counter.getCount());
+    }
+
+    @Test
+    public void testCounterMetricHeaderOverrideValueIncrement() {
+        template.sendBodyAndHeader("direct:increment", null, HEADER_COUNTER_INCREMENT, 20);
+        Counter counter = getCounter("test-counter");
+        assertEquals(20, counter.getCount());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:increment")
+                    .to("microprofile-metrics:counter:test-counter?counterIncrement=10");
+
+                from("direct:default")
+                    .to("microprofile-metrics:counter:test-counter");
+
+                from("direct:defaultMetricType")
+                    .to("microprofile-metrics:test-counter");
+
+                from("direct:incrementFromHeader")
+                    .setHeader(HEADER_COUNTER_INCREMENT, constant(10))
+                    .to("microprofile-metrics:counter:test-counter-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCustomRegistryTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCustomRegistryTest.java
new file mode 100644
index 0000000..912ec8b
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsCustomRegistryTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.SortedMap;
+
+import io.smallrye.metrics.MetricsRegistryImpl;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.junit.Test;
+
+public class MicroProfileMetricsCustomRegistryTest extends CamelTestSupport {
+
+    private MetricRegistry metricRegistry;
+
+    @Test
+    public void testMicroProfileMetricsComponentWithCustomMetricRegistry() {
+        template.sendBody("direct:start", null);
+        SortedMap<MetricID, Counter> counters = metricRegistry.getCounters((metricID, metric) -> metricID.getName().equals("test-counter"));
+        MetricID metricID = counters.firstKey();
+        assertEquals(1, counters.get(metricID).getCount());
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext camelContext = super.createCamelContext();
+        MicroProfileMetricsComponent component = new MicroProfileMetricsComponent();
+        metricRegistry = new MetricsRegistryImpl();
+        component.setMetricRegistry(metricRegistry);
+        camelContext.addComponent("microprofile-metrics", component);
+        return camelContext;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to("microprofile-metrics:counter:test-counter");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsEndpointTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsEndpointTest.java
new file mode 100644
index 0000000..c0b1fc5
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsEndpointTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.Collections;
+
+import org.apache.camel.Producer;
+import org.eclipse.microprofile.metrics.MetricType;
+import org.junit.Test;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+
+public class MicroProfileMetricsEndpointTest {
+
+    @Test
+    public void testCreateCounterProducer() throws Exception {
+        MicroProfileMetricsEndpoint endpoint = createEndpoint(MetricType.COUNTER);
+        Producer producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsCounterProducer.class)));
+    }
+
+    @Test
+    public void testCreateGaugeProducer() throws Exception {
+        MicroProfileMetricsEndpoint endpoint = createEndpoint(MetricType.GAUGE);
+        Producer producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsGaugeProducer.class)));
+
+        endpoint = createEndpoint(MetricType.CONCURRENT_GAUGE);
+        producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsGaugeProducer.class)));
+    }
+
+    @Test
+    public void testCreateHistogramProducer() throws Exception {
+        MicroProfileMetricsEndpoint endpoint = createEndpoint(MetricType.HISTOGRAM);
+        Producer producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsHistogramProducer.class)));
+    }
+
+    @Test
+    public void testCreateMeteredProducer() throws Exception {
+        MicroProfileMetricsEndpoint endpoint = createEndpoint(MetricType.METERED);
+        Producer producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsMeteredProducer.class)));
+    }
+
+    @Test
+    public void testCreateTimerProducer() throws Exception {
+        MicroProfileMetricsEndpoint endpoint = createEndpoint(MetricType.TIMER);
+        Producer producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsTimerProducer.class)));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testInvalidMetricType() throws Exception {
+        MicroProfileMetricsEndpoint endpoint = createEndpoint(MetricType.INVALID);
+        Producer producer = endpoint.createProducer();
+        assertThat(producer, is(instanceOf(MicroProfileMetricsCounterProducer.class)));
+    }
+
+    private MicroProfileMetricsEndpoint createEndpoint(MetricType metricType) {
+        return new MicroProfileMetricsEndpoint("microprofile-metrics:foo:bar", null, null, metricType, null, Collections.emptyList());
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsGaugeTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsGaugeTest.java
new file mode 100644
index 0000000..eca9e7f
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsGaugeTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_GAUGE_DECREMENT;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_GAUGE_INCREMENT;
+
+public class MicroProfileMetricsGaugeTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testGaugeMetric() {
+        template.sendBody("direct:gaugeIncrement", null);
+        ConcurrentGauge gauge = getConcurrentGauge("test-gauge");
+        assertEquals(1, gauge.getCount());
+        template.sendBody("direct:gaugeDecrement", null);
+        assertEquals(0, gauge.getCount());
+    }
+
+    @Test
+    public void testGaugeMetricHeaderIncrementDecrement() {
+        template.sendBody("direct:gaugeIncrementHeader", null);
+        ConcurrentGauge gauge = getConcurrentGauge("test-gauge-header");
+        assertEquals(1, gauge.getCount());
+        template.sendBody("direct:gaugeDecrementHeader", null);
+        assertEquals(0, gauge.getCount());
+    }
+
+    @Test
+    public void testCounterMetricHeaderOverrideIncrement() {
+        template.sendBodyAndHeader("direct:gaugeIncrement", null, HEADER_GAUGE_INCREMENT, false);
+        ConcurrentGauge gauge = getConcurrentGauge("test-gauge");
+        assertEquals(0, gauge.getCount());
+    }
+
+    @Test
+    public void testCounterMetricHeaderOverrideDecrement() {
+        template.sendBody("direct:gaugeIncrement", null);
+        ConcurrentGauge gauge = getConcurrentGauge("test-gauge");
+        assertEquals(1, gauge.getCount());
+        template.sendBodyAndHeader("direct:gaugeDecrement", null, HEADER_GAUGE_DECREMENT, false);
+        assertEquals(1, gauge.getCount());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:gaugeIncrement")
+                    .to("microprofile-metrics:concurrent gauge:test-gauge?gaugeIncrement=true");
+
+                from("direct:gaugeDecrement")
+                    .to("microprofile-metrics:concurrent gauge:test-gauge?gaugeDecrement=true");
+
+                from("direct:gaugeIncrementHeader")
+                    .setHeader(HEADER_GAUGE_INCREMENT, constant(true))
+                    .to("microprofile-metrics:concurrent gauge:test-gauge-header");
+
+                from("direct:gaugeDecrementHeader")
+                    .setHeader(HEADER_GAUGE_DECREMENT, constant(true))
+                    .to("microprofile-metrics:concurrent gauge:test-gauge-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHelperTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHelperTest.java
new file mode 100644
index 0000000..8e4131b
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHelperTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import io.smallrye.metrics.MetricRegistries;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.Registry;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+public class MicroProfileMetricsHelperTest {
+
+    @Test
+    public void testParseTag() {
+        Tag tag = MicroProfileMetricsHelper.parseTag("foo=bar");
+        assertEquals("foo", tag.getTagName());
+        assertEquals("bar", tag.getTagValue());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseTagForEmptyString() {
+        MicroProfileMetricsHelper.parseTag("");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseTagForInvalidString() {
+        MicroProfileMetricsHelper.parseTag("badtag");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseTagForStringWithNotEnoughElements() {
+        MicroProfileMetricsHelper.parseTag("badtag=");
+    }
+
+    @Test
+    public void testParseTags() {
+        Tag[] tags = MicroProfileMetricsHelper.parseTagArray(new String[] {"foo=bar", "cheese=wine"});
+        assertEquals(2, tags.length);
+        assertEquals("foo", tags[0].getTagName());
+        assertEquals("bar", tags[0].getTagValue());
+        assertEquals("cheese", tags[1].getTagName());
+        assertEquals("wine", tags[1].getTagValue());
+    }
+
+    @Test
+    public void testGetMetricRegistry() {
+        DefaultCamelContext camelContext = new DefaultCamelContext();
+        Registry registry = camelContext.getRegistry();
+        registry.bind(MicroProfileMetricsConstants.METRIC_REGISTRY_NAME, MetricRegistries.get(MetricRegistry.Type.APPLICATION));
+        MicroProfileMetricsHelper.getMetricRegistry(camelContext);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testGetMetricRegistryWhenNoRegistryConfigured() {
+        MicroProfileMetricsHelper.getMetricRegistry(new DefaultCamelContext());
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHistogramTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHistogramTest.java
new file mode 100644
index 0000000..b190a91
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsHistogramTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.Histogram;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_HISTOGRAM_VALUE;
+
+public class MicroProfileMetricsHistogramTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testHistogramMetric() {
+        template.sendBody("direct:histogram", null);
+        Histogram histogram = getHistogram("test-histogram");
+        assertEquals(10, histogram.getSnapshot().getMax());
+    }
+
+    @Test
+    public void testHistogramMetricHeaderValueSet() {
+        template.sendBody("direct:histogramFromHeader", null);
+        Histogram histogram = getHistogram("test-histogram-header");
+        assertEquals(10, histogram.getSnapshot().getMax());
+    }
+
+    @Test
+    public void testHistogramMetricHeaderOverrideValueSet() {
+        template.sendBodyAndHeader("direct:histogram", null, HEADER_HISTOGRAM_VALUE, 20);
+        Histogram histogram = getHistogram("test-histogram");
+        assertEquals(20, histogram.getSnapshot().getMax());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:histogram")
+                    .to("microprofile-metrics:histogram:test-histogram?value=10");
+
+                from("direct:histogramFromHeader")
+                        .setHeader(HEADER_HISTOGRAM_VALUE, constant(10))
+                    .to("microprofile-metrics:histogram:test-histogram-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMetadataTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMetadataTest.java
new file mode 100644
index 0000000..1f19968
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMetadataTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_DESCRIPTION;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_DISPLAY_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_UNIT;
+import static org.eclipse.microprofile.metrics.MetricUnits.KILOBYTES;
+import static org.eclipse.microprofile.metrics.MetricUnits.MEGABITS;
+
+public class MicroProfileMetricsMetadataTest extends MicroProfileMetricsTestSupport {
+
+    private static final String METRIC_DISPLAY_NAME = "Test Display Name";
+    private static final String METRIC_DISPLAY_NAME_MODIFIED = METRIC_DISPLAY_NAME + " Modified";
+    private static final String METRIC_DESCRIPTION = "Test Description";
+    private static final String METRIC_DESCRIPTION_MODIFIED = METRIC_DESCRIPTION + " Modified";
+
+    @Test
+    public void testMetricMetadata() {
+        template.sendBody("direct:metadata", null);
+        Metadata metadata = getMetricMetadata("test-counter");
+        assertEquals(METRIC_DESCRIPTION, metadata.getDescription().get());
+        assertEquals(METRIC_DISPLAY_NAME, metadata.getDisplayName());
+        assertEquals(KILOBYTES, metadata.getUnit().get());
+    }
+
+    @Test
+    public void testMetricMetadataFromHeader() {
+        template.sendBody("direct:metadataHeader", null);
+        Metadata metadata = getMetricMetadata("test-counter-header");
+        assertEquals(METRIC_DESCRIPTION, metadata.getDescription().get());
+        assertEquals(METRIC_DISPLAY_NAME, metadata.getDisplayName());
+        assertEquals(KILOBYTES, metadata.getUnit().get());
+    }
+
+    @Test
+    public void testMetricMetadataFromHeadersOverride() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(HEADER_METRIC_DESCRIPTION, METRIC_DISPLAY_NAME_MODIFIED);
+        headers.put(HEADER_METRIC_DISPLAY_NAME, METRIC_DESCRIPTION_MODIFIED);
+        headers.put(HEADER_METRIC_UNIT, MEGABITS);
+
+        template.sendBodyAndHeaders("direct:metadata", null, headers);
+        Metadata metadata = getMetricMetadata("test-counter");
+        assertEquals(METRIC_DISPLAY_NAME_MODIFIED, metadata.getDescription().get());
+        assertEquals(METRIC_DESCRIPTION_MODIFIED, metadata.getDisplayName());
+        assertEquals(MEGABITS, metadata.getUnit().get());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:metadata")
+                    .toF("microprofile-metrics:counter:test-counter?description=%s&displayName=%s&metricUnit=%s", METRIC_DESCRIPTION,
+                        METRIC_DISPLAY_NAME, KILOBYTES);
+
+                from("direct:metadataHeader")
+                    .setHeader(HEADER_METRIC_DESCRIPTION, constant(METRIC_DESCRIPTION))
+                    .setHeader(HEADER_METRIC_DISPLAY_NAME, constant(METRIC_DISPLAY_NAME))
+                    .setHeader(HEADER_METRIC_UNIT, constant(KILOBYTES))
+                    .to("microprofile-metrics:counter:test-counter-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMeterTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMeterTest.java
new file mode 100644
index 0000000..5026a37
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsMeterTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.Meter;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METER_MARK;
+
+public class MicroProfileMetricsMeterTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMeterMetric() {
+        template.sendBody("direct:mark", null);
+        Meter meter = getMeter("test-meter");
+        assertEquals(10, meter.getCount());
+    }
+
+    @Test
+    public void testMeterMetricDefaultMarkValue() {
+        template.sendBody("direct:default", null);
+        Meter meter = getMeter("test-meter");
+        assertEquals(1, meter.getCount());
+    }
+
+    @Test
+    public void testMeterMetricHeaderMarkValue() {
+        template.sendBody("direct:markFromHeader", null);
+        Meter meter = getMeter("test-meter-header");
+        assertEquals(10, meter.getCount());
+    }
+
+    @Test
+    public void testMeterMetricOverrideHeaderMarkValue() {
+        template.sendBodyAndHeader("direct:mark", null, HEADER_METER_MARK, 20);
+        Meter meter = getMeter("test-meter");
+        assertEquals(20, meter.getCount());
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:mark")
+                    .to("microprofile-metrics:meter:test-meter?mark=10");
+
+                from("direct:default")
+                    .to("microprofile-metrics:meter:test-meter");
+
+                from("direct:markFromHeader")
+                    .setHeader(HEADER_METER_MARK, constant(10))
+                    .to("microprofile-metrics:meter:test-meter-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTagTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTagTest.java
new file mode 100644
index 0000000..7ab36f4
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTagTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.List;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.Tag;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_METRIC_TAGS;
+
+public class MicroProfileMetricsTagTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMetricTags() {
+        template.sendBody("direct:tags", null);
+        List<Tag> tags = getMetricTags("test-counter");
+        assertEquals(3, tags.size());
+
+        Tag tagCamelContext = tags.get(0);
+        assertEquals("camelContext", tagCamelContext.getTagName());
+        assertEquals(context.getName(), tagCamelContext.getTagValue());
+
+        Tag tagCheese = tags.get(1);
+        assertEquals("cheese", tagCheese.getTagName());
+        assertEquals("wine", tagCheese.getTagValue());
+
+        Tag tagFoo = tags.get(2);
+        assertEquals("foo", tagFoo.getTagName());
+        assertEquals("bar", tagFoo.getTagValue());
+    }
+
+    @Test
+    public void testMetricTagsFromHeader() {
+        template.sendBody("direct:tagsFromHeader", null);
+        List<Tag> tags = getMetricTags("test-counter-header");
+        assertEquals(3, tags.size());
+
+        Tag tagA = tags.get(0);
+        assertEquals("a", tagA.getTagName());
+        assertEquals("b", tagA.getTagValue());
+
+        Tag tagC = tags.get(1);
+        assertEquals("c", tagC.getTagName());
+        assertEquals("d", tagC.getTagValue());
+
+        Tag tagCamelContext = tags.get(2);
+        assertEquals("camelContext", tagCamelContext.getTagName());
+        assertEquals(context.getName(), tagCamelContext.getTagValue());
+    }
+
+    @Test
+    public void testMetricTagsFromUriMergeWithHeaderValue() {
+        template.sendBodyAndHeader("direct:tags", null, HEADER_METRIC_TAGS, "a=b,c=d");
+        List<Tag> tags = getMetricTags("test-counter");
+        assertEquals(5, tags.size());
+
+        Tag tagA = tags.get(0);
+        assertEquals("a", tagA.getTagName());
+        assertEquals("b", tagA.getTagValue());
+
+        Tag tagC = tags.get(1);
+        assertEquals("c", tagC.getTagName());
+        assertEquals("d", tagC.getTagValue());
+
+        Tag tagCamelContext = tags.get(2);
+        assertEquals("camelContext", tagCamelContext.getTagName());
+        assertEquals(context.getName(), tagCamelContext.getTagValue());
+
+        Tag tagCheese = tags.get(3);
+        assertEquals("cheese", tagCheese.getTagName());
+        assertEquals("wine", tagCheese.getTagValue());
+
+        Tag tagFoo = tags.get(4);
+        assertEquals("foo", tagFoo.getTagName());
+        assertEquals("bar", tagFoo.getTagValue());
+
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:tags")
+                    .to("microprofile-metrics:counter:test-counter?tags=foo=bar,cheese=wine");
+
+                from("direct:tagsFromHeader")
+                    .setHeader(HEADER_METRIC_TAGS, constant("a=b,c=d"))
+                    .to("microprofile-metrics:counter:test-counter-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTestSupport.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTestSupport.java
new file mode 100644
index 0000000..7d2d857
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTestSupport.java
@@ -0,0 +1,98 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import io.smallrye.metrics.MetricRegistries;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.eclipse.microprofile.metrics.Counter;
+import org.eclipse.microprofile.metrics.Histogram;
+import org.eclipse.microprofile.metrics.Metadata;
+import org.eclipse.microprofile.metrics.Meter;
+import org.eclipse.microprofile.metrics.Metric;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.MetricRegistry;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper.findMetric;
+
+public class MicroProfileMetricsTestSupport extends CamelTestSupport {
+
+    @BindToRegistry(MicroProfileMetricsConstants.METRIC_REGISTRY_NAME)
+    protected MetricRegistry metricRegistry;
+
+    private MetricRegistries registries = new MetricRegistries();
+
+    @Override
+    public void setUp() throws Exception {
+        metricRegistry = registries.getApplicationRegistry();
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        registries.cleanUp();
+    }
+
+    protected Counter getCounter(String metricName) {
+        return findMetric(metricRegistry, metricName, Counter.class);
+    }
+
+    protected ConcurrentGauge getConcurrentGauge(String metricName) {
+        return findMetric(metricRegistry, metricName, ConcurrentGauge.class);
+    }
+
+    protected Histogram getHistogram(String metricName) {
+        return findMetric(metricRegistry, metricName, Histogram.class);
+    }
+
+    protected Meter getMeter(String metricName) {
+        return findMetric(metricRegistry, metricName, Meter.class);
+    }
+
+    protected Timer getTimer(String metricName) {
+        return findMetric(metricRegistry, metricName, Timer.class);
+    }
+
+    protected Metadata getMetricMetadata(String metricName) {
+        Map<String, Metadata> metadataMap = metricRegistry.getMetadata();
+        for (Map.Entry<String, Metadata> entry : metadataMap.entrySet()) {
+            Metadata metadata = entry.getValue();
+            if (metadata.getName().equals(metricName)) {
+                return metadata;
+            }
+        }
+        return null;
+    }
+
+    protected List<Tag> getMetricTags(String metricName) {
+        Map<MetricID, Metric> metrics = metricRegistry.getMetrics();
+        for (Map.Entry<MetricID, Metric> entry : metrics.entrySet()) {
+            if (entry.getKey().getName().equals(metricName)) {
+                return entry.getKey().getTagsAsList();
+            }
+        }
+        return Collections.emptyList();
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTimerTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTimerTest.java
new file mode 100644
index 0000000..5b6f78f
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/MicroProfileMetricsTimerTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.camel.component.microprofile.metrics;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.HEADER_TIMER_ACTION;
+
+public class MicroProfileMetricsTimerTest extends MicroProfileMetricsTestSupport {
+
+    private static final long DELAY = 100L;
+
+    @Test
+    public void testTimerMetric() {
+        template.sendBody("direct:timer", null);
+        Timer timer = getTimer("test-timer");
+        assertEquals(1, timer.getCount());
+        assertTrue(timer.getSnapshot().getMax() > DELAY);
+    }
+
+    @Test
+    public void testTimerMetricActionFromHeader() {
+        template.sendBody("direct:timer", null);
+        Timer timer = getTimer("test-timer");
+        assertEquals(1, timer.getCount());
+        assertTrue(timer.getSnapshot().getMax() > DELAY);
+    }
+
+    @Test
+    public void testTimerMetricActionFromHeaderOverride() {
+        template.sendBodyAndHeader("direct:timer", null, HEADER_TIMER_ACTION, "stop");
+        Timer timer = getTimer("test-timer");
+        assertNull(timer);
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:timer")
+                    .to("microprofile-metrics:timer:test-timer?action=start")
+                    .delayer(DELAY)
+                    .to("microprofile-metrics:timer:test-timer?action=stop");
+
+                from("direct:timerFromHeader")
+                    .setHeader(HEADER_TIMER_ACTION, constant(TimerAction.START))
+                    .to("microprofile-metrics:timer:test-timer-header")
+                    .delayer(DELAY)
+                    .setHeader(HEADER_TIMER_ACTION, constant(TimerAction.STOP))
+                    .to("microprofile-metrics:timer:test-timer-header");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifierTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifierTest.java
new file mode 100644
index 0000000..600684e
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/event/notifier/exchange/MicroProfileMetricsExchangeEventNotifierTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier.exchange;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.ExpressionAdapter;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+
+public class MicroProfileMetricsExchangeEventNotifierTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMicroProfileMetricsEventNotifier() {
+        int count = 10;
+        Long delay = 50L;
+
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.returnReplyBody(new ExpressionAdapter() {
+            @Override
+            public Object evaluate(Exchange exchange) {
+                try {
+                    Thread.sleep(50L);
+                    return exchange.getIn().getBody();
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    throw new CamelExecutionException(e.getMessage(), exchange, e);
+                }
+            }
+        });
+        mockEndpoint.expectedMessageCount(count);
+
+        for (int i = 0; i < count; i++) {
+            template.sendBody("direct:start", null);
+        }
+
+        Timer timer = getTimer("mock://result");
+        assertEquals(count, timer.getCount());
+        assertTrue(timer.getSnapshot().getMean() > delay.doubleValue());
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsExchangeEventNotifier eventNotifier = new MicroProfileMetricsExchangeEventNotifier();
+        eventNotifier.setNamingStrategy((exchange, endpoint) -> endpoint.getEndpointUri());
+        eventNotifier.setMetricRegistry(metricRegistry);
+
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.getManagementStrategy().addEventNotifier(eventNotifier);
+        return camelContext;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("test")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifierTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifierTest.java
new file mode 100644
index 0000000..7062fd4
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/event/notifier/route/MicroProfileMetricsRouteEventNotifierTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.camel.component.microprofile.metrics.event.notifier.route;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.eclipse.microprofile.metrics.ConcurrentGauge;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTES_ADDED_METRIC_NAME;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTES_RUNNING_METRIC_NAME;
+
+public class MicroProfileMetricsRouteEventNotifierTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMicroProfileMetricsEventNotifier() throws Exception {
+        ConcurrentGauge routesAdded = getConcurrentGauge(DEFAULT_CAMEL_ROUTES_ADDED_METRIC_NAME);
+        ConcurrentGauge routesRunning = getConcurrentGauge(DEFAULT_CAMEL_ROUTES_RUNNING_METRIC_NAME);
+
+        assertEquals(1, routesAdded.getCount());
+        assertEquals(1, routesRunning.getCount());
+
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:foo").id("test")
+                        .to("mock:bar");
+            }
+        });
+
+        assertEquals(2, routesAdded.getCount());
+        assertEquals(2, routesRunning.getCount());
+
+        context.getRouteController().stopRoute("test");
+        assertEquals(2, routesAdded.getCount());
+        assertEquals(1, routesRunning.getCount());
+
+        context.removeRoute("test");
+        assertEquals(1, routesAdded.getCount());
+        assertEquals(1, routesRunning.getCount());
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsRouteEventNotifier eventNotifier = new MicroProfileMetricsRouteEventNotifier();
+        eventNotifier.setMetricRegistry(metricRegistry);
+
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.getManagementStrategy().addEventNotifier(eventNotifier);
+        return camelContext;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsExceptionInRouteMessageHistoryTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsExceptionInRouteMessageHistoryTest.java
new file mode 100644
index 0000000..6f9cd6e
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsExceptionInRouteMessageHistoryTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.camel.component.microprofile.metrics.message.history;
+
+import java.util.SortedMap;
+
+import io.smallrye.metrics.exporters.JsonExporter;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+
+public class MicroProfileMetricsExceptionInRouteMessageHistoryTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMetricsHistoryWhenRouteThrowsException() throws Exception {
+        getMockEndpoint("mock:foo").expectedMessageCount(5);
+        getMockEndpoint("mock:bar").expectedMessageCount(5);
+        getMockEndpoint("mock:baz").expectedMessageCount(0);
+        getMockEndpoint("mock:exception").expectedMessageCount(5);
+
+        for (int i = 0; i < 10; i++) {
+            if (i % 2 == 0) {
+                template.sendBody("seda:foo", "Hello " + i);
+            } else {
+                template.sendBody("seda:bar", "Hello " + i);
+            }
+        }
+
+        assertMockEndpointsSatisfied();
+
+        SortedMap<MetricID, Timer> timers = metricRegistry.getTimers();
+        assertEquals(3, timers.size());
+
+        MicroProfileMetricsMessageHistoryService service = context.hasService(MicroProfileMetricsMessageHistoryService.class);
+        assertNotNull(service);
+
+        JsonExporter exporter = new JsonExporter();
+        String json = exporter.exportAllScopes().toString();
+        assertNotNull(json);
+        assertTrue(json.contains("nodeId=foo"));
+        assertTrue(json.contains("nodeId=bar"));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                onException(Exception.class)
+                    .routeId("ExceptionRoute")
+                    .to("mock:exception").id("exception");
+
+                from("seda:foo")
+                    .to("mock:foo").id("foo");
+
+                from("seda:bar")
+                    .to("mock:bar").id("bar")
+                    .process(exchange -> {
+                        throw new Exception("Metrics Exception");
+                    })
+                    .to("mock:baz").id("baz");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsMessageHistoryFactory factory = new MicroProfileMetricsMessageHistoryFactory();
+        factory.setMetricRegistry(metricRegistry);
+
+        CamelContext context = super.createCamelContext();
+        context.setMessageHistoryFactory(factory);
+        return context;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryTest.java
new file mode 100644
index 0000000..7b7cd49
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/message/history/MicroProfileMetricsMessageHistoryTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.camel.component.microprofile.metrics.message.history;
+
+import java.util.Arrays;
+import java.util.SortedMap;
+
+import io.smallrye.metrics.TagsUtils;
+import io.smallrye.metrics.exporters.JsonExporter;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME;
+
+public class MicroProfileMetricsMessageHistoryTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMetricsHistory() throws Exception {
+        int count = 10;
+
+        getMockEndpoint("mock:foo").expectedMessageCount(count / 2);
+        getMockEndpoint("mock:bar").expectedMessageCount(count / 2);
+        getMockEndpoint("mock:baz").expectedMessageCount(count / 2);
+
+        for (int i = 0; i < count; i++) {
+            if (i % 2 == 0) {
+                template.sendBody("direct:foo", "Hello " + i);
+            } else {
+                template.sendBody("direct:bar", "Hello " + i);
+            }
+        }
+
+        assertMockEndpointsSatisfied();
+
+        SortedMap<MetricID, Timer> timers = metricRegistry.getTimers();
+        assertEquals(3, timers.size());
+
+        String contextTag = "camelContext=" + context.getName();
+        Tag[] fooTags = getTags(new String[] {contextTag, "nodeId=foo", "routeId=routeA", "serviceName=MicroProfileMetricsMessageHistory"});
+        Timer fooTimer = MicroProfileMetricsHelper.findMetric(metricRegistry, DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME, Timer.class, Arrays.asList(fooTags));
+        assertEquals(count / 2, fooTimer.getCount());
+
+        Tag[] barTags = getTags(new String[] {contextTag, "nodeId=bar", "routeId=routeB", "serviceName=MicroProfileMetricsMessageHistory"});
+        Timer barTimer = MicroProfileMetricsHelper.findMetric(metricRegistry, DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME, Timer.class, Arrays.asList(barTags));
+        assertEquals(count / 2, barTimer.getCount());
+
+        Tag[] bazTags = getTags(new String[] {contextTag, "nodeId=baz", "routeId=routeB", "serviceName=MicroProfileMetricsMessageHistory"});
+        Timer bazTimer = MicroProfileMetricsHelper.findMetric(metricRegistry, DEFAULT_CAMEL_MESSAGE_HISTORY_METRIC_NAME, Timer.class, Arrays.asList(bazTags));
+        assertEquals(count / 2, bazTimer.getCount());
+
+        MicroProfileMetricsMessageHistoryService service = context.hasService(MicroProfileMetricsMessageHistoryService.class);
+        assertNotNull(service);
+
+        JsonExporter exporter = new JsonExporter();
+        String json = exporter.exportAllScopes().toString();
+        assertNotNull(json);
+        assertTrue(json.contains("nodeId=foo"));
+        assertTrue(json.contains("nodeId=bar"));
+        assertTrue(json.contains("nodeId=baz"));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:foo").routeId("routeA")
+                    .to("mock:foo").id("foo");
+
+                from("direct:bar").routeId("routeB")
+                    .to("mock:bar").id("bar")
+                    .to("mock:baz").id("baz");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsMessageHistoryFactory factory = new MicroProfileMetricsMessageHistoryFactory();
+        factory.setMetricRegistry(metricRegistry);
+
+        CamelContext context = super.createCamelContext();
+        context.setMessageHistoryFactory(factory);
+        return context;
+    }
+
+    private Tag[] getTags(String[] tagStrings) {
+        return TagsUtils.parseTagsAsArray(tagStrings);
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyMulticastSubRouteTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyMulticastSubRouteTest.java
new file mode 100644
index 0000000..29e2055
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyMulticastSubRouteTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import java.util.SortedMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+
+public class MicroProfileMetricsRoutePolicyMulticastSubRouteTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMetricsRoutePolicy() throws Exception {
+        int count = 10;
+        getMockEndpoint("mock:foo").expectedMessageCount(count);
+        getMockEndpoint("mock:bar1").expectedMessageCount(count);
+        getMockEndpoint("mock:bar2").expectedMessageCount(count);
+
+        for (int i = 0; i < count; i++) {
+            template.sendBody("direct:multicast", null);
+        }
+
+        assertMockEndpointsSatisfied();
+
+        SortedMap<MetricID, Timer> timers = metricRegistry.getTimers();
+        assertEquals(3, timers.size());
+
+        timers.forEach((metricId, timer) -> {
+            assertEquals(count, timer.getCount());
+        });
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:foo").routeId("foo").to("mock:foo");
+
+                from("direct:bar").routeId("bar").multicast().to("mock:bar1", "mock:bar2");
+
+                from("direct:multicast").routeId("multicast").multicast().to("direct:foo", "direct:bar");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsRoutePolicyFactory factory = new MicroProfileMetricsRoutePolicyFactory();
+        factory.setMetricRegistry(metricRegistry);
+
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.addRoutePolicyFactory(factory);
+        return camelContext;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicySubRouteTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicySubRouteTest.java
new file mode 100644
index 0000000..56e06c2
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicySubRouteTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import java.util.SortedMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.eclipse.microprofile.metrics.MetricID;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+
+public class MicroProfileMetricsRoutePolicySubRouteTest extends MicroProfileMetricsTestSupport {
+
+    @Test
+    public void testMetricsRoutePolicy() throws Exception {
+        int count = 10;
+        getMockEndpoint("mock:foo").expectedMessageCount(count);
+        getMockEndpoint("mock:bar").expectedMessageCount(count);
+
+        for (int i = 0; i < count; i++) {
+            template.sendBody("direct:foo", null);
+        }
+
+        assertMockEndpointsSatisfied();
+
+        SortedMap<MetricID, Timer> timers = metricRegistry.getTimers();
+        assertEquals(2, timers.size());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:foo").routeId("foo")
+                    .to("direct:bar")
+                    .to("mock:foo");
+
+                from("direct:bar").routeId("bar")
+                    .to("mock:bar");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsRoutePolicyFactory factory = new MicroProfileMetricsRoutePolicyFactory();
+        factory.setMetricRegistry(metricRegistry);
+
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.addRoutePolicyFactory(factory);
+        return camelContext;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyTest.java b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyTest.java
new file mode 100644
index 0000000..f518613
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/java/org/apache/camel/component/microprofile/metrics/route/policy/MicroProfileMetricsRoutePolicyTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.camel.component.microprofile.metrics.route.policy;
+
+import java.util.Arrays;
+
+import io.smallrye.metrics.TagsUtils;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsHelper;
+import org.apache.camel.component.microprofile.metrics.MicroProfileMetricsTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.eclipse.microprofile.metrics.Snapshot;
+import org.eclipse.microprofile.metrics.Tag;
+import org.eclipse.microprofile.metrics.Timer;
+import org.junit.Test;
+import static org.apache.camel.component.microprofile.metrics.MicroProfileMetricsConstants.DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME;
+
+public class MicroProfileMetricsRoutePolicyTest extends MicroProfileMetricsTestSupport {
+
+    private static final long DELAY_FOO = 20;
+    private static final long DELAY_BAR = 50;
+
+    @Test
+    public void testMetricsRoutePolicy() throws Exception {
+        int count = 10;
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedMessageCount(count);
+
+        for (int i = 0; i < count; i++) {
+            if (i % 2 == 0) {
+                template.sendBody("direct:foo", "Hello " + i);
+            } else {
+                template.sendBody("direct:bar", "Hello " + i);
+            }
+        }
+
+        assertMockEndpointsSatisfied();
+
+        Timer fooTimer = getTimer(DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME);
+        assertEquals(count / 2, fooTimer.getCount());
+
+        Snapshot fooSnapshot = fooTimer.getSnapshot();
+        assertTrue(fooSnapshot.getMean() > DELAY_FOO);
+        assertTrue(fooSnapshot.getMax() > DELAY_FOO);
+
+        String contextTag = "camelContext=" + context.getName();
+        String[] tagStrings = new String[] {contextTag, "failed=false", "routeId=foo", "serviceName=MicroProfileMetricsRoutePolicyService"};
+        Tag[] tags = TagsUtils.parseTagsAsArray(tagStrings);
+
+        Timer barTimer = MicroProfileMetricsHelper.findMetric(metricRegistry, DEFAULT_CAMEL_ROUTE_POLICY_METRIC_NAME, Timer.class, Arrays.asList(tags));
+        assertEquals(count / 2, barTimer.getCount());
+
+        Snapshot barSnapshot = fooTimer.getSnapshot();
+        assertTrue(barSnapshot.getMean() > DELAY_FOO);
+        assertTrue(barSnapshot.getMax() > DELAY_FOO);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:foo").routeId("foo").delay(DELAY_FOO).to("mock:result");
+
+                from("direct:bar").routeId("bar").delay(DELAY_BAR).to("mock:result");
+            }
+        };
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        MicroProfileMetricsRoutePolicyFactory factory = new MicroProfileMetricsRoutePolicyFactory();
+        factory.setMetricRegistry(metricRegistry);
+
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.addRoutePolicyFactory(factory);
+        return camelContext;
+    }
+}
diff --git a/components/camel-microprofile-metrics/src/test/resources/log4j2.properties b/components/camel-microprofile-metrics/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..ebe74d0
--- /dev/null
+++ b/components/camel-microprofile-metrics/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-microprofile-metrics-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/components/pom.xml b/components/pom.xml
index afc33ce..2e0b609 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -236,6 +236,7 @@
         <module>camel-metrics</module>
         <module>camel-micrometer</module>
         <module>camel-microprofile-config</module>
+        <module>camel-microprofile-metrics</module>
         <module>camel-milo</module>
         <module>camel-mina</module>
         <module>camel-mllp</module>
diff --git a/components/readme.adoc b/components/readme.adoc
index 1843c35..e63f45b 100644
--- a/components/readme.adoc
+++ b/components/readme.adoc
@@ -1,7 +1,7 @@
 = Components
 
 // components: START
-Number of Components: 296 in 234 JAR artifacts (0 deprecated)
+Number of Components: 297 in 235 JAR artifacts (0 deprecated)
 
 [width="100%",cols="4,1,5",options="header"]
 |===
@@ -565,6 +565,9 @@ Number of Components: 296 in 234 JAR artifacts (0 deprecated)
 | link:camel-micrometer/src/main/docs/micrometer-component.adoc[Micrometer] (camel-micrometer) +
 `micrometer:metricsType:metricsName` | 2.22 | To collect various metrics directly from Camel routes using the Micrometer library.
 
+| link:camel-microprofile-metrics/src/main/docs/microprofile-metrics-component.adoc[MicroProfile Metrics] (camel-microprofile-metrics) +
+`microprofile-metrics:metricsType:metricsName` | 3.0 | Camel metrics exposed with Eclipse MicroProfile Metrics
+
 | link:camel-mina/src/main/docs/mina-component.adoc[Mina] (camel-mina) +
 `mina:protocol:host:port` | 2.10 | Socket level networking using TCP or UDP with the Apache Mina 2.x library.
 
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/MicroProfileMetricsEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/MicroProfileMetricsEndpointBuilderFactory.java
new file mode 100644
index 0000000..2040466
--- /dev/null
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/MicroProfileMetricsEndpointBuilderFactory.java
@@ -0,0 +1,300 @@
+/*
+ * 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.camel.builder.endpoint.dsl;
+
+import javax.annotation.Generated;
+import org.apache.camel.builder.EndpointConsumerBuilder;
+import org.apache.camel.builder.EndpointProducerBuilder;
+import org.apache.camel.builder.endpoint.AbstractEndpointBuilder;
+
+/**
+ * Camel metrics exposed with Eclipse MicroProfile Metrics
+ * 
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.EndpointDslMojo")
+public interface MicroProfileMetricsEndpointBuilderFactory {
+
+
+    /**
+     * Builder for endpoint for the MicroProfile Metrics component.
+     */
+    public interface MicroProfileMetricsEndpointBuilder
+            extends
+                EndpointProducerBuilder {
+        default AdvancedMicroProfileMetricsEndpointBuilder advanced() {
+            return (AdvancedMicroProfileMetricsEndpointBuilder) this;
+        }
+        /**
+         * The action to use when using the Timer metric type.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder action(String action) {
+            setProperty("action", action);
+            return this;
+        }
+        /**
+         * The amount to increment to use when using the Counter metric type.
+         * 
+         * The option is a: <code>java.lang.Long</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder counterIncrement(
+                Long counterIncrement) {
+            setProperty("counterIncrement", counterIncrement);
+            return this;
+        }
+        /**
+         * The amount to increment to use when using the Counter metric type.
+         * 
+         * The option will be converted to a <code>java.lang.Long</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder counterIncrement(
+                String counterIncrement) {
+            setProperty("counterIncrement", counterIncrement);
+            return this;
+        }
+        /**
+         * Sets a description within the metric metadata.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder description(
+                String description) {
+            setProperty("description", description);
+            return this;
+        }
+        /**
+         * Sets a display name within the metric metadata.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder displayName(
+                String displayName) {
+            setProperty("displayName", displayName);
+            return this;
+        }
+        /**
+         * Decrements a counter when using the ConcurrentGauge metric type.
+         * 
+         * The option is a: <code>java.lang.Boolean</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder gaugeDecrement(
+                Boolean gaugeDecrement) {
+            setProperty("gaugeDecrement", gaugeDecrement);
+            return this;
+        }
+        /**
+         * Decrements a counter when using the ConcurrentGauge metric type.
+         * 
+         * The option will be converted to a <code>java.lang.Boolean</code>
+         * type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder gaugeDecrement(
+                String gaugeDecrement) {
+            setProperty("gaugeDecrement", gaugeDecrement);
+            return this;
+        }
+        /**
+         * Increments a counter when using the ConcurrentGauge metric type.
+         * 
+         * The option is a: <code>java.lang.Boolean</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder gaugeIncrement(
+                Boolean gaugeIncrement) {
+            setProperty("gaugeIncrement", gaugeIncrement);
+            return this;
+        }
+        /**
+         * Increments a counter when using the ConcurrentGauge metric type.
+         * 
+         * The option will be converted to a <code>java.lang.Boolean</code>
+         * type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder gaugeIncrement(
+                String gaugeIncrement) {
+            setProperty("gaugeIncrement", gaugeIncrement);
+            return this;
+        }
+        /**
+         * The mark value to set when using the Meter metric type.
+         * 
+         * The option is a: <code>java.lang.Long</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder mark(Long mark) {
+            setProperty("mark", mark);
+            return this;
+        }
+        /**
+         * The mark value to set when using the Meter metric type.
+         * 
+         * The option will be converted to a <code>java.lang.Long</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder mark(String mark) {
+            setProperty("mark", mark);
+            return this;
+        }
+        /**
+         * Sets a metric unit within the metric metadata.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder metricUnit(String metricUnit) {
+            setProperty("metricUnit", metricUnit);
+            return this;
+        }
+        /**
+         * The value to set when using the Histogram metric type.
+         * 
+         * The option is a: <code>java.lang.Long</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder value(Long value) {
+            setProperty("value", value);
+            return this;
+        }
+        /**
+         * The value to set when using the Histogram metric type.
+         * 
+         * The option will be converted to a <code>java.lang.Long</code> type.
+         * 
+         * Group: producer
+         */
+        default MicroProfileMetricsEndpointBuilder value(String value) {
+            setProperty("value", value);
+            return this;
+        }
+    }
+
+    /**
+     * Advanced builder for endpoint for the MicroProfile Metrics component.
+     */
+    public interface AdvancedMicroProfileMetricsEndpointBuilder
+            extends
+                EndpointProducerBuilder {
+        default MicroProfileMetricsEndpointBuilder basic() {
+            return (MicroProfileMetricsEndpointBuilder) this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedMicroProfileMetricsEndpointBuilder basicPropertyBinding(
+                boolean basicPropertyBinding) {
+            setProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Whether the endpoint should use basic property binding (Camel 2.x) or
+         * the newer property binding with additional capabilities.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedMicroProfileMetricsEndpointBuilder basicPropertyBinding(
+                String basicPropertyBinding) {
+            setProperty("basicPropertyBinding", basicPropertyBinding);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedMicroProfileMetricsEndpointBuilder synchronous(
+                boolean synchronous) {
+            setProperty("synchronous", synchronous);
+            return this;
+        }
+        /**
+         * Sets whether synchronous processing should be strictly used, or Camel
+         * is allowed to use asynchronous processing (if supported).
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Group: advanced
+         */
+        default AdvancedMicroProfileMetricsEndpointBuilder synchronous(
+                String synchronous) {
+            setProperty("synchronous", synchronous);
+            return this;
+        }
+    }
+    /**
+     * MicroProfile Metrics (camel-microprofile-metrics)
+     * Camel metrics exposed with Eclipse MicroProfile Metrics
+     * 
+     * Category: monitoring
+     * Available as of version: 3.0
+     * Maven coordinates: org.apache.camel:camel-microprofile-metrics
+     * 
+     * Syntax: <code>microprofile-metrics:metricsType:metricsName</code>
+     * 
+     * Path parameter: metricType (required)
+     * Metric type
+     * The value can be one of: CONCURRENT_GAUGE, COUNTER, GAUGE, METERED,
+     * HISTOGRAM, TIMER, INVALID
+     * 
+     * Path parameter: metricName (required)
+     * Metric name
+     * 
+     * Path parameter: tags
+     * Comma delimited list of tags associated with the metric in the format
+     * tagName=tagValue
+     */
+    default MicroProfileMetricsEndpointBuilder microProfileMetrics(String path) {
+        class MicroProfileMetricsEndpointBuilderImpl extends AbstractEndpointBuilder implements MicroProfileMetricsEndpointBuilder, AdvancedMicroProfileMetricsEndpointBuilder {
+            public MicroProfileMetricsEndpointBuilderImpl(String path) {
+                super("microprofile-metrics", path);
+            }
+        }
+        return new MicroProfileMetricsEndpointBuilderImpl(path);
+    }
+}
\ No newline at end of file
diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc
index b9a07cc..cb8ba7f 100644
--- a/docs/components/modules/ROOT/nav.adoc
+++ b/docs/components/modules/ROOT/nav.adoc
@@ -232,6 +232,7 @@
 * xref:metrics-component.adoc[Metrics Component]
 * xref:micrometer-component.adoc[Micrometer Component]
 * xref:microprofile-config.adoc[MicroProfile Config Component]
+* xref:microprofile-metrics-component.adoc[MicroProfile Metrics Component]
 * xref:milo-client-component.adoc[OPC UA Client Component]
 * xref:milo-server-component.adoc[OPC UA Server Component]
 * xref:mina-component.adoc[Mina Component]
diff --git a/docs/components/modules/ROOT/pages/microprofile-metrics-component.adoc b/docs/components/modules/ROOT/pages/microprofile-metrics-component.adoc
new file mode 100644
index 0000000..d03cb35
--- /dev/null
+++ b/docs/components/modules/ROOT/pages/microprofile-metrics-component.adoc
@@ -0,0 +1,413 @@
+[[microprofile-metrics-component]]
+= MicroProfile Metrics Component
+
+*Available as of Camel version 3.0*
+
+The MircoProfile Metrics component provides the capability to expose metrics from Camel routes.
+
+Maven users need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-microprofile-metrics</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+----
+
+It is expected that the component is running in a MicroProfile environment that provides an appropriate implementation of MicroProfile Metrics 2.0. E.g https://github.com/smallrye/smallrye-metrics[SmallRye Metrics].
+
+== URI format
+
+[source]
+----
+microprofile-metrics:[ concurrent gauge | counter | gauge | histogram | meter | timer ]:metricname[?options]
+----
+
+== Options
+// component options: START
+The MicroProfile Metrics component supports 2 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *metricRegistry* (advanced) | Use a custom MetricRegistry. |  | MetricRegistry
+| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+|===
+// component options: END
+
+// endpoint options: START
+The MicroProfile Metrics endpoint is configured using URI syntax:
+
+----
+microprofile-metrics:metricsType:metricsName
+----
+
+with the following path and query parameters:
+
+=== Path Parameters (3 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *metricType* | *Required* Metric type |  | MetricType
+| *metricName* | *Required* Metric name |  | String
+| *tags* | Comma delimited list of tags associated with the metric in the format tagName=tagValue |  | List
+|===
+
+
+=== Query Parameters (12 parameters):
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *action* (producer) | The action to use when using the Timer metric type |  | String
+| *counterIncrement* (producer) | The amount to increment to use when using the Counter metric type |  | Long
+| *description* (producer) | Sets a description within the metric metadata |  | String
+| *displayName* (producer) | Sets a display name within the metric metadata |  | String
+| *gaugeDecrement* (producer) | Decrements a counter when using the ConcurrentGauge metric type |  | Boolean
+| *gaugeIncrement* (producer) | Increments a counter when using the ConcurrentGauge metric type |  | Boolean
+| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *mark* (producer) | The mark value to set when using the Meter metric type |  | Long
+| *metricUnit* (producer) | Sets a metric unit within the metric metadata |  | String
+| *value* (producer) | The value to set when using the Histogram metric type |  | Long
+| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
+| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+|===
+// endpoint options: END
+
+== MetricRegistry Configuration
+
+Configure a `MetricRegistry` to use either by passing it to the MicroProfileMetricsComponent.
+
+[source,java]
+----
+MicroProfileMetricsComponent component = new MicroProfileMetricsComponent();
+component.setRegistry(myMetricRegistryImpl);
+----
+
+Or by binding it to the Camel registry using the binding name 'metricRegistry' (See `MicroProfileMetricsConstants.METRIC_REGISTRY_NAME`).
+
+
+== [[MicroProfileMetrics-counter]]Counter
+
+[source]
+----
+microprofile-metrics:counter:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|counterIncrement  |- |Value to add to the counter
+|=====================================================
+
+If `counterIncrement` is not defined then counter value will be incremented by one.
+
+[source,java]
+----
+// Increment counter simple.counter by 7
+from("direct:in")
+    .to("microprofile-metrics:counter:simple.counter?counterIncrement=7")
+    .to("direct:out");
+----
+
+[source,java]
+----
+// Increment counter simple.counter by 1
+from("direct:in")
+    .to("microprofile-metrics:counter:simple.counter")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`counterIncrement` values specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsCounterIncrement  |Override increment value from the URI |Long
+|====================================================================
+
+[source,java]
+----
+// Increment counter simple.counter by 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_COUNTER_INCREMENT, constant(417))
+    .to("microprofile-metrics:counter:simple.counter?increment=7")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-concurrentGauge]]Concurrent Gauge
+
+[source]
+----
+microprofile-metrics:concurrent gauge:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|gaugeIncrement  |false |Value to add to the counter
+|gaugeDecrement  |false |Value to add to the counter
+|=====================================================
+
+If neither `gaugeIncrement` or `gaugeDecrement` are defined then no action is performed on the gauge.
+
+[source,java]
+----
+// Increment concurrent gauge simple.gauge by 1
+from("direct:in")
+    .to("microprofile-metrics:concurrent gauge:simple.gauge?gaugeIncrement=true")
+    .to("direct:out");
+----
+
+[source,java]
+----
+// Decrement concurrent gauge simple.gauge by 1
+from("direct:in")
+    .to("microprofile-metrics:concurrent gauge:simple.gauge?gaugeDecrement=true")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`gaugeIncrement` and `gaugeDecrement` values specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsGaugeIncrement  |Override gaugeIncrement value from the URI |Boolean
+|CamelMicroProfileMetricsGaugeDecrement  |Override gaugeDecrement value from the URI |Boolean
+|====================================================================
+
+[source,java]
+----
+// Increment concurrent gauge simple.gauge by 1
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_GAUGE_INCREMENT, constant(true))
+    .to("microprofile-metrics:concurrent gauge:simple.gauge")
+    .to("direct:out");
+----
+
+----
+// Decrement concurrent gauge simple.gauge by 1
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_GAUGE_DECREMENT, constant(true))
+    .to("microprofile-metrics:concurrent gauge:simple.gauge")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-histogram]]Histogram
+
+[source]
+----
+microprofile-metrics:histogram:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|value  |- |Value to set on the histogram
+|=====================================================
+
+If `value` is not defined then histogram value will not be changed.
+
+[source,java]
+----
+// Set histogram simple.histogram to 7
+from("direct:in")
+    .to("microprofile-metrics:histogram:simple.histogram?value=7")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`value` specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsHistogramValue  |Override histogram value from the URI |Long
+|====================================================================
+
+[source,java]
+----
+// Set histogram simple.histogram to 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_HISTOGRAM_VALUE, constant(417))
+    .to("microprofile-metrics:histogram:simple.histogram?value=7")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-meter]]Meter
+
+[source]
+----
+microprofile-metrics:meter:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|mark  |- |Mark value to set on the meter
+|=====================================================
+
+If `mark` is not defined then the meter will be marked with the value '1'.
+
+[source,java]
+----
+// Mark the meter simple.meter with 7
+from("direct:in")
+    .to("microprofile-metrics:meter:simple.meter?mark=7")
+    .to("direct:out");
+----
+
+[source,java]
+----
+// Mark the meter simple.meter with 1
+from("direct:in")
+    .to("microprofile-metrics:meter:simple.meter")
+    .to("direct:out");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`value` specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsMeterMark  |Override meter mark value from the URI |Long
+|====================================================================
+
+[source,java]
+----
+// Mark the meter simple.meter with 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_METER_MARK, constant(417))
+    .to("microprofile-metrics:meter:simple.meter?value=7")
+    .to("direct:out");
+----
+
+== [[MicroProfileMetrics-Timer]]Timer
+
+[source]
+----
+microprofile-metrics:timer:name[?options]
+----
+
+=== Options
+
+[width="100%",options="header"]
+|=====================================================
+|Name |Default |Description
+|action  |- |start or stop
+|=====================================================
+
+If no `action` is specified or it's an invalid value, then no timer update occurs.
+
+If the `start` action is called on an already running timer or `stop` is called on an unknown timer, then
+no timer(s) are updated.
+
+[source,java]
+----
+// Measure time spent in route `direct:calculate`
+from("direct:in")
+    .to("microprofile-metrics:timer:simple.timer?action=start")
+    .to("direct:calculate")
+    .to("microprofile-metrics:timer:simple.timer?action=stop");
+----
+
+=== Headers
+
+Message headers can be used to override the
+`action` specified on the `microprofile-metrics` endpoint URI.
+
+[width="100%",cols="10%,80%,10%",options="header",]
+|====================================================================
+|Name |Description |Expected type
+|CamelMicroProfileMetricsTimerAction  |Override time action from the URI |org.apache.camel.component.microprofile.metrics.TimerAction
+|====================================================================
+
+[source,java]
+----
+// Mark the meter simple.meter with 417
+from("direct:in")
+    .setHeader(MicroProfileMetricsConstants.HEADER_TIMER_ACTION, TimerAction.START)
+    .to("microprofile-metrics:timer:simple.timer")
+    .to("direct:out");
+----
+
+
+== MicroProfileMetricsRoutePolicyFactory
+
+This factory allows to add a RoutePolicy for each
+route and exposes route utilization statistics using MicroProfile metrics.
+
+NOTE: Instead of using the MicroProfileMetricsRoutePolicyFactory you can define a
+MicroProfileMetricsRoutePolicy per route you want to instrument, in case you only
+want to instrument a few selected routes.
+
+Add the factory to the `CamelContext` as shown below:
+
+[source,java]
+----
+context.addRoutePolicyFactory(new MicroProfileMetricsRoutePolicyFactory());
+----
+
+
+== MicroProfileMetricsMessageHistoryFactory
+
+This factory captures message history performance statistics while routing messages.
+
+Add the factory to the `CamelContext` as shown below:
+
+[source,java]
+----
+context.setMessageHistoryFactory(new MicroProfileMetricsMessageHistoryFactory());
+----
+
+
+== MicroProfileMetricsExchangeEventNotifier
+
+The exchange event notifer times exchanges from creation through to completion.
+
+EventNotifiers can be added to the `CamelContext`, e.g.:
+
+[source,java]
+----
+camelContext.getManagementStrategy().addEventNotifier(new MicroProfileMetricsExchangeEventNotifier())
+----
+
+
+== MicroProfileMetricsRouteEventNotifier
+
+The route event notifer counts added and running routes within the `CamelContext`.
+
+EventNotifiers can be added to the `CamelContext`, e.g.:
+
+[source,java]
+----
+camelContext.getManagementStrategy().addEventNotifier(new MicroProfileMetricsRouteEventNotifier())
+----
diff --git a/parent/pom.xml b/parent/pom.xml
index 159f418..169718c 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -451,6 +451,7 @@
         <maven-war-plugin-version>3.2.3</maven-war-plugin-version>
         <metrics-version>3.2.6</metrics-version>
         <micrometer-version>1.2.0</micrometer-version>
+        <microprofile-metrics-version>2.0.0</microprofile-metrics-version>
         <milo-version>0.2.5</milo-version>
         <mimepull-version>1.9.11</mimepull-version>
         <mina-version>2.0.21</mina-version>
@@ -567,6 +568,8 @@
         <slf4j-api-version>1.7.28</slf4j-api-version>
         <slf4j-version>1.7.28</slf4j-version>
         <smack-version>4.3.4</smack-version>
+        <smallrye-config-version>1.0.0</smallrye-config-version>
+        <smallrye-metrics-version>1.1.0</smallrye-metrics-version>
         <snakeyaml-version>1.25</snakeyaml-version>
         <snappy-version>1.1.4</snappy-version>
         <snmp4j-version>2.6.3_1</snmp4j-version>
@@ -1704,6 +1707,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-microprofile-metrics</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-milo</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
index 459033c..7d6a961 100644
--- a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
+++ b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
@@ -2120,6 +2120,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-microprofile-metrics</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-milo</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootStarterMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootStarterMojo.java
index dfb1d59..d597b78 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootStarterMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootStarterMojo.java
@@ -77,7 +77,8 @@ public class SpringBootStarterMojo extends AbstractMojo {
         /* OSGi -> */ "camel-blueprint", "camel-core-osgi", "camel-eventadmin", "camel-paxlogging",
         /* extended core */ "camel-attachments",
         /* Java EE -> */ "camel-cdi",
-        /* Microprofile -> */ "camel-microprofile-config",
+        /* MicroProfile -> */ "camel-microprofile-config",
+        /* MicroProfile -> */ "camel-microprofile-metrics",
         /* deprecated (and not working perfectly) -> */ "camel-swagger", "camel-ibatis",
         /* currently incompatible */ "camel-spark-rest",
         /* others (not managed) -> */ "camel-core-xml"};