You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2019/10/16 16:10:13 UTC

[lucene-solr] 02/02: SOLR-13677: API refactoring, cleanup.

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

ab pushed a commit to branch jira/solr-13677-final
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit b541fa373720369e6c038ed261ce6e1575022bf2
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Wed Oct 16 17:59:58 2019 +0200

    SOLR-13677: API refactoring, cleanup.
---
 .../solr/handler/dataimport/DataImportHandler.java |  6 +-
 .../java/org/apache/solr/core/CoreContainer.java   | 77 ++++++++++++----------
 .../org/apache/solr/core/HdfsDirectoryFactory.java | 14 +++-
 .../src/java/org/apache/solr/core/SolrCore.java    | 70 +++++++++++---------
 .../apache/solr/handler/ReplicationHandler.java    | 24 +++----
 .../apache/solr/handler/RequestHandlerBase.java    | 24 +++----
 .../solr/handler/admin/CoreAdminHandler.java       |  8 +--
 .../solr/handler/component/SuggestComponent.java   |  6 +-
 .../apache/solr/metrics/SolrCoreMetricManager.java | 47 +++++++------
 .../org/apache/solr/metrics/SolrMetricManager.java |  4 +-
 .../apache/solr/metrics/SolrMetricProducer.java    | 33 +++++++---
 .../apache/solr/metrics/SolrMetricsContext.java    | 30 +++------
 .../java/org/apache/solr/search/CaffeineCache.java | 16 +++--
 .../java/org/apache/solr/search/FastLRUCache.java  | 14 ++--
 .../src/java/org/apache/solr/search/LFUCache.java  | 13 ++--
 .../src/java/org/apache/solr/search/LRUCache.java  | 11 ++--
 .../org/apache/solr/search/SolrCacheHolder.java    |  4 +-
 .../org/apache/solr/search/SolrFieldCacheBean.java | 16 +++--
 .../org/apache/solr/search/SolrIndexSearcher.java  | 53 ++++++++-------
 .../apache/solr/security/AuthenticationPlugin.java | 24 ++++---
 .../apache/solr/servlet/SolrDispatchFilter.java    |  2 +-
 .../org/apache/solr/store/blockcache/Metrics.java  | 19 +++---
 .../solr/store/hdfs/HdfsLocalityReporter.java      | 20 +++---
 .../org/apache/solr/update/SolrIndexWriter.java    | 38 ++++++-----
 .../org/apache/solr/update/UpdateShardHandler.java |  9 +--
 .../stats/InstrumentedHttpListenerFactory.java     | 15 ++---
 ...rumentedPoolingHttpClientConnectionManager.java | 30 +++++----
 .../solr/handler/admin/MetricsHandlerTest.java     |  8 +--
 28 files changed, 340 insertions(+), 295 deletions(-)

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 3d5c4d5..8e1b8aa 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
@@ -275,8 +275,8 @@ public class DataImportHandler extends RequestHandlerBase implements
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext m) {
-    super.initializeMetrics(m);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    super.initializeMetrics(m, scope);
     metrics = new MetricsMap((detailed, map) -> {
       if (importer != null) {
         DocBuilder.Statistics cumulative = importer.cumulativeStatistics;
@@ -299,7 +299,7 @@ public class DataImportHandler extends RequestHandlerBase implements
         map.put(DataImporter.MSG.TOTAL_DOCS_SKIPPED, cumulative.skipDocCount);
       }
     });
-    solrMetricsContext.gauge(this, metrics, true, "importer", getCategory().toString());
+    solrMetricsContext.gauge(this, metrics, true, "importer", getCategory().toString(), scope);
   }
 
   // //////////////////////SolrInfoMBeans methods //////////////////////
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 054bd67..d4ac97a 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -100,6 +100,7 @@ import org.apache.solr.logging.MDCLoggingContext;
 import org.apache.solr.metrics.SolrCoreMetricManager;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.request.SolrRequestInfo;
 import org.apache.solr.search.SolrFieldCacheBean;
@@ -210,7 +211,9 @@ public class CoreContainer {
 
   protected volatile SolrMetricManager metricManager;
 
-  protected volatile String metricTag = Integer.toHexString(hashCode());
+  protected volatile String metricTag = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
+
+  protected volatile SolrMetricsContext solrMetricsContext;
 
   protected MetricsHandler metricsHandler;
 
@@ -612,6 +615,8 @@ public class CoreContainer {
     containerHandlers.getApiBag().register(new AnnotatedApi(packageStoreAPI.writeAPI), Collections.EMPTY_MAP);
 
     metricManager = new SolrMetricManager(loader, cfg.getMetricsConfig());
+    String registryName = SolrMetricManager.getRegistryName(SolrInfoBean.Group.node);
+    solrMetricsContext = new SolrMetricsContext(metricManager, registryName, metricTag);
 
     coreContainerWorkExecutor = MetricUtils.instrumentedExecutorService(
         coreContainerWorkExecutor, null,
@@ -625,7 +630,7 @@ public class CoreContainer {
     }
 
     updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig());
-    updateShardHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, "updateShardHandler");
+    updateShardHandler.initializeMetrics(solrMetricsContext, "updateShardHandler");
 
     solrCores.load(loader);
 
@@ -638,7 +643,7 @@ public class CoreContainer {
     if (isZooKeeperAware()) {
       pkiAuthenticationPlugin = new PKIAuthenticationPlugin(this, zkSys.getZkController().getNodeName(),
           (PublicKeyHandler) containerHandlers.get(PublicKeyHandler.PATH));
-      pkiAuthenticationPlugin.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, "/authentication/pki");
+      pkiAuthenticationPlugin.initializeMetrics(solrMetricsContext, "/authentication/pki");
       TracerConfigurator.loadTracer(loader, cfg.getTracerConfiguratorPluginInfo(), getZkController().getZkStateReader());
     }
 
@@ -668,7 +673,7 @@ public class CoreContainer {
     metricsCollectorHandler.init(null);
 
     containerHandlers.put(AUTHZ_PATH, securityConfHandler);
-    securityConfHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, AUTHZ_PATH);
+    securityConfHandler.initializeMetrics(solrMetricsContext, AUTHZ_PATH);
     containerHandlers.put(AUTHC_PATH, securityConfHandler);
 
 
@@ -683,22 +688,20 @@ public class CoreContainer {
 
     // initialize gauges for reporting the number of cores and disk total/free
 
-    String registryName = SolrMetricManager.getRegistryName(SolrInfoBean.Group.node);
-    String metricTag = Integer.toHexString(hashCode());
-    metricManager.registerGauge(null, registryName, () -> solrCores.getCores().size(),
-        metricTag, true, "loaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
-    metricManager.registerGauge(null, registryName, () -> solrCores.getLoadedCoreNames().size() - solrCores.getCores().size(),
-        metricTag, true, "lazy", SolrInfoBean.Category.CONTAINER.toString(), "cores");
-    metricManager.registerGauge(null, registryName, () -> solrCores.getAllCoreNames().size() - solrCores.getLoadedCoreNames().size(),
-        metricTag, true, "unloaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
+    solrMetricsContext.gauge(null, () -> solrCores.getCores().size(),
+        true, "loaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
+    solrMetricsContext.gauge(null, () -> solrCores.getLoadedCoreNames().size() - solrCores.getCores().size(),
+        true, "lazy", SolrInfoBean.Category.CONTAINER.toString(), "cores");
+    solrMetricsContext.gauge(null, () -> solrCores.getAllCoreNames().size() - solrCores.getLoadedCoreNames().size(),
+        true, "unloaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
     Path dataHome = cfg.getSolrDataHome() != null ? cfg.getSolrDataHome() : cfg.getCoreRootDirectory();
-    metricManager.registerGauge(null, registryName, () -> dataHome.toFile().getTotalSpace(),
-        metricTag, true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
-    metricManager.registerGauge(null, registryName, () -> dataHome.toFile().getUsableSpace(),
-        metricTag, true, "usableSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
-    metricManager.registerGauge(null, registryName, () -> dataHome.toAbsolutePath().toString(),
-        metricTag, true, "path", SolrInfoBean.Category.CONTAINER.toString(), "fs");
-    metricManager.registerGauge(null, registryName, () -> {
+    solrMetricsContext.gauge(null, () -> dataHome.toFile().getTotalSpace(),
+        true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
+    solrMetricsContext.gauge(null, () -> dataHome.toFile().getUsableSpace(),
+        true, "usableSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
+    solrMetricsContext.gauge(null, () -> dataHome.toAbsolutePath().toString(),
+        true, "path", SolrInfoBean.Category.CONTAINER.toString(), "fs");
+    solrMetricsContext.gauge(null, () -> {
           try {
             return org.apache.lucene.util.IOUtils.spins(dataHome.toAbsolutePath());
           } catch (IOException e) {
@@ -706,14 +709,14 @@ public class CoreContainer {
             return true;
           }
         },
-        metricTag, true, "spins", SolrInfoBean.Category.CONTAINER.toString(), "fs");
-    metricManager.registerGauge(null, registryName, () -> cfg.getCoreRootDirectory().toFile().getTotalSpace(),
-        metricTag, true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
-    metricManager.registerGauge(null, registryName, () -> cfg.getCoreRootDirectory().toFile().getUsableSpace(),
-        metricTag, true, "usableSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
-    metricManager.registerGauge(null, registryName, () -> cfg.getCoreRootDirectory().toAbsolutePath().toString(),
-        metricTag, true, "path", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
-    metricManager.registerGauge(null, registryName, () -> {
+        true, "spins", SolrInfoBean.Category.CONTAINER.toString(), "fs");
+    solrMetricsContext.gauge(null, () -> cfg.getCoreRootDirectory().toFile().getTotalSpace(),
+        true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
+    solrMetricsContext.gauge(null, () -> cfg.getCoreRootDirectory().toFile().getUsableSpace(),
+        true, "usableSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
+    solrMetricsContext.gauge(null, () -> cfg.getCoreRootDirectory().toAbsolutePath().toString(),
+        true, "path", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
+    solrMetricsContext.gauge(null, () -> {
           try {
             return org.apache.lucene.util.IOUtils.spins(cfg.getCoreRootDirectory().toAbsolutePath());
           } catch (IOException e) {
@@ -721,15 +724,15 @@ public class CoreContainer {
             return true;
           }
         },
-        metricTag, true, "spins", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
+        true, "spins", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
     // add version information
-    metricManager.registerGauge(null, registryName, () -> this.getClass().getPackage().getSpecificationVersion(),
-        metricTag, true, "specification", SolrInfoBean.Category.CONTAINER.toString(), "version");
-    metricManager.registerGauge(null, registryName, () -> this.getClass().getPackage().getImplementationVersion(),
-        metricTag, true, "implementation", SolrInfoBean.Category.CONTAINER.toString(), "version");
+    solrMetricsContext.gauge(null, () -> this.getClass().getPackage().getSpecificationVersion(),
+        true, "specification", SolrInfoBean.Category.CONTAINER.toString(), "version");
+    solrMetricsContext.gauge(null, () -> this.getClass().getPackage().getImplementationVersion(),
+        true, "implementation", SolrInfoBean.Category.CONTAINER.toString(), "version");
 
     SolrFieldCacheBean fieldCacheBean = new SolrFieldCacheBean();
-    fieldCacheBean.initializeMetrics(metricManager, registryName, metricTag, null);
+    fieldCacheBean.initializeMetrics(solrMetricsContext, null);
 
     if (isZooKeeperAware()) {
       metricManager.loadClusterReporters(metricReporters, this);
@@ -818,7 +821,7 @@ public class CoreContainer {
       // initialize this handler here when SolrCloudManager is ready
       autoScalingHandler = new AutoScalingHandler(getZkController().getSolrCloudManager(), loader);
       containerHandlers.put(AutoScalingHandler.HANDLER_PATH, autoScalingHandler);
-      autoScalingHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, AutoScalingHandler.HANDLER_PATH);
+      autoScalingHandler.initializeMetrics(solrMetricsContext, AutoScalingHandler.HANDLER_PATH);
     }
     // This is a bit redundant but these are two distinct concepts for all they're accomplished at the same time.
     status |= LOAD_COMPLETE | INITIAL_CORE_LOAD_COMPLETE;
@@ -866,7 +869,7 @@ public class CoreContainer {
     metricsHistoryHandler = new MetricsHistoryHandler(name, metricsHandler,
         client, cloudManager, initArgs);
     containerHandlers.put(METRICS_HISTORY_PATH, metricsHistoryHandler);
-    metricsHistoryHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, METRICS_HISTORY_PATH);
+    metricsHistoryHandler.initializeMetrics(solrMetricsContext, METRICS_HISTORY_PATH);
   }
 
   public void securityNodeChanged() {
@@ -1788,7 +1791,9 @@ public class CoreContainer {
       containerHandlers.put(path, (SolrRequestHandler) handler);
     }
     if (handler instanceof SolrMetricProducer) {
-      ((SolrMetricProducer) handler).initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, path);
+      // use deprecated method for back-compat, remove in 9.0
+      ((SolrMetricProducer) handler).initializeMetrics(solrMetricsContext.metricManager,
+          solrMetricsContext.registry, solrMetricsContext.tag, path);
     }
     return handler;
   }
diff --git a/solr/core/src/java/org/apache/solr/core/HdfsDirectoryFactory.java b/solr/core/src/java/org/apache/solr/core/HdfsDirectoryFactory.java
index 464b030..32010ba 100644
--- a/solr/core/src/java/org/apache/solr/core/HdfsDirectoryFactory.java
+++ b/solr/core/src/java/org/apache/solr/core/HdfsDirectoryFactory.java
@@ -55,6 +55,7 @@ import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.store.blockcache.BlockCache;
 import org.apache.solr.store.blockcache.BlockDirectory;
 import org.apache.solr.store.blockcache.BlockDirectoryCache;
@@ -141,6 +142,13 @@ public class HdfsDirectoryFactory extends CachingDirectoryFactory implements Sol
     }
     tmpFsCache.invalidateAll();
     tmpFsCache.cleanUp();
+    try {
+      SolrMetricProducer.super.close();
+      MetricsHolder.metrics.close();
+      LocalityHolder.reporter.close();
+    } catch (Exception e) {
+      throw new IOException(e);
+    }
   }
 
   private final static class LocalityHolder {
@@ -497,9 +505,9 @@ public class HdfsDirectoryFactory extends CachingDirectoryFactory implements Sol
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
-    MetricsHolder.metrics.initializeMetrics(manager, registry, tag, scope);
-    LocalityHolder.reporter.initializeMetrics(manager, registry, tag, scope);
+  public void initializeMetrics(SolrMetricsContext solrMetricsContext, String scope) {
+    MetricsHolder.metrics.initializeMetrics(solrMetricsContext, scope);
+    LocalityHolder.reporter.initializeMetrics(solrMetricsContext, scope);
   }
 
   @Override
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 9bfade2..4889f1a 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -110,6 +110,7 @@ import org.apache.solr.logging.MDCLoggingContext;
 import org.apache.solr.metrics.SolrCoreMetricManager;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.BinaryResponseWriter;
@@ -231,7 +232,8 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
   private final CoreContainer coreContainer;
 
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
-  private final String metricTag = getUniqueMetricTag(null);
+  private final String metricTag = SolrMetricProducer.getUniqueMetricTag(this, null);
+  private final SolrMetricsContext solrMetricsContext;
 
   public volatile boolean searchEnabled = true;
   public volatile boolean indexEnabled = true;
@@ -687,6 +689,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
   }
 
   private DirectoryFactory initDirectoryFactory() {
+    // XXX some factory implementations are also SolrMetricProducer-s
     return DirectoryFactory.loadDirectoryFactory(solrConfig, coreContainer, coreMetricManager.getRegistryName());
   }
 
@@ -919,6 +922,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
       this.configSetProperties = configSetProperties;
       // Initialize the metrics manager
       this.coreMetricManager = initCoreMetricManager(config);
+      solrMetricsContext = coreMetricManager.getSolrMetricsContext();
       this.coreMetricManager.loadReporters();
 
       if (updateHandler == null) {
@@ -940,15 +944,13 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
 
       checkVersionFieldExistsInSchema(schema, coreDescriptor);
 
-      SolrMetricManager metricManager = coreContainer.getMetricManager();
-
       // initialize searcher-related metrics
-      initializeMetrics(metricManager, coreMetricManager.getRegistryName(), metricTag, null);
+      initializeMetrics(solrMetricsContext, null);
 
       SolrFieldCacheBean solrFieldCacheBean = new SolrFieldCacheBean();
       // this is registered at the CONTAINER level because it's not core-specific - for now we
       // also register it here for back-compat
-      solrFieldCacheBean.initializeMetrics(metricManager, coreMetricManager.getRegistryName(), metricTag, "core");
+      solrFieldCacheBean.initializeMetrics(solrMetricsContext, "core");
       infoRegistry.put("fieldCache", solrFieldCacheBean);
 
       initSchema(config, schema);
@@ -1015,8 +1017,9 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
 
       // Allow the directory factory to report metrics
       if (directoryFactory instanceof SolrMetricProducer) {
-        ((SolrMetricProducer) directoryFactory).initializeMetrics(metricManager, coreMetricManager.getRegistryName(),
-            metricTag, "directoryFactory");
+        // XXX use deprecated method for back-compat, remove in 9.0
+        ((SolrMetricProducer) directoryFactory).initializeMetrics(
+            solrMetricsContext.metricManager, solrMetricsContext.registry, solrMetricsContext.tag, "directoryFactory");
       }
 
       // seed version buckets with max from index during core initialization ... requires a searcher!
@@ -1163,61 +1166,66 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
-    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, getMetricTag(), true, "coreName", Category.CORE.toString());
-    manager.registerGauge(this, registry, () -> startTime, getMetricTag(), true, "startTime", Category.CORE.toString());
-    manager.registerGauge(this, registry, () -> getOpenCount(), getMetricTag(), true, "refCount", Category.CORE.toString());
-    manager.registerGauge(this, registry, () -> resourceLoader.getInstancePath().toString(), getMetricTag(), true, "instanceDir", Category.CORE.toString());
-    manager.registerGauge(this, registry, () -> isClosed() ? "(closed)" : getIndexDir(), getMetricTag(), true, "indexDir", Category.CORE.toString());
-    manager.registerGauge(this, registry, () -> isClosed() ? 0 : getIndexSize(), getMetricTag(), true, "sizeInBytes", Category.INDEX.toString());
-    manager.registerGauge(this, registry, () -> isClosed() ? "(closed)" : NumberUtils.readableSize(getIndexSize()), getMetricTag(), true, "size", Category.INDEX.toString());
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    newSearcherCounter = m.counter(this, "new", Category.SEARCHER.toString());
+    newSearcherTimer = m.timer(this, "time", Category.SEARCHER.toString(), "new");
+    newSearcherWarmupTimer = m.timer(this, "warmup", Category.SEARCHER.toString(), "new");
+    newSearcherMaxReachedCounter = m.counter(this, "maxReached", Category.SEARCHER.toString(), "new");
+    newSearcherOtherErrorsCounter = m.counter(this, "errors", Category.SEARCHER.toString(), "new");
+
+    m.gauge(this, () -> name == null ? "(null)" : name, true, "coreName", Category.CORE.toString());
+    m.gauge(this, () -> startTime, true, "startTime", Category.CORE.toString());
+    m.gauge(this, () -> getOpenCount(), true, "refCount", Category.CORE.toString());
+    m.gauge(this, () -> resourceLoader.getInstancePath().toString(), true, "instanceDir", Category.CORE.toString());
+    m.gauge(this, () -> isClosed() ? "(closed)" : getIndexDir(), true, "indexDir", Category.CORE.toString());
+    m.gauge(this, () -> isClosed() ? 0 : getIndexSize(), true, "sizeInBytes", Category.INDEX.toString());
+    m.gauge(this, () -> isClosed() ? "(closed)" : NumberUtils.readableSize(getIndexSize()), true, "size", Category.INDEX.toString());
     if (coreContainer != null) {
-      manager.registerGauge(this, registry, () -> coreContainer.getNamesForCore(this), getMetricTag(), true, "aliases", Category.CORE.toString());
+      m.gauge(this, () -> coreContainer.getNamesForCore(this), true, "aliases", Category.CORE.toString());
       final CloudDescriptor cd = getCoreDescriptor().getCloudDescriptor();
       if (cd != null) {
-        manager.registerGauge(this, registry, () -> {
+        m.gauge(this, () -> {
           if (cd.getCollectionName() != null) {
             return cd.getCollectionName();
           } else {
             return "_notset_";
           }
-        }, getMetricTag(), true, "collection", Category.CORE.toString());
+        }, true, "collection", Category.CORE.toString());
 
-        manager.registerGauge(this, registry, () -> {
+        m.gauge(this, () -> {
           if (cd.getShardId() != null) {
             return cd.getShardId();
           } else {
             return "_auto_";
           }
-        }, getMetricTag(), true, "shard", Category.CORE.toString());
+        }, true, "shard", Category.CORE.toString());
       }
     }
     // initialize disk total / free metrics
     Path dataDirPath = Paths.get(dataDir);
     File dataDirFile = dataDirPath.toFile();
-    manager.registerGauge(this, registry, () -> dataDirFile.getTotalSpace(), getMetricTag(), true, "totalSpace", Category.CORE.toString(), "fs");
-    manager.registerGauge(this, registry, () -> dataDirFile.getUsableSpace(), getMetricTag(), true, "usableSpace", Category.CORE.toString(), "fs");
-    manager.registerGauge(this, registry, () -> dataDirPath.toAbsolutePath().toString(), getMetricTag(), true, "path", Category.CORE.toString(), "fs");
-    manager.registerGauge(this, registry, () -> {
+    m.gauge(this, () -> dataDirFile.getTotalSpace(), true, "totalSpace", Category.CORE.toString(), "fs");
+    m.gauge(this, () -> dataDirFile.getUsableSpace(), true, "usableSpace", Category.CORE.toString(), "fs");
+    m.gauge(this, () -> dataDirPath.toAbsolutePath().toString(), true, "path", Category.CORE.toString(), "fs");
+    m.gauge(this, () -> {
       try {
         return org.apache.lucene.util.IOUtils.spins(dataDirPath.toAbsolutePath());
       } catch (IOException e) {
         // default to spinning
         return true;
       }
-    }, getMetricTag(), true, "spins", Category.CORE.toString(), "fs");
+    }, true, "spins", Category.CORE.toString(), "fs");
   }
 
   public String getMetricTag() {
     return metricTag;
   }
 
+  @Override
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
+  }
+
   private void checkVersionFieldExistsInSchema(IndexSchema schema, CoreDescriptor coreDescriptor) {
     if (null != coreDescriptor.getCloudDescriptor()) {
       // we are evidently running in cloud mode.  
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 d78490a..69bc27e 100644
--- a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
@@ -863,20 +863,20 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext m) {
-    super.initializeMetrics(m);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    super.initializeMetrics(m, scope);
     solrMetricsContext.gauge(this,  () -> (core != null && !core.isClosed() ? NumberUtils.readableSize(core.getIndexSize()) : ""),
-        true, "indexSize", getCategory().toString());
+        true, "indexSize", getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> (core != null && !core.isClosed() ? getIndexVersion().toString() : ""),
-         true, "indexVersion", getCategory().toString());
+         true, "indexVersion", getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> (core != null && !core.isClosed() ? getIndexVersion().generation : 0),
-        true, GENERATION, getCategory().toString());
+        true, GENERATION, getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> (core != null && !core.isClosed() ? core.getIndexDir() : ""),
-        true, "indexPath", getCategory().toString());
+        true, "indexPath", getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> isMaster,
-         true, "isMaster", getCategory().toString());
+         true, "isMaster", getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> isSlave,
-         true, "isSlave", getCategory().toString());
+         true, "isSlave", getCategory().toString(), scope);
     final MetricsMap fetcherMap = new MetricsMap((detailed, map) -> {
       IndexFetcher fetcher = currentIndexFetcher;
       if (fetcher != null) {
@@ -905,13 +905,13 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
         addVal(map, IndexFetcher.CONF_FILES_REPLICATED, props, String.class);
       }
     });
-    solrMetricsContext.gauge(this , fetcherMap, true, "fetcher", getCategory().toString());
+    solrMetricsContext.gauge(this , fetcherMap, true, "fetcher", getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> isMaster && includeConfFiles != null ? includeConfFiles : "",
-         true, "confFilesToReplicate", getCategory().toString());
+         true, "confFilesToReplicate", getCategory().toString(), scope);
     solrMetricsContext.gauge(this, () -> isMaster ? getReplicateAfterStrings() : Collections.<String>emptyList(),
-        true, REPLICATE_AFTER, getCategory().toString());
+        true, REPLICATE_AFTER, getCategory().toString(), scope);
     solrMetricsContext.gauge(this,  () -> isMaster && replicationEnabled.get(),
-        true, "replicationEnabled", getCategory().toString());
+        true, "replicationEnabled", getCategory().toString(), scope);
   }
 
   //TODO Should a failure retrieving any piece of info mark the overall request as a failure?  Is there a core set of values that are required to make a response here useful?
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 9ea64b9..b744abf 100644
--- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
@@ -148,19 +148,19 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext m) {
-    this.solrMetricsContext = m.getChildInfo(this);
-    numErrors = solrMetricsContext.meter(this, "errors", getCategory().toString());
-    numServerErrors = solrMetricsContext.meter(this, "serverErrors", getCategory().toString());
-    numClientErrors = solrMetricsContext.meter(this, "clientErrors", getCategory().toString());
-    numTimeouts = solrMetricsContext.meter(this, "timeouts", getCategory().toString());
-    requests = solrMetricsContext.counter(this, "requests", getCategory().toString());
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    this.solrMetricsContext = m.getChildContext(this);
+    numErrors = solrMetricsContext.meter(this, "errors", getCategory().toString(), scope);
+    numServerErrors = solrMetricsContext.meter(this, "serverErrors", getCategory().toString(), scope);
+    numClientErrors = solrMetricsContext.meter(this, "clientErrors", getCategory().toString(), scope);
+    numTimeouts = solrMetricsContext.meter(this, "timeouts", getCategory().toString(), scope);
+    requests = solrMetricsContext.counter(this, "requests", getCategory().toString(), scope);
     MetricsMap metricsMap = new MetricsMap((detail, map) ->
         shardPurposes.forEach((k, v) -> map.put(k, v.getCount())));
-    solrMetricsContext.gauge(this, metricsMap, true, "shardRequests", getCategory().toString());
-    requestTimes = solrMetricsContext.timer(this,"requestTimes", getCategory().toString());
-    totalTime = solrMetricsContext.counter(this, "totalTime", getCategory().toString());
-    solrMetricsContext.gauge(this, () -> handlerStart, true, "handlerStart", getCategory().toString());
+    solrMetricsContext.gauge(this, metricsMap, true, "shardRequests", getCategory().toString(), scope);
+    requestTimes = solrMetricsContext.timer(this,"requestTimes", getCategory().toString(), scope);
+    totalTime = solrMetricsContext.counter(this, "totalTime", getCategory().toString(), scope);
+    solrMetricsContext.gauge(this, () -> handlerStart, true, "handlerStart", getCategory().toString(), scope);
   }
 
   public static SolrParams getSolrParamsFromNamedList(NamedList args, String key) {
@@ -276,7 +276,7 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return solrMetricsContext != null ? solrMetricsContext.getRegistry() : null;
+    return solrMetricsContext != null ? solrMetricsContext.getMetricRegistry() : null;
   }
 
   @Override
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 3808b91..5925cdb 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,10 +121,10 @@ public class CoreAdminHandler extends RequestHandlerBase implements PermissionNa
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext m) {
-    super.initializeMetrics(m);
-    parallelExecutor = MetricUtils.instrumentedExecutorService(parallelExecutor, this, solrMetricsContext.getRegistry(),
-        SolrMetricManager.mkName("parallelCoreAdminExecutor", getCategory().name(), solrMetricsContext.scope, "threadPool"));
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    super.initializeMetrics(m, scope);
+    parallelExecutor = MetricUtils.instrumentedExecutorService(parallelExecutor, this, solrMetricsContext.getMetricRegistry(),
+        SolrMetricManager.mkName("parallelCoreAdminExecutor", getCategory().name(), scope, "threadPool"));
   }
   @Override
   public Boolean registerV2() {
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 ca02867..e1cbe1b 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
@@ -355,8 +355,8 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext metricsContext) {
-    this.metricsContext = metricsContext.getChildInfo(this);
+  public void initializeMetrics(SolrMetricsContext metricsContext, String scope) {
+    this.metricsContext = metricsContext.getChildContext(this);
 
     this.metricsContext.gauge(this, () -> ramBytesUsed(), true, "totalSizeInBytes", getCategory().toString());
     MetricsMap suggestersMap = new MetricsMap((detailed, map) -> {
@@ -365,7 +365,7 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
         map.put(entry.getKey(), suggester.toString());
       }
     });
-    this.metricsContext.gauge(this, suggestersMap, true, "suggesters", getCategory().toString());
+    this.metricsContext.gauge(this, suggestersMap, true, "suggesters", getCategory().toString(), scope);
   }
 
   @Override
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
index c57a704..c318b8c 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
@@ -40,9 +40,8 @@ public class SolrCoreMetricManager implements Closeable {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   private final SolrCore core;
-  private final String tag;
-  private final SolrMetricManager metricManager;
-  private String registryName;
+  private SolrMetricsContext solrMetricsContext;
+  private SolrMetricManager metricManager;
   private String collectionName;
   private String shardName;
   private String replicaName;
@@ -56,10 +55,10 @@ public class SolrCoreMetricManager implements Closeable {
    */
   public SolrCoreMetricManager(SolrCore core) {
     this.core = core;
-    this.tag = core.getMetricTag();
-    this.metricManager = core.getCoreContainer().getMetricManager();
     initCloudMode();
-    registryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName());
+    metricManager = core.getCoreContainer().getMetricManager();
+    String registryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName());
+    solrMetricsContext = new SolrMetricsContext(metricManager, registryName, core.getMetricTag());
     leaderRegistryName = createLeaderRegistryName(cloudMode, collectionName, shardName);
   }
 
@@ -86,8 +85,8 @@ public class SolrCoreMetricManager implements Closeable {
     CoreContainer coreContainer = core.getCoreContainer();
     NodeConfig nodeConfig = coreContainer.getConfig();
     PluginInfo[] pluginInfos = nodeConfig.getMetricsConfig().getMetricReporters();
-    metricManager.loadReporters(pluginInfos, core.getResourceLoader(), coreContainer, core, tag,
-        SolrInfoBean.Group.core, registryName);
+    metricManager.loadReporters(pluginInfos, core.getResourceLoader(), coreContainer, core, solrMetricsContext.tag,
+        SolrInfoBean.Group.core, solrMetricsContext.registry);
     if (cloudMode) {
       metricManager.loadShardReporters(pluginInfos, core);
     }
@@ -99,19 +98,20 @@ public class SolrCoreMetricManager implements Closeable {
    * This method also reloads reporters so that they use the new core name.
    */
   public void afterCoreSetName() {
-    String oldRegistryName = registryName;
+    String oldRegistryName = solrMetricsContext.registry;
     String oldLeaderRegistryName = leaderRegistryName;
     initCloudMode();
-    registryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName());
+    String newRegistryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName());
     leaderRegistryName = createLeaderRegistryName(cloudMode, collectionName, shardName);
-    if (oldRegistryName.equals(registryName)) {
+    if (oldRegistryName.equals(newRegistryName)) {
       return;
     }
     // close old reporters
-    metricManager.closeReporters(oldRegistryName, tag);
+    metricManager.closeReporters(oldRegistryName, solrMetricsContext.tag);
     if (oldLeaderRegistryName != null) {
-      metricManager.closeReporters(oldLeaderRegistryName, tag);
+      metricManager.closeReporters(oldLeaderRegistryName, solrMetricsContext.tag);
     }
+    solrMetricsContext = new SolrMetricsContext(metricManager, newRegistryName, solrMetricsContext.tag);
     // load reporters again, using the new core name
     loadReporters();
   }
@@ -127,15 +127,16 @@ public class SolrCoreMetricManager implements Closeable {
       throw new IllegalArgumentException("registerMetricProducer() called with illegal arguments: " +
           "scope = " + scope + ", producer = " + producer);
     }
-    producer.initializeMetrics(metricManager, getRegistryName(), tag, scope);
+    // use deprecated method for back-compat, remove in 9.0
+    producer.initializeMetrics(solrMetricsContext.metricManager, solrMetricsContext.registry, solrMetricsContext.tag, scope);
   }
 
   /**
    * Return the registry used by this SolrCore.
    */
   public MetricRegistry getRegistry() {
-    if (registryName != null) {
-      return metricManager.registry(registryName);
+    if (solrMetricsContext != null) {
+      return solrMetricsContext.getMetricRegistry();
     } else {
       return null;
     }
@@ -146,11 +147,15 @@ public class SolrCoreMetricManager implements Closeable {
    */
   @Override
   public void close() throws IOException {
-    metricManager.closeReporters(getRegistryName(), tag);
+    metricManager.closeReporters(solrMetricsContext.registry, solrMetricsContext.tag);
     if (getLeaderRegistryName() != null) {
-      metricManager.closeReporters(getLeaderRegistryName(), tag);
+      metricManager.closeReporters(getLeaderRegistryName(), solrMetricsContext.tag);
     }
-    metricManager.unregisterGauges(getRegistryName(), tag);
+    metricManager.unregisterGauges(solrMetricsContext.registry, solrMetricsContext.tag);
+  }
+
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
   }
 
   public SolrCore getCore() {
@@ -175,7 +180,7 @@ public class SolrCoreMetricManager implements Closeable {
    * @return the metric registry name of the manager.
    */
   public String getRegistryName() {
-    return registryName;
+    return solrMetricsContext != null ? solrMetricsContext.registry : null;
   }
 
   /**
@@ -190,7 +195,7 @@ public class SolrCoreMetricManager implements Closeable {
    * Return a tag specific to this instance.
    */
   public String getTag() {
-    return tag;
+    return solrMetricsContext.tag;
   }
 
   public static String createRegistryName(boolean cloud, String collectionName, String shardName, String replicaName, String coreName) {
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 201dc08..977b0ca 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
@@ -735,7 +735,9 @@ public class SolrMetricManager {
       if (metric instanceof GaugeWrapper) {
         GaugeWrapper wrapper = (GaugeWrapper) metric;
         boolean toRemove = wrapper.getTag().contains(tagSegment);
-        if (toRemove) removed.incrementAndGet();
+        if (toRemove) {
+          removed.incrementAndGet();
+        }
         return toRemove;
       }
       return false;
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java
index 369cff6..77e2f60 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java
@@ -27,9 +27,11 @@ public interface SolrMetricProducer extends AutoCloseable {
    * A is the parent of B is the parent of C and so on.
    * If object "B" is unregistered C also must get unregistered.
    * If object "A" is unregistered B and C also must get unregistered.
+   * @param o object to create a tag for
+   * @param parentName parent object name, or null if no parent
    */
-  default String getUniqueMetricTag(String parentName) {
-    String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
+  static String getUniqueMetricTag(Object o, String parentName) {
+    String name = o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode());
     if (parentName != null && parentName.contains(name)) {
       throw new RuntimeException("Parent already includes this component? parent=" + parentName + ", this=" + name);
     }
@@ -50,15 +52,22 @@ public interface SolrMetricProducer extends AutoCloseable {
    *                 {@link #initializeMetrics(SolrMetricManager, String, String, String)} is called.
    * @param scope    scope of the metrics (eg. handler name) to separate metrics of components with
    *                 the same implementation but different scope
-   * @deprecated use {@link #initializeMetrics(SolrMetricsContext)} instead
+   * @deprecated use {@link #initializeMetrics(SolrMetricsContext, String)} instead
    */
+  @Deprecated
   default void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
-    initializeMetrics(new SolrMetricsContext(manager, registry, tag, scope));
+    initializeMetrics(new SolrMetricsContext(manager, registry, tag), scope);
 
   }
 
-  default void initializeMetrics(SolrMetricsContext context) {
-    throw new RuntimeException("You must implement either initializeMetrics(SolrMetricsContext) or " +
+  /**
+   * Initialize metrics specific to this producer.
+   * @param context
+   * @param scope
+   */
+  default void initializeMetrics(SolrMetricsContext context, String scope) {
+    throw new RuntimeException("In class " + getClass().getName() +
+        " you must implement either initializeMetrics(SolrMetricsContext, String) or " +
         "initializeMetrics(SolrMetricManager, String, String, String)");
 
   }
@@ -69,9 +78,13 @@ public interface SolrMetricProducer extends AutoCloseable {
 
   @Override
   default void close() throws Exception {
-    SolrMetricsContext info = getSolrMetricsContext();
-    if (info == null || info.tag.indexOf(':') == -1) return;//this will end up unregistering the root itself
-    info.unregister();
+    SolrMetricsContext context = getSolrMetricsContext();
+    if (context == null) {
+      return;
+    } else {
+      context.unregister();
+    }
+    // ??? (ab) no idea what this was supposed to avoid
+    //if (info == null || info.tag.indexOf(':') == -1) return;//this will end up unregistering the root itself
   }
-
 }
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java
index 3cb2554..8c3eb97 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java
@@ -33,13 +33,11 @@ public class SolrMetricsContext {
   public final String registry;
   public final SolrMetricManager metricManager;
   public final String tag;
-  public final String scope;
 
-  public SolrMetricsContext(SolrMetricManager metricManager, String registry, String tag, String scope) {
+  public SolrMetricsContext(SolrMetricManager metricManager, String registry, String tag) {
     this.registry = registry;
     this.metricManager = metricManager;
     this.tag = tag;
-    this.scope = scope;
   }
 
   public String getTag() {
@@ -50,40 +48,30 @@ public class SolrMetricsContext {
     metricManager.unregisterGauges(registry, tag);
   }
 
-  public SolrMetricsContext getChildInfo(SolrMetricProducer producer) {
-    SolrMetricsContext metricsInfo = new SolrMetricsContext(metricManager, registry, producer.getUniqueMetricTag(tag), scope);
-    return metricsInfo;
+  public SolrMetricsContext getChildContext(Object child) {
+    SolrMetricsContext childContext = new SolrMetricsContext(metricManager, registry, SolrMetricProducer.getUniqueMetricTag(child, tag));
+    return childContext;
   }
 
   public Meter meter(SolrInfoBean info, String metricName, String... metricpath) {
-    return metricManager.meter(info, registry, createName(metricName, metricpath));
-  }
-
-  // adds the scope
-  private String createName(String metricName, String... metricpath) {
-    ArrayList<String> l = new ArrayList<>();
-    if(metricpath != null ) {
-      Collections.addAll(l, metricpath);
-    }
-    l.add(scope);
-    return makeName(l, metricName);
+    return metricManager.meter(info, registry, metricName, metricpath);
   }
 
   public Counter counter(SolrInfoBean info, String metricName, String... metricpath) {
-    return metricManager.counter(info, registry, createName(metricName, metricpath));
+    return metricManager.counter(info, registry, metricName, metricpath);
 
   }
 
   public void gauge(SolrInfoBean info, Gauge<?> gauge, boolean force, String metricName, String... metricpath) {
-    metricManager.registerGauge(info, registry, gauge, tag, force, createName(metricName, metricpath));
+    metricManager.registerGauge(info, registry, gauge, tag, force, metricName, metricpath);
   }
 
   public Timer timer(SolrInfoBean info, String metricName, String... metricpath) {
-    return metricManager.timer(info, registry, createName(metricName, metricpath));
+    return metricManager.timer(info, registry, metricName, metricpath);
 
   }
 
-  public MetricRegistry getRegistry() {
+  public MetricRegistry getMetricRegistry() {
     return metricManager.registry(registry);
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/search/CaffeineCache.java b/solr/core/src/java/org/apache/solr/search/CaffeineCache.java
index 8e66eb8..bbcb93f 100644
--- a/solr/core/src/java/org/apache/solr/search/CaffeineCache.java
+++ b/solr/core/src/java/org/apache/solr/search/CaffeineCache.java
@@ -39,6 +39,7 @@ import org.apache.lucene.util.RamUsageEstimator;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -88,7 +89,7 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
 
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
   private MetricsMap cacheMap;
-  private MetricRegistry registry;
+  private SolrMetricsContext solrMetricsContext;
 
   private long initialRamBytes = 0;
   private final LongAdder ramBytes = new LongAdder();
@@ -324,7 +325,12 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return registry;
+    return solrMetricsContext != null ? solrMetricsContext.getMetricRegistry() : null;
+  }
+
+  @Override
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
   }
 
   @Override
@@ -338,8 +344,8 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    registry = manager.registry(registryName);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    solrMetricsContext = m.getChildContext(this);
     cacheMap = new MetricsMap((detailed, map) -> {
       if (cache != null) {
         CacheStats stats = cache.stats();
@@ -363,6 +369,6 @@ public class CaffeineCache<K, V> extends SolrCacheBase implements SolrCache<K, V
         map.put("cumulative_evictions", cumulativeStats.evictionCount());
       }
     });
-    manager.registerGauge(this, registryName, cacheMap, tag, true, scope, getCategory().toString());
+    solrMetricsContext.gauge(this, cacheMap, true, scope, getCategory().toString());
   }
 }
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 414389b..35b8dd1 100644
--- a/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
@@ -29,7 +29,6 @@ import org.apache.lucene.util.Accountable;
 import org.apache.lucene.util.RamUsageEstimator;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.metrics.MetricsMap;
-import org.apache.solr.metrics.SolrMetricProducer;
 import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.util.ConcurrentLRUCache;
 import org.slf4j.Logger;
@@ -75,6 +74,7 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K, V>
 
   private MetricsMap cacheMap;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
+  private SolrMetricsContext solrMetricsContext;
 
   @Override
   public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
@@ -310,17 +310,15 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K, V>
   }
 
 
-  SolrMetricsContext metricsInfo;
-
   @Override
   public SolrMetricsContext getSolrMetricsContext() {
-    return metricsInfo;
+    return solrMetricsContext;
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext metricsInfo) {
-    this.metricsInfo = metricsInfo;
-    metricsInfo.metricManager.registerGauge(this, metricsInfo.registry, cacheMap, metricsInfo.tag, true, metricsInfo.scope, getCategory().toString());
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    this.solrMetricsContext = m.getChildContext(this);
+    this.solrMetricsContext.gauge(this, cacheMap, true, scope, getCategory().toString());
   }
 
   // for unit tests only
@@ -330,7 +328,7 @@ public class FastLRUCache<K, V> extends SolrCacheBase implements SolrCache<K, V>
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return metricsInfo == null ? null : metricsInfo.getRegistry();
+    return solrMetricsContext == null ? null : solrMetricsContext.getMetricRegistry();
   }
 
   @Override
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 13e02e4..f3800da 100644
--- a/solr/core/src/java/org/apache/solr/search/LFUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LFUCache.java
@@ -79,6 +79,8 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
   private int maxIdleTimeSec;
   private MetricsMap cacheMap;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
+  private SolrMetricsContext solrMetricsContext;
+
 
   private int maxSize;
   private int minSizeLimit;
@@ -262,17 +264,14 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
     return "0." + hundredths;
   }
 
-
-  private SolrMetricsContext solrMetricsContext;
-
   @Override
   public SolrMetricsContext getSolrMetricsContext() {
     return solrMetricsContext;
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext info) {
-    solrMetricsContext = info.getChildInfo(this);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    solrMetricsContext = m.getChildContext(this);
     cacheMap = new MetricsMap((detailed, map) -> {
       if (cache != null) {
         ConcurrentLFUCache.Stats stats = cache.getStats();
@@ -338,7 +337,7 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
 
       }
     });
-    solrMetricsContext.metricManager.registerGauge(this, solrMetricsContext.registry, cacheMap, solrMetricsContext.getTag(), true, solrMetricsContext.scope, getCategory().toString());
+    solrMetricsContext.gauge(this, cacheMap, true, scope, getCategory().toString());
   }
 
   // for unit tests only
@@ -353,7 +352,7 @@ public class LFUCache<K, V> implements SolrCache<K, V>, Accountable {
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return solrMetricsContext == null ? null : solrMetricsContext.getRegistry();
+    return solrMetricsContext == null ? null : solrMetricsContext.getMetricRegistry();
 
   }
 
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 c8c5cdd..5755fdb 100644
--- a/solr/core/src/java/org/apache/solr/search/LRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LRUCache.java
@@ -77,6 +77,7 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
   private String description="LRU Cache";
   private MetricsMap cacheMap;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
+  private SolrMetricsContext solrMetricsContext;
   private int maxSize;
   private int initialSize;
 
@@ -395,16 +396,14 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
     return metricNames;
   }
 
-  SolrMetricsContext solrMetricsContext;
-
   @Override
   public SolrMetricsContext getSolrMetricsContext() {
     return solrMetricsContext;
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext m) {
-    solrMetricsContext = m.getChildInfo(this);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    solrMetricsContext = m.getChildContext(this);
     cacheMap = new MetricsMap((detailed, res) -> {
       synchronized (map) {
         res.put(LOOKUPS_PARAM, lookups);
@@ -433,7 +432,7 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
       res.put("cumulative_evictionsRamUsage", stats.evictionsRamUsage.longValue());
       res.put("cumulative_evictionsIdleTime", stats.evictionsIdleTime.longValue());
     });
-    solrMetricsContext.metricManager.registerGauge(this, solrMetricsContext.registry, cacheMap, solrMetricsContext.tag, true, solrMetricsContext.scope, getCategory().toString());
+    solrMetricsContext.gauge(this, cacheMap, true, scope, getCategory().toString());
   }
 
   // for unit tests only
@@ -443,7 +442,7 @@ public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V>, Acco
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return solrMetricsContext ==null ?null: solrMetricsContext.getRegistry();
+    return solrMetricsContext ==null ?null: solrMetricsContext.getMetricRegistry();
   }
 
   @Override
diff --git a/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java b/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java
index d0d9293..149c9ef 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrCacheHolder.java
@@ -141,8 +141,8 @@ public class SolrCacheHolder<K, V> implements SolrCache<K,V> {
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext info) {
-    delegate.initializeMetrics(info);
+  public void initializeMetrics(SolrMetricsContext context, String scope) {
+    delegate.initializeMetrics(context, scope);
   }
 
 }
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 b2647cd..0db6e88 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
@@ -24,6 +24,7 @@ import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.uninverting.UninvertingReader;
 
 /**
@@ -35,7 +36,7 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
   private boolean disableEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryList");
   private boolean disableJmxEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryListJmx");
 
-  private MetricRegistry registry;
+  private SolrMetricsContext solrMetricsContext;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
 
   @Override
@@ -52,12 +53,17 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
   }
   @Override
   public MetricRegistry getMetricRegistry() {
-    return registry;
+    return solrMetricsContext != null ? solrMetricsContext.getMetricRegistry() : null;
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    registry = manager.registry(registryName);
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
+  }
+
+  @Override
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    this.solrMetricsContext = m;
     MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
       if (detailed && !disableEntryList && !disableJmxEntryList) {
         UninvertingReader.FieldCacheStats fieldCacheStats = UninvertingReader.getUninvertedStats();
@@ -72,6 +78,6 @@ public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
         map.put("entries_count", UninvertingReader.getUninvertedStatsSize());
       }
     });
-    manager.registerGauge(this, registryName, metricsMap, tag, true, "fieldCache", Category.CACHE.toString(), scope);
+    solrMetricsContext.gauge(this, metricsMap, true, "fieldCache", Category.CACHE.toString(), scope);
   }
 }
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 fe33095..4a5c194 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -70,6 +70,7 @@ import org.apache.solr.index.SlowCompositeReaderWrapper;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestInfo;
@@ -141,8 +142,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
   private final StatsCache statsCache;
 
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
-  private SolrMetricManager metricManager;
-  private String registryName;
+  private SolrMetricsContext solrMetricsContext;
 
   private static DirectoryReader getReader(SolrCore core, SolrIndexConfig config, DirectoryFactory directoryFactory,
                                            String path) throws IOException {
@@ -432,12 +432,13 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       cache.setState(SolrCache.State.LIVE);
       infoRegistry.put(cache.name(), cache);
     }
-    metricManager = core.getCoreContainer().getMetricManager();
-    registryName = core.getCoreMetricManager().getRegistryName();
+    this.solrMetricsContext = core.getSolrMetricsContext().getChildContext(this);
     for (SolrCache cache : cacheList) {
-      cache.initializeMetrics(metricManager, registryName, core.getMetricTag(), SolrMetricManager.mkName(cache.name(), STATISTICS_KEY));
+      // XXX use the deprecated method for back-compat. remove in 9.0
+      cache.initializeMetrics(solrMetricsContext.metricManager,
+          solrMetricsContext.registry, solrMetricsContext.tag, SolrMetricManager.mkName(cache.name(), STATISTICS_KEY));
     }
-    initializeMetrics(metricManager, registryName, core.getMetricTag(), STATISTICS_KEY);
+    initializeMetrics(solrMetricsContext, STATISTICS_KEY);
     registerTime = new Date();
   }
 
@@ -2280,23 +2281,26 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
-    this.registryName = registry;
-    this.metricManager = manager;
-    manager.registerGauge(this, registry, () -> name, tag, true, "searcherName", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> cachingEnabled, tag, true, "caching", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> openTime, tag, true, "openedAt", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> warmupTime, tag, true, "warmupTime", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> registerTime, tag, true, "registeredAt", Category.SEARCHER.toString(), scope);
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
+  }
+
+  @Override
+  public void initializeMetrics(SolrMetricsContext solrMetricsContext, String scope) {
+    solrMetricsContext.gauge(this, () -> name, true, "searcherName", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> cachingEnabled, true, "caching", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> openTime, true, "openedAt", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> warmupTime, true, "warmupTime", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> registerTime, true, "registeredAt", Category.SEARCHER.toString(), scope);
     // reader stats
-    manager.registerGauge(this, registry, () -> reader.numDocs(), tag, true, "numDocs", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.maxDoc(), tag, true, "maxDoc", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.maxDoc() - reader.numDocs(), tag, true, "deletedDocs", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.toString(), tag, true, "reader", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.directory().toString(), tag, true, "readerDir", Category.SEARCHER.toString(), scope);
-    manager.registerGauge(this, registry, () -> reader.getVersion(), tag, true, "indexVersion", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> reader.numDocs(), true, "numDocs", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> reader.maxDoc(), true, "maxDoc", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> reader.maxDoc() - reader.numDocs(), true, "deletedDocs", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> reader.toString(), true, "reader", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> reader.directory().toString(), true, "readerDir", Category.SEARCHER.toString(), scope);
+    solrMetricsContext.gauge(this, () -> reader.getVersion(), true, "indexVersion", Category.SEARCHER.toString(), scope);
     // size of the currently opened commit
-    manager.registerGauge(this, registry, () -> {
+    solrMetricsContext.gauge(this, () -> {
       try {
         Collection<String> files = reader.getIndexCommit().getFileNames();
         long total = 0;
@@ -2307,14 +2311,13 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       } catch (Exception e) {
         return -1;
       }
-    }, tag, true, "indexCommitSize", Category.SEARCHER.toString(), scope);
+    }, true, "indexCommitSize", Category.SEARCHER.toString(), scope);
     // statsCache metrics
-    manager.registerGauge(this, registry,
+    solrMetricsContext.gauge(this,
         new MetricsMap((detailed, map) -> {
           statsCache.getCacheMetrics().getSnapshot(map::put);
           map.put("statsCacheImpl", statsCache.getClass().getSimpleName());
-        }),
-        tag, true, "statsCache", Category.CACHE.toString(), scope);
+        }), true, "statsCache", Category.CACHE.toString(), scope);
   }
 
   @Override
diff --git a/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java
index cf30a2e..688c3c0 100644
--- a/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java
@@ -146,19 +146,17 @@ public abstract class AuthenticationPlugin implements SolrInfoBean, SolrMetricPr
   }
 
   @Override
-  public void initializeMetrics(SolrMetricsContext metrics) {
-    this.metrics = metrics.getChildInfo(this);
+  public void initializeMetrics(SolrMetricsContext metrics, String scope) {
+    this.metrics = metrics.getChildContext(this);
     // Metrics
-    numErrors = this.metrics.meter(this, "errors", getCategory().toString());
-    requests = this.metrics.counter(this, "requests", getCategory().toString());
-    numAuthenticated = this.metrics.counter(this, "authenticated",getCategory().toString());
-    numPassThrough = this.metrics.counter(this, "passThrough",  getCategory().toString());
-    numWrongCredentials = this.metrics.counter(this, "failWrongCredentials",getCategory().toString());
-    numMissingCredentials = this.metrics.counter(this,  "failMissingCredentials",getCategory().toString());
-    requestTimes = this.metrics.timer(this,"requestTimes", getCategory().toString());
-    totalTime = this.metrics.counter(this,"totalTime", getCategory().toString());
-    metricNames.addAll(Arrays.asList("errors", "requests", "authenticated", "passThrough",
-        "failWrongCredentials", "failMissingCredentials", "requestTimes", "totalTime"));
+    numErrors = this.metrics.meter(this, "errors", getCategory().toString(), scope);
+    requests = this.metrics.counter(this, "requests", getCategory().toString(), scope);
+    numAuthenticated = this.metrics.counter(this, "authenticated",getCategory().toString(), scope);
+    numPassThrough = this.metrics.counter(this, "passThrough",  getCategory().toString(), scope);
+    numWrongCredentials = this.metrics.counter(this, "failWrongCredentials",getCategory().toString(), scope);
+    numMissingCredentials = this.metrics.counter(this,  "failMissingCredentials",getCategory().toString(), scope);
+    requestTimes = this.metrics.timer(this,"requestTimes", getCategory().toString(), scope);
+    totalTime = this.metrics.counter(this,"totalTime", getCategory().toString(), scope);
   }
 
   @Override
@@ -183,7 +181,7 @@ public abstract class AuthenticationPlugin implements SolrInfoBean, SolrMetricPr
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return metrics == null ? null : metrics.getRegistry();
+    return metrics == null ? null : metrics.getMetricRegistry();
   }
 
 }
diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
index 90d6b17..717ff01 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -108,7 +108,7 @@ public class SolrDispatchFilter extends BaseSolrFilter {
   
   private boolean isV2Enabled = !"true".equals(System.getProperty("disable.v2.api", "false"));
 
-  private final String metricTag = Integer.toHexString(hashCode());
+  private final String metricTag = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
   private SolrMetricManager metricManager;
   private String registryName;
   private volatile boolean closeOnDestroy = true;
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 6d9e9ea..8790ba4 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
@@ -25,6 +25,7 @@ import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.search.SolrCacheBase;
 
 /**
@@ -54,17 +55,13 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
   public AtomicLong shardBuffercacheLost = new AtomicLong(0);
 
   private MetricsMap metricsMap;
-  private MetricRegistry registry;
   private Set<String> metricNames = ConcurrentHashMap.newKeySet();
-  private SolrMetricManager metricManager;
-  private String registryName;
+  private SolrMetricsContext solrMetricsContext;
   private long previous = System.nanoTime();
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    this.metricManager = manager;
-    this.registryName = registryName;
-    registry = manager.registry(registryName);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    solrMetricsContext = m.getChildContext(this);
     metricsMap = new MetricsMap((detailed, map) -> {
       long now = System.nanoTime();
       long delta = Math.max(now - previous, 1);
@@ -108,7 +105,7 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
       previous = now;
 
     });
-    manager.registerGauge(this, registryName, metricsMap, tag, true, getName(), getCategory().toString(), scope);
+    solrMetricsContext.gauge(this, metricsMap, true, getName(), getCategory().toString(), scope);
   }
 
   private float getPerSecond(long value, double seconds) {
@@ -134,7 +131,11 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricPr
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return registry;
+    return solrMetricsContext != null ? solrMetricsContext.getMetricRegistry() : null;
   }
 
+  @Override
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
+  }
 }
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 2bf60cb..e51fa3c 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
@@ -34,6 +34,7 @@ import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.MetricsMap;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,9 +52,7 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
   private final ConcurrentMap<HdfsDirectory,ConcurrentMap<FileStatus,BlockLocation[]>> cache;
 
   private final Set<String> metricNames = ConcurrentHashMap.newKeySet();
-  private MetricRegistry registry;
-  private SolrMetricManager metricManager;
-  private String registryName;
+  private SolrMetricsContext solrMetricsContext;
 
   public HdfsLocalityReporter() {
     cache = new ConcurrentHashMap<>();
@@ -89,17 +88,20 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
 
   @Override
   public MetricRegistry getMetricRegistry() {
-    return registry;
+    return solrMetricsContext != null ? solrMetricsContext.getMetricRegistry() : null;
+  }
+
+  @Override
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
   }
 
   /**
    * Provide statistics on HDFS block locality, both in terms of bytes and block counts.
    */
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    this.metricManager = manager;
-    this.registryName = registryName;
-    registry = manager.registry(registryName);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    solrMetricsContext = m.getChildContext(this);
     MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
       long totalBytes = 0;
       long localBytes = 0;
@@ -149,7 +151,7 @@ public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
         map.put(LOCALITY_BLOCKS_RATIO, localCount / (double) totalCount);
       }
     });
-    manager.registerGauge(this, registryName, metricsMap, tag, true, "hdfsLocality", getCategory().toString(), scope);
+    solrMetricsContext.gauge(this, metricsMap, true, "hdfsLocality", getCategory().toString(), scope);
   }
 
   /**
diff --git a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
index 538a983..b377561 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
@@ -43,6 +43,8 @@ import org.apache.solr.core.DirectoryFactory.DirContext;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.schema.IndexSchema;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -88,8 +90,7 @@ public class SolrIndexWriter extends IndexWriter {
   private final AtomicLong runningMajorMergesDocs = new AtomicLong();
   private final AtomicLong runningMinorMergesDocs = new AtomicLong();
 
-  private final SolrMetricManager metricManager;
-  private final String registryName;
+  private final SolrMetricsContext solrMetricsContext;
   // merge diagnostics.
   private final Map<String, Long> runningMerges = new ConcurrentHashMap<>();
 
@@ -120,8 +121,7 @@ public class SolrIndexWriter extends IndexWriter {
     // no metrics
     mergeTotals = false;
     mergeDetails = false;
-    metricManager = null;
-    registryName = null;
+    solrMetricsContext = null;
   }
 
   private SolrIndexWriter(SolrCore core, String name, String path, Directory directory, boolean create, IndexSchema schema, SolrIndexConfig config, IndexDeletionPolicy delPolicy, Codec codec) throws IOException {
@@ -135,8 +135,7 @@ public class SolrIndexWriter extends IndexWriter {
     infoStream = getConfig().getInfoStream();
     this.directory = directory;
     numOpens.incrementAndGet();
-    metricManager = core.getCoreContainer().getMetricManager();
-    registryName = core.getCoreMetricManager().getRegistryName();
+    solrMetricsContext = core.getSolrMetricsContext().getChildContext(this);
     if (config.metricsInfo != null && config.metricsInfo.initArgs != null) {
       Object v = config.metricsInfo.initArgs.get("majorMergeDocs");
       if (v != null) {
@@ -160,21 +159,21 @@ public class SolrIndexWriter extends IndexWriter {
       }
       if (mergeDetails) {
         mergeTotals = true; // override
-        majorMergedDocs = metricManager.meter(null, registryName, "docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        majorDeletedDocs = metricManager.meter(null, registryName, "deletedDocs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+        majorMergedDocs = solrMetricsContext.meter(null, "docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+        majorDeletedDocs = solrMetricsContext.meter(null, "deletedDocs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
       }
       if (mergeTotals) {
-        minorMerge = metricManager.timer(null, registryName, "minor", SolrInfoBean.Category.INDEX.toString(), "merge");
-        majorMerge = metricManager.timer(null, registryName, "major", SolrInfoBean.Category.INDEX.toString(), "merge");
-        mergeErrors = metricManager.counter(null, registryName, "errors", SolrInfoBean.Category.INDEX.toString(), "merge");
+        minorMerge = solrMetricsContext.timer(null, "minor", SolrInfoBean.Category.INDEX.toString(), "merge");
+        majorMerge = solrMetricsContext.timer(null, "major", SolrInfoBean.Category.INDEX.toString(), "merge");
+        mergeErrors = solrMetricsContext.counter(null, "errors", SolrInfoBean.Category.INDEX.toString(), "merge");
         String tag = core.getMetricTag();
-        metricManager.registerGauge(null, registryName, () -> runningMajorMerges.get(), tag, true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        metricManager.registerGauge(null, registryName, () -> runningMinorMerges.get(), tag, true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
-        metricManager.registerGauge(null, registryName, () -> runningMajorMergesDocs.get(), tag, true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        metricManager.registerGauge(null, registryName, () -> runningMinorMergesDocs.get(), tag, true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
-        metricManager.registerGauge(null, registryName, () -> runningMajorMergesSegments.get(), tag, true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
-        metricManager.registerGauge(null, registryName, () -> runningMinorMergesSegments.get(), tag, true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
-        flushMeter = metricManager.meter(null, registryName, "flush", SolrInfoBean.Category.INDEX.toString());
+        solrMetricsContext.gauge(null, () -> runningMajorMerges.get(), true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+        solrMetricsContext.gauge(null, () -> runningMinorMerges.get(), true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+        solrMetricsContext.gauge(null, () -> runningMajorMergesDocs.get(), true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+        solrMetricsContext.gauge(null, () -> runningMinorMergesDocs.get(), true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+        solrMetricsContext.gauge(null, () -> runningMajorMergesSegments.get(), true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+        solrMetricsContext.gauge(null, () -> runningMinorMergesSegments.get(), true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+        flushMeter = solrMetricsContext.meter(null, "flush", SolrInfoBean.Category.INDEX.toString());
       }
     }
   }
@@ -345,6 +344,9 @@ public class SolrIndexWriter extends IndexWriter {
       if (directoryFactory != null) {
         directoryFactory.release(directory);
       }
+      if (solrMetricsContext != null) {
+        solrMetricsContext.unregister();
+      }
     }
   }
 
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
index 8e3486b..f41102c 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
@@ -40,6 +40,7 @@ import org.apache.solr.common.util.SolrjNamedThreadFactory;
 import org.apache.solr.core.SolrInfoBean;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.apache.solr.security.HttpClientBuilderPlugin;
 import org.apache.solr.update.processor.DistributedUpdateProcessor;
 import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
@@ -179,11 +180,11 @@ public class UpdateShardHandler implements SolrMetricProducer, SolrInfoBean {
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registryName, String tag, String scope) {
-    registry = manager.registry(registryName);
+  public void initializeMetrics(SolrMetricsContext m, String scope) {
+    registry = m.getMetricRegistry();
     String expandedScope = SolrMetricManager.mkName(scope, getCategory().name());
-    updateHttpListenerFactory.initializeMetrics(manager, registryName, tag, expandedScope);
-    defaultConnectionManager.initializeMetrics(manager, registryName, tag, expandedScope);
+    updateHttpListenerFactory.initializeMetrics(m, expandedScope);
+    defaultConnectionManager.initializeMetrics(m, expandedScope);
     updateExecutor = MetricUtils.instrumentedExecutorService(updateExecutor, this, registry,
         SolrMetricManager.mkName("updateOnlyExecutor", expandedScope, "threadPool"));
     recoveryExecutor = MetricUtils.instrumentedExecutorService(recoveryExecutor, this, registry,
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java
index d452502..f57cb25 100644
--- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java
@@ -26,6 +26,7 @@ import com.codahale.metrics.Timer;
 import org.apache.solr.client.solrj.impl.HttpListenerFactory;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Result;
 
@@ -64,9 +65,7 @@ public class InstrumentedHttpListenerFactory implements SolrMetricProducer, Http
     KNOWN_METRIC_NAME_STRATEGIES.put("methodOnly", METHOD_ONLY);
   }
 
-  protected MetricRegistry metricsRegistry;
-  protected SolrMetricManager metricManager;
-  protected String registryName;
+  protected SolrMetricsContext solrMetricsContext;
   protected String scope;
   protected NameStrategy nameStrategy;
 
@@ -85,7 +84,7 @@ public class InstrumentedHttpListenerFactory implements SolrMetricProducer, Http
 
       @Override
       public void onBegin(Request request) {
-        if (metricsRegistry != null) {
+        if (solrMetricsContext != null) {
           timerContext = timer(request).time();
         }
       }
@@ -100,14 +99,12 @@ public class InstrumentedHttpListenerFactory implements SolrMetricProducer, Http
   }
 
   private Timer timer(Request request) {
-    return metricsRegistry.timer(nameStrategy.getNameFor(scope, request));
+    return solrMetricsContext.timer(null, nameStrategy.getNameFor(scope, request));
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
-    this.metricManager = manager;
-    this.registryName = registry;
-    this.metricsRegistry = manager.registry(registry);
+  public void initializeMetrics(SolrMetricsContext solrMetricsContext, String scope) {
+    this.solrMetricsContext = solrMetricsContext;
     this.scope = scope;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java
index 398ab8b..cf67181 100644
--- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingHttpClientConnectionManager.java
@@ -22,6 +22,7 @@ import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.metrics.SolrMetricsContext;
 
 /**
  * Sub-class of PoolingHttpClientConnectionManager which tracks metrics interesting to Solr.
@@ -29,25 +30,28 @@ import org.apache.solr.metrics.SolrMetricProducer;
  */
 public class InstrumentedPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager implements SolrMetricProducer {
 
-  private SolrMetricManager metricManager;
-  private String registryName;
+  private SolrMetricsContext solrMetricsContext;
 
   public InstrumentedPoolingHttpClientConnectionManager(Registry<ConnectionSocketFactory> socketFactoryRegistry) {
     super(socketFactoryRegistry);
   }
 
   @Override
-  public void initializeMetrics(SolrMetricManager manager, String registry, String tag, String scope) {
-    this.metricManager = manager;
-    this.registryName = registry;
-    manager.registerGauge(null, registry, () -> getTotalStats().getAvailable(),
-        tag, true, SolrMetricManager.mkName("availableConnections", scope));
+  public SolrMetricsContext getSolrMetricsContext() {
+    return solrMetricsContext;
+  }
+
+  @Override
+  public void initializeMetrics(SolrMetricsContext solrMetricsContext, String scope) {
+    this.solrMetricsContext = solrMetricsContext.getChildContext(this);
+    solrMetricsContext.gauge(null, () -> getTotalStats().getAvailable(),
+        true, SolrMetricManager.mkName("availableConnections", scope));
     // this acquires a lock on the connection pool; remove if contention sucks
-    manager.registerGauge(null, registry, () -> getTotalStats().getLeased(),
-        tag, true, SolrMetricManager.mkName("leasedConnections", scope));
-    manager.registerGauge(null, registry, () -> getTotalStats().getMax(),
-        tag, true, SolrMetricManager.mkName("maxConnections", scope));
-    manager.registerGauge(null, registry, () -> getTotalStats().getPending(),
-        tag, true, SolrMetricManager.mkName("pendingConnections", scope));
+    solrMetricsContext.gauge(null, () -> getTotalStats().getLeased(),
+        true, SolrMetricManager.mkName("leasedConnections", scope));
+    solrMetricsContext.gauge(null, () -> getTotalStats().getMax(),
+        true, SolrMetricManager.mkName("maxConnections", scope));
+    solrMetricsContext.gauge(null, () -> getTotalStats().getPending(),
+        true, SolrMetricManager.mkName("pendingConnections", scope));
   }
 }
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
index 9a3856d..f4e9d52 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
@@ -416,7 +416,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
     void reset(DumpRequestHandler rh) throws Exception {
         this.rh = rh;
         if(metricsInfo != null)
-        this.rh.initializeMetrics(metricsInfo);
+        this.rh.initializeMetrics(metricsInfo, "/dumphandler");
     }
 
 
@@ -441,11 +441,11 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
     }
 
     @Override
-    public void initializeMetrics(SolrMetricsContext m) {
-      super.initializeMetrics(m);
+    public void initializeMetrics(SolrMetricsContext m, String scope) {
+      super.initializeMetrics(m, scope);
       MetricsMap metrics = new MetricsMap((detailed, map) -> map.putAll(gaugevals));
       solrMetricsContext.gauge(this,
-           metrics,  true, "dumphandlergauge", getCategory().toString());
+           metrics,  true, "dumphandlergauge", getCategory().toString(), scope);
 
     }