lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a.@apache.org
Subject [2/2] lucene-solr:jira/solr-9959: SOLR-9959 Report per-component metric names. Implement JMX field & type support for MetricsMap.
Date Mon, 03 Apr 2017 10:51:38 GMT
SOLR-9959 Report per-component metric names. Implement JMX field & type support for MetricsMap.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/5be37efa
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/5be37efa
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/5be37efa

Branch: refs/heads/jira/solr-9959
Commit: 5be37efa0d0c66ac4cebc0a5a9dfa86c00a7e3ef
Parents: 5d028e0
Author: Andrzej Bialecki <ab@apache.org>
Authored: Mon Apr 3 12:49:10 2017 +0200
Committer: Andrzej Bialecki <ab@apache.org>
Committed: Mon Apr 3 12:49:10 2017 +0200

----------------------------------------------------------------------
 .../plugin/AnalyticsStatisticsCollector.java    |   5 +-
 .../handler/component/AnalyticsComponent.java   |   4 +-
 .../handler/dataimport/DataImportHandler.java   |   9 +-
 .../org/apache/solr/core/CoreContainer.java     |  18 +--
 .../src/java/org/apache/solr/core/SolrCore.java |  49 +++---
 .../java/org/apache/solr/core/SolrInfoBean.java |  34 ++++
 .../apache/solr/handler/ReplicationHandler.java |  27 ++--
 .../apache/solr/handler/RequestHandlerBase.java |  36 ++++-
 .../solr/handler/admin/CoreAdminHandler.java    |   2 +-
 .../solr/handler/admin/PluginInfoHandler.java   |   4 +
 .../handler/admin/SolrInfoMBeanHandler.java     |   3 +
 .../component/HttpShardHandlerFactory.java      |   2 +-
 .../solr/handler/component/SearchComponent.java |  20 ++-
 .../handler/component/SuggestComponent.java     |  13 +-
 .../solr/highlight/HighlightingPluginBase.java  |  24 ++-
 .../org/apache/solr/metrics/MetricsMap.java     | 156 ++++++++++++++++++-
 .../apache/solr/metrics/SolrMetricManager.java  |  58 +++++--
 .../metrics/reporters/JmxObjectNameFactory.java |  14 ++
 .../solr/metrics/reporters/SolrJmxReporter.java |  51 +++++-
 .../org/apache/solr/search/FastLRUCache.java    |  28 +++-
 .../java/org/apache/solr/search/LFUCache.java   |  28 +++-
 .../java/org/apache/solr/search/LRUCache.java   |  30 ++--
 .../org/apache/solr/search/QParserPlugin.java   |   6 +
 .../apache/solr/search/SolrFieldCacheBean.java  |  32 ++--
 .../apache/solr/search/SolrIndexSearcher.java   |  36 +++--
 .../apache/solr/store/blockcache/Metrics.java   |  28 +++-
 .../solr/store/hdfs/HdfsLocalityReporter.java   |  26 +++-
 .../solr/update/DirectUpdateHandler2.java       |  44 +++---
 .../java/org/apache/solr/update/PeerSync.java   |   6 +-
 .../org/apache/solr/update/SolrIndexWriter.java |  24 +--
 .../org/apache/solr/update/UpdateHandler.java   |  16 ++
 .../java/org/apache/solr/update/UpdateLog.java  |  12 +-
 .../apache/solr/update/UpdateShardHandler.java  |  31 +++-
 ...entedPoolingHttpClientConnectionManager.java |   8 +-
 .../org/apache/solr/util/stats/MetricUtils.java |  78 +++++++---
 .../cloud/TestRandomRequestDistribution.java    |   4 +-
 .../test/org/apache/solr/core/MockInfoBean.java |  29 +++-
 .../core/MockQuerySenderListenerReqHandler.java |   2 +-
 .../solr/metrics/SolrMetricManagerTest.java     |  18 +--
 .../solr/metrics/SolrMetricTestUtils.java       |   2 +-
 .../metrics/SolrMetricsIntegrationTest.java     |   2 +-
 .../apache/solr/search/TestFastLRUCache.java    |  12 +-
 .../org/apache/solr/search/TestLFUCache.java    |  10 +-
 .../org/apache/solr/search/TestLRUCache.java    |   6 +-
 .../solr/search/TestSolrFieldCacheBean.java     |  24 ++-
 45 files changed, 799 insertions(+), 272 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java
index 062bd50..a796803 100644
--- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java
+++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.analytics.plugin;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -85,7 +86,9 @@ public class AnalyticsStatisticsCollector {
   }
 
   public Map<String, Object> getStatistics() {
-    Map<String, Object> map = MetricUtils.convertTimer(requestTimes, false);
+
+    Map<String, Object> map = new HashMap<>();
+    map.putAll(MetricUtils.convertTimer(requestTimes, false));
     map.put("requests", numRequests.longValue());
     map.put("analyticsRequests", numAnalyticsRequests.longValue());
     map.put("statsRequests", numStatsRequests.longValue());

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
----------------------------------------------------------------------
diff --git a/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java b/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
index 17094d5..505533b 100644
--- a/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
+++ b/solr/contrib/analytics/src/java/org/apache/solr/handler/component/AnalyticsComponent.java
@@ -83,7 +83,7 @@ public class AnalyticsComponent extends SearchComponent implements SolrMetricPro
 
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    MetricsMap metrics = detailed -> analyticsCollector.getStatistics();
-    manager.registerGauge(registry, metrics, true, getClass().getSimpleName(), getCategory().toString(), scope);
+    MetricsMap metrics = new MetricsMap((detailed, map) -> map.putAll(analyticsCollector.getStatistics()));
+    manager.registerGauge(this, registry, metrics, true, getClass().getSimpleName(), getCategory().toString(), scope);
   }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
----------------------------------------------------------------------
diff --git a/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java b/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
index 582c0fc..faea3ba 100644
--- a/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
+++ b/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/DataImportHandler.java
@@ -43,7 +43,6 @@ import org.apache.solr.util.plugin.SolrCoreAware;
 import java.util.*;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Constructor;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -268,8 +267,7 @@ public class DataImportHandler extends RequestHandlerBase implements
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
     super.initializeMetrics(manager, registryName, scope);
-    metrics = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
+    metrics = new MetricsMap((detailed, map) -> {
       if (importer != null) {
         DocBuilder.Statistics cumulative = importer.cumulativeStatistics;
 
@@ -290,9 +288,8 @@ public class DataImportHandler extends RequestHandlerBase implements
         map.put(DataImporter.MSG.TOTAL_DOCS_DELETED, cumulative.deletedDocCount);
         map.put(DataImporter.MSG.TOTAL_DOCS_SKIPPED, cumulative.skipDocCount);
       }
-      return map;
-    };
-    manager.registerGauge(registryName, metrics, true, "importer", getCategory().toString(), scope);
+    });
+    manager.registerGauge(this, registryName, metrics, true, "importer", getCategory().toString(), scope);
   }
 
   // //////////////////////SolrInfoMBeans methods //////////////////////

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/core/CoreContainer.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 4843c63..87a7d99 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -480,7 +480,7 @@ public class CoreContainer {
     metricManager = new SolrMetricManager();
 
     coreContainerWorkExecutor = MetricUtils.instrumentedExecutorService(
-        coreContainerWorkExecutor,
+        coreContainerWorkExecutor, null,
         metricManager.registry(SolrMetricManager.getRegistryName(SolrInfoBean.Group.node)),
         SolrMetricManager.mkName("coreContainerWorkExecutor", SolrInfoBean.Category.CONTAINER.toString(), "threadPool"));
 
@@ -534,20 +534,20 @@ public class CoreContainer {
     // initialize gauges for reporting the number of cores and disk total/free
 
     String registryName = SolrMetricManager.getRegistryName(SolrInfoBean.Group.node);
-    metricManager.registerGauge(registryName, () -> solrCores.getCores().size(),
+    metricManager.registerGauge(null, registryName, () -> solrCores.getCores().size(),
         true, "loaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
-    metricManager.registerGauge(registryName, () -> solrCores.getCoreNames().size() - solrCores.getCores().size(),
+    metricManager.registerGauge(null, registryName, () -> solrCores.getCoreNames().size() - solrCores.getCores().size(),
         true, "lazy", SolrInfoBean.Category.CONTAINER.toString(), "cores");
-    metricManager.registerGauge(registryName, () -> solrCores.getAllCoreNames().size() - solrCores.getCoreNames().size(),
+    metricManager.registerGauge(null, registryName, () -> solrCores.getAllCoreNames().size() - solrCores.getCoreNames().size(),
         true, "unloaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
-    metricManager.registerGauge(registryName, () -> cfg.getCoreRootDirectory().toFile().getTotalSpace(),
+    metricManager.registerGauge(null, registryName, () -> cfg.getCoreRootDirectory().toFile().getTotalSpace(),
         true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
-    metricManager.registerGauge(registryName, () -> cfg.getCoreRootDirectory().toFile().getUsableSpace(),
+    metricManager.registerGauge(null, registryName, () -> cfg.getCoreRootDirectory().toFile().getUsableSpace(),
         true, "usableSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
     // add version information
-    metricManager.registerGauge(registryName, () -> this.getClass().getPackage().getSpecificationVersion(),
+    metricManager.registerGauge(null, registryName, () -> this.getClass().getPackage().getSpecificationVersion(),
         true, "specification", SolrInfoBean.Category.CONTAINER.toString(), "version");
-    metricManager.registerGauge(registryName, () -> this.getClass().getPackage().getImplementationVersion(),
+    metricManager.registerGauge(null, registryName, () -> this.getClass().getPackage().getImplementationVersion(),
         true, "implementation", SolrInfoBean.Category.CONTAINER.toString(), "version");
 
     SolrFieldCacheBean fieldCacheBean = new SolrFieldCacheBean();
@@ -561,7 +561,7 @@ public class CoreContainer {
     ExecutorService coreLoadExecutor = MetricUtils.instrumentedExecutorService(
         ExecutorUtil.newMDCAwareFixedThreadPool(
             cfg.getCoreLoadThreadCount(isZooKeeperAware()),
-            new DefaultSolrThreadFactory("coreLoadExecutor")),
+            new DefaultSolrThreadFactory("coreLoadExecutor")), null,
         metricManager.registry(SolrMetricManager.getRegistryName(SolrInfoBean.Group.node)),
         SolrMetricManager.mkName("coreLoadExecutor", SolrInfoBean.Category.CONTAINER.toString(), "threadPool"));
     final List<Future<SolrCore>> futures = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/core/SolrCore.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 0121d9e..56e5660 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -57,6 +57,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
 
 import com.codahale.metrics.Counter;
+import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.Timer;
 import com.google.common.collect.MapMaker;
 import org.apache.commons.io.FileUtils;
@@ -159,6 +160,7 @@ import org.apache.solr.util.RefCounted;
 import org.apache.solr.util.plugin.NamedListInitializedPlugin;
 import org.apache.solr.util.plugin.PluginInfoInitialized;
 import org.apache.solr.util.plugin.SolrCoreAware;
+import org.apache.solr.util.stats.MetricUtils;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
@@ -221,6 +223,12 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
   private Counter newSearcherMaxReachedCounter;
   private Counter newSearcherOtherErrorsCounter;
 
+  private Set<String> metricNames = new HashSet<>();
+
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
   public Date getStartTimeStamp() { return startTime; }
 
   private final Map<IndexReader.CacheKey, IndexFingerprint> perSegmentFingerprintCache = new MapMaker().weakKeys().makeMap();
@@ -1120,24 +1128,24 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
 
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    newSearcherCounter = manager.counter(registry, "new", Category.SEARCHER.toString());
-    newSearcherTimer = manager.timer(registry, "time", Category.SEARCHER.toString(), "new");
-    newSearcherWarmupTimer = manager.timer(registry, "warmup", Category.SEARCHER.toString(), "new");
-    newSearcherMaxReachedCounter = manager.counter(registry, "maxReached", Category.SEARCHER.toString(), "new");
-    newSearcherOtherErrorsCounter = manager.counter(registry, "errors", Category.SEARCHER.toString(), "new");
-
-    manager.registerGauge(registry, () -> name == null ? "(null)" : name, true, "coreName", Category.CORE.toString());
-    manager.registerGauge(registry, () -> startTime, true, "startTime", Category.CORE.toString());
-    manager.registerGauge(registry, () -> getOpenCount(), true, "refCount", Category.CORE.toString());
-    manager.registerGauge(registry, () -> resourceLoader.getInstancePath().toString(), true, "instanceDir", Category.CORE.toString());
-    manager.registerGauge(registry, () -> getIndexDir(), true, "indexDir", Category.CORE.toString());
-    manager.registerGauge(registry, () -> getIndexSize(), true, "sizeInBytes", Category.INDEX.toString());
-    manager.registerGauge(registry, () -> NumberUtils.readableSize(getIndexSize()), true, "size", Category.INDEX.toString());
+    newSearcherCounter = manager.counter(this, registry, "new", Category.SEARCHER.toString());
+    newSearcherTimer = manager.timer(this, registry, "time", Category.SEARCHER.toString(), "new");
+    newSearcherWarmupTimer = manager.timer(this, registry, "warmup", Category.SEARCHER.toString(), "new");
+    newSearcherMaxReachedCounter = manager.counter(this, registry, "maxReached", Category.SEARCHER.toString(), "new");
+    newSearcherOtherErrorsCounter = manager.counter(this, registry, "errors", Category.SEARCHER.toString(), "new");
+
+    manager.registerGauge(this, registry, () -> name == null ? "(null)" : name, true, "coreName", Category.CORE.toString());
+    manager.registerGauge(this, registry, () -> startTime, true, "startTime", Category.CORE.toString());
+    manager.registerGauge(this, registry, () -> getOpenCount(), true, "refCount", Category.CORE.toString());
+    manager.registerGauge(this, registry, () -> resourceLoader.getInstancePath().toString(), true, "instanceDir", Category.CORE.toString());
+    manager.registerGauge(this, registry, () -> getIndexDir(), true, "indexDir", Category.CORE.toString());
+    manager.registerGauge(this, registry, () -> getIndexSize(), true, "sizeInBytes", Category.INDEX.toString());
+    manager.registerGauge(this, registry, () -> NumberUtils.readableSize(getIndexSize()), true, "size", Category.INDEX.toString());
     if (coreDescriptor != null && coreDescriptor.getCoreContainer() != null) {
-      manager.registerGauge(registry, () -> coreDescriptor.getCoreContainer().getCoreNames(this), true, "aliases", Category.CORE.toString());
+      manager.registerGauge(this, registry, () -> coreDescriptor.getCoreContainer().getCoreNames(this), true, "aliases", Category.CORE.toString());
       final CloudDescriptor cd = coreDescriptor.getCloudDescriptor();
       if (cd != null) {
-        manager.registerGauge(registry, () -> {
+        manager.registerGauge(this, registry, () -> {
           if (cd.getCollectionName() != null) {
             return cd.getCollectionName();
           } else {
@@ -1145,7 +1153,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
           }
         }, true, "collection", Category.CORE.toString());
 
-        manager.registerGauge(registry, () -> {
+        manager.registerGauge(this, registry, () -> {
           if (cd.getShardId() != null) {
             return cd.getShardId();
           } else {
@@ -1158,8 +1166,8 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
     // initialize disk total / free metrics
     Path dataDirPath = Paths.get(dataDir);
     File dataDirFile = dataDirPath.toFile();
-    manager.registerGauge(registry, () -> dataDirFile.getTotalSpace(), true, "totalSpace", Category.CORE.toString(), "fs");
-    manager.registerGauge(registry, () -> dataDirFile.getUsableSpace(), true, "usableSpace", Category.CORE.toString(), "fs");
+    manager.registerGauge(this, registry, () -> dataDirFile.getTotalSpace(), true, "totalSpace", Category.CORE.toString(), "fs");
+    manager.registerGauge(this, registry, () -> dataDirFile.getUsableSpace(), true, "usableSpace", Category.CORE.toString(), "fs");
   }
 
   private void checkVersionFieldExistsInSchema(IndexSchema schema, CoreDescriptor coreDescriptor) {
@@ -2803,6 +2811,11 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
     return Category.CORE;
   }
 
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return coreMetricManager.getRegistry();
+  }
+
   public Codec getCodec() {
     return codec;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/core/SolrInfoBean.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrInfoBean.java b/solr/core/src/java/org/apache/solr/core/SolrInfoBean.java
index 669a8b3..a2e213f 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrInfoBean.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrInfoBean.java
@@ -16,6 +16,12 @@
  */
 package org.apache.solr.core;
 
+import java.util.Map;
+import java.util.Set;
+
+import com.codahale.metrics.MetricRegistry;
+import org.apache.solr.util.stats.MetricUtils;
+
 /**
  * Interface for getting various ui friendly strings
  * for use by objects which are 'pluggable' to make server administration
@@ -43,4 +49,32 @@ public interface SolrInfoBean {
   String getDescription();
   /** Category of this component */
   Category getCategory();
+
+  /** Optionally return metrics that this component reports, or null. */
+  default Map<String, Object> getMetrics() {
+    if (getMetricRegistry() == null || getMetricNames() == null) {
+      return null;
+    }
+    return MetricUtils.convertMetrics(getMetricRegistry(), getMetricNames());
+  }
+
+  /**
+   * Modifiable set of metric names that this component reports, or null if none.
+   */
+  Set<String> getMetricNames();
+
+  /**
+   * An instance of {@link MetricRegistry} that this component uses for keeping metrics, or null.
+   */
+  default MetricRegistry getMetricRegistry() {
+    return null;
+  }
+
+  /** Register a metric name that this component reports. */
+  default void registerMetricName(String name) {
+    Set<String> names = getMetricNames();
+    if (names != null) {
+      names.add(name);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
index 0d051bc..36f4254 100644
--- a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
@@ -42,7 +42,6 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
 import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -861,20 +860,19 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
   public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
     super.initializeMetrics(manager, registry, scope);
 
-    manager.registerGauge(registry, () -> core != null ? NumberUtils.readableSize(core.getIndexSize()) : "", true,
+    manager.registerGauge(this, registry, () -> core != null ? NumberUtils.readableSize(core.getIndexSize()) : "", true,
         "indexSize", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> (core != null && !core.isClosed() ? getIndexVersion().toString() : ""), true,
+    manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? getIndexVersion().toString() : ""), true,
         "indexVersion", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> (core != null && !core.isClosed() ? getIndexVersion().generation : 0), true,
+    manager.registerGauge(this, registry, () -> (core != null && !core.isClosed() ? getIndexVersion().generation : 0), true,
         GENERATION, getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> core != null ? core.getIndexDir() : "", true,
+    manager.registerGauge(this, registry, () -> core != null ? core.getIndexDir() : "", true,
         "indexPath", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> isMaster, true,
+    manager.registerGauge(this, registry, () -> isMaster, true,
         "isMaster", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> isSlave, true,
+    manager.registerGauge(this, registry, () -> isSlave, true,
         "isSlave", getCategory().toString(), scope);
-    final MetricsMap fetcherMap = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
+    final MetricsMap fetcherMap = new MetricsMap((detailed, map) -> {
       IndexFetcher fetcher = currentIndexFetcher;
       if (fetcher != null) {
         map.put(MASTER_URL, fetcher.getMasterUrl());
@@ -901,14 +899,13 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
         addVal(map, IndexFetcher.TIMES_CONFIG_REPLICATED, props, Integer.class);
         addVal(map, IndexFetcher.CONF_FILES_REPLICATED, props, String.class);
       }
-      return map;
-    };
-    manager.registerGauge(registry, fetcherMap, true, "fetcher", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> isMaster && includeConfFiles != null ? includeConfFiles : "", true,
+    });
+    manager.registerGauge(this, registry, fetcherMap, true, "fetcher", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> isMaster && includeConfFiles != null ? includeConfFiles : "", true,
         "confFilesToReplicate", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> isMaster ? getReplicateAfterStrings() : Collections.<String>emptyList(), true,
+    manager.registerGauge(this, registry, () -> isMaster ? getReplicateAfterStrings() : Collections.<String>emptyList(), true,
         REPLICATE_AFTER, getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> isMaster && replicationEnabled.get(), true,
+    manager.registerGauge(this, registry, () -> isMaster && replicationEnabled.get(), true,
         "replicationEnabled", getCategory().toString(), scope);
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
index 28cf3fe..4d0f8ab 100644
--- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
@@ -18,7 +18,12 @@ package org.apache.solr.handler;
 
 import java.lang.invoke.MethodHandles;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
+import com.codahale.metrics.MetricRegistry;
 import com.google.common.collect.ImmutableList;
 import com.codahale.metrics.Counter;
 import com.codahale.metrics.Meter;
@@ -40,6 +45,7 @@ import org.apache.solr.util.SolrPluginUtils;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
 import org.apache.solr.api.ApiSupport;
+import org.apache.solr.util.stats.MetricUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,6 +77,9 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
 
   private PluginInfo pluginInfo;
 
+  private Set<String> metricNames = new HashSet<>();
+  private MetricRegistry registry;
+
   @SuppressForbidden(reason = "Need currentTimeMillis, used only for stats output")
   public RequestHandlerBase() {
     handlerStart = System.currentTimeMillis();
@@ -135,14 +144,15 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
 
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
-    numErrors = manager.meter(registryName, "errors", getCategory().toString(), scope);
-    numServerErrors = manager.meter(registryName, "serverErrors", getCategory().toString(), scope);
-    numClientErrors = manager.meter(registryName, "clientErrors", getCategory().toString(), scope);
-    numTimeouts = manager.meter(registryName, "timeouts", getCategory().toString(), scope);
-    requests = manager.counter(registryName, "requests", getCategory().toString(), scope);
-    requestTimes = manager.timer(registryName, "requestTimes", getCategory().toString(), scope);
-    totalTime = manager.counter(registryName, "totalTime", getCategory().toString(), scope);
-    manager.registerGauge(registryName, () -> handlerStart, true, "handlerStart", getCategory().toString(), scope);
+    registry = manager.registry(registryName);
+    numErrors = manager.meter(this, registryName, "errors", getCategory().toString(), scope);
+    numServerErrors = manager.meter(this, registryName, "serverErrors", getCategory().toString(), scope);
+    numClientErrors = manager.meter(this, registryName, "clientErrors", getCategory().toString(), scope);
+    numTimeouts = manager.meter(this, registryName, "timeouts", getCategory().toString(), scope);
+    requests = manager.counter(this, registryName, "requests", getCategory().toString(), scope);
+    requestTimes = manager.timer(this, registryName, "requestTimes", getCategory().toString(), scope);
+    totalTime = manager.counter(this, registryName, "totalTime", getCategory().toString(), scope);
+    manager.registerGauge(this, registryName, () -> handlerStart, true, "handlerStart", getCategory().toString(), scope);
   }
 
   public static SolrParams getSolrParamsFromNamedList(NamedList args, String key) {
@@ -230,6 +240,16 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
   }
 
   @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
+  @Override
   public SolrRequestHandler getSubHandler(String subPath) {
     return null;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
index 275ec18..6746332 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
@@ -121,7 +121,7 @@ public class CoreAdminHandler extends RequestHandlerBase implements PermissionNa
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
     super.initializeMetrics(manager, registryName, scope);
-    parallelExecutor = MetricUtils.instrumentedExecutorService(parallelExecutor, manager.registry(registryName),
+    parallelExecutor = MetricUtils.instrumentedExecutorService(parallelExecutor, this, manager.registry(registryName),
         SolrMetricManager.mkName("parallelCoreAdminExecutor", getCategory().name(),scope, "threadPool"));
   }
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java
index 3bf3d3e..e4457bf 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/PluginInfoHandler.java
@@ -61,6 +61,10 @@ public class PluginInfoHandler extends RequestHandlerBase
 
         info.add( NAME,          (m.getName()       !=null ? m.getName()        : na) );
         info.add( "description", (m.getDescription()!=null ? m.getDescription() : na) );
+
+        if (stats) {
+          info.add( "stats", m.getMetrics());
+        }
       }
     }
     return list;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java
index d9cd21d..9efcaf7 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/SolrInfoMBeanHandler.java
@@ -144,6 +144,9 @@ public class SolrInfoMBeanHandler extends RequestHandlerBase {
     mBeanInfo.add("class", m.getName());
     mBeanInfo.add("description", m.getDescription());
 
+    if (req.getParams().getFieldBool(key, "stats", false))
+      mBeanInfo.add("stats", m.getMetrics());
+
     catInfo.add(key, mBeanInfo);
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
index 304cd2b..57b785d 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
@@ -380,7 +380,7 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.
     String expandedScope = SolrMetricManager.mkName(scope, SolrInfoBean.Category.QUERY.name());
     clientConnectionManager.initializeMetrics(manager, registry, expandedScope);
     httpRequestExecutor.initializeMetrics(manager, registry, expandedScope);
-    commExecutor = MetricUtils.instrumentedExecutorService(commExecutor,
+    commExecutor = MetricUtils.instrumentedExecutorService(commExecutor, null,
         manager.registry(registry),
         SolrMetricManager.mkName("httpShardExecutor", expandedScope, "threadPool"));
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
index ad8ace9..dc82993 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
@@ -19,12 +19,16 @@ package org.apache.solr.handler.component;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.search.facet.FacetModule;
 import org.apache.solr.util.plugin.NamedListInitializedPlugin;
+import org.apache.solr.util.stats.MetricUtils;
 
 /**
  * TODO!
@@ -38,6 +42,10 @@ public abstract class SearchComponent implements SolrInfoBean, NamedListInitiali
    * The name given to this component in solrconfig.xml file
    */
   private String name = this.getClass().getName();
+
+  protected Set<String> metricNames = new HashSet<>();
+  protected MetricRegistry registry;
+
   /**
    * Prepare the response.  Guaranteed to be called before any SearchComponent {@link #process(org.apache.solr.handler.component.ResponseBuilder)} method.
    * Called for every incoming request.
@@ -108,8 +116,18 @@ public abstract class SearchComponent implements SolrInfoBean, NamedListInitiali
     return Category.OTHER;
   }
 
+  @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
   public static final Map<String, Class<? extends SearchComponent>> standard_components;
-  ;
+
 
   static {
     HashMap<String, Class<? extends SearchComponent>> map = new HashMap<>();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
index b591571..4ca6ce4 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
@@ -348,17 +348,16 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    manager.registerGauge(registry, () -> ramBytesUsed(), true, "totalSizeInBytes", getCategory().toString(), scope);
-    MetricsMap suggestersMap = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    manager.registerGauge(this, registryName, () -> ramBytesUsed(), true, "totalSizeInBytes", getCategory().toString(), scope);
+    MetricsMap suggestersMap = new MetricsMap((detailed, map) -> {
       for (Map.Entry<String, SolrSuggester> entry : suggesters.entrySet()) {
         SolrSuggester suggester = entry.getValue();
         map.put(entry.getKey(), suggester.toString());
       }
-      return map;
-    };
-    manager.registerGauge(registry, suggestersMap, true, "suggesters", getCategory().toString(), scope);
+    });
+    manager.registerGauge(this, registryName, suggestersMap, true, "suggesters", getCategory().toString(), scope);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java b/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
index a5f7443..de9c14c 100644
--- a/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
+++ b/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
@@ -16,12 +16,19 @@
  */
 package org.apache.solr.highlight;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
 import com.codahale.metrics.Counter;
+import com.codahale.metrics.MetricRegistry;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.util.stats.MetricUtils;
 
 /**
  * 
@@ -31,6 +38,8 @@ public abstract class HighlightingPluginBase implements SolrInfoBean, SolrMetric
 {
   protected Counter numRequests;
   protected SolrParams defaults;
+  protected Set<String> metricNames = new HashSet<>(1);
+  protected MetricRegistry registry;
 
   public void init(NamedList args) {
     if( args != null ) {
@@ -58,8 +67,19 @@ public abstract class HighlightingPluginBase implements SolrInfoBean, SolrMetric
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-   numRequests = manager.counter(registry, "requests", getCategory().toString(), scope);
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
+  @Override
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    numRequests = manager.counter(this, registryName, "requests", getCategory().toString(), scope);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java b/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java
index b580b76..f43c60b 100644
--- a/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java
+++ b/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java
@@ -16,25 +16,169 @@
  */
 package org.apache.solr.metrics;
 
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.ReflectionException;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.function.BiConsumer;
 
 import com.codahale.metrics.Gauge;
 import com.codahale.metrics.Metric;
+import org.apache.lucene.store.AlreadyClosedException;
+import org.apache.solr.common.SolrException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Dynamically constructed map of metrics, intentionally different from {@link com.codahale.metrics.MetricSet}
  * where each metric had to be known in advance and registered separately in {@link com.codahale.metrics.MetricRegistry}.
  * <p>Note: this awkwardly extends {@link Gauge} and not {@link Metric} because awkwardly {@link Metric} instances
  * are not supported by {@link com.codahale.metrics.MetricRegistryListener} :(</p>
- * <p>Note 2: values added to this metric map have to belong to the list of types supported by JMX:
- * {@link javax.management.openmbean.OpenType#ALLOWED_CLASSNAMES_LIST}, otherwise they will show up as
- * "Unavailable" in JConsole.</p>
+ * <p>Note 2: values added to this metric map should belong to the list of types supported by JMX:
+ * {@link javax.management.openmbean.OpenType#ALLOWED_CLASSNAMES_LIST}, otherwise only their toString()
+ * representation will be shown in JConsole.</p>
  */
-public interface MetricsMap extends Gauge<Map<String, Object>> {
+public class MetricsMap implements Gauge<Map<String,Object>>, DynamicMBean {
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-  Map<String, Object> getValue(boolean detailed);
+  // set to true to use cached statistics between getMBeanInfo calls to work
+  // around over calling getStatistics on MBeanInfos when iterating over all attributes (SOLR-6586)
+  private final boolean useCachedStatsBetweenGetMBeanInfoCalls = Boolean.getBoolean("useCachedStatsBetweenGetMBeanInfoCalls");
 
-  default Map<String, Object> getValue() {
+  private BiConsumer<Boolean, Map<String, Object>> initializer;
+  private volatile Map<String,Object> cachedValue;
+
+  public MetricsMap(BiConsumer<Boolean, Map<String,Object>> initializer) {
+    this.initializer = initializer;
+  }
+
+  @Override
+  public Map<String,Object> getValue() {
     return getValue(true);
   }
+
+  public Map<String,Object> getValue(boolean detailed) {
+    Map<String,Object> map = new HashMap<>();
+    initializer.accept(detailed, map);
+    return map;
+  }
+
+  public String toString() {
+    return getValue().toString();
+  }
+
+  @Override
+  public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
+    Object val;
+    Map<String,Object> stats = null;
+    if (useCachedStatsBetweenGetMBeanInfoCalls) {
+      Map<String,Object> cachedStats = this.cachedValue;
+      if (cachedStats != null) {
+        stats = cachedStats;
+      }
+    }
+    if (stats == null) {
+      stats = getValue(true);
+    }
+    val = stats.get(attribute);
+
+    if (val != null) {
+      // It's String or one of the simple types, just return it as JMX suggests direct support for such types
+      for (String simpleTypeName : SimpleType.ALLOWED_CLASSNAMES_LIST) {
+        if (val.getClass().getName().equals(simpleTypeName)) {
+          return val;
+        }
+      }
+      // It's an arbitrary object which could be something complex and odd, return its toString, assuming that is
+      // a workable representation of the object
+      return val.toString();
+    }
+    return null;
+  }
+
+  @Override
+  public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+    throw new UnsupportedOperationException("Operation not Supported");
+  }
+
+  @Override
+  public AttributeList getAttributes(String[] attributes) {
+    AttributeList list = new AttributeList();
+    for (String attribute : attributes) {
+      try {
+        list.add(new Attribute(attribute, getAttribute(attribute)));
+      } catch (Exception e) {
+        log.warn("Could not get attribute " + attribute);
+      }
+    }
+    return list;
+  }
+
+  @Override
+  public AttributeList setAttributes(AttributeList attributes) {
+    throw new UnsupportedOperationException("Operation not Supported");
+  }
+
+  @Override
+  public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
+    throw new UnsupportedOperationException("Operation not Supported");
+  }
+
+  @Override
+  public MBeanInfo getMBeanInfo() {
+    ArrayList<MBeanAttributeInfo> attrInfoList = new ArrayList<>();
+    Map<String,Object> stats = getValue(true);
+    if (useCachedStatsBetweenGetMBeanInfoCalls) {
+      cachedValue = stats;
+    }
+    try {
+      stats.forEach((k, v) -> {
+        Class type = v.getClass();
+        OpenType typeBox = determineType(type);
+        if (type.equals(String.class) || typeBox == null) {
+          attrInfoList.add(new MBeanAttributeInfo(k, String.class.getName(),
+              null, true, false, false));
+        } else {
+          attrInfoList.add(new OpenMBeanAttributeInfoSupport(
+              k, k, typeBox, true, false, false));
+        }
+      });
+    } catch (Exception e) {
+      // don't log issue if the core is closing
+      if (!(SolrException.getRootCause(e) instanceof AlreadyClosedException))
+        log.warn("Could not get attributes of MetricsMap: {}", this, e);
+    }
+    MBeanAttributeInfo[] attrInfoArr = attrInfoList
+        .toArray(new MBeanAttributeInfo[attrInfoList.size()]);
+    return new MBeanInfo(getClass().getName(), "MetricsMap", attrInfoArr, null, null, null);
+  }
+
+  private OpenType determineType(Class type) {
+    try {
+      for (Field field : SimpleType.class.getFields()) {
+        if (field.getType().equals(SimpleType.class)) {
+          SimpleType candidate = (SimpleType) field.get(SimpleType.class);
+          if (candidate.getTypeName().equals(type.getName())) {
+            return candidate;
+          }
+        }
+      }
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+    return null;
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
index ba9f9f2..a285b4c 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
@@ -69,7 +69,7 @@ import org.slf4j.LoggerFactory;
  * {@link MetricRegistry} instances are automatically created when first referenced by name. Similarly,
  * instances of {@link Metric} implementations, such as {@link Meter}, {@link Counter}, {@link Timer} and
  * {@link Histogram} are automatically created and registered under hierarchical names, in a specified
- * registry, when {@link #meter(String, String, String...)} and other similar methods are called.
+ * registry, when {@link #meter(SolrInfoBean, String, String, String...)} and other similar methods are called.
  * <p>This class enforces a common prefix ({@link #REGISTRY_NAME_PREFIX}) in all registry
  * names.</p>
  * <p>Solr uses several different registries for collecting metrics belonging to different groups, using
@@ -482,6 +482,21 @@ public class SolrMetricManager {
   }
 
   /**
+   * Retrieve matching metrics and their names.
+   * @param registry registry name.
+   * @param metricFilter filter (null is equivalent to {@link MetricFilter#ALL}).
+   * @return map of matching names and metrics
+   */
+  public Map<String, Metric> getMetrics(String registry, MetricFilter metricFilter) {
+    if (metricFilter == null || metricFilter == MetricFilter.ALL) {
+      return registry(registry).getMetrics();
+    }
+    return registry(registry).getMetrics().entrySet().stream()
+        .filter(entry -> metricFilter.matches(entry.getKey(), entry.getValue()))
+        .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
+  }
+
+  /**
    * Create or get an existing named {@link Meter}
    * @param registry registry name
    * @param metricName metric name, either final name or a fully-qualified name
@@ -489,8 +504,12 @@ public class SolrMetricManager {
    * @param metricPath (optional) additional top-most metric name path elements
    * @return existing or a newly created {@link Meter}
    */
-  public Meter meter(String registry, String metricName, String... metricPath) {
-    return registry(registry).meter(mkName(metricName, metricPath));
+  public Meter meter(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+    final String name = mkName(metricName, metricPath);
+    if (info != null) {
+      info.registerMetricName(name);
+    }
+    return registry(registry).meter(name);
   }
 
   /**
@@ -501,8 +520,12 @@ public class SolrMetricManager {
    * @param metricPath (optional) additional top-most metric name path elements
    * @return existing or a newly created {@link Timer}
    */
-  public Timer timer(String registry, String metricName, String... metricPath) {
-    return registry(registry).timer(mkName(metricName, metricPath));
+  public Timer timer(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+    final String name = mkName(metricName, metricPath);
+    if (info != null) {
+      info.registerMetricName(name);
+    }
+    return registry(registry).timer(name);
   }
 
   /**
@@ -513,8 +536,12 @@ public class SolrMetricManager {
    * @param metricPath (optional) additional top-most metric name path elements
    * @return existing or a newly created {@link Counter}
    */
-  public Counter counter(String registry, String metricName, String... metricPath) {
-    return registry(registry).counter(mkName(metricName, metricPath));
+  public Counter counter(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+    final String name = mkName(metricName, metricPath);
+    if (info != null) {
+      info.registerMetricName(name);
+    }
+    return registry(registry).counter(name);
   }
 
   /**
@@ -525,8 +552,12 @@ public class SolrMetricManager {
    * @param metricPath (optional) additional top-most metric name path elements
    * @return existing or a newly created {@link Histogram}
    */
-  public Histogram histogram(String registry, String metricName, String... metricPath) {
-    return registry(registry).histogram(mkName(metricName, metricPath));
+  public Histogram histogram(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+    final String name = mkName(metricName, metricPath);
+    if (info != null) {
+      info.registerMetricName(name);
+    }
+    return registry(registry).histogram(name);
   }
 
   /**
@@ -540,9 +571,12 @@ public class SolrMetricManager {
    *                   using dotted notation
    * @param metricPath (optional) additional top-most metric name path elements
    */
-  public void register(String registry, Metric metric, boolean force, String metricName, String... metricPath) {
+  public void register(SolrInfoBean info, String registry, Metric metric, boolean force, String metricName, String... metricPath) {
     MetricRegistry metricRegistry = registry(registry);
     String fullName = mkName(metricName, metricPath);
+    if (info != null) {
+      info.registerMetricName(fullName);
+    }
     synchronized (metricRegistry) {
       if (force && metricRegistry.getMetrics().containsKey(fullName)) {
         metricRegistry.remove(fullName);
@@ -551,8 +585,8 @@ public class SolrMetricManager {
     }
   }
 
-  public void registerGauge(String registry, Gauge<?> gauge, boolean force, String metricName, String... metricPath) {
-    register(registry, gauge, force, metricName, metricPath);
+  public void registerGauge(SolrInfoBean info, String registry, Gauge<?> gauge, boolean force, String metricName, String... metricPath) {
+    register(info, registry, gauge, force, metricName, metricPath);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java b/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
index c9c9439..f502c02 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
@@ -51,6 +51,20 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
   }
 
   /**
+   * Return current domain.
+   */
+  public String getDomain() {
+    return domain;
+  }
+
+  /**
+   * Return current reporterName.
+   */
+  public String getReporterName() {
+    return reporterName;
+  }
+
+  /**
    * Create a hierarchical name.
    *
    * @param type    metric class, eg. "counters", may be null for non-metric MBeans

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
index f8f2eed..3bed6f1 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
@@ -16,14 +16,24 @@
  */
 package org.apache.solr.metrics.reporters;
 
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.Locale;
 
+import com.codahale.metrics.Gauge;
 import com.codahale.metrics.JmxReporter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricRegistryListener;
 import org.apache.solr.core.PluginInfo;
+import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricReporter;
 import org.apache.solr.util.JmxUtil;
@@ -45,7 +55,9 @@ public class SolrJmxReporter extends SolrMetricReporter {
   private String serviceUrl;
 
   private JmxReporter reporter;
+  private MetricRegistry registry;
   private MBeanServer mBeanServer;
+  private MetricsMapListener listener;
 
   /**
    * Creates a new instance of {@link SolrJmxReporter}.
@@ -91,13 +103,20 @@ public class SolrJmxReporter extends SolrMetricReporter {
     }
 
     JmxObjectNameFactory jmxObjectNameFactory = new JmxObjectNameFactory(pluginInfo.name, domain);
+    registry = metricManager.registry(registryName);
+    // filter out MetricsMap gauges
+    MetricFilter filter = (name, metric) -> !(metric instanceof MetricsMap);
 
-    reporter = JmxReporter.forRegistry(metricManager.registry(registryName))
+    reporter = JmxReporter.forRegistry(registry)
                           .registerWith(mBeanServer)
                           .inDomain(domain)
+                          .filter(filter)
                           .createsObjectNamesWith(jmxObjectNameFactory)
                           .build();
     reporter.start();
+    // work around for inability to register custom MBeans
+    listener = new MetricsMapListener(mBeanServer, jmxObjectNameFactory);
+    registry.addListener(listener);
 
     log.info("JMX monitoring enabled at server: " + mBeanServer);
   }
@@ -111,6 +130,9 @@ public class SolrJmxReporter extends SolrMetricReporter {
       reporter.close();
       reporter = null;
     }
+    if (listener != null && registry != null) {
+      registry.removeListener(listener);
+    }
   }
 
   /**
@@ -194,4 +216,31 @@ public class SolrJmxReporter extends SolrMetricReporter {
         getClass().getName(), Integer.toHexString(hashCode()), domain, serviceUrl, agentId);
   }
 
+  private static class MetricsMapListener extends MetricRegistryListener.Base {
+    MBeanServer server;
+    JmxObjectNameFactory nameFactory;
+
+    MetricsMapListener(MBeanServer server, JmxObjectNameFactory nameFactory) {
+      this.server = server;
+      this.nameFactory = nameFactory;
+    }
+
+    @Override
+    public void onGaugeAdded(String name, Gauge<?> gauge) {
+      if (!(gauge instanceof MetricsMap)) {
+        return;
+      }
+      MetricsMap metricsMap = (MetricsMap)gauge;
+      ObjectName objectName = nameFactory.createName("gauges", nameFactory.getDomain(), name);
+      try {
+        server.registerMBean(gauge, objectName);
+      } catch (InstanceAlreadyExistsException e) {
+        log.warn("##### registration error", e);
+      } catch (MBeanRegistrationException e) {
+        log.warn("##### registration error", e);
+      } catch (NotCompliantMBeanException e) {
+        log.warn("##### registration error", e);
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/FastLRUCache.java b/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
index b0b65a1..cb699b2 100644
--- a/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.search;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
@@ -24,10 +25,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.invoke.MethodHandles;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 
@@ -59,6 +60,8 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K,V>
   private long maxRamBytes;
 
   private MetricsMap cacheMap;
+  private Set<String> metricNames = new HashSet<>();
+  private MetricRegistry registry;
 
   @Override
   public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
@@ -218,9 +221,14 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K,V>
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    cacheMap = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    cacheMap = new MetricsMap((detailed, map) -> {
       if (cache != null) {
         ConcurrentLRUCache.Stats stats = cache.getStats();
         long lookups = stats.getCumulativeLookups();
@@ -268,17 +276,21 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K,V>
 
         }
       }
-      return map;
-    };
-    manager.registerGauge(registry, cacheMap, true, scope, getCategory().toString());
+    });
+    manager.registerGauge(this, registryName, cacheMap, true, scope, getCategory().toString());
   }
 
   // for unit tests only
-  MetricsMap getMetrics() {
+  MetricsMap getMetricsMap() {
     return cacheMap;
   }
 
   @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
+  @Override
   public String toString() {
     return name() + cacheMap != null ? cacheMap.getValue().toString() : "";
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/search/LFUCache.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/LFUCache.java b/solr/core/src/java/org/apache/solr/search/LFUCache.java
index 6997e3f..82ba6d2 100644
--- a/solr/core/src/java/org/apache/solr/search/LFUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LFUCache.java
@@ -17,13 +17,14 @@
 package org.apache.solr.search;
 
 import java.lang.invoke.MethodHandles;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
@@ -64,6 +65,8 @@ public class LFUCache<K, V> implements SolrCache<K, V> {
   private int showItems = 0;
   private Boolean timeDecay = true;
   private MetricsMap cacheMap;
+  private Set<String> metricNames = new HashSet<>();
+  private MetricRegistry registry;
 
   @Override
   public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
@@ -231,9 +234,9 @@ public class LFUCache<K, V> implements SolrCache<K, V> {
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    cacheMap = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    cacheMap = new MetricsMap((detailed, map) -> {
       if (cache != null) {
         ConcurrentLFUCache.Stats stats = cache.getStats();
         long lookups = stats.getCumulativeLookups();
@@ -284,17 +287,26 @@ public class LFUCache<K, V> implements SolrCache<K, V> {
         }
 
       }
-      return map;
-    };
-    manager.registerGauge(registry, cacheMap, true, scope, getCategory().toString());
+    });
+    manager.registerGauge(this, registryName, cacheMap, true, scope, getCategory().toString());
   }
 
   // for unit tests only
-  MetricsMap getMetrics() {
+  MetricsMap getMetricsMap() {
     return cacheMap;
   }
 
   @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
+  @Override
   public String toString() {
     return name + cacheMap != null ? cacheMap.getValue().toString() : "";
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/search/LRUCache.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/LRUCache.java b/solr/core/src/java/org/apache/solr/search/LRUCache.java
index b8fda87..6c12451 100644
--- a/solr/core/src/java/org/apache/solr/search/LRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LRUCache.java
@@ -19,13 +19,15 @@ package org.apache.solr.search;
 import java.lang.invoke.MethodHandles;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.LongAdder;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.lucene.util.Accountable;
 import org.apache.lucene.util.Accountables;
 import org.apache.lucene.util.RamUsageEstimator;
@@ -85,6 +87,8 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
   private Map<K,V> map;
   private String description="LRU Cache";
   private MetricsMap cacheMap;
+  private Set<String> metricNames = new HashSet<>();
+  private MetricRegistry registry;
 
   private long maxRamBytes = Long.MAX_VALUE;
   // The synchronization used for the map will be used to update this,
@@ -322,9 +326,14 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    cacheMap = detailed -> {
-      Map<String, Object> res = new ConcurrentHashMap<>();
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    cacheMap = new MetricsMap((detailed, res) -> {
       synchronized (map) {
         res.put("lookups", lookups);
         res.put("hits", hits);
@@ -350,16 +359,19 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
       if (maxRamBytes != Long.MAX_VALUE)  {
         res.put("cumulative_evictionsRamUsage", stats.evictionsRamUsage.longValue());
       }
-
-      return res;
-    };
-    manager.registerGauge(registry, cacheMap, true, scope, getCategory().toString());
+    });
+    manager.registerGauge(this, registryName, cacheMap, true, scope, getCategory().toString());
   }
 
   // for unit tests only
-  MetricsMap getMetrics() {
+  MetricsMap getMetricsMap() {
     return cacheMap;
   }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
   
   @Override
   public String toString() {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/QParserPlugin.java b/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
index c82e2fc..872c618 100644
--- a/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
@@ -19,6 +19,7 @@ package org.apache.solr.search;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
@@ -107,6 +108,11 @@ public abstract class QParserPlugin implements NamedListInitializedPlugin, SolrI
     return Category.QUERYPARSER;
   }
 
+  @Override
+  public Set<String> getMetricNames() {
+    return null;
+  }
+
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
index 3e99f4c..ffcc37d 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
@@ -16,9 +16,10 @@
  */
 package org.apache.solr.search;
 
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.HashSet;
+import java.util.Set;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
@@ -32,8 +33,10 @@ import org.apache.solr.uninverting.UninvertingReader;
 public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
 
   private boolean disableEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryList");
+  private boolean disableJmxEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryListJmx");
 
-  private MetricsMap metricsMap;
+  private MetricRegistry registry;
+  private Set<String> metricNames = new HashSet<>();
 
   @Override
   public String getName() { return this.getClass().getName(); }
@@ -42,13 +45,21 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
     return "Provides introspection of the Solr FieldCache ";
   }
   @Override
-  public Category getCategory() { return Category.CACHE; } 
+  public Category getCategory() { return Category.CACHE; }
+  @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    metricsMap = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
-      if (detailed && !disableEntryList) {
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
+      if (detailed && !disableEntryList && !disableJmxEntryList) {
         UninvertingReader.FieldCacheStats fieldCacheStats = UninvertingReader.getUninvertedStats();
         String[] entries = fieldCacheStats.info;
         map.put("entries_count", entries.length);
@@ -60,8 +71,7 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
       } else {
         map.put("entries_count", UninvertingReader.getUninvertedStatsSize());
       }
-      return map;
-    };
-    manager.register(registry, metricsMap, true, "fieldCache", Category.CACHE.toString(), scope);
+    });
+    manager.register(this, registryName, metricsMap, true, "fieldCache", Category.CACHE.toString(), scope);
   }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index 1c30a6c..04e970c 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -38,6 +38,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
+import com.codahale.metrics.MetricRegistry;
 import com.google.common.collect.Iterables;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.TokenStream;
@@ -84,6 +85,7 @@ import org.apache.solr.search.stats.StatsSource;
 import org.apache.solr.uninverting.UninvertingReader;
 import org.apache.solr.update.IndexFingerprint;
 import org.apache.solr.update.SolrIndexConfig;
+import org.apache.solr.util.stats.MetricUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -158,6 +160,8 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
   private final String path;
   private boolean releaseDirectory;
 
+  private Set<String> metricNames = new HashSet<>();
+
   private static DirectoryReader getReader(SolrCore core, SolrIndexConfig config, DirectoryFactory directoryFactory,
       String path) throws IOException {
     final Directory dir = directoryFactory.get(path, DirContext.DEFAULT, config.lockType);
@@ -2691,23 +2695,33 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
   }
 
   @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
   public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
 
-    manager.registerGauge(registry, () -> name, true, "searcherName", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> cachingEnabled, true, "caching", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> openTime, true, "openedAt", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> warmupTime, true, "warmupTime", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> registerTime, true, "registeredAt", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> name, true, "searcherName", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> cachingEnabled, true, "caching", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> openTime, true, "openedAt", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> warmupTime, true, "warmupTime", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> registerTime, true, "registeredAt", Category.SEARCHER.toString(), scope);
     // reader stats
-    manager.registerGauge(registry, () -> reader.numDocs(), true, "numDocs", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> reader.maxDoc(), true, "maxDoc", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> reader.maxDoc() - reader.numDocs(), true, "deletedDocs", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> reader.toString(), true, "reader", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> reader.directory().toString(), true, "readerDir", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(registry, () -> reader.getVersion(), true, "indexVersion", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> reader.numDocs(), true, "numDocs", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> reader.maxDoc(), true, "maxDoc", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> reader.maxDoc() - reader.numDocs(), true, "deletedDocs", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> reader.toString(), true, "reader", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> reader.directory().toString(), true, "readerDir", Category.SEARCHER.toString(), scope);
+    manager.registerGauge(this, registry, () -> reader.getVersion(), true, "indexVersion", Category.SEARCHER.toString(), scope);
 
   }
 
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return core.getMetricRegistry();
+  }
+
   private static class FilterImpl extends Filter {
     private final Filter topFilter;
     private final List<Weight> weights;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java b/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
index f00169a..b8b9bea 100644
--- a/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
+++ b/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
@@ -16,10 +16,11 @@
  */
 package org.apache.solr.store.blockcache;
 
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
@@ -53,13 +54,15 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
   public AtomicLong shardBuffercacheLost = new AtomicLong(0);
 
   private MetricsMap metricsMap;
+  private MetricRegistry registry;
+  private Set<String> metricNames = new HashSet<>();
 
   private long previous = System.nanoTime();
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    metricsMap = detailed -> {
-      Map<String,Object> map = new ConcurrentHashMap<>();
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    metricsMap = new MetricsMap((detailed, map) -> {
       long now = System.nanoTime();
       long delta = Math.max(now - previous, 1);
       double seconds = delta / 1000000000.0;
@@ -101,9 +104,8 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
 
       previous = now;
 
-      return map;
-    };
-    manager.registerGauge(registry, metricsMap, true, getName(), getCategory().toString(), scope);
+    });
+    manager.registerGauge(this, registryName, metricsMap, true, getName(), getCategory().toString(), scope);
   }
 
   private float getPerSecond(long value, double seconds) {
@@ -122,4 +124,14 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
     return "Provides metrics for the HdfsDirectoryFactory BlockCache.";
   }
 
+  @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java b/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
index 9135c5c..64e6356 100644
--- a/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
+++ b/solr/core/src/java/org/apache/solr/store/hdfs/HdfsLocalityReporter.java
@@ -19,6 +19,7 @@ package org.apache.solr.store.hdfs;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -26,6 +27,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import com.codahale.metrics.MetricRegistry;
 import org.apache.hadoop.fs.BlockLocation;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
@@ -49,6 +51,9 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
   private String hostname;
   private final ConcurrentMap<HdfsDirectory,ConcurrentMap<FileStatus,BlockLocation[]>> cache;
 
+  private final Set<String> metricNames = new HashSet<>();
+  private MetricRegistry registry;
+
   public HdfsLocalityReporter() {
     cache = new ConcurrentHashMap<>();
   }
@@ -76,13 +81,23 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
     return Category.OTHER;
   }
 
+  @Override
+  public Set<String> getMetricNames() {
+    return metricNames;
+  }
+
+  @Override
+  public MetricRegistry getMetricRegistry() {
+    return registry;
+  }
+
   /**
    * Provide statistics on HDFS block locality, both in terms of bytes and block counts.
    */
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    MetricsMap metricsMap = detailed -> {
-      Map<String, Object> map = new ConcurrentHashMap<>();
+  public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+    registry = manager.registry(registryName);
+    MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
       long totalBytes = 0;
       long localBytes = 0;
       int totalCount = 0;
@@ -130,9 +145,8 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
       } else {
         map.put(LOCALITY_BLOCKS_RATIO, localCount / (double) totalCount);
       }
-      return map;
-    };
-    manager.registerGauge(registry, metricsMap, true, "hdfsLocality", getCategory().toString(), scope);
+    });
+    manager.registerGauge(this, registryName, metricsMap, true, "hdfsLocality", getCategory().toString(), scope);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
index 9d0983e..4ef91e4 100644
--- a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
+++ b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
@@ -159,40 +159,40 @@ public class DirectUpdateHandler2 extends UpdateHandler implements SolrCoreState
 
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    commitCommands = manager.meter(registry, "commits", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> commitTracker.getCommitCount(), true, "autoCommits", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> softCommitTracker.getCommitCount(), true, "softAutoCommits", getCategory().toString(), scope);
+    commitCommands = manager.meter(this, registry, "commits", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> commitTracker.getCommitCount(), true, "autoCommits", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> softCommitTracker.getCommitCount(), true, "softAutoCommits", getCategory().toString(), scope);
     if (commitTracker.getDocsUpperBound() > 0) {
-      manager.registerGauge(registry, () -> commitTracker.getDocsUpperBound(), true, "autoCommitMaxDocs",
+      manager.registerGauge(this, registry, () -> commitTracker.getDocsUpperBound(), true, "autoCommitMaxDocs",
           getCategory().toString(), scope);
     }
     if (commitTracker.getTimeUpperBound() > 0) {
-      manager.registerGauge(registry, () -> "" + commitTracker.getTimeUpperBound() + "ms", true, "autoCommitMaxTime",
+      manager.registerGauge(this, registry, () -> "" + commitTracker.getTimeUpperBound() + "ms", true, "autoCommitMaxTime",
           getCategory().toString(), scope);
     }
     if (softCommitTracker.getDocsUpperBound() > 0) {
-      manager.registerGauge(registry, () -> softCommitTracker.getDocsUpperBound(), true, "softAutoCommitMaxDocs",
+      manager.registerGauge(this, registry, () -> softCommitTracker.getDocsUpperBound(), true, "softAutoCommitMaxDocs",
           getCategory().toString(), scope);
     }
     if (softCommitTracker.getTimeUpperBound() > 0) {
-      manager.registerGauge(registry, () -> "" + softCommitTracker.getTimeUpperBound() + "ms", true, "softAutoCommitMaxTime",
+      manager.registerGauge(this, registry, () -> "" + softCommitTracker.getTimeUpperBound() + "ms", true, "softAutoCommitMaxTime",
           getCategory().toString(), scope);
     }
-    optimizeCommands = manager.meter(registry, "optimizes", getCategory().toString(), scope);
-    rollbackCommands = manager.meter(registry, "rollbacks", getCategory().toString(), scope);
-    splitCommands = manager.meter(registry, "splits", getCategory().toString(), scope);
-    mergeIndexesCommands = manager.meter(registry, "merges", getCategory().toString(), scope);
-    expungeDeleteCommands = manager.meter(registry, "expungeDeletes", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> numDocsPending.longValue(), true, "docsPending", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> addCommands.longValue(), true, "adds", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> deleteByIdCommands.longValue(), true, "deletesById", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> deleteByQueryCommands.longValue(), true, "deletesByQuery", getCategory().toString(), scope);
-    manager.registerGauge(registry, () -> numErrors.longValue(), true, "errors", getCategory().toString(), scope);
-
-    addCommandsCumulative = manager.meter(registry, "cumulativeAdds", getCategory().toString(), scope);
-    deleteByIdCommandsCumulative = manager.meter(registry, "cumulativeDeletesById", getCategory().toString(), scope);
-    deleteByQueryCommandsCumulative = manager.meter(registry, "cumulativeDeletesByQuery", getCategory().toString(), scope);
-    numErrorsCumulative = manager.meter(registry, "cumulativeErrors", getCategory().toString(), scope);
+    optimizeCommands = manager.meter(this, registry, "optimizes", getCategory().toString(), scope);
+    rollbackCommands = manager.meter(this, registry, "rollbacks", getCategory().toString(), scope);
+    splitCommands = manager.meter(this, registry, "splits", getCategory().toString(), scope);
+    mergeIndexesCommands = manager.meter(this, registry, "merges", getCategory().toString(), scope);
+    expungeDeleteCommands = manager.meter(this, registry, "expungeDeletes", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> numDocsPending.longValue(), true, "docsPending", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> addCommands.longValue(), true, "adds", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> deleteByIdCommands.longValue(), true, "deletesById", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> deleteByQueryCommands.longValue(), true, "deletesByQuery", getCategory().toString(), scope);
+    manager.registerGauge(this, registry, () -> numErrors.longValue(), true, "errors", getCategory().toString(), scope);
+
+    addCommandsCumulative = manager.meter(this, registry, "cumulativeAdds", getCategory().toString(), scope);
+    deleteByIdCommandsCumulative = manager.meter(this, registry, "cumulativeDeletesById", getCategory().toString(), scope);
+    deleteByQueryCommandsCumulative = manager.meter(this, registry, "cumulativeDeletesByQuery", getCategory().toString(), scope);
+    numErrorsCumulative = manager.meter(this, registry, "cumulativeErrors", getCategory().toString(), scope);
   }
 
   private void deleteAll() throws IOException {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5be37efa/solr/core/src/java/org/apache/solr/update/PeerSync.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/PeerSync.java b/solr/core/src/java/org/apache/solr/update/PeerSync.java
index 171a3e6..f599844 100644
--- a/solr/core/src/java/org/apache/solr/update/PeerSync.java
+++ b/solr/core/src/java/org/apache/solr/update/PeerSync.java
@@ -167,9 +167,9 @@ public class PeerSync implements SolrMetricProducer {
 
   @Override
   public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
-    syncTime = manager.timer(registry, "time", scope, METRIC_SCOPE);
-    syncErrors = manager.counter(registry, "errors", scope, METRIC_SCOPE);
-    syncSkipped = manager.counter(registry, "skipped", scope, METRIC_SCOPE);
+    syncTime = manager.timer(null, registry, "time", scope, METRIC_SCOPE);
+    syncErrors = manager.counter(null, registry, "errors", scope, METRIC_SCOPE);
+    syncSkipped = manager.counter(null, registry, "skipped", scope, METRIC_SCOPE);
   }
 
   /** optional list of updates we had before possibly receiving new updates */


Mime
View raw message