blob: 60fb253e0dff03dc28a5af4a02369fffc4167a3d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.metrics;
import java.io.Closeable;
import java.io.IOException;
import com.codahale.metrics.MetricRegistry;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.common.ParWork;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.NodeConfig;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.search.SolrFieldCacheBean;
/**
* Helper class for managing registration of {@link SolrMetricProducer}'s
* and {@link SolrMetricReporter}'s specific to a {@link SolrCore} instance.
*/
public class SolrCoreMetricManager implements Closeable {
private final SolrCore core;
private volatile SolrMetricsContext solrMetricsContext;
private SolrMetricManager metricManager;
private String collectionName;
private String shardName;
private String replicaName;
private String leaderRegistryName;
private boolean cloudMode;
/**
* Constructs a metric manager.
*
* @param core the metric manager's core
*/
public SolrCoreMetricManager(SolrCore core) {
this.core = core;
initCloudMode();
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);
}
private void initCloudMode() {
CloudDescriptor cd = core.getCoreDescriptor().getCloudDescriptor();
if (cd != null) {
cloudMode = true;
collectionName = core.getCoreDescriptor().getCollectionName();
shardName = cd.getShardId();
String coreName = core.getName();
replicaName = coreName;
}
}
/**
* Load reporters configured globally and specific to {@link org.apache.solr.core.SolrInfoBean.Group#core}
* group or with a registry name specific to this core.
*/
public void loadReporters() {
CoreContainer coreContainer = core.getCoreContainer();
NodeConfig nodeConfig = coreContainer.getConfig();
PluginInfo[] pluginInfos = nodeConfig.getMetricsConfig().getMetricReporters();
metricManager.loadReporters(pluginInfos, core.getResourceLoader(), coreContainer, core, solrMetricsContext.getTag(),
SolrInfoBean.Group.core, solrMetricsContext.getRegistryName());
if (cloudMode) {
metricManager.loadShardReporters(pluginInfos, core);
}
}
/**
* Make sure that metrics already collected that correspond to the old core name
* are carried over and will be used under the new core name.
* This method also reloads reporters so that they use the new core name.
*/
public void afterCoreSetName() {
String oldRegistryName = solrMetricsContext.getRegistryName();
String oldLeaderRegistryName = leaderRegistryName;
initCloudMode();
String newRegistryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName());
leaderRegistryName = createLeaderRegistryName(cloudMode, collectionName, shardName);
if (oldRegistryName.equals(newRegistryName)) {
return;
}
// close old reporters
metricManager.closeReporters(oldRegistryName, solrMetricsContext.getTag());
if (oldLeaderRegistryName != null) {
metricManager.closeReporters(oldLeaderRegistryName, solrMetricsContext.getTag());
}
solrMetricsContext = new SolrMetricsContext(metricManager, newRegistryName, solrMetricsContext.getTag());
// load reporters again, using the new core name
loadReporters();
}
/**
* Registers a mapping of name/metric's with the manager's metric registry.
*
* @param scope the scope of the metrics to be registered (e.g. `/admin/ping`)
* @param producer producer of metrics to be registered
*/
public void registerMetricProducer(String scope, SolrMetricProducer producer) {
if (scope == null || producer == null) {
throw new IllegalArgumentException("registerMetricProducer() called with illegal arguments: " +
"scope = " + scope + ", producer = " + producer);
}
// use deprecated method for back-compat, remove in 9.0
producer.initializeMetrics(solrMetricsContext, scope);
}
/**
* Return the registry used by this SolrCore.
*/
public MetricRegistry getRegistry() {
if (solrMetricsContext != null) {
return solrMetricsContext.getMetricRegistry();
} else {
return null;
}
}
/**
* Closes reporters specific to this core and unregisters gauges with this core's instance tag.
*/
@Override
public void close() throws IOException {
try (ParWork closer = new ParWork(this)) {
closer.collect("CloseReporters", () -> {metricManager.closeReporters(getRegistryName(), solrMetricsContext.tag); return "reporters";});
closer.collect("leaderReporters", () -> {
if (getLeaderRegistryName() != null) metricManager.closeReporters(getLeaderRegistryName(), solrMetricsContext.tag);
});
closer.addCollect();
closer.collect("gauges", () -> {
metricManager.unregisterGauges(getRegistryName(), solrMetricsContext.tag);
});
}
}
public SolrMetricsContext getSolrMetricsContext() {
return solrMetricsContext;
}
public SolrCore getCore() {
return core;
}
/**
* Metric registry name of the manager.
*
* In order to make it easier for reporting tools to aggregate metrics from
* different cores that logically belong to a single collection we convert the
* core name into a dot-separated hierarchy of: collection name, shard name (with optional split)
* and replica name.
*
* <p>For example, when the core name looks like this but it's NOT a SolrCloud collection:
* <code>my_collection_shard1_1_replica1</code> then this will be used as the registry name (plus
* the required <code>solr.core</code> prefix). However,
* if this is a SolrCloud collection <code>my_collection</code> then the registry name will become
* <code>solr.core.my_collection.shard1_1.replica1</code>.</p>
*
*
* @return the metric registry name of the manager.
*/
public String getRegistryName() {
return solrMetricsContext != null ? solrMetricsContext.getRegistryName() : null;
}
/**
* Metric registry name for leader metrics. This is null if not in cloud mode.
* @return metric registry name for leader metrics
*/
public String getLeaderRegistryName() {
return leaderRegistryName;
}
/**
* Return a tag specific to this instance.
*/
public String getTag() {
return solrMetricsContext.getTag();
}
public static String createRegistryName(boolean cloud, String collectionName, String shardName, String replicaName, String coreName) {
if (cloud) { // build registry name from logical names
return SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, collectionName, shardName, replicaName);
} else {
return SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, coreName);
}
}
/**
* This method is used by {@link org.apache.solr.core.CoreContainer#rename(String, String)}.
* @param aCore existing core with old name
* @param coreName new name
* @return new registry name
*/
public static String createRegistryName(SolrCore aCore, String coreName) {
CloudDescriptor cd = aCore.getCoreDescriptor().getCloudDescriptor();
String replicaName = null;
if (cd != null) {
replicaName = Utils.parseMetricsReplicaName(cd.getCollectionName(), coreName);
}
return createRegistryName(
cd != null,
cd != null ? cd.getCollectionName() : null,
cd != null ? cd.getShardId() : null,
replicaName,
coreName
);
}
public static String createLeaderRegistryName(boolean cloud, String collectionName, String shardName) {
if (cloud) {
return SolrMetricManager.getRegistryName(SolrInfoBean.Group.collection, collectionName, shardName, "leader");
} else {
return null;
}
}
}