You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2020/09/01 21:27:12 UTC

[qpid-broker-j] branch master updated (6d75b73 -> 2c071a3)

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

orudyy pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git.


    from 6d75b73  QPID-8368: [Broker-J] Update GraylogLogger section in broker documentation
     new e979480  QPID-8454:[Broker-J] Add Prometheus integration
     new 2c071a3  QPID-8454:[Broker-J] Update documentation

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../dependency-verification/DEPENDENCIES_REFERENCE |   6 +
 .../java/org/apache/qpid/server/model/Broker.java  |  80 +++--
 .../qpid/server/model/BrokerAttributeInjector.java |  20 +-
 .../org/apache/qpid/server/model/BrokerLogger.java |   4 +-
 .../model/ConfiguredObjectInjectedStatistic.java   |  20 +-
 .../model/ConfiguredObjectMethodStatistic.java     |  12 +
 .../server/model/ConfiguredObjectStatistic.java    |   4 +
 .../org/apache/qpid/server/model/Connection.java   |  14 +-
 .../org/apache/qpid/server/model/Consumer.java     |   4 +-
 .../org/apache/qpid/server/model/Exchange.java     |  10 +-
 .../apache/qpid/server/model/ManagedStatistic.java |   2 +
 .../java/org/apache/qpid/server/model/Queue.java   |  36 +--
 .../java/org/apache/qpid/server/model/Session.java |   2 +-
 .../qpid/server/model/VirtualHostLogger.java       |   4 +-
 .../apache/qpid/server/model/port/AmqpPort.java    |  12 +-
 ...ObjectRegistration.java => ContentFactory.java} |   9 +-
 .../virtualhost/QueueManagingVirtualHost.java      |  28 +-
 .../hierarchy/InjectedAttributeTest.java           |  16 +-
 .../testmodels/hierarchy/TestAbstractCarImpl.java  |  21 ++
 .../hierarchy/TestAbstractEngineImpl.java          |   7 +
 .../hierarchy/TestAbstractInstrumentPanelImpl.java |   2 +
 .../hierarchy/TestAbstractSensorImpl.java          |   9 +
 .../server/model/testmodels/hierarchy/TestCar.java |  14 +
 .../model/testmodels/hierarchy/TestEngine.java     |   6 +
 .../model/testmodels/hierarchy/TestSensor.java     |   5 +
 .../hierarchy/TestTemperatureSensorImpl.java       |   9 +
 broker-plugins/management-http/pom.xml             |   5 +
 .../server/management/plugin/HttpManagement.java   |  19 ++
 .../plugin/HttpManagementConfiguration.java        |   5 +
 .../management/plugin/servlet/ContentServlet.java  |  95 ++++++
 .../plugin/servlet/rest/AbstractServlet.java       |  21 +-
 .../pom.xml                                        |  40 +--
 .../IncludeDisabledStatisticPredicate.java         |  27 +-
 .../server/prometheus/IncludeMetricPredicate.java  |  31 +-
 .../prometheus/PrometheusContentFactory.java       | 105 ++++++
 .../qpid/server/prometheus/QpidCollector.java      | 257 +++++++++++++++
 .../prometheus/PrometheusContentFactoryTest.java   | 176 ++++++++++
 .../qpid/server/prometheus/QpidCollectorTest.java  | 359 +++++++++++++++++++++
 .../src/docbkx/Java-Broker-Management-Channels.xml |   1 +
 .../channels/Java-Broker-Management-Metrics.xml    |  49 +++
 pom.xml                                            |  19 ++
 .../BrokerMetricsAuthenticationTest.java}          |  32 +-
 .../qpid/tests/http/metrics/BrokerMetricsTest.java |  80 +++++
 .../qpid/tests/http/metrics/TestMetricsHelper.java |  93 ++++++
 .../tests/http/metrics/VirtualHostMetricsTest.java |  20 +-
 45 files changed, 1605 insertions(+), 185 deletions(-)
 copy broker-core/src/main/java/org/apache/qpid/server/plugin/{ConfiguredObjectRegistration.java => ContentFactory.java} (81%)
 create mode 100644 broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java
 copy broker-plugins/{amqp-1-0-jdbc-store => prometheus-exporter}/pom.xml (68%)
 copy broker-core/src/test/java/org/apache/qpid/server/store/MessageCounter.java => broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java (62%)
 copy broker-core/src/test/java/org/apache/qpid/server/store/MessageCounter.java => broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java (63%)
 create mode 100644 broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java
 create mode 100644 broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java
 create mode 100644 broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java
 create mode 100644 broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java
 create mode 100644 doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
 copy systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/{v7_0/LegacyManagementTest.java => metrics/BrokerMetricsAuthenticationTest.java} (55%)
 create mode 100644 systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
 create mode 100644 systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java
 copy broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementUtilTest.java => systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java (57%)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 02/02: QPID-8454:[Broker-J] Update documentation

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 2c071a3ee3ebd43b8655f9e42f8c986dd15ea68c
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Tue Sep 1 21:54:50 2020 +0100

    QPID-8454:[Broker-J] Update documentation
---
 .../src/docbkx/management/channels/Java-Broker-Management-Metrics.xml  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
index c8aeb9d..a75ec05 100644
--- a/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
+++ b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
@@ -37,7 +37,8 @@
 
     <para>The Broker JVM statistics are disabled by default. The metrics endpoints can be called with parameter
       <literal>includeDisabled</literal> set to <literal>true</literal> to include JVM  broker metrics into endpoint
-      output.
+      output. If required, the JVM metrics could be enabled by setting context variable
+      <literal>qpid.metrics.includeDisabled</literal> to <literal>true</literal>.
     </para>
     <note>
       <para>For more information about Prometheus, check out the


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 01/02: QPID-8454:[Broker-J] Add Prometheus integration

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit e9794802df6ee22bd3b9dc55faffc26d74459c71
Author: Dedeepya T <de...@yahoo.co.in>
AuthorDate: Tue Aug 25 15:11:50 2020 +0100

    QPID-8454:[Broker-J] Add Prometheus integration
    
    This closes #56
---
 .../dependency-verification/DEPENDENCIES_REFERENCE |   6 +
 .../java/org/apache/qpid/server/model/Broker.java  |  80 +++--
 .../qpid/server/model/BrokerAttributeInjector.java |  20 +-
 .../org/apache/qpid/server/model/BrokerLogger.java |   4 +-
 .../model/ConfiguredObjectInjectedStatistic.java   |  20 +-
 .../model/ConfiguredObjectMethodStatistic.java     |  12 +
 .../server/model/ConfiguredObjectStatistic.java    |   4 +
 .../org/apache/qpid/server/model/Connection.java   |  14 +-
 .../org/apache/qpid/server/model/Consumer.java     |   4 +-
 .../org/apache/qpid/server/model/Exchange.java     |  10 +-
 .../apache/qpid/server/model/ManagedStatistic.java |   2 +
 .../java/org/apache/qpid/server/model/Queue.java   |  36 +--
 .../java/org/apache/qpid/server/model/Session.java |   2 +-
 .../qpid/server/model/VirtualHostLogger.java       |   4 +-
 .../apache/qpid/server/model/port/AmqpPort.java    |  12 +-
 .../apache/qpid/server/plugin/ContentFactory.java} |  13 +-
 .../virtualhost/QueueManagingVirtualHost.java      |  28 +-
 .../hierarchy/InjectedAttributeTest.java           |  16 +-
 .../testmodels/hierarchy/TestAbstractCarImpl.java  |  21 ++
 .../hierarchy/TestAbstractEngineImpl.java          |   7 +
 .../hierarchy/TestAbstractInstrumentPanelImpl.java |   2 +
 .../hierarchy/TestAbstractSensorImpl.java          |   9 +
 .../server/model/testmodels/hierarchy/TestCar.java |  14 +
 .../model/testmodels/hierarchy/TestEngine.java     |   6 +
 .../model/testmodels/hierarchy/TestSensor.java     |   5 +
 .../hierarchy/TestTemperatureSensorImpl.java       |   9 +
 broker-plugins/management-http/pom.xml             |   5 +
 .../server/management/plugin/HttpManagement.java   |  19 ++
 .../plugin/HttpManagementConfiguration.java        |   5 +
 .../management/plugin/servlet/ContentServlet.java  |  95 ++++++
 .../plugin/servlet/rest/AbstractServlet.java       |  21 +-
 broker-plugins/prometheus-exporter/pom.xml         |  70 ++++
 .../IncludeDisabledStatisticPredicate.java         |  26 +-
 .../server/prometheus/IncludeMetricPredicate.java  |  26 +-
 .../prometheus/PrometheusContentFactory.java       | 105 ++++++
 .../qpid/server/prometheus/QpidCollector.java      | 257 +++++++++++++++
 .../prometheus/PrometheusContentFactoryTest.java   | 176 ++++++++++
 .../qpid/server/prometheus/QpidCollectorTest.java  | 359 +++++++++++++++++++++
 .../src/docbkx/Java-Broker-Management-Channels.xml |   1 +
 .../channels/Java-Broker-Management-Metrics.xml    |  48 +++
 pom.xml                                            |  19 ++
 .../metrics/BrokerMetricsAuthenticationTest.java   |  52 +++
 .../qpid/tests/http/metrics/BrokerMetricsTest.java |  80 +++++
 .../qpid/tests/http/metrics/TestMetricsHelper.java |  93 ++++++
 .../tests/http/metrics/VirtualHostMetricsTest.java |  25 +-
 45 files changed, 1712 insertions(+), 130 deletions(-)

diff --git a/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE b/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
index e5cd01f..f3f789a 100644
--- a/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
+++ b/apache-qpid-broker-j/src/main/assembly/dependency-verification/DEPENDENCIES_REFERENCE
@@ -29,6 +29,10 @@ From: 'an unknown organization'
     License: The Apache Software License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
   - Guava: Google Core Libraries for Java (https://github.com/google/guava/guava) com.google.guava:guava:bundle:28.2-jre
     License: Apache License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
+  - Prometheus Java Simpleclient (http://github.com/prometheus/client_java/simpleclient) io.prometheus:simpleclient:bundle:0.9.0
+    License: The Apache Software License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
+  - Prometheus Java Simpleclient Common (http://github.com/prometheus/client_java/simpleclient_common) io.prometheus:simpleclient_common:bundle:0.9.0
+    License: The Apache Software License, Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0.txt)
   - dgrid (http://webjars.org) org.webjars.bower:dgrid:jar:1.2.1
     License: BSD 3-Clause  (https://spdx.org/licenses/BSD 3-Clause#licenseText)
   - dstore (http://webjars.org) org.webjars.bower:dstore:jar:1.1.2
@@ -113,6 +117,8 @@ From: 'The Apache Software Foundation' (https://www.apache.org/)
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
   - Apache Qpid Broker-J Memory Message Store Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-memory-store) org.apache.qpid:qpid-broker-plugins-memory-store:jar
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
+  - qpid-broker-plugins-prometheus-exporter (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-prometheus-exporter) org.apache.qpid:qpid-broker-plugins-prometheus-exporter:jar
+    License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
   - Apache Qpid Broker-J WebSocket Plug-in (http://qpid.apache.org/components/broker-plugins/qpid-broker-plugins-websocket) org.apache.qpid:qpid-broker-plugins-websocket:jar
     License: Apache License, Version 2.0  (https://www.apache.org/licenses/LICENSE-2.0.txt)
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java b/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
index 53bd58f..df8f783 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
@@ -197,36 +197,52 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
     String getModelVersion();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of all messages received by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.BYTES,
+            label = "Inbound",
+            description = "Total size of all messages received by the Broker.",
+            metricName = "inbound_bytes_count")
     long getBytesIn();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound",
-                      description = "Total size of all messages delivered by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.BYTES,
+            label = "Outbound",
+            description = "Total size of all messages delivered by the Broker.",
+            metricName = "outbound_bytes_count")
     long getBytesOut();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Total number of messages received by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
+            label = "Inbound",
+            description = "Total number of messages received by the Broker.",
+            metricName = "inbound_messages_count")
     long getMessagesIn();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound",
-                      description = "Total number of messages delivered by the Broker.")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
+            label = "Outbound",
+            description = "Total number of messages delivered by the Broker.",
+            metricName = "outbound_messages_count")
     long getMessagesOut();
 
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
             label = "Transacted Inbound",
-            description = "Total number of messages delivered by the Broker within a transaction.")
+            description = "Total number of messages delivered by the Broker within a transaction.",
+            metricName = "inbound_transacted_messages_count")
     long getTransactedMessagesIn();
 
     @SuppressWarnings("unused")
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.MESSAGES,
             label = "Transacted Outbound",
-            description = "Total number of messages received by the Broker within a transaction.")
+            description = "Total number of messages received by the Broker within a transaction.",
+            metricName = "outbound_transacted_messages_count")
     long getTransactedMessagesOut();
 
     @ManagedOperation(nonModifying = true,
@@ -257,37 +273,44 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.COUNT,
-                      label = "Live threads",
-                      description = "Number of live threads")
+            units = StatisticUnit.COUNT,
+            label = "Live threads",
+            description = "Number of live threads",
+            metricName = "live_threads_total",
+            metricDisabled = true)
     int getNumberOfLiveThreads();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.BYTES,
-                      label = "Used Heap Memory Size",
-                      description = "Size of used heap memory")
+            units = StatisticUnit.BYTES,
+            label = "Used Heap Memory Size",
+            description = "Size of used heap memory",
+            metricDisabled = true)
     long getUsedHeapMemorySize();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.BYTES,
-                      label = "Used Direct Memory Size",
-                      description = "Size of used direct memory")
+            units = StatisticUnit.BYTES,
+            label = "Used Direct Memory Size",
+            description = "Size of used direct memory",
+            metricDisabled = true)
     long getUsedDirectMemorySize();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.BYTES,
-                      label = "Direct Memory Total Capacity",
-                      description = "Total capacity of direct memory allocated for the Broker process")
+            units = StatisticUnit.BYTES,
+            label = "Direct Memory Total Capacity",
+            description = "Total capacity of direct memory allocated for the Broker process",
+            metricName = "direct_memory_capacity_bytes_total",
+            metricDisabled = true)
     long getDirectMemoryTotalCapacity();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
-                      units = StatisticUnit.COUNT,
-                      label = "Number Of Object Pending Finalization",
-                      description = "Number of objects pending finalization")
+            units = StatisticUnit.COUNT,
+            label = "Number Of Object Pending Finalization",
+            description = "Number of objects pending finalization",
+            metricDisabled = true)
     int getNumberOfObjectsPendingFinalization();
 
     @SuppressWarnings("unused")
@@ -308,7 +331,8 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
             units = StatisticUnit.BYTES,
             label = "Maximum recorded size of inbound messages",
-            description = "Maximum size of messages published into the Broker since start-up.")
+            description = "Maximum size of messages published into the Broker since start-up.",
+            metricName = "inbound_message_size_high_watermark")
     long getInboundMessageSizeHighWatermark();
 
     @ManagedOperation(nonModifying = true,
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
index dc4fa3a..f5e741b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
@@ -165,7 +165,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 _typeValidator,
                                                                 StatisticUnit.BYTES,
                                                                 StatisticType.POINT_IN_TIME,
-                                                                memoryPoolMXBean.getName() + " Memory Used");
+                                                                memoryPoolMXBean.getName() + " Memory Used",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
             }
             catch (NoSuchMethodException e)
@@ -193,7 +195,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.COUNT,
                                                                 StatisticType.CUMULATIVE,
                                                                 garbageCollectorMXBean.getName()
-                                                                + " GC Collection Time");
+                                                                + " GC Collection Time",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
             }
             catch (NoSuchMethodException e)
@@ -216,7 +220,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.COUNT,
                                                                 StatisticType.CUMULATIVE,
                                                                 garbageCollectorMXBean.getName()
-                                                                + " GC Collection Count");
+                                                                + " GC Collection Count",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
             }
             catch (NoSuchMethodException e)
@@ -261,7 +267,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.TIME_DURATION,
                                                                 StatisticType.CUMULATIVE,
                                                                 _operatingSystemMXBeanClass.getName()
-                                                                + " Process CPU Time");
+                                                                + " Process CPU Time",
+                                                                "process_cpu_time_nanoseconds",
+                                                                true);
                 statistics.add(injectedStatistic);
 
             }
@@ -306,7 +314,9 @@ public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjecto
                                                                 StatisticUnit.COUNT,
                                                                 StatisticType.POINT_IN_TIME,
                                                                 _operatingSystemMXBean.getName()
-                                                                + " Process CPU Load");
+                                                                + " Process CPU Load",
+                                                                null,
+                                                                true);
                 statistics.add(injectedStatistic);
 
             }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
index 07e61cd..8c4ad5b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
@@ -28,9 +28,9 @@ public interface BrokerLogger<X extends BrokerLogger<X>> extends ConfiguredObjec
 
     void stopLogging();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors", metricName = "errors_count")
     long getErrorCount();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings", metricName = "warnings_count")
     long getWarnCount();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java
index 95c8507..f1d9c6b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectInjectedStatistic.java
@@ -41,6 +41,8 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
     private final StatisticType _type;
     private final String _label;
     private final Object[] _staticParams;
+    private final String _metricName;
+    private final boolean _metricDisabled;
 
     public ConfiguredObjectInjectedStatistic(final String name,
                                              final Method method,
@@ -49,7 +51,9 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
                                              final TypeValidator typeValidator,
                                              final StatisticUnit units,
                                              final StatisticType type,
-                                             final String label)
+                                             final String label,
+                                             final String metricName,
+                                             final boolean metricDisabled)
     {
         super(name,
               (Class<T>) AttributeValueConverter.getTypeFromMethod(method), method.getGenericReturnType(), typeValidator);
@@ -57,6 +61,8 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
         _type = type;
         _label = label;
         _staticParams = staticParams == null ? new Object[0] : staticParams;
+        _metricName = metricName;
+        _metricDisabled = metricDisabled;
         if(!(method.getParameterTypes().length == 1 + _staticParams.length
              && ConfiguredObject.class.isAssignableFrom(method.getParameterTypes()[0])
              && Modifier.isStatic(method.getModifiers())
@@ -147,4 +153,16 @@ final public class ConfiguredObjectInjectedStatistic<C extends ConfiguredObject,
         }
 
     }
+
+    @Override
+    public String getMetricName()
+    {
+        return _metricName;
+    }
+
+    @Override
+    public boolean isMetricDisabled()
+    {
+        return _metricDisabled;
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java
index 2cc2fe9..528d80e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectMethodStatistic.java
@@ -66,4 +66,16 @@ public final class ConfiguredObjectMethodStatistic<C extends ConfiguredObject, T
     {
         return _annotation.label();
     }
+
+    @Override
+    public String getMetricName()
+    {
+        return _annotation.metricName();
+    }
+
+    @Override
+    public boolean isMetricDisabled()
+    {
+        return _annotation.metricDisabled();
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
index cc22d62..4585b42 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
@@ -29,4 +29,8 @@ public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends
     StatisticType getStatisticType();
 
     String getLabel();
+
+    String getMetricName();
+
+    boolean isMetricDisabled();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java b/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java
index 62cefc1..0638e53 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java
@@ -117,24 +117,24 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X>
     // See also QPID-7689: https://issues.apache.org/jira/browse/QPID-7689?focusedCommentId=16022923#comment-16022923
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of all messages received by this connection.")
+                      description = "Total size of all messages received by this connection.", metricName = "inbound_bytes_count")
     long getBytesIn();
 
     // currently this reports outbound message content size without header.
     // See also QPID-7689: https://issues.apache.org/jira/browse/QPID-7689?focusedCommentId=16022923#comment-16022923
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound",
-                      description = "Total size of all messages delivered by this connection.")
+                      description = "Total size of all messages delivered by this connection.", metricName = "outbound_bytes_count")
     long getBytesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Total number of messages delivered by this connection.")
+                      description = "Total number of messages delivered by this connection.", metricName = "inbound_messages_count")
     long getMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound",
-                      description = "Total number of messages received by this connection.")
+                      description = "Total number of messages received by this connection.", metricName = "outbound_messages_count")
     long getMessagesOut();
 
     @SuppressWarnings("unused")
@@ -162,7 +162,7 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X>
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Sessions",
-                      description = "Current number of sessions belonging to this connection.")
+                      description = "Current number of sessions belonging to this connection.", metricName = "sessions_total")
     int getSessionCount();
 
     @SuppressWarnings("unused")
@@ -188,12 +188,12 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X>
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Transacted Inbound",
-            description = "Total number of messages delivered by this connection within a transaction.")
+            description = "Total number of messages delivered by this connection within a transaction.", metricName = "transacted_inbound_messages_count")
     long getTransactedMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Transacted Outbound",
-            description = "Total number of messages received by this connection within a transaction.")
+            description = "Total number of messages received by this connection within a transaction.", metricName = "transacted_outbound_messages_count")
     long getTransactedMessagesOut();
 
     //children
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java b/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
index d516f51..033f263 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
@@ -69,10 +69,10 @@ public interface Consumer<X extends Consumer<X,T>, T extends ConsumerTarget> ext
                         + "consumers.  Priority 2147483647 is the highest priority.")
     int getPriority();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound", metricName = "outbound_bytes_count")
     long getBytesOut();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound", metricName = "outbound_messages_count")
     long getMessagesOut();
 
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Prefetch")
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java b/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java
index 800f57c..5e2d68f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Exchange.java
@@ -88,27 +88,27 @@ public interface Exchange<X extends Exchange<X>> extends ConfiguredObject<X>, Me
     // Statistics
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Bindings",
-                      description = "Current number of bindings to this exchange.")
+                      description = "Current number of bindings to this exchange.", metricName = "bindings_total")
     long getBindingCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Dropped",
-                      description = "Total size of all unroutable messages dropped by this exchange.")
+                      description = "Total size of all unroutable messages dropped by this exchange.", metricName = "dropped_bytes_count")
     long getBytesDropped();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of messages received by this exchange.")
+                      description = "Total size of messages received by this exchange.", metricName = "inbound_bytes_count")
     long getBytesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Dropped",
-                      description = "Number of unroutable messages dropped by this exchange.")
+                      description = "Number of unroutable messages dropped by this exchange.", metricName = "dropped_messages_count")
     long getMessagesDropped();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Number of messages received by this exchange.")
+                      description = "Number of messages received by this exchange.", metricName = "inbound_messages_count")
     long getMessagesIn();
 
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java b/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java
index d9bb129..1bcd52e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ManagedStatistic.java
@@ -33,4 +33,6 @@ public @interface ManagedStatistic
     String label() default "";
     StatisticUnit units();
     StatisticType statisticType();
+    String metricName()  default "";
+    boolean metricDisabled() default false;
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java b/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
index d9b7efa..c0a5f2f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
@@ -390,17 +390,17 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Bindings",
-                      description = "Current number of bindings to this queue.")
+                      description = "Current number of bindings to this queue.", metricName = "bindings_total")
     int getBindingCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers",
-                      description = "Current number of consumers attached to this queue.")
+                      description = "Current number of consumers attached to this queue.", metricName = "consumers_total")
     int getConsumerCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers with credit",
-                      description = "Current number of consumers attached to this queue with credit")
+                      description = "Current number of consumers attached to this queue with credit", metricName = "consumers_with_credit_total")
     int getConsumerCountWithCredit();
 
     @SuppressWarnings("unused")
@@ -425,42 +425,42 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Queue Depth",
-                      description = "Current size of all messages enqueued by this queue.")
+                      description = "Current size of all messages enqueued by this queue.", metricName = "depth_bytes_total")
     long getQueueDepthBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Queue Depth",
-                      description = "Current number of messages enqueued by this queue.")
+                      description = "Current number of messages enqueued by this queue.", metricName = "depth_messages_total")
     int getQueueDepthMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Delivered",
-                      description = "Total size of all messages delivered by this queue.")
+                      description = "Total size of all messages delivered by this queue.", metricName = "dequeued_bytes_count")
     long getTotalDequeuedBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Delivered",
-                      description = "Total number of messages delivered by this queue.")
+                      description = "Total number of messages delivered by this queue.", metricName = "dequeued_messages_count")
     long getTotalDequeuedMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Enqueued",
-                      description = "Total size of all messages received by this queue.")
+                      description = "Total size of all messages received by this queue.", metricName = "enqueue_bytes_count")
     long getTotalEnqueuedBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Enqueued",
-                      description = "Total number of messages received by this queue.")
+                      description = "Total number of messages received by this queue.", metricName = "enqueued_messages_count")
     long getTotalEnqueuedMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Expired",
-            description = "Total size of all messages expired by message time-to-live on this queue.")
+            description = "Total size of all messages expired by message time-to-live on this queue.", metricName = "expired_bytes_count")
     long getTotalExpiredBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Expired",
-            description = "Total number of messages expired by message time-to-live on this queue.")
+            description = "Total number of messages expired by message time-to-live on this queue.", metricName = "expired_messages_count")
     long getTotalExpiredMessages();
 
 
@@ -486,37 +486,37 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Available HWM",
-                      description = "Maximum recorded size of available messages.")
+                      description = "Maximum recorded size of available messages.", metricName = "available_bytes_high_water_mark")
     long getAvailableBytesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Available HWM",
-                      description = "Maximum recorded number of available messages.")
+                      description = "Maximum recorded number of available messages.", metricName = "available_messages_high_water_mark")
     int getAvailableMessagesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Queue Depth HWM",
-                      description = "Maximum recorded size of enqueued messages.")
+                      description = "Maximum recorded size of enqueued messages.", metricName = "depth_bytes_high_water_mark")
     long getQueueDepthBytesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Queue Depth HWM",
-                      description = "Maximum recorded number of enqueued messages.")
+                      description = "Maximum recorded number of enqueued messages.", metricName = "depth_messages_high_water_mark")
     int getQueueDepthMessagesHighWatermark();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.TIME_DURATION, label = "Oldest Message",
-                      description = "Current age of oldest message on the queue.")
+                      description = "Current age of oldest message on the queue.", metricName = "oldest_message_age_milliseconds")
     long getOldestMessageAge();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Malformed",
-            description = "Total size of enqueued malformed messages.")
+            description = "Total size of enqueued malformed messages.", metricName = "malformed_bytes_count")
     long getTotalMalformedBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Malformed",
-            description = "Total number of enqueued malformed messages.")
+            description = "Total number of enqueued malformed messages.", metricName = "malformed_messages_count")
     long getTotalMalformedMessages();
 
     @ManagedOperation(description = "move messages from this queue to another", changesConfiguredObjectState = false)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Session.java b/broker-core/src/main/java/org/apache/qpid/server/model/Session.java
index af1084e..343e5ba 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Session.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Session.java
@@ -55,7 +55,7 @@ public interface Session<X extends Session<X>> extends ConfiguredObject<X>
     boolean isProducerFlowBlocked();
 
 
-    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers")
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Consumers", metricName = "consumers_total")
     long getConsumerCount();
 
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Prefetched")
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java b/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java
index c30f6a7..6599a0f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostLogger.java
@@ -25,9 +25,9 @@ public interface VirtualHostLogger <X extends VirtualHostLogger<X>> extends Conf
 {
     void stopLogging();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Errors", metricName = "errors_count")
     long getErrorCount();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Warnings", metricName = "warnings_count")
     long getWarnCount();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
index f88b99a..530d603 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
@@ -159,12 +159,16 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X>
     @ManagedAttribute( defaultValue = "${" + PORT_MAX_OPEN_CONNECTIONS + "}" )
     int getMaxOpenConnections();
 
-    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Open Connections",
-                      description = "Current number of connections made through this port")
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT,
+            label = "Open Connections",
+            description = "Current number of connections made through this port",
+            metricName = "open_connections_total")
     int getConnectionCount();
 
-    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Total Connections",
-            description = "Total number of connections made through this port since broker startup")
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT,
+            label = "Total Connections",
+            description = "Total number of connections made through this port since broker startup",
+            metricName = "aggregate_connection_count")
     long getTotalConnectionCount();
 
     @DerivedAttribute(description = "Maximum time allowed for a new connection to send a protocol header."
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java b/broker-core/src/main/java/org/apache/qpid/server/plugin/ContentFactory.java
similarity index 75%
copy from broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
copy to broker-core/src/main/java/org/apache/qpid/server/plugin/ContentFactory.java
index 41e07f2..bc0ad33 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/plugin/ContentFactory.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,13 +17,15 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model.testmodels.hierarchy;
+
+package org.apache.qpid.server.plugin;
+
+import java.util.Map;
 
 import org.apache.qpid.server.model.ConfiguredObject;
-import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.Content;
 
-@ManagedObject( defaultType = TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE)
-public interface TestSensor<X extends TestSensor<X>> extends ConfiguredObject<X>
+public interface ContentFactory extends Pluggable
 {
-
+    Content createContent(ConfiguredObject<?> object, Map<String, String[]> filter);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
index f76835d..2022aa4 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/QueueManagingVirtualHost.java
@@ -215,69 +215,69 @@ public interface QueueManagingVirtualHost<X extends QueueManagingVirtualHost<X>>
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Queues",
-                      description = "Current number of queues on this virtualhost.")
+                      description = "Current number of queues on this virtualhost.", metricName = "queues_total")
     long getQueueCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Exchanges",
-                      description = "Current number of exchanges on this virtualhost.")
+                      description = "Current number of exchanges on this virtualhost.", metricName = "exchanges_total")
     long getExchangeCount();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT, label = "Connections",
-                      description = "Current number of messaging connections made to this virtualhost.")
+                      description = "Current number of messaging connections made to this virtualhost.", metricName = "connections_total")
     long getConnectionCount();
 
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT, label = "Total Connections",
-            description = "Total number of messaging connections made to this virtualhost since broker startup")
+            description = "Total number of messaging connections made to this virtualhost since broker startup", metricName = "aggregate_connection_count")
     long getTotalConnectionCount();
 
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Inbound",
-                      description = "Total size of all messages received by this virtualhost.")
+                      description = "Total size of all messages received by this virtualhost.", metricName = "inbound_bytes_count")
     long getBytesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.BYTES, label = "Outbound",
-                      description = "Total size of all messages delivered by this virtualhost.")
+                      description = "Total size of all messages delivered by this virtualhost.", metricName = "outbound_bytes_count")
     long getBytesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Inbound",
-                      description = "Total number of messages received by this virtualhost.")
+                      description = "Total number of messages received by this virtualhost.", metricName = "inbound_messages_count")
     long getMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES, label = "Outbound",
-                      description = "Total number of messages delivered by this virtualhost.")
+                      description = "Total number of messages delivered by this virtualhost.", metricName = "outbound_messages_count")
     long getMessagesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
             label = "Transacted Inbound",
-            description = "Total number of messages delivered by this virtualhost within a transaction.")
+            description = "Total number of messages delivered by this virtualhost within a transaction.", metricName = "inbound_transacted_messages_count")
     long getTransactedMessagesIn();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.MESSAGES,
             label = "Transacted Outbound",
-            description = "Total number of messages received by this virtualhost within a transaction.")
+            description = "Total number of messages received by this virtualhost within a transaction.", metricName = "outbound_transacted_messages_count")
     long getTransactedMessagesOut();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "Queue Depth",
-            description = "Current size of all messages enqueued by this virtualhost.")
+            description = "Current size of all messages enqueued by this virtualhost.", metricName = "queue_depth_bytes_total")
     long getTotalDepthOfQueuesBytes();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Queue Depth",
-                      description = "Current number of messages enqueued by this virtualhost.")
+                      description = "Current number of messages enqueued by this virtualhost.", metricName = "queue_depth_messages_total")
     long getTotalDepthOfQueuesMessages();
 
     @SuppressWarnings("unused")
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.BYTES, label = "In-Memory Message Bytes",
-                      description="Current size of all messages cached in-memory.")
+                      description="Current size of all messages cached in-memory.", metricName = "in_memory_message_size_bytes_total")
     long getInMemoryMessageSize();
 
     @SuppressWarnings("unused")
@@ -289,7 +289,7 @@ public interface QueueManagingVirtualHost<X extends QueueManagingVirtualHost<X>>
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
             units = StatisticUnit.BYTES,
             label = "Maximum recorded size of inbound messages",
-            description = "Maximum size of message published into the Virtual Host since start-up.")
+            description = "Maximum size of message published into the Virtual Host since start-up.", metricName = "inbound_message_size_high_water_mark")
     long getInboundMessageSizeHighWatermark();
 
     @Override
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
index 90ce83e..8afa95e 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
@@ -292,14 +292,16 @@ public class InjectedAttributeTest extends UnitTestBase
                                                                            TYPE_VALIDATOR,
                                                                            StatisticUnit.COUNT,
                                                                            StatisticType.POINT_IN_TIME,
-                                                                           "What is 6 x 9?");
+                                                                           "What is 6 x 9?",
+                                                                           null,
+                                                                           false);
 
         TestModel model = new TestModel(null, new TestInjector(statInjector));
 
         TestCar<?> testCar = new TestStandardCarImpl(Collections.<String,Object>singletonMap("name", "Arthur"), model);
 
         final Map<String, Object> statistics = testCar.getStatistics();
-        assertEquals("incorrect number of statistics", (long) 1, (long) statistics.size());
+        assertEquals("incorrect number of statistics", (long) 3, (long) statistics.size());
         assertEquals("incorrect statistic value", 42, statistics.get("meaningOfLife"));
     }
 
@@ -317,7 +319,9 @@ public class InjectedAttributeTest extends UnitTestBase
                                                                            TYPE_VALIDATOR,
                                                                            StatisticUnit.COUNT,
                                                                            StatisticType.POINT_IN_TIME,
-                                                                           "One");
+                                                                           "One",
+                                                                           null,
+                                                                           false);
         final ConfiguredObjectInjectedStatistic<?, ?> statInjector2 =
                 new ConfiguredObjectInjectedStatistic<TestCar<?>, Integer>("whatISent2",
                                                                            method,
@@ -325,13 +329,15 @@ public class InjectedAttributeTest extends UnitTestBase
                                                                            TYPE_VALIDATOR,
                                                                            StatisticUnit.COUNT,
                                                                            StatisticType.POINT_IN_TIME,
-                                                                           "Two");
+                                                                           "Two",
+                                                                           null,
+                                                                           false);
         TestModel model = new TestModel(null, new TestInjector(statInjector1, statInjector2));
 
         TestCar<?> testCar = new TestStandardCarImpl(Collections.<String,Object>singletonMap("name", "Arthur"), model);
 
         final Map<String, Object> statistics = testCar.getStatistics();
-        assertEquals("incorrect number of statistics", (long) 2, (long) statistics.size());
+        assertEquals("incorrect number of statistics", (long) 4, (long) statistics.size());
         assertEquals("incorrect statistic value", 1, statistics.get("whatISent1"));
         assertEquals("incorrect statistic value", 2, statistics.get("whatISent2"));
     }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java
index 447c324..f01a6a4 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractCarImpl.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
@@ -37,6 +38,8 @@ public abstract class TestAbstractCarImpl<X extends TestAbstractCarImpl<X>> exte
     @ManagedAttributeField
     private Colour _interiorColour;
 
+    private AtomicInteger _mileage = new AtomicInteger();
+
     private volatile boolean _rejectStateChange;
 
     public TestAbstractCarImpl(final Map<String, Object> attributes)
@@ -102,4 +105,22 @@ public abstract class TestAbstractCarImpl<X extends TestAbstractCarImpl<X>> exte
     {
         _rejectStateChange = rejectStateChange;
     }
+
+    @Override
+    public int getMileage()
+    {
+        return _mileage.get();
+    }
+
+    @Override
+    public int move(final int value)
+    {
+        return _mileage.addAndGet(value);
+    }
+
+    @Override
+    public int getAge()
+    {
+        return 0;
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java
index 722ddc8..5e84a12 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractEngineImpl.java
@@ -34,6 +34,7 @@ import org.apache.qpid.server.model.StateTransition;
 
 public class TestAbstractEngineImpl<X extends TestAbstractEngineImpl<X>> extends AbstractConfiguredObject<X> implements TestEngine<X>
 {
+    public static final int TEST_TEMPERATURE = 50;
     @ManagedAttributeField
     private ListenableFuture<Void> _beforeCloseFuture = Futures.immediateFuture(null);
 
@@ -109,4 +110,10 @@ public class TestAbstractEngineImpl<X extends TestAbstractEngineImpl<X>> extends
         setState(State.ACTIVE);
         return (ListenableFuture<Void>) _stateChangeFuture;
     }
+
+    @Override
+    public int getTemperature()
+    {
+        return TEST_TEMPERATURE;
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java
index 5ef7001..73db9d3 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractInstrumentPanelImpl.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
+import java.util.Random;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -51,4 +52,5 @@ public class TestAbstractInstrumentPanelImpl<X extends TestAbstractInstrumentPan
         setState(State.ACTIVE);
         return Futures.immediateFuture(null);
     }
+
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java
index dc41c23..00ff611 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestAbstractSensorImpl.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -33,6 +34,8 @@ public class TestAbstractSensorImpl<X extends TestAbstractSensorImpl<X>> extends
         implements TestSensor<X>
 {
 
+    private AtomicInteger _alertCount;
+
     protected TestAbstractSensorImpl(final TestInstrumentPanel<?> parent,
                                      final Map<String, Object> attributes)
     {
@@ -51,4 +54,10 @@ public class TestAbstractSensorImpl<X extends TestAbstractSensorImpl<X>> extends
         setState(State.ACTIVE);
         return Futures.immediateFuture(null);
     }
+
+    @Override
+    public int getNumberOfAlerts()
+    {
+        return _alertCount.getAndIncrement();
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java
index a184227..8588d60 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestCar.java
@@ -25,7 +25,10 @@ import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedContextDefault;
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedOperation;
+import org.apache.qpid.server.model.ManagedStatistic;
 import org.apache.qpid.server.model.Param;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
 
 @ManagedObject( defaultType = TestStandardCarImpl.TEST_STANDARD_CAR_TYPE)
 public interface TestCar<X extends TestCar<X>> extends ConfiguredObject<X>
@@ -60,4 +63,15 @@ public interface TestCar<X extends TestCar<X>> extends ConfiguredObject<X>
 
     void setRejectStateChange(boolean b);
 
+    @ManagedStatistic(statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT)
+    int getMileage();
+
+    @ManagedStatistic(metricName = "age",
+            statisticType = StatisticType.CUMULATIVE,
+            units = StatisticUnit.TIME_DURATION,
+            metricDisabled = true)
+    int getAge();
+
+    @ManagedOperation(changesConfiguredObjectState = false)
+    int move(@Param(name = "mileage", mandatory = true) int mileage);
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java
index d5284cb..97229b2 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestEngine.java
@@ -25,6 +25,9 @@ import com.google.common.util.concurrent.ListenableFuture;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedStatistic;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
 
 @ManagedObject(category = true, defaultType = TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE)
 public interface TestEngine<X extends TestEngine<X>> extends ConfiguredObject<X>
@@ -52,4 +55,7 @@ public interface TestEngine<X extends TestEngine<X>> extends ConfiguredObject<X>
     Object getStateChangeException();
     void setStateChangeException(RuntimeException exception);
 
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT)
+    int getTemperature();
+
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
index 41e07f2..c2bbc79 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestSensor.java
@@ -22,9 +22,14 @@ package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedStatistic;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
 
 @ManagedObject( defaultType = TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE)
 public interface TestSensor<X extends TestSensor<X>> extends ConfiguredObject<X>
 {
 
+    @ManagedStatistic(metricName = "alert_count", statisticType = StatisticType.CUMULATIVE, units = StatisticUnit.COUNT)
+    int getNumberOfAlerts();
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java
index f2c176b..96f1fcf 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/TestTemperatureSensorImpl.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model.testmodels.hierarchy;
 
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
@@ -32,9 +33,17 @@ public class TestTemperatureSensorImpl extends TestAbstractSensorImpl<TestTemper
 
     public static final String TEST_TEMPERATURE_SENSOR_TYPE = "temperature";
 
+    private AtomicInteger _alertCount = new AtomicInteger();
+
     @ManagedObjectFactoryConstructor
     protected TestTemperatureSensorImpl(final Map<String, Object> attributes,final TestInstrumentPanel<?> parent)
     {
         super(parent, attributes);
     }
+
+    @Override
+    public int getNumberOfAlerts()
+    {
+        return _alertCount.getAndIncrement();
+    }
 }
diff --git a/broker-plugins/management-http/pom.xml b/broker-plugins/management-http/pom.xml
index 3c34234..e38a2fd 100644
--- a/broker-plugins/management-http/pom.xml
+++ b/broker-plugins/management-http/pom.xml
@@ -101,6 +101,11 @@
       </exclusions>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-broker-plugins-prometheus-exporter</artifactId>
+    </dependency>
+
     <!-- test dependencies -->
     <dependency>
       <groupId>org.apache.qpid</groupId>
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index d3f805d..75ace26 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -90,6 +90,7 @@ import org.apache.qpid.server.management.plugin.filter.RewriteRequestForUncompre
 import org.apache.qpid.server.management.plugin.portunification.TlsOrPlainConnectionFactory;
 import org.apache.qpid.server.management.plugin.servlet.FileServlet;
 import org.apache.qpid.server.management.plugin.servlet.RootServlet;
+import org.apache.qpid.server.management.plugin.servlet.ContentServlet;
 import org.apache.qpid.server.management.plugin.servlet.rest.ApiDocsServlet;
 import org.apache.qpid.server.management.plugin.servlet.rest.BrokerQueryServlet;
 import org.apache.qpid.server.management.plugin.servlet.rest.JsonValueServlet;
@@ -119,6 +120,8 @@ import org.apache.qpid.server.model.TrustStore;
 import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
 import org.apache.qpid.server.model.port.HttpPort;
 import org.apache.qpid.server.model.port.PortManager;
+import org.apache.qpid.server.plugin.ContentFactory;
+import org.apache.qpid.server.plugin.QpidServiceLoader;
 import org.apache.qpid.server.transport.PortBindFailureException;
 import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
 import org.apache.qpid.server.util.DaemonThreadFactory;
@@ -385,6 +388,22 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
         root.addServlet(new ServletHolder(new QueueReportServlet()), "/service/queuereport/*");
         root.addServlet(new ServletHolder(new MetaDataServlet()), "/service/metadata");
         root.addServlet(new ServletHolder(new TimeZoneServlet()), "/service/timezones");
+
+        final Iterable<ContentFactory> contentFactories = new QpidServiceLoader().instancesOf(ContentFactory.class);
+        contentFactories.forEach(f->{
+            ServletHolder metricsServlet = new ServletHolder(new ContentServlet(f));
+            String path = f.getType().toLowerCase();
+            root.addServlet(metricsServlet, "/" + path);
+            root.addServlet(metricsServlet, "/" + path  + "/*");
+
+            if (getContextValue(Boolean.class, HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION))
+            {
+                root.addFilter(restAuthorizationFilter, "/" + path, EnumSet.of(DispatcherType.REQUEST));
+                root.addFilter(restAuthorizationFilter, "/" + path  + "/*", EnumSet.of(DispatcherType.REQUEST));
+            }
+
+        });
+
     }
 
     private void addFiltersAndServletsForUserInterfaces(final ServletContextHandler root)
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
index 85f0606..e0b4115 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
@@ -90,6 +90,11 @@ public interface HttpManagementConfiguration<X extends HttpManagementConfigurati
     @ManagedContextDefault( name = DISABLE_UI_CONTEXT_NAME)
     boolean DEFAULT_DISABLE_UI = false;
 
+    String HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION = "qpid.httpManagement.enableMetricContentAuthentication";
+    @SuppressWarnings("unused")
+    @ManagedContextDefault(name = HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION)
+    boolean DEFAULT_HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION = false;
+
     AuthenticationProvider getAuthenticationProvider(HttpServletRequest request);
     Port<?> getPort(HttpServletRequest request);
 }
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.java
new file mode 100644
index 0000000..36ea0a7
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/ContentServlet.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.qpid.server.management.plugin.servlet;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.servlet.rest.AbstractServlet;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectFinder;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.plugin.ContentFactory;
+
+public class ContentServlet extends AbstractServlet
+{
+    private static final long serialVersionUID = 1L;
+    private final ContentFactory _contentFactory;
+
+    public ContentServlet(final ContentFactory contentFactory)
+    {
+        super();
+        _contentFactory = contentFactory;
+    }
+
+    @Override
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response,
+                      final ConfiguredObject<?> managedObject) throws IOException
+    {
+
+        ConfiguredObject root = managedObject;
+        String pathInfo = request.getPathInfo();
+        if (managedObject instanceof Broker && null != pathInfo && !pathInfo.isEmpty())
+        {
+            final ConfiguredObjectFinder finder = getConfiguredObjectFinder(managedObject);
+            final ConfiguredObject virtualHost = finder.findObjectFromPath(pathInfo.substring(1), VirtualHost.class);
+            if (null == virtualHost)
+            {
+                sendError(response, HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+            else
+            {
+                root = virtualHost;
+            }
+        }
+        else if (managedObject instanceof VirtualHost && null != pathInfo && !pathInfo.isEmpty())
+        {
+            sendError(response, HttpServletResponse.SC_BAD_REQUEST);
+            return;
+        }
+        final Map<String, String[]> parameters = request.getParameterMap();
+        Content content = _contentFactory.createContent(root, parameters);
+        try
+        {
+            writeContent(content, request, response);
+        }
+        finally
+        {
+            content.release();
+        }
+    }
+
+    @Override
+    protected void doPost(final HttpServletRequest req,
+                          final HttpServletResponse resp,
+                          final ConfiguredObject<?> managedObject)
+            throws IOException
+    {
+        doGet(req, resp, managedObject);
+    }
+
+}
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
index 76d87f1..e324c7a 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
@@ -284,8 +284,22 @@ public abstract class AbstractServlet extends HttpServlet
     protected void writeTypedContent(Content content, HttpServletRequest request, HttpServletResponse response)
             throws IOException
     {
-        Map<String, Object> headers = getResponseHeaders(content);
+        try
+        {
+            writeContent(content, request, response);
+        }
+        catch (IOException e)
+        {
+            LOGGER.warn("Unexpected exception processing request", e);
+            sendJsonErrorResponse(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+        }
+    }
 
+    protected void writeContent(final Content content,
+                                final HttpServletRequest request,
+                                final HttpServletResponse response) throws IOException
+    {
+        Map<String, Object> headers = new HashMap<>(getResponseHeaders(content));
         try (OutputStream os = getOutputStream(request, response, headers))
         {
             response.setStatus(HttpServletResponse.SC_OK);
@@ -295,11 +309,6 @@ public abstract class AbstractServlet extends HttpServlet
             }
             content.write(os);
         }
-        catch (IOException e)
-        {
-            LOGGER.warn("Unexpected exception processing request", e);
-            sendJsonErrorResponse(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
-        }
     }
 
     private OutputStream getOutputStream(final HttpServletRequest request,
diff --git a/broker-plugins/prometheus-exporter/pom.xml b/broker-plugins/prometheus-exporter/pom.xml
new file mode 100644
index 0000000..9ec0617
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/pom.xml
@@ -0,0 +1,70 @@
+<?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="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>qpid-broker-parent</artifactId>
+        <groupId>org.apache.qpid</groupId>
+        <version>9.0.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>qpid-broker-plugins-prometheus-exporter</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-broker-codegen</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-broker-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.prometheus</groupId>
+            <artifactId>simpleclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.prometheus</groupId>
+            <artifactId>simpleclient_common</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-broker-core</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java
similarity index 59%
copy from broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
copy to broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java
index cc22d62..f675e55 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeDisabledStatisticPredicate.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,15 +17,26 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model;
 
-public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends Object> extends ConfiguredObjectAttributeOrStatistic<C,T>
-{
-    String getDescription();
+package org.apache.qpid.server.prometheus;
+
+import java.util.function.Predicate;
 
-    StatisticUnit getUnits();
+import org.apache.qpid.server.model.ConfiguredObjectStatistic;
+
+public class IncludeDisabledStatisticPredicate implements Predicate<ConfiguredObjectStatistic<?,?>>
+
+{
+    private final boolean _includeDisabled;
 
-    StatisticType getStatisticType();
+    IncludeDisabledStatisticPredicate(final boolean includeDisabled)
+    {
+        _includeDisabled = includeDisabled;
+    }
 
-    String getLabel();
+    @Override
+    public boolean test(final ConfiguredObjectStatistic s)
+    {
+        return _includeDisabled || !s.isMetricDisabled();
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java
similarity index 60%
copy from broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
copy to broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java
index cc22d62..e921352 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/IncludeMetricPredicate.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,15 +17,26 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model;
 
-public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends Object> extends ConfiguredObjectAttributeOrStatistic<C,T>
-{
-    String getDescription();
+package org.apache.qpid.server.prometheus;
 
-    StatisticUnit getUnits();
+import java.util.Set;
+import java.util.function.Predicate;
+
+public class IncludeMetricPredicate implements Predicate<String>
+{
+    private final Set<String> _allowedNames;
+    private final boolean _isEmpty;
 
-    StatisticType getStatisticType();
+    public IncludeMetricPredicate(final Set<String> allowedNames)
+    {
+        _allowedNames = allowedNames;
+        _isEmpty = _allowedNames.isEmpty();
+    }
 
-    String getLabel();
+    @Override
+    public boolean test(final String name)
+    {
+        return _isEmpty || _allowedNames.contains(name);
+    }
 }
diff --git a/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java
new file mode 100644
index 0000000..af98978
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/PrometheusContentFactory.java
@@ -0,0 +1,105 @@
+/*
+ * 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.qpid.server.prometheus;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+
+import io.prometheus.client.exporter.common.TextFormat;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.RestContentHeader;
+import org.apache.qpid.server.plugin.ContentFactory;
+import org.apache.qpid.server.plugin.PluggableService;
+
+@PluggableService
+public class PrometheusContentFactory implements ContentFactory
+{
+    static final String INCLUDE_DISABLED = "includeDisabled";
+    static final String INCLUDE_METRIC = "name[]";
+    static final String INCLUDE_DISABLED_CONTEXT_VARIABLE = "qpid.metrics.includeDisabled";
+
+    @Override
+    public Content createContent(final ConfiguredObject<?> object, final Map<String, String[]> filter)
+    {
+        final String[] includeDisabledValues = filter.get(INCLUDE_DISABLED);
+        boolean includeDisabled = includeDisabledValues!= null && includeDisabledValues.length == 1 && Boolean.parseBoolean(includeDisabledValues[0]);
+        if (!includeDisabled)
+        {
+            Boolean val = object.getContextValue(Boolean.class, INCLUDE_DISABLED_CONTEXT_VARIABLE);
+            if (val != null)
+            {
+                includeDisabled = val;
+            }
+        }
+
+        final String[] includedMetricNames = filter.get(INCLUDE_METRIC);
+
+        final IncludeMetricPredicate metricIncludeFilter =
+                new IncludeMetricPredicate(includedMetricNames == null || includedMetricNames.length == 0
+                                                   ? Collections.emptySet()
+                                                   : new HashSet<>(Arrays.asList(includedMetricNames)));
+        final QpidCollector qpidCollector = new QpidCollector(object,
+                                                              new IncludeDisabledStatisticPredicate(includeDisabled),
+                                                              metricIncludeFilter);
+
+        return new Content()
+        {
+            @Override
+            public void write(final OutputStream outputStream) throws IOException
+            {
+                try (final Writer writer = new OutputStreamWriter(outputStream))
+                {
+                    TextFormat.write004(writer, Collections.enumeration(qpidCollector.collect()));
+                    writer.flush();
+                }
+            }
+
+            @Override
+            public void release()
+            {
+
+            }
+
+            @SuppressWarnings("unused")
+            @RestContentHeader("Content-Type")
+            public String getContentType()
+            {
+                return TextFormat.CONTENT_TYPE_004;
+            }
+
+        };
+
+    }
+
+    @Override
+    public String getType()
+    {
+        return "metrics";
+    }
+}
diff --git a/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java
new file mode 100644
index 0000000..3997700
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/main/java/org/apache/qpid/server/prometheus/QpidCollector.java
@@ -0,0 +1,257 @@
+/*
+ * 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.qpid.server.prometheus;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import io.prometheus.client.Collector;
+import io.prometheus.client.CounterMetricFamily;
+import io.prometheus.client.GaugeMetricFamily;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectStatistic;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
+
+public class QpidCollector extends Collector
+{
+    private final static MetricFamilySamples IGNORED = new MetricFamilySamples(null, null, null, null);
+    static final String COUNT_SUFFIX = "count";
+    static final String TOTAL_SUFFIX = "total";
+    private final Predicate<ConfiguredObjectStatistic<?,?>> _includeStatisticFilter;
+    private final Predicate<String> _includeMetricFilter;
+    private ConfiguredObject<?> _root;
+    private Model _model;
+
+
+    QpidCollector(final ConfiguredObject<?> root,
+                  final Predicate<ConfiguredObjectStatistic<?,?>> includeStatisticFilter,
+                  final Predicate<String> includeMetricFilter)
+    {
+        _root = root;
+        _model = _root.getModel();
+        _includeStatisticFilter = includeStatisticFilter;
+        _includeMetricFilter = includeMetricFilter;
+    }
+
+    @Override
+    public List<MetricFamilySamples> collect()
+    {
+        final List<MetricFamilySamples> metricFamilySamples = new ArrayList<>();
+        addObjectMetrics(_root, Collections.emptyList(), new HashMap<>(), metricFamilySamples);
+        addChildrenMetrics(metricFamilySamples, _root, Collections.singletonList("name"));
+        return metricFamilySamples;
+    }
+
+    private void addObjectMetrics(final ConfiguredObject<?> object,
+                                  final List<String> labelNames,
+                                  final Map<String, MetricFamilySamples> metricFamilyMap,
+                                  final List<MetricFamilySamples> metricFamilySamples)
+    {
+        final Map<String, Object> statsMap = object.getStatistics();
+        for (final Map.Entry<String, Object> entry : statsMap.entrySet())
+        {
+            MetricFamilySamples family = metricFamilyMap.get(entry.getKey());
+            if (family == null)
+            {
+                family = createMetricFamilySamples(entry.getKey(), object, labelNames);
+                metricFamilyMap.put(entry.getKey(), family);
+                if (family != IGNORED)
+                {
+                    metricFamilySamples.add(family);
+                }
+            }
+            if (family != IGNORED)
+            {
+                final List<String> labelsValues = buildLabelValues(object);
+                final double doubleValue = toDoubleValue(entry.getValue());
+                family.samples.add(new MetricFamilySamples.Sample(family.name, labelNames, labelsValues, doubleValue));
+            }
+        }
+    }
+
+    private MetricFamilySamples createMetricFamilySamples(final String statisticName,
+                                                          final ConfiguredObject<?> object,
+                                                          final List<String> labelNames)
+    {
+        final ConfiguredObjectStatistic<?, ?> configuredObjectStatistic =
+                findConfiguredObjectStatistic(statisticName, object.getTypeClass());
+        if (configuredObjectStatistic == null || !_includeStatisticFilter.test(configuredObjectStatistic))
+        {
+            return IGNORED;
+        }
+        final StatisticType type = configuredObjectStatistic.getStatisticType();
+        final String familyName = getFamilyName(object.getCategoryClass(), configuredObjectStatistic);
+
+        if (!_includeMetricFilter.test(familyName))
+        {
+            return IGNORED;
+        }
+
+        if (type == StatisticType.CUMULATIVE)
+        {
+            return new CounterMetricFamily(familyName, configuredObjectStatistic.getDescription(), labelNames);
+        }
+        else
+        {
+            return new GaugeMetricFamily(familyName, configuredObjectStatistic.getDescription(), labelNames);
+        }
+    }
+
+    private ConfiguredObjectStatistic<?, ?> findConfiguredObjectStatistic(final String statisticName,
+                                                                          final Class<? extends ConfiguredObject> typeClass)
+    {
+        final Collection<ConfiguredObjectStatistic<?, ?>> statisticsDefinitions =
+                _model.getTypeRegistry().getStatistics(typeClass);
+        return statisticsDefinitions.stream()
+                                    .filter(s -> statisticName.equals(s.getName()))
+                                    .findFirst()
+                                    .orElse(null);
+    }
+
+    private List<String> buildLabelValues(final ConfiguredObject<?> object)
+    {
+        final List<String> labelsValues = new ArrayList<>();
+        ConfiguredObject o = object;
+        while (o != null && o != _root)
+        {
+            labelsValues.add(o.getName());
+            o = o.getParent();
+        }
+        return labelsValues;
+    }
+
+    private void addChildrenMetrics(final List<MetricFamilySamples> metricFamilySamples,
+                                    final ConfiguredObject<?> object,
+                                    final List<String> childLabelNames)
+    {
+        final Class<? extends ConfiguredObject> category = object.getCategoryClass();
+        for (final Class<? extends ConfiguredObject> childClass : _model.getChildTypes(category))
+        {
+            final Collection<? extends ConfiguredObject> children = object.getChildren(childClass);
+            if (children != null && !children.isEmpty())
+            {
+                final Map<String, MetricFamilySamples> childrenMetricFamilyMap = new HashMap<>();
+                for (final ConfiguredObject<?> child : children)
+                {
+                    addObjectMetrics(child, childLabelNames, childrenMetricFamilyMap, metricFamilySamples);
+                    final List<String> labelNames = new ArrayList<>(childLabelNames);
+                    final String label = String.format("%s_name", toSnakeCase(childClass.getSimpleName()));
+                    labelNames.add(label);
+                    addChildrenMetrics(metricFamilySamples, child, labelNames);
+                }
+            }
+        }
+    }
+
+    static String toSnakeCase(final String simpleName)
+    {
+        final StringBuilder sb = new StringBuilder();
+        final char[] chars = simpleName.toCharArray();
+        for (int i = 0; i < chars.length; i++)
+        {
+            final char ch = chars[i];
+            if (Character.isUpperCase(ch))
+            {
+                if (i > 0)
+                {
+                    sb.append('_');
+                }
+                sb.append(Character.toLowerCase(ch));
+            }
+            else
+            {
+                sb.append(ch);
+            }
+        }
+        return sb.toString();
+    }
+
+    private double toDoubleValue(final Object value)
+    {
+        if (value instanceof Number)
+        {
+            return ((Number) value).doubleValue();
+        }
+        return 0;
+    }
+
+    static String getFamilyName(final Class<? extends ConfiguredObject> categoryClass,
+                                ConfiguredObjectStatistic<?, ?> statistics)
+    {
+        String metricName = statistics.getMetricName();
+        if (metricName == null || metricName.isEmpty())
+        {
+            metricName = generateMetricName(statistics);
+        }
+
+        return String.format("qpid_%s_%s",
+                             toSnakeCase(categoryClass.getSimpleName()),
+                             metricName);
+    }
+
+    private static String generateMetricName(final ConfiguredObjectStatistic<?, ?> statistics)
+    {
+        String metricName = toSnakeCase(statistics.getName());
+        String suffix;
+        switch (statistics.getStatisticType())
+        {
+            case CUMULATIVE:
+                suffix = generateMetricSuffix(statistics, COUNT_SUFFIX, metricName);
+                break;
+            case POINT_IN_TIME:
+                suffix = generateMetricSuffix(statistics, TOTAL_SUFFIX, metricName);
+                break;
+            default:
+                suffix = "";
+        }
+
+        return metricName + suffix;
+    }
+
+    private static String generateMetricSuffix(final ConfiguredObjectStatistic<?, ?> statistics,
+                                               final String typeSuffix,
+                                               final String metricName)
+    {
+        String suffix = "";
+        if (!statistics.getName().toLowerCase().contains(typeSuffix)
+            && statistics.getUnits() != StatisticUnit.ABSOLUTE_TIME
+            && statistics.getUnits() != StatisticUnit.TIME_DURATION)
+        {
+            if (statistics.getUnits() == StatisticUnit.MESSAGES || statistics.getUnits() == StatisticUnit.BYTES)
+            {
+                final String units = statistics.getUnits().toString() + "s";
+                if (!metricName.contains(units))
+                {
+                    suffix = "_" + units;
+                }
+            }
+            suffix = suffix + "_" + typeSuffix;
+        }
+        return suffix;
+    }
+}
diff --git a/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java
new file mode 100644
index 0000000..7959a77
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/PrometheusContentFactoryTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.qpid.server.prometheus;
+
+import static org.apache.qpid.server.prometheus.PrometheusContentFactory.INCLUDE_DISABLED;
+import static org.apache.qpid.server.prometheus.PrometheusContentFactory.INCLUDE_METRIC;
+import static org.apache.qpid.server.prometheus.PrometheusContentFactory.INCLUDE_DISABLED_CONTEXT_VARIABLE;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestCar;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestKitCarImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestModel;
+
+public class PrometheusContentFactoryTest
+{
+    public static final String QPID_TEST_CAR_MILEAGE_COUNT = "qpid_test_car_mileage_count";
+    public static final String QPID_TEST_CAR_AGE = "qpid_test_car_age";
+    public static final String PROMETHEUS_COMMENT = "#";
+    private ConfiguredObject _root;
+    private PrometheusContentFactory _prometheusContentFactory;
+
+    @Before
+    public void setUp()
+    {
+        final Model model = TestModel.getInstance();
+        final Map<String, Object> carAttributes = new HashMap<>();
+        carAttributes.put(ConfiguredObject.NAME, "MyPrometheusCar");
+        carAttributes.put(ConfiguredObject.TYPE, TestKitCarImpl.TEST_KITCAR_TYPE);
+
+        @SuppressWarnings("unchecked") final TestCar<?> car =
+                model.getObjectFactory().create(TestCar.class, carAttributes, null);
+        _root = car;
+        _prometheusContentFactory = new PrometheusContentFactory();
+    }
+
+    @Test
+    public void testCreateContent() throws Exception
+    {
+        final Content content = _prometheusContentFactory.createContent(_root, Collections.emptyMap());
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+
+        assertThat(metrics.size(), is(equalTo(1)));
+        String metric = metrics.iterator().next();
+        assertThat(metric, startsWith(QPID_TEST_CAR_MILEAGE_COUNT));
+    }
+
+    @Test
+    public void testCreateContentIncludeDisabled() throws Exception
+    {
+        final Content content = _prometheusContentFactory.createContent(_root, Collections.singletonMap(INCLUDE_DISABLED, new String[]{"true"}));
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+
+        assertThat(metrics.size(), is(equalTo(2)));
+        Map<String, String> metricsMap = convertMetricsToMap(metrics);
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_MILEAGE_COUNT), equalTo(Boolean.TRUE));
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_AGE), equalTo(Boolean.TRUE));
+    }
+
+    @Test
+    public void testCreateContentIncludeDisabledUsingContextVariable() throws Exception
+    {
+        _root.setContextVariable(INCLUDE_DISABLED_CONTEXT_VARIABLE, "true");
+        final Content content = _prometheusContentFactory.createContent(_root, Collections.emptyMap());
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+        assertThat(metrics.size(), is(equalTo(2)));
+        Map<String, String> metricsMap = convertMetricsToMap(metrics);
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_MILEAGE_COUNT), equalTo(Boolean.TRUE));
+        assertThat(metricsMap.containsKey(QPID_TEST_CAR_AGE), equalTo(Boolean.TRUE));
+    }
+
+    @Test
+    public void testCreateContentIncludeName() throws Exception
+    {
+        final Map<String, String[]> filter = new HashMap<>();
+        filter.put(INCLUDE_DISABLED, new String[]{"true"});
+        filter.put(INCLUDE_METRIC, new String[]{QPID_TEST_CAR_AGE});
+        final Content content = _prometheusContentFactory.createContent(_root, filter);
+        assertThat(content, is(notNullValue()));
+        Collection<String> metrics;
+        try (final ByteArrayOutputStream output = new ByteArrayOutputStream())
+        {
+            content.write(output);
+            metrics = getMetricLines(output.toByteArray());
+        }
+        assertThat(metrics, is(notNullValue()));
+
+        assertThat(metrics.size(), is(equalTo(1)));
+        String metric = metrics.iterator().next();
+        assertThat(metric, startsWith(QPID_TEST_CAR_AGE));
+    }
+
+    private static Collection<String> getMetricLines(final byte[] metricsBytes) throws IOException
+    {
+        final List<String> results = new ArrayList<>();
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(metricsBytes))))
+        {
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                if (!(line.startsWith(PROMETHEUS_COMMENT) || line.isEmpty()))
+                {
+                    results.add(line);
+                }
+            }
+        }
+        return results;
+    }
+
+    private Map<String, String> convertMetricsToMap(final Collection<String> metrics)
+    {
+        return metrics.stream().map(m -> m.split(" ")).collect(Collectors.toMap(m -> m[0], m -> m[1]));
+    }
+
+}
diff --git a/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java
new file mode 100644
index 0000000..5efbc59
--- /dev/null
+++ b/broker-plugins/prometheus-exporter/src/test/java/org/apache/qpid/server/prometheus/QpidCollectorTest.java
@@ -0,0 +1,359 @@
+/*
+ * 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.qpid.server.prometheus;
+
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.closeTo;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import io.prometheus.client.Collector;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObjectStatistic;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.StatisticType;
+import org.apache.qpid.server.model.StatisticUnit;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestAbstractEngineImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestCar;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestDigitalInstrumentPanelImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestElecEngineImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestEngine;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestInstrumentPanel;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestKitCarImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestModel;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestPetrolEngineImpl;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestSensor;
+import org.apache.qpid.server.model.testmodels.hierarchy.TestTemperatureSensorImpl;
+import org.apache.qpid.test.utils.UnitTestBase;
+
+public class QpidCollectorTest extends UnitTestBase
+{
+    private static final String CAR_NAME = "myCar";
+    private static final String ELECTRIC_ENGINE_NAME = "myEngine";
+    private static final String INSTRUMENT_PANEL_NAME = "instrumentPanel";
+    private static final String PETROL_ENGINE_NAME = "myPetrolModel";
+    private static final String SENSOR = "sensor";
+    private static final int DESIRED_MILEAGE = 100;
+    private static final String QPID_TEST_CAR_MILEAGE_COUNT = "qpid_test_car_mileage_count";
+    private static final String QPID_TEST_ENGINE_TEMPERATURE_TOTAL = "qpid_test_engine_temperature_total";
+    private static final String QPID_TEST_SENSOR_ALERT_COUNT = "qpid_test_sensor_alert_count";
+    private static final String QPID_TEST_CAR_AGE_COUNT = "qpid_test_car_age";
+
+    private TestCar<?> _root;
+    private QpidCollector _qpidCollector;
+    private static final StatisticUnit[] UNITS = new StatisticUnit[]{
+            StatisticUnit.BYTES,
+            StatisticUnit.MESSAGES,
+            StatisticUnit.COUNT,
+            StatisticUnit.ABSOLUTE_TIME,
+            StatisticUnit.TIME_DURATION};
+    private static final String[] UNIT_SUFFIXES = new String[]{"_bytes", "_messages", "", "", ""};
+
+    @Before
+    public void setUp()
+    {
+        final Model model = TestModel.getInstance();
+        final Map<String, Object> carAttributes = new HashMap<>();
+        carAttributes.put(ConfiguredObject.NAME, CAR_NAME);
+        carAttributes.put(ConfiguredObject.TYPE, TestKitCarImpl.TEST_KITCAR_TYPE);
+
+        @SuppressWarnings("unchecked") final TestCar<?> car =
+                model.getObjectFactory().create(TestCar.class, carAttributes, null);
+        _root = car;
+        _qpidCollector = new QpidCollector(_root, new IncludeDisabledStatisticPredicate(false), s->true);
+    }
+
+    @Test
+    public void testCollectForHierarchyOfTwoObjects()
+    {
+        createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE);
+        _root.move(DESIRED_MILEAGE);
+
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames = {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_ENGINE_TEMPERATURE_TOTAL};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+        final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT);
+        assertMetricFamilySamplesSize(carMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0);
+        assertThat(carSample.value, closeTo(DESIRED_MILEAGE, 0.01));
+        assertThat(carSample.labelNames.size(), is(equalTo(0)));
+
+        final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(
+                QPID_TEST_ENGINE_TEMPERATURE_TOTAL);
+        assertMetricFamilySamplesSize(engineMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample engineSample = engineMetricFamilySamples.samples.get(0);
+        assertThat(engineSample.labelNames, is(equalTo(Collections.singletonList("name"))));
+        assertThat(engineSample.labelValues, is(equalTo(Collections.singletonList(ELECTRIC_ENGINE_NAME))));
+        assertThat(engineSample.value, Matchers.closeTo(TestAbstractEngineImpl.TEST_TEMPERATURE, 0.01));
+    }
+
+    @Test
+    public void testCollectForHierarchyOfThreeObjects()
+    {
+        final TestInstrumentPanel instrumentPanel = getTestInstrumentPanel();
+        createTestSensor(instrumentPanel);
+
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames =
+                {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_SENSOR_ALERT_COUNT};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+        final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT);
+        assertMetricFamilySamplesSize(carMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0);
+        assertThat(carSample.labelNames.size(), is(equalTo(0)));
+        assertThat(carSample.labelValues.size(), is(equalTo(0)));
+        assertThat(carSample.value, closeTo(0, 0.01));
+
+        final Collector.MetricFamilySamples sensorlMetricFamilySamples =
+                metricsMap.get(QPID_TEST_SENSOR_ALERT_COUNT);
+        assertMetricFamilySamplesSize(sensorlMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample sensorSample = sensorlMetricFamilySamples.samples.get(0);
+        assertThat(sensorSample.labelNames, is(equalTo(Arrays.asList("name", "test_instrument_panel_name"))));
+        assertThat(sensorSample.labelValues, is(equalTo(Arrays.asList(SENSOR, INSTRUMENT_PANEL_NAME))));
+    }
+
+    @Test
+    public void testCollectForSiblingObjects()
+    {
+        createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE);
+        createTestEngine(PETROL_ENGINE_NAME, TestPetrolEngineImpl.TEST_PETROL_ENGINE_TYPE);
+
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames = {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_ENGINE_TEMPERATURE_TOTAL};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+        final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT);
+        assertMetricFamilySamplesSize(carMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0);
+        assertThat(carSample.labelNames.size(), is(equalTo(0)));
+        assertThat(carSample.labelValues.size(), is(equalTo(0)));
+
+        final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(
+                QPID_TEST_ENGINE_TEMPERATURE_TOTAL);
+        assertMetricFamilySamplesSize(engineMetricFamilySamples, 2);
+        final String[] engineNames = {PETROL_ENGINE_NAME, ELECTRIC_ENGINE_NAME};
+        for (String engineName : engineNames)
+        {
+            final Collector.MetricFamilySamples.Sample sample =
+                    findSampleByLabelValue(engineMetricFamilySamples, engineName);
+            assertThat(sample.labelNames, is(equalTo(Collections.singletonList("name"))));
+            assertThat(sample.labelValues, is(equalTo(Collections.singletonList(engineName))));
+            assertThat(sample.value, Matchers.closeTo(TestAbstractEngineImpl.TEST_TEMPERATURE, 0.01));
+        }
+    }
+
+    @Test
+    public void testCollectWithFilter(){
+        createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE);
+        _root.move(DESIRED_MILEAGE);
+
+        _qpidCollector = new QpidCollector(_root,
+                                           new IncludeDisabledStatisticPredicate(true),
+                                           new IncludeMetricPredicate(Collections.singleton(QPID_TEST_CAR_AGE_COUNT)));
+        final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect();
+
+        final String[] expectedFamilyNames = {QPID_TEST_CAR_AGE_COUNT};
+        final Map<String, Collector.MetricFamilySamples> metricsMap =
+                convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames);
+
+
+        final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_AGE_COUNT);
+        assertMetricFamilySamplesSize(engineMetricFamilySamples, 1);
+        final Collector.MetricFamilySamples.Sample engineSample = engineMetricFamilySamples.samples.get(0);
+        assertThat(engineSample.labelNames, is(equalTo(Collections.emptyList())));
+        assertThat(engineSample.labelValues, is(equalTo(Collections.emptyList())));
+        assertThat(engineSample.value, Matchers.closeTo(0.0, 0.01));
+
+    }
+
+
+    private Collector.MetricFamilySamples.Sample findSampleByLabelValue(final Collector.MetricFamilySamples metricFamilySamples,
+                                                                        final String nameLabelValue)
+    {
+        final List<Collector.MetricFamilySamples.Sample> found = metricFamilySamples.samples
+                .stream()
+                .filter(s -> s.labelValues != null
+                             && s.labelValues.size() > 0
+                             && nameLabelValue.equals(s.labelValues.get(0)))
+                .collect(Collectors.toList());
+        assertThat(found.size(), is(equalTo(1)));
+        return found.get(0);
+    }
+
+    private void createTestEngine(final String engineName, final String engineType)
+    {
+        final Map<String, Object> engineAttributes = new HashMap<>();
+        engineAttributes.put(ConfiguredObject.NAME, engineName);
+        engineAttributes.put(ConfiguredObject.TYPE, engineType);
+        _root.createChild(TestEngine.class, engineAttributes);
+    }
+
+    private void createTestSensor(final TestInstrumentPanel instrumentPanel)
+    {
+        final Map<String, Object> sensorAttributes = new HashMap<>();
+        sensorAttributes.put(ConfiguredObject.NAME, SENSOR);
+        sensorAttributes.put(ConfiguredObject.TYPE, TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE);
+        instrumentPanel.createChild(TestSensor.class, sensorAttributes);
+    }
+
+    private TestInstrumentPanel getTestInstrumentPanel()
+    {
+        final Map<String, Object> instrumentPanelAttributes = new HashMap<>();
+        instrumentPanelAttributes.put(ConfiguredObject.NAME, INSTRUMENT_PANEL_NAME);
+        instrumentPanelAttributes.put(ConfiguredObject.TYPE,
+                                      TestDigitalInstrumentPanelImpl.TEST_DIGITAL_INSTRUMENT_PANEL_TYPE);
+        return _root.createChild(TestInstrumentPanel.class, instrumentPanelAttributes);
+    }
+
+    private Map<String, Collector.MetricFamilySamples> convertMetricFamilySamplesIntoMap(List<Collector.MetricFamilySamples> metricFamilySamples)
+    {
+        Map<String, Collector.MetricFamilySamples> result = new HashMap<>();
+        for (Collector.MetricFamilySamples metricFamilySample : metricFamilySamples)
+        {
+            final String name = metricFamilySample.name;
+
+            if (result.put(name, metricFamilySample) != null)
+            {
+                fail(String.format("Duplicate family name : %s", name));
+            }
+        }
+        return result;
+    }
+
+    private void assertMetricFamilySamples(final Collector.MetricFamilySamples metricFamilySamples)
+    {
+        assertThat(metricFamilySamples, is(notNullValue()));
+        assertThat(metricFamilySamples.samples, is(notNullValue()));
+
+        for (final Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples)
+        {
+            assertThat(sample, is(notNullValue()));
+            assertThat(sample.name, is(equalTo(metricFamilySamples.name)));
+        }
+    }
+
+
+    private void assertMetricFamilySamplesSize(final Collector.MetricFamilySamples metricFamilySamples,
+                                               final int expectedSamplesSize)
+    {
+        assertThat(metricFamilySamples.samples.size(), equalTo(expectedSamplesSize));
+    }
+
+    private Map<String, Collector.MetricFamilySamples> convertMetricFamilySamplesIntoMapAndAssert(final List<Collector.MetricFamilySamples> metrics,
+                                                                                                  final String[] expectedFamilyNames)
+    {
+        assertThat(metrics.size(), equalTo(expectedFamilyNames.length));
+        final Map<String, Collector.MetricFamilySamples> metricsMap = convertMetricFamilySamplesIntoMap(metrics);
+
+        for (String expectedFamily : expectedFamilyNames)
+        {
+            assertMetricFamilySamples(metricsMap.get(expectedFamily));
+        }
+        return metricsMap;
+    }
+
+    @Test
+    public void testToSnakeCase()
+    {
+        assertThat(QpidCollector.toSnakeCase("carEngineOilChanges"), is(equalTo("car_engine_oil_changes")));
+    }
+
+    @Test
+    public void getFamilyNameForCumulativeStatistic()
+    {
+        for (int i = 0; i < UNITS.length; i++)
+        {
+            final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class);
+            when(statistics.getUnits()).thenReturn(UNITS[i]);
+            when(statistics.getStatisticType()).thenReturn(StatisticType.CUMULATIVE);
+            when(statistics.getName()).thenReturn("diagnosticData");
+            final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics);
+            final String expectedName =
+                    String.format("qpid_test_car_diagnostic_data%s%s", UNIT_SUFFIXES[i], getSuffix(UNITS[i],QpidCollector.COUNT_SUFFIX));
+            assertThat(String.format("unexpected metric name for units %s", UNITS[i]),
+                       familyName,
+                       is(equalTo(expectedName)));
+        }
+    }
+
+    @Test
+    public void getFamilyNameForCumulativeStatisticContainingCountInName()
+    {
+        final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class);
+        when(statistics.getUnits()).thenReturn(StatisticUnit.BYTES);
+        when(statistics.getStatisticType()).thenReturn(StatisticType.CUMULATIVE);
+        when(statistics.getName()).thenReturn("CountOfDiagnosticData");
+        final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics);
+        assertThat(familyName, is(equalTo("qpid_test_car_count_of_diagnostic_data")));
+    }
+
+    @Test
+    public void getFamilyNameForPointInTimeStatistic()
+    {
+        for (int i = 0; i < UNITS.length; i++)
+        {
+            final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class);
+            when(statistics.getUnits()).thenReturn(UNITS[i]);
+            when(statistics.getStatisticType()).thenReturn(StatisticType.POINT_IN_TIME);
+            when(statistics.getName()).thenReturn("diagnosticData");
+            final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics);
+
+            final String expectedName =
+                    String.format("qpid_test_car_diagnostic_data%s%s", UNIT_SUFFIXES[i],  getSuffix(UNITS[i],QpidCollector.TOTAL_SUFFIX));
+            assertThat(String.format("unexpected metric name for units %s", UNITS[i]),
+                       familyName,
+                       is(equalTo(expectedName)));
+        }
+    }
+
+    String getSuffix(final StatisticUnit unit,final String requiredSuffix)
+    {
+        String suffix = "_" + requiredSuffix;
+        if(unit.equals(StatisticUnit.ABSOLUTE_TIME) || unit.equals(StatisticUnit.TIME_DURATION)){
+            suffix = "";
+        }
+        return suffix;
+    }
+}
diff --git a/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml b/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml
index 9211056..13e7fa2 100644
--- a/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml
+++ b/doc/java-broker/src/docbkx/Java-Broker-Management-Channels.xml
@@ -37,5 +37,6 @@
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-HTTP.xml"/>
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-Web-Console.xml"/>
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-REST-API.xml"/>
+  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Metrics.xml"/>
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="management/channels/Java-Broker-Management-Channel-AMQP-Intrinsic.xml"/>
 </chapter>
diff --git a/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
new file mode 100644
index 0000000..c8aeb9d
--- /dev/null
+++ b/doc/java-broker/src/docbkx/management/channels/Java-Broker-Management-Metrics.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="Java-Broker-Management-Metrics">
+  <title>Prometheus Metrics</title>
+    <para>This section describes the metrics endpoints exposing broker statistics in
+      <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://prometheus.io/">Prometheus format</link>.
+      The metrics endpoint is intended for scraping by Prometheus server to collect the Broker telemetry.</para>
+    <para>The Prometheus metric endpoints are mapped under /metrics path and /metrics/*.
+      The latter allows to get the Virtual Host statistics by specify the path to the virtual host as
+      /metrics/&lt;virtual host node name&gt;/&lt; virtual host name&gt;.
+      The former allow to get all Broker statistics or Virtual Host statistics when called with HOST header
+      set to the Virtual Host name</para>
+    <para>
+      The metrics endpoints allow anonymous access by default. If required, an authentication can be enabled for the
+      metrics endpoints by setting http management context variable
+      <literal>qpid.httpManagement.enableMetricContentAuthentication</literal> to <literal>true</literal>.
+    </para>
+
+    <para>The Broker JVM statistics are disabled by default. The metrics endpoints can be called with parameter
+      <literal>includeDisabled</literal> set to <literal>true</literal> to include JVM  broker metrics into endpoint
+      output.
+    </para>
+    <note>
+      <para>For more information about Prometheus, check out the
+        <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://prometheus.io/docs/introduction/overview/">prometheus documentation</link>.
+      </para>
+    </note>
+
+</section>
diff --git a/pom.xml b/pom.xml
index 785a444..c82e55b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -158,6 +158,7 @@
     <bcprov-version>1.64</bcprov-version>
     <bcpkix-version>1.64</bcpkix-version>
     <logback-gelf-version>3.0.0</logback-gelf-version>
+    <prometheus-client-version>0.9.0</prometheus-client-version>
   </properties>
 
   <modules>
@@ -183,6 +184,7 @@
     <module>broker-plugins/websocket</module>
     <module>broker-plugins/amqp-1-0-bdb-store</module>
     <module>broker-plugins/amqp-1-0-jdbc-store</module>
+    <module>broker-plugins/prometheus-exporter</module>
     <module>tools</module>
 
     <module>qpid-systests-parent</module>
@@ -473,6 +475,12 @@
         <version>${project.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.apache.qpid</groupId>
+        <artifactId>qpid-broker-plugins-prometheus-exporter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
       <!-- External dependencies -->
       <dependency>
         <groupId>org.apache.qpid</groupId>
@@ -822,6 +830,17 @@
         <version>${bcpkix-version}</version>
       </dependency>
 
+      <!-- prometheus client dependencies -->
+      <dependency>
+        <groupId>io.prometheus</groupId>
+        <artifactId>simpleclient</artifactId>
+        <version>${prometheus-client-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.prometheus</groupId>
+        <artifactId>simpleclient_common</artifactId>
+        <version>${prometheus-client-version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsAuthenticationTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsAuthenticationTest.java
new file mode 100644
index 0000000..fcfca5e
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsAuthenticationTest.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.qpid.tests.http.metrics;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+
+import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.tests.http.HttpRequestConfig;
+import org.apache.qpid.tests.http.HttpTestBase;
+import org.apache.qpid.tests.http.HttpTestHelper;
+import org.apache.qpid.tests.utils.ConfigItem;
+
+@HttpRequestConfig(useVirtualHostAsHost = false)
+@ConfigItem(name = HttpManagement.HTTP_MANAGEMENT_ENABLE_CONTENT_AUTHENTICATION, value = "true")
+public class BrokerMetricsAuthenticationTest extends HttpTestBase
+{
+    @Test
+    public void testBrokerMetricsForAuthenticatedUser() throws Exception
+    {
+        getHelper().submitRequest("/metrics", "GET", HttpServletResponse.SC_OK);
+    }
+
+    @Test
+    public void testBrokerMetricsForUnauthenticatedUser() throws Exception
+    {
+        final HttpTestHelper helper = new HttpTestHelper(getBrokerAdmin(), null);
+        helper.setUserName(null);
+        helper.setPassword(null);
+        helper.submitRequest("/metrics", "GET", HttpServletResponse.SC_UNAUTHORIZED);
+    }
+
+}
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
new file mode 100644
index 0000000..7423588
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/BrokerMetricsTest.java
@@ -0,0 +1,80 @@
+package org.apache.qpid.tests.http.metrics;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.QUEUE_NAME;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.assertMetricsInclusion;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.assertVirtualHostHierarchyMetrics;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.createQueueMetricPattern;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Collection;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+import org.apache.qpid.tests.http.HttpRequestConfig;
+import org.apache.qpid.tests.http.HttpTestBase;
+
+@HttpRequestConfig(useVirtualHostAsHost = false)
+public class BrokerMetricsTest extends HttpTestBase
+{
+    private static final String[] EXPECTED_BROKER_METRIC_NAMES =
+            new String[]{"qpid_broker_inbound_bytes_count", "qpid_broker_outbound_bytes_count"};
+
+    @Test
+    public void testBrokerMetrics() throws Exception
+    {
+        final String[] unexpectedMetricNames =
+                {"qpid_broker_live_threads_total", "qpid_broker_direct_memory_capacity_bytes_total"};
+
+        final byte[] metricsBytes = getHelper().getBytes("/metrics");
+        final String metricsString = new String(metricsBytes, UTF_8);
+        assertMetricsInclusion(metricsString, EXPECTED_BROKER_METRIC_NAMES, true);
+        assertMetricsInclusion(metricsString, unexpectedMetricNames, false);
+
+        final byte[] metricsBytesIncludingDisabled = getHelper().getBytes("/metrics?includeDisabled=true");
+        final String metricsStringIncludingDisabled = new String(metricsBytesIncludingDisabled, UTF_8);
+        assertMetricsInclusion(metricsStringIncludingDisabled, unexpectedMetricNames, true);
+        assertMetricsInclusion(metricsStringIncludingDisabled, EXPECTED_BROKER_METRIC_NAMES, true);
+    }
+
+    @Test
+    public void testQueueMetrics() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes = getHelper().getBytes("/metrics");
+        final String metricsString = new String(metricsBytes, UTF_8);
+
+        final Pattern[] expectedMetricPattens = {createQueueMetricPattern("qpid_queue_consumers_total"),
+                createQueueMetricPattern("qpid_queue_depth_messages_total")};
+
+        assertMetricsInclusion(metricsString, expectedMetricPattens, true);
+    }
+
+    @Test
+    public void testQueueMetricsIncludeOnlyMessageDepth() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes = getHelper().getBytes("/metrics?name[]=qpid_queue_depth_messages_total&name[]=qpid_queue_depth_bytes_total");
+        Collection<String> metricLines = TestMetricsHelper.getMetricLines(metricsBytes);
+        assertThat(metricLines.size(), is(equalTo(2)));
+
+        final String metricsString = new String(metricsBytes, UTF_8);
+        final Pattern[] expectedMetricPattens = {createQueueMetricPattern("qpid_queue_depth_bytes_total"),
+                createQueueMetricPattern("qpid_queue_depth_messages_total")};
+
+        assertMetricsInclusion(metricsString, expectedMetricPattens, true);
+    }
+
+    @Test
+    public void testMappingForVirtualHost() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes =
+                getHelper().getBytes(String.format("/metrics/%s/%s", getVirtualHostNode(), getVirtualHost()));
+
+        assertVirtualHostHierarchyMetrics(metricsBytes);
+    }
+}
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.java
new file mode 100644
index 0000000..fa9b679
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/TestMetricsHelper.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.qpid.tests.http.metrics;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+class TestMetricsHelper
+{
+    static final String QUEUE_NAME = "foo";
+
+    static void assertMetricsInclusion(final String metricsString,
+                                       final String[] metricNames,
+                                       final boolean inclusionFlag)
+    {
+        for (String expected : metricNames)
+        {
+            assertThat(metricsString.contains(expected), equalTo(inclusionFlag));
+        }
+    }
+
+    static void assertMetricsInclusion(final String metricsString,
+                                       final Pattern[] expectedMetricPattens,
+                                       final boolean inclusionFlag)
+    {
+        for (Pattern expected : expectedMetricPattens)
+        {
+            assertThat(expected.matcher(metricsString).find(), equalTo(inclusionFlag));
+        }
+    }
+
+    static Pattern createQueueMetricPattern(final String metricName)
+    {
+        return Pattern.compile(String.format("%s\\s*\\{.*name\\s*=\\s*\"%s\"\\s*,.*\\}\\s*0\\.0",
+                                             metricName,
+                                             QUEUE_NAME));
+    }
+
+    static void assertVirtualHostHierarchyMetrics(final byte[] metricsBytes) throws IOException
+    {
+        final Predicate<String> unexpectedMetricPredicate = line -> !(line.startsWith("qpid_virtual_host")
+                                                                      || line.startsWith("qpid_queue")
+                                                                      || line.startsWith("qpid_exchange"));
+        getMetricLines(metricsBytes).stream().filter(unexpectedMetricPredicate)
+                                    .findFirst().ifPresent(found -> fail("Unexpected metric: " + found));
+    }
+
+    static Collection<String> getMetricLines(final byte[] metricsBytes) throws IOException
+    {
+        final List<String> results = new ArrayList<>();
+        try(BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(metricsBytes))))
+        {
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                if (!(line.startsWith("#") || line.isEmpty()))
+                {
+                    results.add(line);
+                }
+            }
+        }
+        return results;
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java
similarity index 54%
copy from broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
copy to systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java
index cc22d62..bd06588 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectStatistic.java
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/metrics/VirtualHostMetricsTest.java
@@ -1,5 +1,4 @@
 /*
- *
  * 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
@@ -18,15 +17,25 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.model;
 
-public interface ConfiguredObjectStatistic<C extends ConfiguredObject, T extends Object> extends ConfiguredObjectAttributeOrStatistic<C,T>
-{
-    String getDescription();
+package org.apache.qpid.tests.http.metrics;
 
-    StatisticUnit getUnits();
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.QUEUE_NAME;
+import static org.apache.qpid.tests.http.metrics.TestMetricsHelper.assertVirtualHostHierarchyMetrics;
 
-    StatisticType getStatisticType();
+import org.junit.Test;
 
-    String getLabel();
+import org.apache.qpid.tests.http.HttpRequestConfig;
+import org.apache.qpid.tests.http.HttpTestBase;
+
+@HttpRequestConfig
+public class VirtualHostMetricsTest extends HttpTestBase
+{
+    @Test
+    public void testVirtualHostMetrics() throws Exception
+    {
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+        final byte[] metricsBytes = getHelper().getBytes("/metrics");
+        assertVirtualHostHierarchyMetrics(metricsBytes);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org