blob: a30c5dc1fc52d38a67d5a298a2484e97469106ec [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.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Random;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.TestUtil;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.SolrTestUtil;
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.core.SolrXmlConfig;
import org.apache.solr.metrics.reporters.MockMetricReporter;
import org.apache.solr.util.TestHarness;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class SolrMetricsIntegrationTest extends SolrTestCaseJ4 {
private static final int MAX_ITERATIONS = 20;
private static final String CORE_NAME = "metrics_integration";
private static final String METRIC_NAME = "requestTimes";
private static final String HANDLER_NAME = "/select";
private static final String[] REPORTER_NAMES = {"reporter1", "reporter2"};
private static final String UNIVERSAL = "universal";
private static final String SPECIFIC = "specific";
private static final String DEFAULT = "default";
private static final String MULTIGROUP = "multigroup";
private static final String MULTIREGISTRY = "multiregistry";
private static final String[] INITIAL_REPORTERS = {REPORTER_NAMES[0], REPORTER_NAMES[1], UNIVERSAL, SPECIFIC, MULTIGROUP, MULTIREGISTRY};
private static final String[] RENAMED_REPORTERS = {REPORTER_NAMES[0], REPORTER_NAMES[1], UNIVERSAL, MULTIGROUP};
private static final SolrInfoBean.Category HANDLER_CATEGORY = SolrInfoBean.Category.QUERY;
private CoreContainer cc;
private SolrMetricManager metricManager;
private String tag;
private volatile int jmxReporter;
@BeforeClass
public static void beforeSolrMetricsIntegrationTest() throws Exception {
System.setProperty("solr.disableDefaultJmxReporter", "false");
System.setProperty("solr.suppressDefaultConfigBootstrap", "false");
System.setProperty("solr.enableMetrics", "true");
}
private void assertTagged(Map<String, SolrMetricReporter> reporters, String name) {
assertTrue("Reporter '" + name + "' missing in " + reporters, reporters.containsKey(name + "@" + tag));
}
@Before
public void beforeTest() throws Exception {
Path home = Paths.get(SolrTestUtil.TEST_HOME());
// define these properties, they are used in solrconfig.xml
System.setProperty("solr.test.sys.prop1", "propone");
System.setProperty("solr.test.sys.prop2", "proptwo");
String solrXml = FileUtils.readFileToString(Paths.get(home.toString(), "solr-metricreporter.xml").toFile(), "UTF-8");
NodeConfig cfg = new SolrXmlConfig().fromString(home, solrXml);
cc = createCoreContainer(cfg, new TestHarness.TestCoresLocator
(DEFAULT_TEST_CORENAME, initAndGetDataDir().getAbsolutePath(),
"solrconfig.xml", "schema.xml"));
h.coreName = DEFAULT_TEST_CORENAME;
jmxReporter = 1;
metricManager = cc.getMetricManager();
try (SolrCore core = h.getCore()) {
tag = core.getCoreMetricManager().getTag();
}
// initially there are more reporters, because two of them are added via a matching collection name
Map<String, SolrMetricReporter> reporters = metricManager.getReporters("solr.core." + DEFAULT_TEST_CORENAME);
for (int i = 0; i < 10; i++) {
if (INITIAL_REPORTERS.length + jmxReporter == reporters.size()) {
break;
}
Thread.sleep(250);
}
assertEquals(reporters.toString(), INITIAL_REPORTERS.length + jmxReporter, reporters.size());
for (String r : INITIAL_REPORTERS) {
assertTagged(reporters, r);
}
// test rename operation
cc.rename(DEFAULT_TEST_CORENAME, CORE_NAME);
h.coreName = CORE_NAME;
cfg = cc.getConfig();
PluginInfo[] plugins = cfg.getMetricsConfig().getMetricReporters();
assertNotNull(plugins);
assertEquals(10 + jmxReporter, plugins.length);
reporters = metricManager.getReporters("solr.node");
assertEquals(4 + jmxReporter, reporters.size());
assertTrue("Reporter '" + REPORTER_NAMES[0] + "' missing in solr.node", reporters.containsKey(REPORTER_NAMES[0]));
assertTrue("Reporter '" + UNIVERSAL + "' missing in solr.node", reporters.containsKey(UNIVERSAL));
assertTrue("Reporter '" + MULTIGROUP + "' missing in solr.node", reporters.containsKey(MULTIGROUP));
assertTrue("Reporter '" + MULTIREGISTRY + "' missing in solr.node", reporters.containsKey(MULTIREGISTRY));
SolrMetricReporter reporter = reporters.get(REPORTER_NAMES[0]);
assertTrue("Reporter " + reporter + " is not an instance of " + MockMetricReporter.class.getName(),
reporter instanceof MockMetricReporter);
reporter = reporters.get(UNIVERSAL);
assertTrue("Reporter " + reporter + " is not an instance of " + MockMetricReporter.class.getName(),
reporter instanceof MockMetricReporter);
}
@After
public void afterTest() throws Exception {
if (null == metricManager) {
return; // test failed to init, nothing to cleanup
}
try (SolrCore core = h.getCore()) {
SolrCoreMetricManager coreMetricManager = core.getCoreMetricManager();
Map<String,SolrMetricReporter> reporters = metricManager.getReporters(coreMetricManager.getRegistryName());
}
deleteCore();
}
@Test
public void testConfigureReporter() throws Exception {
Random random = random();
try (SolrCore core = h.getCore()) {
String metricName = SolrMetricManager.mkName(METRIC_NAME, HANDLER_CATEGORY.toString(), HANDLER_NAME);
SolrCoreMetricManager coreMetricManager = core.getCoreMetricManager();
Timer timer = (Timer) metricManager.timer(null, coreMetricManager.getRegistryName(), metricName);
long initialCount = timer.getCount();
int iterations = TestUtil.nextInt(random, 0, MAX_ITERATIONS);
for (int i = 0; i < iterations; ++i) {
query(req("*"));
}
long finalCount = timer.getCount();
// MRM TODO: - those timers are disabled right now
// assertEquals("metric counter incorrect", iterations, finalCount - initialCount);
Map<String,SolrMetricReporter> reporters = metricManager.getReporters(coreMetricManager.getRegistryName());;
for (int i = 0; i < 50; i++) {
if ((RENAMED_REPORTERS.length + jmxReporter) != reporters.size()) {
Thread.sleep(100);
reporters = metricManager.getReporters(coreMetricManager.getRegistryName());
} else {
break;
}
}
assertEquals(RENAMED_REPORTERS.length + jmxReporter, reporters.size());
// SPECIFIC and MULTIREGISTRY were skipped because they were
// specific to collection1
for (String reporterName : RENAMED_REPORTERS) {
SolrMetricReporter reporter = reporters.get(reporterName + "@" + tag);
assertNotNull("Reporter " + reporterName + " was not found.", reporter);
assertTrue(reporter instanceof MockMetricReporter);
MockMetricReporter mockReporter = (MockMetricReporter) reporter;
assertTrue("Reporter " + reporterName + " was not initialized: " + mockReporter, mockReporter.didInit);
assertTrue("Reporter " + reporterName + " was not validated: " + mockReporter, mockReporter.didValidate);
assertFalse("Reporter " + reporterName + " was incorrectly closed: " + mockReporter, mockReporter.didClose);
}
}
}
@Test
public void testCoreContainerMetrics() throws Exception {
String registryName = SolrMetricManager.getRegistryName(SolrInfoBean.Group.node);
assertTrue(cc.getMetricManager().registryNames().toString(), cc.getMetricManager().registryNames().contains(registryName));
MetricRegistry registry = cc.getMetricManager().registry(registryName);
Map<String, Metric> metrics = registry.getMetrics();
assertTrue(metrics.containsKey("CONTAINER.cores.loaded"));
assertTrue(metrics.containsKey("CONTAINER.cores.lazy"));
assertTrue(metrics.containsKey("CONTAINER.cores.unloaded"));
assertTrue(metrics.containsKey("CONTAINER.fs.totalSpace"));
assertTrue(metrics.containsKey("CONTAINER.fs.usableSpace"));
assertTrue(metrics.containsKey("CONTAINER.fs.path"));
assertTrue(metrics.containsKey("CONTAINER.fs.spins"));
assertTrue(metrics.containsKey("CONTAINER.fs.coreRoot.totalSpace"));
assertTrue(metrics.containsKey("CONTAINER.fs.coreRoot.usableSpace"));
assertTrue(metrics.containsKey("CONTAINER.fs.coreRoot.path"));
assertTrue(metrics.containsKey("CONTAINER.fs.coreRoot.spins"));
assertTrue(metrics.containsKey("CONTAINER.version.specification"));
assertTrue(metrics.containsKey("CONTAINER.version.implementation"));
Gauge<?> g = (Gauge<?>)metrics.get("CONTAINER.fs.path");
Object val = g.getValue();
if (val != null) {
assertEquals(val, cc.getSolrHome());
}
boolean spins = IOUtils.spins(cc.getCoreRootDirectory());
g = (Gauge<?>)metrics.get("CONTAINER.fs.coreRoot.spins");
val = g.getValue();
if (val != null) {
assertEquals(spins, val);
}
g = (Gauge<?>)metrics.get("CONTAINER.fs.spins");
val = g.getValue();
if (val != null) {
if (cc.getConfig().getSolrDataHome() != null) {
spins = IOUtils.spins(cc.getConfig().getSolrDataHome());
assertEquals(spins, val);
} else {
assertEquals(spins, val);
}
}
}
}