/* * 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.core; import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricReporter; import org.apache.solr.metrics.reporters.JmxObjectNameFactory; import org.apache.solr.metrics.reporters.SolrJmxReporter; import org.apache.solr.util.AbstractSolrTestCase; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.AttributeNotFoundException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanServer; import javax.management.ObjectInstance; import javax.management.ObjectName; import java.lang.invoke.MethodHandles; import java.lang.management.ManagementFactory; import java.util.Map; import java.util.Set; /** * Test for JMX Integration * * * @since solr 1.3 */ public class TestJmxIntegration extends AbstractSolrTestCase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static MBeanServer mbeanServer = null; private static JmxObjectNameFactory nameFactory = null; private static String registryName = null; @BeforeClass public static void beforeClass() throws Exception { // Make sure that at least one MBeanServer is available // prior to initializing the core // // (test configs are setup to use existing server if any, // otherwise skip JMX) MBeanServer platformServer = ManagementFactory.getPlatformMBeanServer(); initCore("solrconfig.xml", "schema.xml"); // we should be able to see that the core has JmxIntegration enabled registryName = h.getCore().getCoreMetricManager().getRegistryName(); SolrMetricManager manager = h.getCoreContainer().getMetricManager(); Map<String,SolrMetricReporter> reporters = manager.getReporters(registryName); assertEquals(1, reporters.size()); SolrMetricReporter reporter = reporters.values().iterator().next(); assertTrue(reporter instanceof SolrJmxReporter); SolrJmxReporter jmx = (SolrJmxReporter)reporter; assertTrue("JMX not enabled", jmx.isActive()); // and we should be able to see that the reporter // refers to the JMX server we started mbeanServer = jmx.getMBeanServer(); assertNotNull("No JMX server found in the reporter", mbeanServer); // NOTE: we can't guarantee that "mbeanServer == platformServer" // the JVM may have multiple MBean servers running when the test started // and the contract of not specifying one when configuring solr.xml without // agetnId or serviceUrl is that it will use whatever the "first" MBean server // returned by the JVM is. nameFactory = new JmxObjectNameFactory("default", registryName); } @AfterClass public static void afterClass() throws Exception { mbeanServer = null; } @Test public void testJmxRegistration() throws Exception { assertTrue("No MBeans found in server", mbeanServer.getMBeanCount() > 0); Set<ObjectInstance> objects = mbeanServer.queryMBeans(null, null); assertFalse("No objects found in mbean server", objects .isEmpty()); int numDynamicMbeans = 0; for (ObjectInstance o : objects) { ObjectName name = o.getObjectName(); assertNotNull("Null name on: " + o.toString(), name); MBeanInfo mbeanInfo = mbeanServer.getMBeanInfo(name); if (name.getDomain().equals("solr")) { numDynamicMbeans++; MBeanAttributeInfo[] attrs = mbeanInfo.getAttributes(); if (name.getKeyProperty("name").equals("fetcher")) { // no attributes without active replication continue; } assertTrue("No Attributes found for mbean: " + o.getObjectName() + ", " + mbeanInfo, 0 < attrs.length); for (MBeanAttributeInfo attr : attrs) { // ensure every advertised attribute is gettable try { Object trash = mbeanServer.getAttribute(o.getObjectName(), attr.getName()); } catch (javax.management.AttributeNotFoundException e) { throw new RuntimeException("Unable to featch attribute for " + o.getObjectName() + ": " + attr.getName(), e); } } } } assertTrue("No MBeans found", 0 < numDynamicMbeans); } @Test public void testJmxUpdate() throws Exception { SolrInfoBean bean = null; // wait until searcher is registered for (int i=0; i<100; i++) { bean = h.getCore().getInfoRegistry().get("searcher"); if (bean != null) break; Thread.sleep(250); } if (bean==null) throw new RuntimeException("searcher was never registered"); ObjectName searcher = nameFactory.createName("gauge", registryName, "SEARCHER.searcher.*"); log.info("Mbeans in server: " + mbeanServer.queryNames(null, null)); Set<ObjectInstance> objects = mbeanServer.queryMBeans(searcher, null); assertFalse("No mbean found for SolrIndexSearcher", mbeanServer.queryMBeans(searcher, null).isEmpty()); ObjectName name = nameFactory.createName("gauge", registryName, "SEARCHER.searcher.numDocs"); int oldNumDocs = (Integer)mbeanServer.getAttribute(name, "Value"); assertU(adoc("id", "1")); assertU("commit", commit()); int numDocs = (Integer)mbeanServer.getAttribute(name, "Value"); assertTrue("New numDocs is same as old numDocs as reported by JMX", numDocs > oldNumDocs); } @Test @Ignore("timing problem? https://issues.apache.org/jira/browse/SOLR-2715") public void testJmxOnCoreReload() throws Exception { String coreName = h.getCore().getName(); Set<ObjectInstance> oldBeans = mbeanServer.queryMBeans(null, null); int oldNumberOfObjects = 0; for (ObjectInstance bean : oldBeans) { try { if (String.valueOf(h.getCore().hashCode()).equals(mbeanServer.getAttribute(bean.getObjectName(), "coreHashCode"))) { oldNumberOfObjects++; } } catch (AttributeNotFoundException e) { // expected } } log.info("Before Reload: Size of infoRegistry: " + h.getCore().getInfoRegistry().size() + " MBeans: " + oldNumberOfObjects); assertEquals("Number of registered MBeans is not the same as info registry size", h.getCore().getInfoRegistry().size(), oldNumberOfObjects); h.getCoreContainer().reload(coreName); Set<ObjectInstance> newBeans = mbeanServer.queryMBeans(null, null); int newNumberOfObjects = 0; int registrySize = 0; try (SolrCore core = h.getCoreContainer().getCore(coreName)) { registrySize = core.getInfoRegistry().size(); for (ObjectInstance bean : newBeans) { try { if (String.valueOf(core.hashCode()).equals(mbeanServer.getAttribute(bean.getObjectName(), "coreHashCode"))) { newNumberOfObjects++; } } catch (AttributeNotFoundException e) { // expected } } } log.info("After Reload: Size of infoRegistry: " + registrySize + " MBeans: " + newNumberOfObjects); assertEquals("Number of registered MBeans is not the same as info registry size", registrySize, newNumberOfObjects); } }