docs = new ArrayList<>(urls.length);
- for(URL url : urls) {
- docs.add(url.toExternalForm());
- }
- mBeanInfo.add("docs", docs);
- }
if (req.getParams().getFieldBool(key, "stats", false))
- mBeanInfo.add("stats", m.getStatistics());
+ mBeanInfo.add("stats", m.getMetricsSnapshot());
catInfo.add(key, mBeanInfo);
}
@@ -246,6 +231,9 @@ public class SolrInfoMBeanHandler extends RequestHandlerBase {
}
public Object diffObject(Object ref, Object now) {
+ if (now instanceof Map) {
+ now = new NamedList((Map)now);
+ }
if(ref instanceof NamedList) {
return diffNamedList((NamedList)ref, (NamedList)now);
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
index fc1679ff896..ab2d4496941 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
@@ -16,10 +16,6 @@
*/
package org.apache.solr.handler.admin;
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -27,23 +23,20 @@ import java.io.InputStreamReader;
import java.lang.invoke.MethodHandles;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
-import java.lang.management.PlatformManagedObject;
import java.lang.management.RuntimeMXBean;
-import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
-import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import com.codahale.metrics.Gauge;
import org.apache.commons.io.IOUtils;
import org.apache.lucene.LucenePackage;
import org.apache.lucene.util.Constants;
-import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
@@ -53,6 +46,7 @@ import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.RTimer;
import org.apache.solr.util.RedactionUtils;
+import org.apache.solr.util.stats.MetricUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -207,29 +201,13 @@ public class SystemInfoHandler extends RequestHandlerBase
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
info.add(NAME, os.getName()); // add at least this one
- try {
- // add remaining ones dynamically using Java Beans API
- addMXBeanProperties(os, OperatingSystemMXBean.class, info);
- } catch (IntrospectionException | ReflectiveOperationException e) {
- log.warn("Unable to fetch properties of OperatingSystemMXBean.", e);
- }
-
- // There are some additional beans we want to add (not available on all JVMs):
- for (String clazz : Arrays.asList(
- "com.sun.management.OperatingSystemMXBean",
- "com.sun.management.UnixOperatingSystemMXBean",
- "com.ibm.lang.management.OperatingSystemMXBean"
- )) {
- try {
- final Class extends PlatformManagedObject> intf = Class.forName(clazz)
- .asSubclass(PlatformManagedObject.class);
- addMXBeanProperties(os, intf, info);
- } catch (ClassNotFoundException e) {
- // ignore
- } catch (IntrospectionException | ReflectiveOperationException e) {
- log.warn("Unable to fetch properties of JVM-specific OperatingSystemMXBean.", e);
+ // add remaining ones dynamically using Java Beans API
+ // also those from JVM implementation-specific classes
+ MetricUtils.addMXBeanMetrics(os, MetricUtils.OS_MXBEAN_CLASSES, null, (name, metric) -> {
+ if (info.get(name) == null) {
+ info.add(name, ((Gauge) metric).getValue());
}
- }
+ });
// Try some command line things:
try {
@@ -243,34 +221,6 @@ public class SystemInfoHandler extends RequestHandlerBase
return info;
}
- /**
- * Add all bean properties of a {@link PlatformManagedObject} to the given {@link NamedList}.
- *
- * If you are running a OpenJDK/Oracle JVM, there are nice properties in:
- * {@code com.sun.management.UnixOperatingSystemMXBean} and
- * {@code com.sun.management.OperatingSystemMXBean}
- */
- static void addMXBeanProperties(T obj, Class extends T> intf, NamedList info)
- throws IntrospectionException, ReflectiveOperationException {
- if (intf.isInstance(obj)) {
- final BeanInfo beanInfo = Introspector.getBeanInfo(intf, intf.getSuperclass(), Introspector.IGNORE_ALL_BEANINFO);
- for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) {
- final String name = desc.getName();
- if (info.get(name) == null) {
- try {
- final Object v = desc.getReadMethod().invoke(obj);
- if(v != null) {
- info.add(name, v);
- }
- } catch (InvocationTargetException ite) {
- // ignore (some properties throw UOE)
- }
- }
- }
- }
- }
-
-
/**
* Utility function to execute a function
*/
diff --git a/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java b/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java
index be2173339ea..f43a0e17f94 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java
@@ -17,7 +17,6 @@
package org.apache.solr.handler.component;
import java.io.IOException;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -380,7 +379,7 @@ public class DebugComponent extends SearchComponent
/////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
@@ -392,9 +391,4 @@ public class DebugComponent extends SearchComponent
public Category getCategory() {
return Category.OTHER;
}
-
- @Override
- public URL[] getDocs() {
- return null;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
index 656ac7113f0..2519a47969a 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
@@ -17,8 +17,6 @@
package org.apache.solr.handler.component;
import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -764,7 +762,7 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia
////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
@@ -777,17 +775,6 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia
return Category.QUERY;
}
- @Override
- public URL[] getDocs() {
- try {
- return new URL[]{
- new URL("http://wiki.apache.org/solr/ExpandComponent")
- };
- } catch (MalformedURLException e) {
- throw new RuntimeException(e);
- }
- }
-
// this reader alters the content of the given reader so it should not
// delegate the caching stuff
private static class ReaderWrapper extends FilterLeafReader {
diff --git a/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java b/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java
index 66b9ab8d713..80cca1577a5 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java
@@ -18,7 +18,6 @@ package org.apache.solr.handler.component;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -1212,7 +1211,7 @@ public class FacetComponent extends SearchComponent {
/////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
@@ -1225,11 +1224,6 @@ public class FacetComponent extends SearchComponent {
return Category.QUERY;
}
- @Override
- public URL[] getDocs() {
- return null;
- }
-
/**
* This class is used exclusively for merging results from each shard
* in a distributed facet request. It plays no role in the computation
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
index d147be2fa73..cc5211b3292 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
@@ -17,7 +17,6 @@
package org.apache.solr.handler.component;
import java.io.IOException;
-import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -266,7 +265,7 @@ public class HighlightComponent extends SearchComponent implements PluginInfoIni
}
////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
@@ -278,9 +277,4 @@ public class HighlightComponent extends SearchComponent implements PluginInfoIni
public Category getCategory() {
return Category.HIGHLIGHTER;
}
-
- @Override
- public URL[] getDocs() {
- return null;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
index 4262c20658c..1e1ce5ef830 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
@@ -36,7 +36,7 @@ import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.URLUtil;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.PluginInfo;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.update.UpdateShardHandlerConfig;
@@ -373,10 +373,10 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.
@Override
public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
- String expandedScope = SolrMetricManager.mkName(scope, SolrInfoMBean.Category.QUERY.name());
+ String expandedScope = SolrMetricManager.mkName(scope, SolrInfoBean.Category.QUERY.name());
clientConnectionManager.initializeMetrics(manager, registry, expandedScope);
httpRequestExecutor.initializeMetrics(manager, registry, expandedScope);
- commExecutor = MetricUtils.instrumentedExecutorService(commExecutor,
+ commExecutor = MetricUtils.instrumentedExecutorService(commExecutor, null,
manager.registry(registry),
SolrMetricManager.mkName("httpShardExecutor", expandedScope, "threadPool"));
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/MoreLikeThisComponent.java b/solr/core/src/java/org/apache/solr/handler/component/MoreLikeThisComponent.java
index ffb58588907..fd9d37d4aad 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/MoreLikeThisComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/MoreLikeThisComponent.java
@@ -18,7 +18,6 @@ package org.apache.solr.handler.component;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -414,7 +413,7 @@ public class MoreLikeThisComponent extends SearchComponent {
}
// ///////////////////////////////////////////
- // / SolrInfoMBean
+ // / SolrInfoBean
// //////////////////////////////////////////
@Override
@@ -426,9 +425,4 @@ public class MoreLikeThisComponent extends SearchComponent {
public Category getCategory() {
return Category.QUERY;
}
-
- @Override
- public URL[] getDocs() {
- return null;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
index 08a0e842e08..7555158f8c6 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -1378,7 +1377,7 @@ public class QueryComponent extends SearchComponent
}
/////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
@@ -1391,11 +1390,6 @@ public class QueryComponent extends SearchComponent
return Category.QUERY;
}
- @Override
- public URL[] getDocs() {
- return null;
- }
-
/**
* Fake scorer for a single document
*
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
index c12902e83b5..568000a2e66 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java
@@ -24,8 +24,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.invoke.MethodHandles;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -597,7 +595,7 @@ public class QueryElevationComponent extends SearchComponent implements SolrCore
}
//---------------------------------------------------------------------------------
- // SolrInfoMBean
+ // SolrInfoBean
//---------------------------------------------------------------------------------
@Override
@@ -605,16 +603,6 @@ public class QueryElevationComponent extends SearchComponent implements SolrCore
return "Query Boosting -- boost particular documents for a given query";
}
- @Override
- public URL[] getDocs() {
- try {
- return new URL[]{
- new URL("http://wiki.apache.org/solr/QueryElevationComponent")
- };
- } catch (MalformedURLException e) {
- throw new RuntimeException(e);
- }
- }
class ElevationComparatorSource extends FieldComparatorSource {
private QueryElevationComponent.ElevationObj elevations;
private SentinelIntSet ordSet; //the key half of the map
diff --git a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java
index 882decb1627..2a4776224b8 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java
@@ -18,7 +18,6 @@ package org.apache.solr.handler.component;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -927,7 +926,7 @@ public class RealTimeGetComponent extends SearchComponent
////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
@@ -940,13 +939,6 @@ public class RealTimeGetComponent extends SearchComponent
return Category.QUERY;
}
- @Override
- public URL[] getDocs() {
- return null;
- }
-
-
-
public void processGetFingeprint(ResponseBuilder rb) throws IOException {
SolrQueryRequest req = rb.req;
SolrParams params = req.getParams();
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
index 6ef0ee4f237..c615c5a7ac1 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java
@@ -17,13 +17,15 @@
package org.apache.solr.handler.component;
import java.io.IOException;
-import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.search.facet.FacetModule;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
@@ -33,12 +35,16 @@ import org.apache.solr.util.plugin.NamedListInitializedPlugin;
*
* @since solr 1.3
*/
-public abstract class SearchComponent implements SolrInfoMBean, NamedListInitializedPlugin
+public abstract class SearchComponent implements SolrInfoBean, NamedListInitializedPlugin
{
/**
* The name given to this component in solrconfig.xml file
*/
private String name = this.getClass().getName();
+
+ protected Set metricNames = new HashSet<>();
+ protected MetricRegistry registry;
+
/**
* Prepare the response. Guaranteed to be called before any SearchComponent {@link #process(org.apache.solr.handler.component.ResponseBuilder)} method.
* Called for every incoming request.
@@ -103,31 +109,24 @@ public abstract class SearchComponent implements SolrInfoMBean, NamedListInitial
@Override
public abstract String getDescription();
- @Override
- public String getSource() { return null; }
-
- @Override
- public String getVersion() {
- return getClass().getPackage().getSpecificationVersion();
- }
-
+
@Override
public Category getCategory() {
return Category.OTHER;
}
@Override
- public URL[] getDocs() {
- return null; // this can be overridden, but not required
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public NamedList getStatistics() {
- return null;
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
public static final Map> standard_components;
- ;
+
static {
HashMap> map = new HashMap<>();
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
index 2f805f45d02..4e3cd125c27 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
@@ -853,7 +853,7 @@ public class SpellCheckComponent extends SearchComponent implements SolrCoreAwar
}
// ///////////////////////////////////////////
- // / SolrInfoMBean
+ // / SolrInfoBean
// //////////////////////////////////////////
@Override
diff --git a/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java b/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java
index 6a6e9bef0d6..8ecd51c523a 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java
@@ -160,7 +160,7 @@ public class StatsComponent extends SearchComponent {
}
/////////////////////////////////////////////
- /// SolrInfoMBean
+ /// SolrInfoBean
////////////////////////////////////////////
@Override
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 bb87440c174..4ca6ce4b752 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
@@ -47,6 +47,9 @@ import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrEventListener;
+import org.apache.solr.metrics.MetricsMap;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.spelling.suggest.SolrSuggester;
import org.apache.solr.spelling.suggest.SuggesterOptions;
@@ -61,7 +64,7 @@ import org.slf4j.LoggerFactory;
* Responsible for routing commands and queries to the appropriate {@link SolrSuggester}
* and for initializing them as specified by SolrConfig
*/
-public class SuggestComponent extends SearchComponent implements SolrCoreAware, SuggesterParams, Accountable {
+public class SuggestComponent extends SearchComponent implements SolrCoreAware, SuggesterParams, Accountable, SolrMetricProducer {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/** Name used to identify whether the user query concerns this component */
@@ -89,7 +92,7 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
* Key is the dictionary name used in SolrConfig, value is the corresponding {@link SolrSuggester}
*/
protected Map suggesters = new ConcurrentHashMap<>();
-
+
/** Container for various labels used in the responses generated by this component */
private static class SuggesterResultLabels {
static final String SUGGEST = "suggest";
@@ -345,16 +348,18 @@ public class SuggestComponent extends SearchComponent implements SolrCoreAware,
}
@Override
- public NamedList getStatistics() {
- NamedList stats = new SimpleOrderedMap<>();
- stats.add("totalSizeInBytes", String.valueOf(ramBytesUsed()));
- for (Map.Entry entry : suggesters.entrySet()) {
- SolrSuggester suggester = entry.getValue();
- stats.add(entry.getKey(), suggester.toString());
- }
- return stats;
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ manager.registerGauge(this, registryName, () -> ramBytesUsed(), true, "totalSizeInBytes", getCategory().toString(), scope);
+ MetricsMap suggestersMap = new MetricsMap((detailed, map) -> {
+ for (Map.Entry entry : suggesters.entrySet()) {
+ SolrSuggester suggester = entry.getValue();
+ map.put(entry.getKey(), suggester.toString());
+ }
+ });
+ manager.registerGauge(this, registryName, suggestersMap, true, "suggesters", getCategory().toString(), scope);
}
-
+
@Override
public long ramBytesUsed() {
long sizeInBytes = 0;
diff --git a/solr/core/src/java/org/apache/solr/highlight/DefaultSolrHighlighter.java b/solr/core/src/java/org/apache/solr/highlight/DefaultSolrHighlighter.java
index 24304d0a1b6..7e56ee44e58 100644
--- a/solr/core/src/java/org/apache/solr/highlight/DefaultSolrHighlighter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/DefaultSolrHighlighter.java
@@ -128,40 +128,58 @@ public class DefaultSolrHighlighter extends SolrHighlighter implements PluginInf
// Load the fragmenters
SolrFragmenter frag = solrCore.initPlugins(info.getChildren("fragmenter") , fragmenters,SolrFragmenter.class,null);
- if (frag == null) frag = new GapFragmenter();
+ if (frag == null) {
+ frag = new GapFragmenter();
+ solrCore.initDefaultPlugin(frag, SolrFragmenter.class);
+ }
fragmenters.put("", frag);
fragmenters.put(null, frag);
// Load the formatters
SolrFormatter fmt = solrCore.initPlugins(info.getChildren("formatter"), formatters,SolrFormatter.class,null);
- if (fmt == null) fmt = new HtmlFormatter();
+ if (fmt == null) {
+ fmt = new HtmlFormatter();
+ solrCore.initDefaultPlugin(fmt, SolrFormatter.class);
+ }
formatters.put("", fmt);
formatters.put(null, fmt);
// Load the encoders
SolrEncoder enc = solrCore.initPlugins(info.getChildren("encoder"), encoders,SolrEncoder.class,null);
- if (enc == null) enc = new DefaultEncoder();
+ if (enc == null) {
+ enc = new DefaultEncoder();
+ solrCore.initDefaultPlugin(enc, SolrEncoder.class);
+ }
encoders.put("", enc);
encoders.put(null, enc);
// Load the FragListBuilders
SolrFragListBuilder fragListBuilder = solrCore.initPlugins(info.getChildren("fragListBuilder"),
fragListBuilders, SolrFragListBuilder.class, null );
- if( fragListBuilder == null ) fragListBuilder = new SimpleFragListBuilder();
+ if( fragListBuilder == null ) {
+ fragListBuilder = new SimpleFragListBuilder();
+ solrCore.initDefaultPlugin(fragListBuilder, SolrFragListBuilder.class);
+ }
fragListBuilders.put( "", fragListBuilder );
fragListBuilders.put( null, fragListBuilder );
// Load the FragmentsBuilders
SolrFragmentsBuilder fragsBuilder = solrCore.initPlugins(info.getChildren("fragmentsBuilder"),
fragmentsBuilders, SolrFragmentsBuilder.class, null);
- if( fragsBuilder == null ) fragsBuilder = new ScoreOrderFragmentsBuilder();
+ if( fragsBuilder == null ) {
+ fragsBuilder = new ScoreOrderFragmentsBuilder();
+ solrCore.initDefaultPlugin(fragsBuilder, SolrFragmentsBuilder.class);
+ }
fragmentsBuilders.put( "", fragsBuilder );
fragmentsBuilders.put( null, fragsBuilder );
// Load the BoundaryScanners
SolrBoundaryScanner boundaryScanner = solrCore.initPlugins(info.getChildren("boundaryScanner"),
boundaryScanners, SolrBoundaryScanner.class, null);
- if(boundaryScanner == null) boundaryScanner = new SimpleBoundaryScanner();
+ if(boundaryScanner == null) {
+ boundaryScanner = new SimpleBoundaryScanner();
+ solrCore.initDefaultPlugin(boundaryScanner, SolrBoundaryScanner.class);
+ }
boundaryScanners.put("", boundaryScanner);
boundaryScanners.put(null, boundaryScanner);
diff --git a/solr/core/src/java/org/apache/solr/highlight/GapFragmenter.java b/solr/core/src/java/org/apache/solr/highlight/GapFragmenter.java
index 64cb280a25a..6a11bb9018c 100644
--- a/solr/core/src/java/org/apache/solr/highlight/GapFragmenter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/GapFragmenter.java
@@ -30,7 +30,7 @@ public class GapFragmenter extends HighlightingPluginBase implements SolrFragmen
@Override
public Fragmenter getFragmenter(String fieldName, SolrParams params )
{
- numRequests++;
+ numRequests.inc();
params = SolrParams.wrapDefaults(params, defaults);
int fragsize = params.getFieldInt( fieldName, HighlightParams.FRAGSIZE, 100 );
diff --git a/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java b/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
index f60ada82d1b..7acaacdd03c 100644
--- a/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
+++ b/solr/core/src/java/org/apache/solr/highlight/HighlightingPluginBase.java
@@ -16,21 +16,27 @@
*/
package org.apache.solr.highlight;
-import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
/**
*
* @since solr 1.3
*/
-public abstract class HighlightingPluginBase implements SolrInfoMBean
+public abstract class HighlightingPluginBase implements SolrInfoBean, SolrMetricProducer
{
- protected long numRequests;
+ protected Counter numRequests;
protected SolrParams defaults;
+ protected Set metricNames = new HashSet<>(1);
+ protected MetricRegistry registry;
public void init(NamedList args) {
if( args != null ) {
@@ -50,14 +56,7 @@ public abstract class HighlightingPluginBase implements SolrInfoMBean
@Override
public abstract String getDescription();
- @Override
- public String getSource() { return null; }
-
- @Override
- public String getVersion() {
- return getClass().getPackage().getSpecificationVersion();
- }
-
+
@Override
public Category getCategory()
{
@@ -65,15 +64,19 @@ public abstract class HighlightingPluginBase implements SolrInfoMBean
}
@Override
- public URL[] getDocs() {
- return null; // this can be overridden, but not required
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public NamedList getStatistics() {
- NamedList lst = new SimpleOrderedMap<>();
- lst.add("requests", numRequests);
- return lst;
+ public MetricRegistry getMetricRegistry() {
+ return registry;
+ }
+
+ @Override
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ numRequests = manager.counter(this, registryName, "requests", getCategory().toString(), scope);
}
}
diff --git a/solr/core/src/java/org/apache/solr/highlight/HtmlFormatter.java b/solr/core/src/java/org/apache/solr/highlight/HtmlFormatter.java
index 842d5cdbfe6..0950c53e7ef 100644
--- a/solr/core/src/java/org/apache/solr/highlight/HtmlFormatter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/HtmlFormatter.java
@@ -29,7 +29,7 @@ public class HtmlFormatter extends HighlightingPluginBase implements SolrFormatt
@Override
public Formatter getFormatter(String fieldName, SolrParams params )
{
- numRequests++;
+ numRequests.inc();
params = SolrParams.wrapDefaults(params, defaults);
return new SimpleHTMLFormatter(
diff --git a/solr/core/src/java/org/apache/solr/highlight/RegexFragmenter.java b/solr/core/src/java/org/apache/solr/highlight/RegexFragmenter.java
index b755b2d0a92..ffefbad33ac 100644
--- a/solr/core/src/java/org/apache/solr/highlight/RegexFragmenter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/RegexFragmenter.java
@@ -60,7 +60,7 @@ public class RegexFragmenter extends HighlightingPluginBase implements SolrFragm
@Override
public Fragmenter getFragmenter(String fieldName, SolrParams params )
{
- numRequests++;
+ numRequests.inc();
params = SolrParams.wrapDefaults(params, defaults);
int fragsize = params.getFieldInt( fieldName, HighlightParams.FRAGSIZE, LuceneRegexFragmenter.DEFAULT_FRAGMENT_SIZE );
diff --git a/solr/core/src/java/org/apache/solr/highlight/SimpleFragListBuilder.java b/solr/core/src/java/org/apache/solr/highlight/SimpleFragListBuilder.java
index ed5430ce1e6..7e30a9231ae 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SimpleFragListBuilder.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SimpleFragListBuilder.java
@@ -28,7 +28,7 @@ public class SimpleFragListBuilder extends HighlightingPluginBase implements
// If that ever changes, it should wrap them with defaults...
// params = SolrParams.wrapDefaults(params, defaults)
- numRequests++;
+ numRequests.inc();
return new org.apache.lucene.search.vectorhighlight.SimpleFragListBuilder();
}
diff --git a/solr/core/src/java/org/apache/solr/highlight/SingleFragListBuilder.java b/solr/core/src/java/org/apache/solr/highlight/SingleFragListBuilder.java
index 0b79929b35d..0dfa16e454a 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SingleFragListBuilder.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SingleFragListBuilder.java
@@ -28,7 +28,7 @@ public class SingleFragListBuilder extends HighlightingPluginBase implements
// If that ever changes, it should wrap them with defaults...
// params = SolrParams.wrapDefaults(params, defaults)
- numRequests++;
+ numRequests.inc();
return new org.apache.lucene.search.vectorhighlight.SingleFragListBuilder();
}
diff --git a/solr/core/src/java/org/apache/solr/highlight/SolrBoundaryScanner.java b/solr/core/src/java/org/apache/solr/highlight/SolrBoundaryScanner.java
index 6f442f72bf1..ddbbfdeb88b 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SolrBoundaryScanner.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SolrBoundaryScanner.java
@@ -18,14 +18,14 @@ package org.apache.solr.highlight;
import org.apache.lucene.search.vectorhighlight.BoundaryScanner;
import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
public abstract class SolrBoundaryScanner extends HighlightingPluginBase implements
- SolrInfoMBean, NamedListInitializedPlugin {
+ SolrInfoBean, NamedListInitializedPlugin {
public BoundaryScanner getBoundaryScanner(String fieldName, SolrParams params){
- numRequests++;
+ numRequests.inc();
params = SolrParams.wrapDefaults(params, defaults);
return get(fieldName, params);
diff --git a/solr/core/src/java/org/apache/solr/highlight/SolrEncoder.java b/solr/core/src/java/org/apache/solr/highlight/SolrEncoder.java
index 9f49228805d..7b78a06969f 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SolrEncoder.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SolrEncoder.java
@@ -19,10 +19,10 @@ package org.apache.solr.highlight;
import org.apache.lucene.search.highlight.Encoder;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
-public interface SolrEncoder extends SolrInfoMBean, NamedListInitializedPlugin {
+public interface SolrEncoder extends SolrInfoBean, NamedListInitializedPlugin {
/** init
will be called just once, immediately after creation.
* The args are user-level initialization parameters that
diff --git a/solr/core/src/java/org/apache/solr/highlight/SolrFormatter.java b/solr/core/src/java/org/apache/solr/highlight/SolrFormatter.java
index a8f51dbcd46..1a6443e6def 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SolrFormatter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SolrFormatter.java
@@ -19,10 +19,10 @@ package org.apache.solr.highlight;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
-public interface SolrFormatter extends SolrInfoMBean, NamedListInitializedPlugin {
+public interface SolrFormatter extends SolrInfoBean, NamedListInitializedPlugin {
/** init
will be called just once, immediately after creation.
*
The args are user-level initialization parameters that
diff --git a/solr/core/src/java/org/apache/solr/highlight/SolrFragListBuilder.java b/solr/core/src/java/org/apache/solr/highlight/SolrFragListBuilder.java
index f0c36b4d602..87da23513b0 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SolrFragListBuilder.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SolrFragListBuilder.java
@@ -19,10 +19,10 @@ package org.apache.solr.highlight;
import org.apache.lucene.search.vectorhighlight.FragListBuilder;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
-public interface SolrFragListBuilder extends SolrInfoMBean, NamedListInitializedPlugin {
+public interface SolrFragListBuilder extends SolrInfoBean, NamedListInitializedPlugin {
/** init
will be called just once, immediately after creation.
*
The args are user-level initialization parameters that
diff --git a/solr/core/src/java/org/apache/solr/highlight/SolrFragmenter.java b/solr/core/src/java/org/apache/solr/highlight/SolrFragmenter.java
index 547506f5cf1..98c3056993d 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SolrFragmenter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SolrFragmenter.java
@@ -19,10 +19,10 @@ package org.apache.solr.highlight;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
-public interface SolrFragmenter extends SolrInfoMBean, NamedListInitializedPlugin {
+public interface SolrFragmenter extends SolrInfoBean, NamedListInitializedPlugin {
/** init
will be called just once, immediately after creation.
*
The args are user-level initialization parameters that
diff --git a/solr/core/src/java/org/apache/solr/highlight/SolrFragmentsBuilder.java b/solr/core/src/java/org/apache/solr/highlight/SolrFragmentsBuilder.java
index 78ea5a4deee..023d55ae391 100644
--- a/solr/core/src/java/org/apache/solr/highlight/SolrFragmentsBuilder.java
+++ b/solr/core/src/java/org/apache/solr/highlight/SolrFragmentsBuilder.java
@@ -21,11 +21,11 @@ import org.apache.lucene.search.vectorhighlight.FragmentsBuilder;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.HighlightParams;
import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
public abstract class SolrFragmentsBuilder extends HighlightingPluginBase
- implements SolrInfoMBean, NamedListInitializedPlugin {
+ implements SolrInfoBean, NamedListInitializedPlugin {
public static final String DEFAULT_PRE_TAGS = "";
public static final String DEFAULT_POST_TAGS = " ";
@@ -37,7 +37,7 @@ public abstract class SolrFragmentsBuilder extends HighlightingPluginBase
* @return An appropriate {@link org.apache.lucene.search.vectorhighlight.FragmentsBuilder}.
*/
public FragmentsBuilder getFragmentsBuilder(SolrParams params, BoundaryScanner bs) {
- numRequests++;
+ numRequests.inc();
params = SolrParams.wrapDefaults(params, defaults);
return getFragmentsBuilder( params, getPreTags( params, null ), getPostTags( params, null ), bs );
diff --git a/solr/core/src/java/org/apache/solr/highlight/WeightedFragListBuilder.java b/solr/core/src/java/org/apache/solr/highlight/WeightedFragListBuilder.java
index f44c0f0b430..b97cc31c89d 100644
--- a/solr/core/src/java/org/apache/solr/highlight/WeightedFragListBuilder.java
+++ b/solr/core/src/java/org/apache/solr/highlight/WeightedFragListBuilder.java
@@ -28,7 +28,7 @@ public class WeightedFragListBuilder extends HighlightingPluginBase implements
// If that ever changes, it should wrap them with defaults...
// params = SolrParams.wrapDefaults(params, defaults)
- numRequests++;
+ numRequests.inc();
return new org.apache.lucene.search.vectorhighlight.WeightedFragListBuilder();
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/AltBufferPoolMetricSet.java b/solr/core/src/java/org/apache/solr/metrics/AltBufferPoolMetricSet.java
new file mode 100644
index 00000000000..f9d3a43b7dc
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/metrics/AltBufferPoolMetricSet.java
@@ -0,0 +1,47 @@
+/*
+ * 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.lang.management.BufferPoolMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricSet;
+
+/**
+ * This is an alternative implementation of {@link com.codahale.metrics.jvm.BufferPoolMetricSet} that
+ * doesn't need an MBean server.
+ */
+public class AltBufferPoolMetricSet implements MetricSet {
+
+ @Override
+ public Map getMetrics() {
+ final Map metrics = new HashMap<>();
+ List pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
+ for (final BufferPoolMXBean pool : pools) {
+ String name = pool.getName();
+ metrics.put(name + ".Count", (Gauge)() -> pool.getCount());
+ metrics.put(name + ".MemoryUsed", (Gauge)() -> pool.getMemoryUsed());
+ metrics.put(name + ".TotalCapacity", (Gauge)() -> pool.getTotalCapacity());
+ }
+ return metrics;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java b/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java
new file mode 100644
index 00000000000..f43c60b5927
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java
@@ -0,0 +1,184 @@
+/*
+ * 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 javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.ReflectionException;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiConsumer;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+import org.apache.lucene.store.AlreadyClosedException;
+import org.apache.solr.common.SolrException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Dynamically constructed map of metrics, intentionally different from {@link com.codahale.metrics.MetricSet}
+ * where each metric had to be known in advance and registered separately in {@link com.codahale.metrics.MetricRegistry}.
+ * Note: this awkwardly extends {@link Gauge} and not {@link Metric} because awkwardly {@link Metric} instances
+ * are not supported by {@link com.codahale.metrics.MetricRegistryListener} :(
+ * Note 2: values added to this metric map should belong to the list of types supported by JMX:
+ * {@link javax.management.openmbean.OpenType#ALLOWED_CLASSNAMES_LIST}, otherwise only their toString()
+ * representation will be shown in JConsole.
+ */
+public class MetricsMap implements Gauge>, DynamicMBean {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ // set to true to use cached statistics between getMBeanInfo calls to work
+ // around over calling getStatistics on MBeanInfos when iterating over all attributes (SOLR-6586)
+ private final boolean useCachedStatsBetweenGetMBeanInfoCalls = Boolean.getBoolean("useCachedStatsBetweenGetMBeanInfoCalls");
+
+ private BiConsumer> initializer;
+ private volatile Map cachedValue;
+
+ public MetricsMap(BiConsumer> initializer) {
+ this.initializer = initializer;
+ }
+
+ @Override
+ public Map getValue() {
+ return getValue(true);
+ }
+
+ public Map getValue(boolean detailed) {
+ Map map = new HashMap<>();
+ initializer.accept(detailed, map);
+ return map;
+ }
+
+ public String toString() {
+ return getValue().toString();
+ }
+
+ @Override
+ public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
+ Object val;
+ Map stats = null;
+ if (useCachedStatsBetweenGetMBeanInfoCalls) {
+ Map cachedStats = this.cachedValue;
+ if (cachedStats != null) {
+ stats = cachedStats;
+ }
+ }
+ if (stats == null) {
+ stats = getValue(true);
+ }
+ val = stats.get(attribute);
+
+ if (val != null) {
+ // It's String or one of the simple types, just return it as JMX suggests direct support for such types
+ for (String simpleTypeName : SimpleType.ALLOWED_CLASSNAMES_LIST) {
+ if (val.getClass().getName().equals(simpleTypeName)) {
+ return val;
+ }
+ }
+ // It's an arbitrary object which could be something complex and odd, return its toString, assuming that is
+ // a workable representation of the object
+ return val.toString();
+ }
+ return null;
+ }
+
+ @Override
+ public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+ throw new UnsupportedOperationException("Operation not Supported");
+ }
+
+ @Override
+ public AttributeList getAttributes(String[] attributes) {
+ AttributeList list = new AttributeList();
+ for (String attribute : attributes) {
+ try {
+ list.add(new Attribute(attribute, getAttribute(attribute)));
+ } catch (Exception e) {
+ log.warn("Could not get attribute " + attribute);
+ }
+ }
+ return list;
+ }
+
+ @Override
+ public AttributeList setAttributes(AttributeList attributes) {
+ throw new UnsupportedOperationException("Operation not Supported");
+ }
+
+ @Override
+ public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
+ throw new UnsupportedOperationException("Operation not Supported");
+ }
+
+ @Override
+ public MBeanInfo getMBeanInfo() {
+ ArrayList attrInfoList = new ArrayList<>();
+ Map stats = getValue(true);
+ if (useCachedStatsBetweenGetMBeanInfoCalls) {
+ cachedValue = stats;
+ }
+ try {
+ stats.forEach((k, v) -> {
+ Class type = v.getClass();
+ OpenType typeBox = determineType(type);
+ if (type.equals(String.class) || typeBox == null) {
+ attrInfoList.add(new MBeanAttributeInfo(k, String.class.getName(),
+ null, true, false, false));
+ } else {
+ attrInfoList.add(new OpenMBeanAttributeInfoSupport(
+ k, k, typeBox, true, false, false));
+ }
+ });
+ } catch (Exception e) {
+ // don't log issue if the core is closing
+ if (!(SolrException.getRootCause(e) instanceof AlreadyClosedException))
+ log.warn("Could not get attributes of MetricsMap: {}", this, e);
+ }
+ MBeanAttributeInfo[] attrInfoArr = attrInfoList
+ .toArray(new MBeanAttributeInfo[attrInfoList.size()]);
+ return new MBeanInfo(getClass().getName(), "MetricsMap", attrInfoArr, null, null, null);
+ }
+
+ private OpenType determineType(Class type) {
+ try {
+ for (Field field : SimpleType.class.getFields()) {
+ if (field.getType().equals(SimpleType.class)) {
+ SimpleType candidate = (SimpleType) field.get(SimpleType.class);
+ if (candidate.getTypeName().equals(type.getName())) {
+ return candidate;
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/solr/core/src/java/org/apache/solr/metrics/OperatingSystemMetricSet.java b/solr/core/src/java/org/apache/solr/metrics/OperatingSystemMetricSet.java
index 34ef5d1c2e6..21957eb2285 100644
--- a/solr/core/src/java/org/apache/solr/metrics/OperatingSystemMetricSet.java
+++ b/solr/core/src/java/org/apache/solr/metrics/OperatingSystemMetricSet.java
@@ -16,77 +16,31 @@
*/
package org.apache.solr.metrics;
-import javax.management.JMException;
-import javax.management.MBeanAttributeInfo;
-import javax.management.MBeanInfo;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-import java.lang.invoke.MethodHandles;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
-import com.codahale.metrics.JmxAttributeGauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.solr.util.stats.MetricUtils;
/**
* This is an extended replacement for {@link com.codahale.metrics.jvm.FileDescriptorRatioGauge}
- * - that class uses reflection and doesn't work under Java 9. We can also get much more
- * information about OS environment once we have to go through MBeanServer anyway.
+ * - that class uses reflection and doesn't work under Java 9. This implementation tries to retrieve
+ * bean properties from known implementations of {@link java.lang.management.OperatingSystemMXBean}.
*/
public class OperatingSystemMetricSet implements MetricSet {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- /** Metric names - these correspond to known numeric MBean attributes. Depending on the OS and
- * Java implementation only some of them may be actually present.
- */
- public static final String[] METRICS = {
- "AvailableProcessors",
- "CommittedVirtualMemorySize",
- "FreePhysicalMemorySize",
- "FreeSwapSpaceSize",
- "MaxFileDescriptorCount",
- "OpenFileDescriptorCount",
- "ProcessCpuLoad",
- "ProcessCpuTime",
- "SystemLoadAverage",
- "TotalPhysicalMemorySize",
- "TotalSwapSpaceSize"
- };
-
- private final MBeanServer mBeanServer;
-
- public OperatingSystemMetricSet(MBeanServer mBeanServer) {
- this.mBeanServer = mBeanServer;
- }
@Override
public Map getMetrics() {
final Map metrics = new HashMap<>();
-
- try {
- final ObjectName on = new ObjectName("java.lang:type=OperatingSystem");
- // verify that it exists
- MBeanInfo info = mBeanServer.getMBeanInfo(on);
- // collect valid attributes
- Set attributes = new HashSet<>();
- for (MBeanAttributeInfo ai : info.getAttributes()) {
- attributes.add(ai.getName());
+ OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
+ MetricUtils.addMXBeanMetrics(os, MetricUtils.OS_MXBEAN_CLASSES, null, (k, v) -> {
+ if (!metrics.containsKey(k)) {
+ metrics.put(k, v);
}
- for (String metric : METRICS) {
- // verify that an attribute exists before attempting to add it
- if (attributes.contains(metric)) {
- metrics.put(metric, new JmxAttributeGauge(mBeanServer, on, metric));
- }
- }
- } catch (JMException ignored) {
- log.debug("Unable to load OperatingSystem MBean", ignored);
- }
-
+ });
return metrics;
}
}
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 43f35352ebf..193bf68ff3e 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java
@@ -20,11 +20,12 @@ import java.io.Closeable;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.core.NodeConfig;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,14 +77,14 @@ public class SolrCoreMetricManager implements Closeable {
}
/**
- * Load reporters configured globally and specific to {@link org.apache.solr.core.SolrInfoMBean.Group#core}
+ * 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() {
NodeConfig nodeConfig = core.getCoreDescriptor().getCoreContainer().getConfig();
PluginInfo[] pluginInfos = nodeConfig.getMetricReporterPlugins();
metricManager.loadReporters(pluginInfos, core.getResourceLoader(), tag,
- SolrInfoMBean.Group.core, registryName);
+ SolrInfoBean.Group.core, registryName);
if (cloudMode) {
metricManager.loadShardReporters(pluginInfos, core);
}
@@ -126,12 +127,26 @@ public class SolrCoreMetricManager implements Closeable {
producer.initializeMetrics(metricManager, getRegistryName(), scope);
}
+ /**
+ * Return the registry used by this SolrCore.
+ */
+ public MetricRegistry getRegistry() {
+ if (registryName != null) {
+ return metricManager.registry(registryName);
+ } else {
+ return null;
+ }
+ }
+
/**
* Closes reporters specific to this core.
*/
@Override
public void close() throws IOException {
metricManager.closeReporters(getRegistryName(), tag);
+ if (getLeaderRegistryName() != null) {
+ metricManager.closeReporters(getLeaderRegistryName(), tag);
+ }
}
public SolrCore getCore() {
@@ -176,9 +191,9 @@ public class SolrCoreMetricManager implements Closeable {
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(SolrInfoMBean.Group.core, collectionName, shardName, replicaName);
+ return SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, collectionName, shardName, replicaName);
} else {
- return SolrMetricManager.getRegistryName(SolrInfoMBean.Group.core, coreName);
+ return SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, coreName);
}
}
@@ -224,7 +239,7 @@ public class SolrCoreMetricManager implements Closeable {
public static String createLeaderRegistryName(boolean cloud, String collectionName, String shardName) {
if (cloud) {
- return SolrMetricManager.getRegistryName(SolrInfoMBean.Group.collection, collectionName, shardName, "leader");
+ return SolrMetricManager.getRegistryName(SolrInfoBean.Group.collection, collectionName, shardName, "leader");
} else {
return null;
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java
index 4d093ebb43c..8edfa042809 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java
@@ -17,7 +17,7 @@
package org.apache.solr.metrics;
import com.codahale.metrics.MetricRegistry;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
/**
* Wraps meta-data for a metric.
@@ -25,7 +25,7 @@ import org.apache.solr.core.SolrInfoMBean;
public final class SolrMetricInfo {
public final String name;
public final String scope;
- public final SolrInfoMBean.Category category;
+ public final SolrInfoBean.Category category;
/**
* Creates a new instance of {@link SolrMetricInfo}.
@@ -34,7 +34,7 @@ public final class SolrMetricInfo {
* @param scope the scope of the metric (e.g. `/admin/ping`)
* @param name the name of the metric (e.g. `Requests`)
*/
- public SolrMetricInfo(SolrInfoMBean.Category category, String scope, String name) {
+ public SolrMetricInfo(SolrInfoBean.Category category, String scope, String name) {
this.name = name;
this.scope = scope;
this.category = category;
@@ -45,18 +45,25 @@ public final class SolrMetricInfo {
return null;
}
String[] names = fullName.split("\\.");
- if (names.length < 3) { // not a valid info
+ if (names.length < 2) { // not a valid info
return null;
}
// check top-level name for valid category
- SolrInfoMBean.Category category;
+ SolrInfoBean.Category category;
try {
- category = SolrInfoMBean.Category.valueOf(names[0]);
+ category = SolrInfoBean.Category.valueOf(names[0]);
} catch (IllegalArgumentException e) { // not a valid category
return null;
}
- String scope = names[1];
- String name = fullName.substring(names[0].length() + names[1].length() + 2);
+ String scope;
+ String name;
+ if (names.length == 2) {
+ scope = null;
+ name = fullName.substring(names[0].length() + 1);
+ } else {
+ scope = names[1];
+ name = fullName.substring(names[0].length() + names[1].length() + 2);
+ }
return new SolrMetricInfo(category, scope, name);
}
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 f4abee0cc92..d4eb06ae7de 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
@@ -51,7 +51,7 @@ import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.metrics.reporters.solr.SolrClusterReporter;
import org.apache.solr.metrics.reporters.solr.SolrShardReporter;
@@ -69,11 +69,11 @@ import org.slf4j.LoggerFactory;
* {@link MetricRegistry} instances are automatically created when first referenced by name. Similarly,
* instances of {@link Metric} implementations, such as {@link Meter}, {@link Counter}, {@link Timer} and
* {@link Histogram} are automatically created and registered under hierarchical names, in a specified
- * registry, when {@link #meter(String, String, String...)} and other similar methods are called.
+ * registry, when {@link #meter(SolrInfoBean, String, String, String...)} and other similar methods are called.
* This class enforces a common prefix ({@link #REGISTRY_NAME_PREFIX}) in all registry
* names.
* Solr uses several different registries for collecting metrics belonging to different groups, using
- * {@link org.apache.solr.core.SolrInfoMBean.Group} as the main name of the registry (plus the
+ * {@link org.apache.solr.core.SolrInfoBean.Group} as the main name of the registry (plus the
* above-mentioned prefix). Instances of {@link SolrMetricManager} are created for each {@link org.apache.solr.core.CoreContainer},
* and most registries are local to each instance, with the exception of two global registries:
* solr.jetty
and solr.jvm
, which are shared between all {@link org.apache.solr.core.CoreContainer}-s
@@ -87,11 +87,11 @@ public class SolrMetricManager {
/** Registry name for Jetty-specific metrics. This name is also subject to overrides controlled by
* system properties. This registry is shared between instances of {@link SolrMetricManager}. */
- public static final String JETTY_REGISTRY = REGISTRY_NAME_PREFIX + SolrInfoMBean.Group.jetty.toString();
+ public static final String JETTY_REGISTRY = REGISTRY_NAME_PREFIX + SolrInfoBean.Group.jetty.toString();
/** Registry name for JVM-specific metrics. This name is also subject to overrides controlled by
* system properties. This registry is shared between instances of {@link SolrMetricManager}. */
- public static final String JVM_REGISTRY = REGISTRY_NAME_PREFIX + SolrInfoMBean.Group.jvm.toString();
+ public static final String JVM_REGISTRY = REGISTRY_NAME_PREFIX + SolrInfoBean.Group.jvm.toString();
private final ConcurrentMap registries = new ConcurrentHashMap<>();
@@ -247,6 +247,66 @@ public class SolrMetricManager {
}
}
+ public static class OrFilter implements MetricFilter {
+ List filters = new ArrayList<>();
+
+ public OrFilter(Collection filters) {
+ if (filters != null) {
+ this.filters.addAll(filters);
+ }
+ }
+
+ public OrFilter(MetricFilter... filters) {
+ if (filters != null) {
+ for (MetricFilter filter : filters) {
+ if (filter != null) {
+ this.filters.add(filter);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean matches(String s, Metric metric) {
+ for (MetricFilter filter : filters) {
+ if (filter.matches(s, metric)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public static class AndFilter implements MetricFilter {
+ List filters = new ArrayList<>();
+
+ public AndFilter(Collection filters) {
+ if (filters != null) {
+ this.filters.addAll(filters);
+ }
+ }
+
+ public AndFilter(MetricFilter... filters) {
+ if (filters != null) {
+ for (MetricFilter filter : filters) {
+ if (filter != null) {
+ this.filters.add(filter);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean matches(String s, Metric metric) {
+ for (MetricFilter filter : filters) {
+ if (!filter.matches(s, metric)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
/**
* Return a set of existing registry names.
*/
@@ -451,6 +511,21 @@ public class SolrMetricManager {
return filter.getMatched();
}
+ /**
+ * Retrieve matching metrics and their names.
+ * @param registry registry name.
+ * @param metricFilter filter (null is equivalent to {@link MetricFilter#ALL}).
+ * @return map of matching names and metrics
+ */
+ public Map getMetrics(String registry, MetricFilter metricFilter) {
+ if (metricFilter == null || metricFilter == MetricFilter.ALL) {
+ return registry(registry).getMetrics();
+ }
+ return registry(registry).getMetrics().entrySet().stream()
+ .filter(entry -> metricFilter.matches(entry.getKey(), entry.getValue()))
+ .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
+ }
+
/**
* Create or get an existing named {@link Meter}
* @param registry registry name
@@ -459,8 +534,12 @@ public class SolrMetricManager {
* @param metricPath (optional) additional top-most metric name path elements
* @return existing or a newly created {@link Meter}
*/
- public Meter meter(String registry, String metricName, String... metricPath) {
- return registry(registry).meter(mkName(metricName, metricPath));
+ public Meter meter(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+ final String name = mkName(metricName, metricPath);
+ if (info != null) {
+ info.registerMetricName(name);
+ }
+ return registry(registry).meter(name);
}
/**
@@ -471,8 +550,12 @@ public class SolrMetricManager {
* @param metricPath (optional) additional top-most metric name path elements
* @return existing or a newly created {@link Timer}
*/
- public Timer timer(String registry, String metricName, String... metricPath) {
- return registry(registry).timer(mkName(metricName, metricPath));
+ public Timer timer(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+ final String name = mkName(metricName, metricPath);
+ if (info != null) {
+ info.registerMetricName(name);
+ }
+ return registry(registry).timer(name);
}
/**
@@ -483,8 +566,12 @@ public class SolrMetricManager {
* @param metricPath (optional) additional top-most metric name path elements
* @return existing or a newly created {@link Counter}
*/
- public Counter counter(String registry, String metricName, String... metricPath) {
- return registry(registry).counter(mkName(metricName, metricPath));
+ public Counter counter(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+ final String name = mkName(metricName, metricPath);
+ if (info != null) {
+ info.registerMetricName(name);
+ }
+ return registry(registry).counter(name);
}
/**
@@ -495,8 +582,12 @@ public class SolrMetricManager {
* @param metricPath (optional) additional top-most metric name path elements
* @return existing or a newly created {@link Histogram}
*/
- public Histogram histogram(String registry, String metricName, String... metricPath) {
- return registry(registry).histogram(mkName(metricName, metricPath));
+ public Histogram histogram(SolrInfoBean info, String registry, String metricName, String... metricPath) {
+ final String name = mkName(metricName, metricPath);
+ if (info != null) {
+ info.registerMetricName(name);
+ }
+ return registry(registry).histogram(name);
}
/**
@@ -510,9 +601,12 @@ public class SolrMetricManager {
* using dotted notation
* @param metricPath (optional) additional top-most metric name path elements
*/
- public void register(String registry, Metric metric, boolean force, String metricName, String... metricPath) {
+ public void register(SolrInfoBean info, String registry, Metric metric, boolean force, String metricName, String... metricPath) {
MetricRegistry metricRegistry = registry(registry);
String fullName = mkName(metricName, metricPath);
+ if (info != null) {
+ info.registerMetricName(fullName);
+ }
synchronized (metricRegistry) {
if (force && metricRegistry.getMetrics().containsKey(fullName)) {
metricRegistry.remove(fullName);
@@ -521,8 +615,8 @@ public class SolrMetricManager {
}
}
- public void registerGauge(String registry, Gauge> gauge, boolean force, String metricName, String... metricPath) {
- register(registry, gauge, force, metricName, metricPath);
+ public void registerGauge(SolrInfoBean info, String registry, Gauge> gauge, boolean force, String metricName, String... metricPath) {
+ register(info, registry, gauge, force, metricName, metricPath);
}
/**
@@ -569,7 +663,7 @@ public class SolrMetricManager {
*
* NOTE: Once a registry is renamed in a way that its metrics are combined with another repository
* it is no longer possible to retrieve the original metrics until this renaming is removed and the Solr
- * {@link org.apache.solr.core.SolrInfoMBean.Group} of components that reported to that name is restarted.
+ * {@link org.apache.solr.core.SolrInfoBean.Group} of components that reported to that name is restarted.
* @param registry The name of the registry
* @return A potentially overridden (via System properties) registry name
*/
@@ -600,7 +694,7 @@ public class SolrMetricManager {
* and the group parameter will be ignored.
* @return fully-qualified and prefixed registry name, with overrides applied.
*/
- public static String getRegistryName(SolrInfoMBean.Group group, String... names) {
+ public static String getRegistryName(SolrInfoBean.Group group, String... names) {
String fullName;
String prefix = REGISTRY_NAME_PREFIX + group.toString() + ".";
// check for existing prefix and group
@@ -622,7 +716,7 @@ public class SolrMetricManager {
// reporter management
/**
- * Create and register {@link SolrMetricReporter}-s specific to a {@link org.apache.solr.core.SolrInfoMBean.Group}.
+ * Create and register {@link SolrMetricReporter}-s specific to a {@link org.apache.solr.core.SolrInfoBean.Group}.
* Note: reporters that specify neither "group" nor "registry" attributes are treated as universal -
* they will always be loaded for any group. These two attributes may also contain multiple comma- or
* whitespace-separated values, in which case the reporter will be loaded for any matching value from
@@ -634,7 +728,7 @@ public class SolrMetricManager {
* @param group selected group, not null
* @param registryNames optional child registry name elements
*/
- public void loadReporters(PluginInfo[] pluginInfos, SolrResourceLoader loader, String tag, SolrInfoMBean.Group group, String... registryNames) {
+ public void loadReporters(PluginInfo[] pluginInfos, SolrResourceLoader loader, String tag, SolrInfoBean.Group group, String... registryNames) {
if (pluginInfos == null || pluginInfos.length == 0) {
return;
}
@@ -941,13 +1035,13 @@ public class SolrMetricManager {
// prepare default plugin if none present in the config
Map attrs = new HashMap<>();
attrs.put("name", "shardDefault");
- attrs.put("group", SolrInfoMBean.Group.shard.toString());
+ attrs.put("group", SolrInfoBean.Group.shard.toString());
Map initArgs = new HashMap<>();
initArgs.put("period", DEFAULT_CLOUD_REPORTER_PERIOD);
String registryName = core.getCoreMetricManager().getRegistryName();
// collect infos and normalize
- List infos = prepareCloudPlugins(pluginInfos, SolrInfoMBean.Group.shard.toString(), SolrShardReporter.class.getName(),
+ List infos = prepareCloudPlugins(pluginInfos, SolrInfoBean.Group.shard.toString(), SolrShardReporter.class.getName(),
attrs, initArgs, null);
for (PluginInfo info : infos) {
try {
@@ -967,12 +1061,12 @@ public class SolrMetricManager {
}
Map attrs = new HashMap<>();
attrs.put("name", "clusterDefault");
- attrs.put("group", SolrInfoMBean.Group.cluster.toString());
+ attrs.put("group", SolrInfoBean.Group.cluster.toString());
Map initArgs = new HashMap<>();
initArgs.put("period", DEFAULT_CLOUD_REPORTER_PERIOD);
- List infos = prepareCloudPlugins(pluginInfos, SolrInfoMBean.Group.cluster.toString(), SolrClusterReporter.class.getName(),
+ List infos = prepareCloudPlugins(pluginInfos, SolrInfoBean.Group.cluster.toString(), SolrClusterReporter.class.getName(),
attrs, initArgs, null);
- String registryName = getRegistryName(SolrInfoMBean.Group.cluster);
+ String registryName = getRegistryName(SolrInfoBean.Group.cluster);
for (PluginInfo info : infos) {
try {
SolrMetricReporter reporter = loadReporter(registryName, cc.getResourceLoader(), info, null);
diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java
index ff2d3fcbdc6..9ad15d0168d 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java
@@ -30,6 +30,7 @@ public abstract class SolrMetricReporter implements Closeable, PluginInfoInitial
protected final String registryName;
protected final SolrMetricManager metricManager;
protected PluginInfo pluginInfo;
+ protected boolean enabled = true;
/**
* Create a reporter for metrics managed in a named registry.
@@ -57,6 +58,17 @@ public abstract class SolrMetricReporter implements Closeable, PluginInfoInitial
validate();
}
+ /**
+ * Enable reporting, defaults to true. Implementations should check this flag in
+ * {@link #validate()} and accordingly enable or disable reporting.
+ * @param enabled enable, defaults to true when null or not set.
+ */
+ public void setEnabled(Boolean enabled) {
+ if (enabled != null) {
+ this.enabled = enabled;
+ }
+ }
+
/**
* Get the effective {@link PluginInfo} instance that was used for
* initialization of this plugin.
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java b/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
index 1f5b4f01513..4298c1842da 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
@@ -50,6 +50,20 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
this.props = additionalProperties;
}
+ /**
+ * Return current domain.
+ */
+ public String getDomain() {
+ return domain;
+ }
+
+ /**
+ * Return current reporterName.
+ */
+ public String getReporterName() {
+ return reporterName;
+ }
+
/**
* Create a hierarchical name.
*
@@ -60,7 +74,8 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
@Override
public ObjectName createName(String type, String currentDomain, String name) {
SolrMetricInfo metricInfo = SolrMetricInfo.of(name);
-
+ String safeName = metricInfo != null ? metricInfo.name : name;
+ safeName = safeName.replaceAll(":", "_");
// It turns out that ObjectName(String) mostly preserves key ordering
// as specified in the constructor (except for the 'type' key that ends
// up at top level) - unlike ObjectName(String, Map) constructor
@@ -90,24 +105,42 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
sb.append(currentDomain);
sb.append(':');
}
- sb.append("reporter=");
- sb.append(reporterName);
- sb.append(',');
+ if (props != null && props.length > 0) {
+ boolean added = false;
+ for (int i = 0; i < props.length; i += 2) {
+ if (props[i] == null || props[i].isEmpty()) {
+ continue;
+ }
+ if (props[i + 1] == null || props[i + 1].isEmpty()) {
+ continue;
+ }
+ sb.append(',');
+ sb.append(props[i]);
+ sb.append('=');
+ sb.append(props[i + 1]);
+ added = true;
+ }
+ if (added) {
+ sb.append(',');
+ }
+ }
if (metricInfo != null) {
sb.append("category=");
sb.append(metricInfo.category.toString());
- sb.append(",scope=");
- sb.append(metricInfo.scope);
+ if (metricInfo.scope != null) {
+ sb.append(",scope=");
+ sb.append(metricInfo.scope);
+ }
// we could also split by type, but don't call it 'type' :)
// if (type != null) {
// sb.append(",class=");
// sb.append(type);
// }
sb.append(",name=");
- sb.append(metricInfo.name);
+ sb.append(safeName);
} else {
// make dotted names into hierarchies
- String[] path = name.split("\\.");
+ String[] path = safeName.split("\\.");
for (int i = 0; i < path.length - 1; i++) {
if (i > 0) {
sb.append(',');
@@ -127,20 +160,6 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
sb.append("name=");
sb.append(path[path.length - 1]);
}
- if (props != null && props.length > 0) {
- for (int i = 0; i < props.length; i += 2) {
- if (props[i] == null || props[i].isEmpty()) {
- continue;
- }
- if (props[i + 1] == null || props[i + 1].isEmpty()) {
- continue;
- }
- sb.append(',');
- sb.append(props[i]);
- sb.append('=');
- sb.append(props[i + 1]);
- }
- }
ObjectName objectName;
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java b/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java
new file mode 100644
index 00000000000..5745dec1738
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java
@@ -0,0 +1,84 @@
+/*
+ * 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.reporters;
+
+import java.io.Closeable;
+import java.lang.invoke.MethodHandles;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simple cache for reusable service clients used by some implementations of
+ * {@link org.apache.solr.metrics.SolrMetricReporter}.
+ */
+public class ReporterClientCache implements Closeable {
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private final Map cache = new ConcurrentHashMap<>();
+
+ /**
+ * Provide an instance of service client.
+ * @param formal type
+ */
+ public interface ClientProvider {
+ /**
+ * Get an instance of a service client. It's not specified that each time this
+ * method is invoked a new client instance should be returned.
+ * @return client instance
+ * @throws Exception when client creation encountered an error.
+ */
+ T get() throws Exception;
+ }
+
+ /**
+ * Get existing or register a new client.
+ * @param id client id
+ * @param clientProvider provider of new client instances
+ */
+ public synchronized T getOrCreate(String id, ClientProvider clientProvider) {
+ T item = cache.get(id);
+ if (item == null) {
+ try {
+ item = clientProvider.get();
+ cache.put(id, item);
+ } catch (Exception e) {
+ LOG.warn("Error providing a new client for id=" + id, e);
+ item = null;
+ }
+ }
+ return item;
+ }
+
+ /**
+ * Empty this cache, and close all clients that are {@link Closeable}.
+ */
+ public void close() {
+ for (T client : cache.values()) {
+ if (client instanceof Closeable) {
+ try {
+ ((Closeable)client).close();
+ } catch (Exception e) {
+ LOG.warn("Error closing client " + client + ", ignoring...", e);
+ }
+ }
+ }
+ cache.clear();
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGangliaReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGangliaReporter.java
index 45561e58b58..142ddd884e6 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGangliaReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGangliaReporter.java
@@ -17,6 +17,9 @@
package org.apache.solr.metrics.reporters;
import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import com.codahale.metrics.MetricFilter;
@@ -24,21 +27,26 @@ import com.codahale.metrics.ganglia.GangliaReporter;
import info.ganglia.gmetric4j.gmetric.GMetric;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricReporter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
*
*/
public class SolrGangliaReporter extends SolrMetricReporter {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private String host = null;
private int port = -1;
private boolean multicast;
private int period = 60;
private String instancePrefix = null;
- private String filterPrefix = null;
+ private List filters = new ArrayList<>();
private boolean testing;
private GangliaReporter reporter;
+ private static final ReporterClientCache serviceRegistry = new ReporterClientCache<>();
+
// for unit tests
GMetric ganglia = null;
@@ -65,10 +73,24 @@ public class SolrGangliaReporter extends SolrMetricReporter {
this.instancePrefix = prefix;
}
- public void setFilter(String filter) {
- this.filterPrefix = filter;
+ /**
+ * Report only metrics with names matching any of the prefix filters.
+ * @param filters list of 0 or more prefixes. If the list is empty then
+ * all names will match.
+ */
+ public void setFilter(List filters) {
+ if (filters == null || filters.isEmpty()) {
+ return;
+ }
+ this.filters.addAll(filters);
}
+ // due to vagaries of SolrPluginUtils.invokeSetters we need this too
+ public void setFilter(String filter) {
+ if (filter != null && !filter.isEmpty()) {
+ this.filters.add(filter);
+ }
+ }
public void setPeriod(int period) {
this.period = period;
@@ -89,6 +111,10 @@ public class SolrGangliaReporter extends SolrMetricReporter {
@Override
protected void validate() throws IllegalStateException {
+ if (!enabled) {
+ log.info("Reporter disabled for registry " + registryName);
+ return;
+ }
if (host == null) {
throw new IllegalStateException("Init argument 'host' must be set to a valid Ganglia server name.");
}
@@ -106,12 +132,12 @@ public class SolrGangliaReporter extends SolrMetricReporter {
//this is a separate method for unit tests
void start() {
if (!testing) {
- try {
- ganglia = new GMetric(host, port,
- multicast ? GMetric.UDPAddressingMode.MULTICAST : GMetric.UDPAddressingMode.UNICAST,
- 1);
- } catch (IOException ioe) {
- throw new IllegalStateException("Exception connecting to Ganglia", ioe);
+ String id = host + ":" + port + ":" + multicast;
+ ganglia = serviceRegistry.getOrCreate(id, () -> new GMetric(host, port,
+ multicast ? GMetric.UDPAddressingMode.MULTICAST : GMetric.UDPAddressingMode.UNICAST,
+ 1));
+ if (ganglia == null) {
+ return;
}
}
if (instancePrefix == null) {
@@ -125,8 +151,8 @@ public class SolrGangliaReporter extends SolrMetricReporter {
.convertDurationsTo(TimeUnit.MILLISECONDS)
.prefixedWith(instancePrefix);
MetricFilter filter;
- if (filterPrefix != null) {
- filter = new SolrMetricManager.PrefixFilter(filterPrefix);
+ if (!filters.isEmpty()) {
+ filter = new SolrMetricManager.PrefixFilter(filters);
} else {
filter = MetricFilter.ALL;
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGraphiteReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGraphiteReporter.java
index 8565ce86c05..d5b7a203ab8 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGraphiteReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGraphiteReporter.java
@@ -18,6 +18,8 @@ package org.apache.solr.metrics.reporters;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import com.codahale.metrics.MetricFilter;
@@ -41,9 +43,11 @@ public class SolrGraphiteReporter extends SolrMetricReporter {
private int period = 60;
private boolean pickled = false;
private String instancePrefix = null;
- private String filterPrefix = null;
+ private List filters = new ArrayList<>();
private GraphiteReporter reporter = null;
+ private static final ReporterClientCache serviceRegistry = new ReporterClientCache<>();
+
/**
* Create a Graphite reporter for metrics managed in a named registry.
*
@@ -67,10 +71,25 @@ public class SolrGraphiteReporter extends SolrMetricReporter {
this.instancePrefix = prefix;
}
- public void setFilter(String filter) {
- this.filterPrefix = filter;
+ /**
+ * Report only metrics with names matching any of the prefix filters.
+ * @param filters list of 0 or more prefixes. If the list is empty then
+ * all names will match.
+ */
+ public void setFilter(List filters) {
+ if (filters == null || filters.isEmpty()) {
+ return;
+ }
+ this.filters.addAll(filters);
}
+ public void setFilter(String filter) {
+ if (filter != null && !filter.isEmpty()) {
+ this.filters.add(filter);
+ }
+ }
+
+
public void setPickled(boolean pickled) {
this.pickled = pickled;
}
@@ -81,6 +100,10 @@ public class SolrGraphiteReporter extends SolrMetricReporter {
@Override
protected void validate() throws IllegalStateException {
+ if (!enabled) {
+ log.info("Reporter disabled for registry " + registryName);
+ return;
+ }
if (host == null) {
throw new IllegalStateException("Init argument 'host' must be set to a valid Graphite server name.");
}
@@ -93,12 +116,15 @@ public class SolrGraphiteReporter extends SolrMetricReporter {
if (period < 1) {
throw new IllegalStateException("Init argument 'period' is in time unit 'seconds' and must be at least 1.");
}
- final GraphiteSender graphite;
- if (pickled) {
- graphite = new PickledGraphite(host, port);
- } else {
- graphite = new Graphite(host, port);
- }
+ GraphiteSender graphite;
+ String id = host + ":" + port + ":" + pickled;
+ graphite = serviceRegistry.getOrCreate(id, () -> {
+ if (pickled) {
+ return new PickledGraphite(host, port);
+ } else {
+ return new Graphite(host, port);
+ }
+ });
if (instancePrefix == null) {
instancePrefix = registryName;
} else {
@@ -110,8 +136,8 @@ public class SolrGraphiteReporter extends SolrMetricReporter {
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS);
MetricFilter filter;
- if (filterPrefix != null) {
- filter = new SolrMetricManager.PrefixFilter(filterPrefix);
+ if (!filters.isEmpty()) {
+ filter = new SolrMetricManager.PrefixFilter(filters);
} else {
filter = MetricFilter.ALL;
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
index 0e78eee038a..d09e0437214 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
@@ -16,15 +16,25 @@
*/
package org.apache.solr.metrics.reporters;
+import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
-import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
+import java.util.Set;
+import com.codahale.metrics.Gauge;
import com.codahale.metrics.JmxReporter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricRegistryListener;
import org.apache.solr.core.PluginInfo;
+import org.apache.solr.metrics.MetricsMap;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricReporter;
import org.apache.solr.util.JmxUtil;
@@ -34,17 +44,25 @@ import org.slf4j.LoggerFactory;
/**
* A {@link SolrMetricReporter} that finds (or creates) a MBeanServer from
* the given configuration and registers metrics to it with JMX.
+ * NOTE: {@link JmxReporter} that this class uses exports only newly added metrics (it doesn't
+ * process already existing metrics in a registry)
*/
public class SolrJmxReporter extends SolrMetricReporter {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private static final ReporterClientCache serviceRegistry = new ReporterClientCache<>();
+
private String domain;
private String agentId;
private String serviceUrl;
+ private String rootName;
+ private List filters = new ArrayList<>();
private JmxReporter reporter;
+ private MetricRegistry registry;
private MBeanServer mBeanServer;
+ private MetricsMapListener listener;
/**
* Creates a new instance of {@link SolrJmxReporter}.
@@ -57,7 +75,7 @@ public class SolrJmxReporter extends SolrMetricReporter {
}
/**
- * Initializes the reporter by finding (or creating) a MBeanServer
+ * Initializes the reporter by finding an MBeanServer
* and registering the metricManager's metric registry.
*
* @param pluginInfo the configuration for the reporter
@@ -65,44 +83,62 @@ public class SolrJmxReporter extends SolrMetricReporter {
@Override
public synchronized void init(PluginInfo pluginInfo) {
super.init(pluginInfo);
-
+ if (!enabled) {
+ log.info("Reporter disabled for registry " + registryName);
+ return;
+ }
+ log.debug("Initializing for registry " + registryName);
if (serviceUrl != null && agentId != null) {
- ManagementFactory.getPlatformMBeanServer(); // Ensure at least one MBeanServer is available.
mBeanServer = JmxUtil.findFirstMBeanServer();
- log.warn("No more than one of serviceUrl(%s) and agentId(%s) should be configured, using first MBeanServer instead of configuration.",
+ log.warn("No more than one of serviceUrl({}) and agentId({}) should be configured, using first MBeanServer instead of configuration.",
serviceUrl, agentId, mBeanServer);
- }
- else if (serviceUrl != null) {
- try {
- mBeanServer = JmxUtil.findMBeanServerForServiceUrl(serviceUrl);
- } catch (IOException e) {
- log.warn("findMBeanServerForServiceUrl(%s) exception: %s", serviceUrl, e);
- mBeanServer = null;
- }
- }
- else if (agentId != null) {
+ } else if (serviceUrl != null) {
+ // reuse existing services
+ mBeanServer = serviceRegistry.getOrCreate(serviceUrl, () -> JmxUtil.findMBeanServerForServiceUrl(serviceUrl));
+ } else if (agentId != null) {
mBeanServer = JmxUtil.findMBeanServerForAgentId(agentId);
} else {
- ManagementFactory.getPlatformMBeanServer(); // Ensure at least one MBeanServer is available.
mBeanServer = JmxUtil.findFirstMBeanServer();
- log.warn("No serviceUrl or agentId was configured, using first MBeanServer.", mBeanServer);
+ log.debug("No serviceUrl or agentId was configured, using first MBeanServer: " + mBeanServer);
}
if (mBeanServer == null) {
- log.warn("No JMX server found. Not exposing Solr metrics.");
+ log.warn("No JMX server found. Not exposing Solr metrics via JMX.");
return;
}
- JmxObjectNameFactory jmxObjectNameFactory = new JmxObjectNameFactory(pluginInfo.name, domain);
+ if (domain == null || domain.isEmpty()) {
+ domain = registryName;
+ }
+ String fullDomain = domain;
+ if (rootName != null && !rootName.isEmpty()) {
+ fullDomain = rootName + "." + domain;
+ }
+ JmxObjectNameFactory jmxObjectNameFactory = new JmxObjectNameFactory(pluginInfo.name, fullDomain);
+ registry = metricManager.registry(registryName);
+ // filter out MetricsMap gauges - we have a better way of handling them
+ MetricFilter mmFilter = (name, metric) -> !(metric instanceof MetricsMap);
+ MetricFilter filter;
+ if (filters.isEmpty()) {
+ filter = mmFilter;
+ } else {
+ // apply also prefix filters
+ SolrMetricManager.PrefixFilter prefixFilter = new SolrMetricManager.PrefixFilter(filters);
+ filter = new SolrMetricManager.AndFilter(prefixFilter, mmFilter);
+ }
- reporter = JmxReporter.forRegistry(metricManager.registry(registryName))
+ reporter = JmxReporter.forRegistry(registry)
.registerWith(mBeanServer)
- .inDomain(domain)
+ .inDomain(fullDomain)
+ .filter(filter)
.createsObjectNamesWith(jmxObjectNameFactory)
.build();
reporter.start();
+ // workaround for inability to register custom MBeans (to be available in metrics 4.0?)
+ listener = new MetricsMapListener(mBeanServer, jmxObjectNameFactory);
+ registry.addListener(listener);
- log.info("JMX monitoring enabled at server: " + mBeanServer);
+ log.info("JMX monitoring for '" + fullDomain + "' (registry '" + registryName + "') enabled at server: " + mBeanServer);
}
/**
@@ -114,6 +150,11 @@ public class SolrJmxReporter extends SolrMetricReporter {
reporter.close();
reporter = null;
}
+ if (listener != null && registry != null) {
+ registry.removeListener(listener);
+ listener.close();
+ listener = null;
+ }
}
/**
@@ -127,9 +168,19 @@ public class SolrJmxReporter extends SolrMetricReporter {
// Nothing to validate
}
+
+ /**
+ * Set root name of the JMX hierarchy for this reporter. Default (null or empty) is none, ie.
+ * the hierarchy will start from the domain name.
+ * @param rootName root name of the JMX name hierarchy, or null or empty for default.
+ */
+ public void setRootName(String rootName) {
+ this.rootName = rootName;
+ }
+
/**
* Sets the domain with which MBeans are published. If none is set,
- * the domain defaults to the name of the core.
+ * the domain defaults to the name of the registry.
*
* @param domain the domain
*/
@@ -162,7 +213,46 @@ public class SolrJmxReporter extends SolrMetricReporter {
}
/**
- * Retrieves the reporter's MBeanServer.
+ * Return configured agentId or null.
+ */
+ public String getAgentId() {
+ return agentId;
+ }
+
+ /**
+ * Return configured serviceUrl or null.
+ */
+ public String getServiceUrl() {
+ return serviceUrl;
+ }
+
+ /**
+ * Return configured domain or null.
+ */
+ public String getDomain() {
+ return domain;
+ }
+
+ /**
+ * Report only metrics with names matching any of the prefix filters.
+ * @param filters list of 0 or more prefixes. If the list is empty then
+ * all names will match.
+ */
+ public void setFilter(List filters) {
+ if (filters == null || filters.isEmpty()) {
+ return;
+ }
+ this.filters.addAll(filters);
+ }
+
+ public void setFilter(String filter) {
+ if (filter != null && !filter.isEmpty()) {
+ this.filters.add(filter);
+ }
+ }
+
+ /**
+ * Return the reporter's MBeanServer.
*
* @return the reporter's MBeanServer
*/
@@ -170,10 +260,72 @@ public class SolrJmxReporter extends SolrMetricReporter {
return mBeanServer;
}
- @Override
- public String toString() {
- return String.format(Locale.ENGLISH, "[%s@%s: domain = %s, service url = %s, agent id = %s]",
- getClass().getName(), Integer.toHexString(hashCode()), domain, serviceUrl, agentId);
+ /**
+ * For unit tests.
+ * @return true if this reporter is actively reporting metrics to JMX.
+ */
+ public boolean isActive() {
+ return reporter != null;
}
+ @Override
+ public String toString() {
+ return String.format(Locale.ENGLISH, "[%s@%s: rootName = %s, domain = %s, service url = %s, agent id = %s]",
+ getClass().getName(), Integer.toHexString(hashCode()), rootName, domain, serviceUrl, agentId);
+ }
+
+ private static class MetricsMapListener extends MetricRegistryListener.Base {
+ MBeanServer server;
+ JmxObjectNameFactory nameFactory;
+ // keep the names so that we can unregister them on core close
+ Set registered = new HashSet<>();
+
+ MetricsMapListener(MBeanServer server, JmxObjectNameFactory nameFactory) {
+ this.server = server;
+ this.nameFactory = nameFactory;
+ }
+
+ @Override
+ public void onGaugeAdded(String name, Gauge> gauge) {
+ if (!(gauge instanceof MetricsMap)) {
+ return;
+ }
+ synchronized (server) {
+ try {
+ ObjectName objectName = nameFactory.createName("gauges", nameFactory.getDomain(), name);
+ log.debug("REGISTER " + objectName);
+ if (registered.contains(objectName) || server.isRegistered(objectName)) {
+ log.debug("-unregistering old instance of " + objectName);
+ try {
+ server.unregisterMBean(objectName);
+ } catch (InstanceNotFoundException e) {
+ // ignore
+ }
+ }
+ // some MBean servers re-write object name to include additional properties
+ ObjectInstance instance = server.registerMBean(gauge, objectName);
+ if (instance != null) {
+ registered.add(instance.getObjectName());
+ }
+ } catch (Exception e) {
+ log.warn("bean registration error", e);
+ }
+ }
+ }
+
+ public void close() {
+ synchronized (server) {
+ for (ObjectName name : registered) {
+ try {
+ if (server.isRegistered(name)) {
+ server.unregisterMBean(name);
+ }
+ } catch (Exception e) {
+ log.debug("bean unregistration error", e);
+ }
+ }
+ registered.clear();
+ }
+ }
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrSlf4jReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrSlf4jReporter.java
index 817dda17f94..8b7c35e88e4 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/SolrSlf4jReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrSlf4jReporter.java
@@ -18,6 +18,8 @@ package org.apache.solr.metrics.reporters;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import com.codahale.metrics.MetricFilter;
@@ -47,7 +49,7 @@ public class SolrSlf4jReporter extends SolrMetricReporter {
private int period = 60;
private String instancePrefix = null;
private String logger = null;
- private String filterPrefix = null;
+ private List filters = new ArrayList<>();
private Slf4jReporter reporter;
/**
@@ -65,10 +67,25 @@ public class SolrSlf4jReporter extends SolrMetricReporter {
this.instancePrefix = prefix;
}
- public void setFilter(String filter) {
- this.filterPrefix = filter;
+ /**
+ * Report only metrics with names matching any of the prefix filters.
+ * @param filters list of 0 or more prefixes. If the list is empty then
+ * all names will match.
+ */
+ public void setFilter(List filters) {
+ if (filters == null || filters.isEmpty()) {
+ return;
+ }
+ this.filters.addAll(filters);
}
+ public void setFilter(String filter) {
+ if (filter != null && !filter.isEmpty()) {
+ this.filters.add(filter);
+ }
+ }
+
+
public void setLogger(String logger) {
this.logger = logger;
}
@@ -79,6 +96,10 @@ public class SolrSlf4jReporter extends SolrMetricReporter {
@Override
protected void validate() throws IllegalStateException {
+ if (!enabled) {
+ log.info("Reporter disabled for registry " + registryName);
+ return;
+ }
if (period < 1) {
throw new IllegalStateException("Init argument 'period' is in time unit 'seconds' and must be at least 1.");
}
@@ -93,8 +114,8 @@ public class SolrSlf4jReporter extends SolrMetricReporter {
.convertDurationsTo(TimeUnit.MILLISECONDS);
MetricFilter filter;
- if (filterPrefix != null) {
- filter = new SolrMetricManager.PrefixFilter(filterPrefix);
+ if (!filters.isEmpty()) {
+ filter = new SolrMetricManager.PrefixFilter(filters);
} else {
filter = MetricFilter.ALL;
}
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrClusterReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrClusterReporter.java
index a34accd82aa..c4374570b23 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrClusterReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrClusterReporter.java
@@ -33,7 +33,7 @@ import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.core.CoreContainer;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.handler.admin.MetricsCollectorHandler;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricReporter;
@@ -92,14 +92,14 @@ import static org.apache.solr.common.params.CommonParams.ID;
public class SolrClusterReporter extends SolrMetricReporter {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- public static final String CLUSTER_GROUP = SolrMetricManager.overridableRegistryName(SolrInfoMBean.Group.cluster.toString());
+ public static final String CLUSTER_GROUP = SolrMetricManager.overridableRegistryName(SolrInfoBean.Group.cluster.toString());
public static final List DEFAULT_REPORTS = new ArrayList() {{
add(new SolrReporter.Report(CLUSTER_GROUP, "jetty",
- SolrMetricManager.overridableRegistryName(SolrInfoMBean.Group.jetty.toString()),
+ SolrMetricManager.overridableRegistryName(SolrInfoBean.Group.jetty.toString()),
Collections.emptySet())); // all metrics
add(new SolrReporter.Report(CLUSTER_GROUP, "jvm",
- SolrMetricManager.overridableRegistryName(SolrInfoMBean.Group.jvm.toString()),
+ SolrMetricManager.overridableRegistryName(SolrInfoBean.Group.jvm.toString()),
new HashSet() {{
add("memory\\.total\\..*");
add("memory\\.heap\\..*");
@@ -109,7 +109,7 @@ public class SolrClusterReporter extends SolrMetricReporter {
add("os\\.OpenFileDescriptorCount");
add("threads\\.count");
}}));
- add(new SolrReporter.Report(CLUSTER_GROUP, "node", SolrMetricManager.overridableRegistryName(SolrInfoMBean.Group.node.toString()),
+ add(new SolrReporter.Report(CLUSTER_GROUP, "node", SolrMetricManager.overridableRegistryName(SolrInfoBean.Group.node.toString()),
new HashSet() {{
add("CONTAINER\\.cores\\..*");
add("CONTAINER\\.fs\\..*");
@@ -159,6 +159,16 @@ public class SolrClusterReporter extends SolrMetricReporter {
});
}
+ public void setReport(Map map) {
+ if (map == null || map.isEmpty()) {
+ return;
+ }
+ SolrReporter.Report r = SolrReporter.Report.fromMap(map);
+ if (r != null) {
+ reports.add(r);
+ }
+ }
+
// for unit tests
int getPeriod() {
return period;
@@ -170,9 +180,6 @@ public class SolrClusterReporter extends SolrMetricReporter {
@Override
protected void validate() throws IllegalStateException {
- if (period < 1) {
- log.info("Turning off node reporter, period=" + period);
- }
if (reports.isEmpty()) { // set defaults
reports = DEFAULT_REPORTS;
}
@@ -189,12 +196,17 @@ public class SolrClusterReporter extends SolrMetricReporter {
if (reporter != null) {
reporter.close();;
}
+ if (!enabled) {
+ log.info("Reporter disabled for registry " + registryName);
+ return;
+ }
// start reporter only in cloud mode
if (!cc.isZooKeeperAware()) {
log.warn("Not ZK-aware, not starting...");
return;
}
if (period < 1) { // don't start it
+ log.info("Turning off node reporter, period=" + period);
return;
}
HttpClient httpClient = cc.getUpdateShardHandler().getHttpClient();
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrShardReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrShardReporter.java
index 8b36d3e0c96..b36c59679b7 100644
--- a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrShardReporter.java
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrShardReporter.java
@@ -98,7 +98,13 @@ public class SolrShardReporter extends SolrMetricReporter {
if (filterConfig == null || filterConfig.isEmpty()) {
return;
}
- filters = filterConfig;
+ filters.addAll(filterConfig);
+ }
+
+ public void setFilter(String filter) {
+ if (filter != null && !filter.isEmpty()) {
+ this.filters.add(filter);
+ }
}
// for unit tests
@@ -108,9 +114,6 @@ public class SolrShardReporter extends SolrMetricReporter {
@Override
protected void validate() throws IllegalStateException {
- if (period < 1) {
- log.info("Turning off shard reporter, period=" + period);
- }
if (filters.isEmpty()) {
filters = DEFAULT_FILTERS;
}
@@ -128,13 +131,17 @@ public class SolrShardReporter extends SolrMetricReporter {
if (reporter != null) {
reporter.close();
}
+ if (!enabled) {
+ log.info("Reporter disabled for registry " + registryName);
+ return;
+ }
if (core.getCoreDescriptor().getCloudDescriptor() == null) {
// not a cloud core
log.warn("Not initializing shard reporter for non-cloud core " + core.getName());
return;
}
if (period < 1) { // don't start it
- log.warn("Not starting shard reporter ");
+ log.warn("period=" + period + ", not starting shard reporter ");
return;
}
// our id is coreNodeName
diff --git a/solr/core/src/java/org/apache/solr/request/SolrRequestHandler.java b/solr/core/src/java/org/apache/solr/request/SolrRequestHandler.java
index 82ce2e0fbeb..8350f9ed1c0 100644
--- a/solr/core/src/java/org/apache/solr/request/SolrRequestHandler.java
+++ b/solr/core/src/java/org/apache/solr/request/SolrRequestHandler.java
@@ -17,7 +17,7 @@
package org.apache.solr.request;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.response.SolrQueryResponse;
/**
@@ -38,7 +38,7 @@ import org.apache.solr.response.SolrQueryResponse;
*
*
*/
-public interface SolrRequestHandler extends SolrInfoMBean {
+public interface SolrRequestHandler extends SolrInfoBean {
/** init
will be called just once, immediately after creation.
* The args are user-level initialization parameters that
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 9c4b8920aab..cb699b25abc 100644
--- a/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/FastLRUCache.java
@@ -15,15 +15,17 @@
* limitations under the License.
*/
package org.apache.solr.search;
+
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.common.SolrException;
+import org.apache.solr.metrics.MetricsMap;
+import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.util.ConcurrentLRUCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import java.io.Serializable;
import java.lang.invoke.MethodHandles;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -57,6 +59,10 @@ public class FastLRUCache extends SolrCacheBase implements SolrCache
private long maxRamBytes;
+ private MetricsMap cacheMap;
+ private Set metricNames = new HashSet<>();
+ private MetricRegistry registry;
+
@Override
public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
super.init(args, regenerator);
@@ -215,68 +221,80 @@ public class FastLRUCache extends SolrCacheBase implements SolrCache
}
@Override
- public String getSource() {
- return null;
+ public Set getMetricNames() {
+ return metricNames;
}
+ @Override
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ cacheMap = new MetricsMap((detailed, map) -> {
+ if (cache != null) {
+ ConcurrentLRUCache.Stats stats = cache.getStats();
+ long lookups = stats.getCumulativeLookups();
+ long hits = stats.getCumulativeHits();
+ long inserts = stats.getCumulativePuts();
+ long evictions = stats.getCumulativeEvictions();
+ long size = stats.getCurrentSize();
+ long clookups = 0;
+ long chits = 0;
+ long cinserts = 0;
+ long cevictions = 0;
+
+ // NOTE: It is safe to iterate on a CopyOnWriteArrayList
+ for (ConcurrentLRUCache.Stats statistiscs : statsList) {
+ clookups += statistiscs.getCumulativeLookups();
+ chits += statistiscs.getCumulativeHits();
+ cinserts += statistiscs.getCumulativePuts();
+ cevictions += statistiscs.getCumulativeEvictions();
+ }
+
+ map.put("lookups", lookups);
+ map.put("hits", hits);
+ map.put("hitratio", calcHitRatio(lookups, hits));
+ map.put("inserts", inserts);
+ map.put("evictions", evictions);
+ map.put("size", size);
+
+ map.put("warmupTime", warmupTime);
+ map.put("cumulative_lookups", clookups);
+ map.put("cumulative_hits", chits);
+ map.put("cumulative_hitratio", calcHitRatio(clookups, chits));
+ map.put("cumulative_inserts", cinserts);
+ map.put("cumulative_evictions", cevictions);
+
+ if (detailed && showItems != 0) {
+ Map items = cache.getLatestAccessedItems( showItems == -1 ? Integer.MAX_VALUE : showItems );
+ for (Map.Entry e : (Set )items.entrySet()) {
+ Object k = e.getKey();
+ Object v = e.getValue();
+
+ String ks = "item_" + k;
+ String vs = v.toString();
+ map.put(ks,vs);
+ }
+
+ }
+ }
+ });
+ manager.registerGauge(this, registryName, cacheMap, true, scope, getCategory().toString());
+ }
+
+ // for unit tests only
+ MetricsMap getMetricsMap() {
+ return cacheMap;
+ }
@Override
- public NamedList getStatistics() {
- NamedList lst = new SimpleOrderedMap<>();
- if (cache == null) return lst;
- ConcurrentLRUCache.Stats stats = cache.getStats();
- long lookups = stats.getCumulativeLookups();
- long hits = stats.getCumulativeHits();
- long inserts = stats.getCumulativePuts();
- long evictions = stats.getCumulativeEvictions();
- long size = stats.getCurrentSize();
- long clookups = 0;
- long chits = 0;
- long cinserts = 0;
- long cevictions = 0;
-
- // NOTE: It is safe to iterate on a CopyOnWriteArrayList
- for (ConcurrentLRUCache.Stats statistiscs : statsList) {
- clookups += statistiscs.getCumulativeLookups();
- chits += statistiscs.getCumulativeHits();
- cinserts += statistiscs.getCumulativePuts();
- cevictions += statistiscs.getCumulativeEvictions();
- }
-
- lst.add("lookups", lookups);
- lst.add("hits", hits);
- lst.add("hitratio", calcHitRatio(lookups, hits));
- lst.add("inserts", inserts);
- lst.add("evictions", evictions);
- lst.add("size", size);
-
- lst.add("warmupTime", warmupTime);
- lst.add("cumulative_lookups", clookups);
- lst.add("cumulative_hits", chits);
- lst.add("cumulative_hitratio", calcHitRatio(clookups, chits));
- lst.add("cumulative_inserts", cinserts);
- lst.add("cumulative_evictions", cevictions);
-
- if (showItems != 0) {
- Map items = cache.getLatestAccessedItems( showItems == -1 ? Integer.MAX_VALUE : showItems );
- for (Map.Entry e : (Set )items.entrySet()) {
- Object k = e.getKey();
- Object v = e.getValue();
-
- String ks = "item_" + k;
- String vs = v.toString();
- lst.add(ks,vs);
- }
-
- }
-
- return lst;
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
@Override
public String toString() {
- return name() + getStatistics().toString();
+ return name() + cacheMap != null ? cacheMap.getValue().toString() : "";
}
+
}
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 2b593c6f57a..82ba6d26536 100644
--- a/solr/core/src/java/org/apache/solr/search/LFUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LFUCache.java
@@ -15,19 +15,19 @@
* limitations under the License.
*/
package org.apache.solr.search;
-import java.io.Serializable;
+
import java.lang.invoke.MethodHandles;
-import java.net.URL;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.SolrCore;
+import org.apache.solr.metrics.MetricsMap;
+import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.util.ConcurrentLFUCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,6 +64,9 @@ public class LFUCache implements SolrCache {
private ConcurrentLFUCache cache;
private int showItems = 0;
private Boolean timeDecay = true;
+ private MetricsMap cacheMap;
+ private Set metricNames = new HashSet<>();
+ private MetricRegistry registry;
@Override
public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
@@ -211,11 +214,6 @@ public class LFUCache implements SolrCache {
return LFUCache.class.getName();
}
- @Override
- public String getVersion() {
- return SolrCore.version;
- }
-
@Override
public String getDescription() {
return description;
@@ -226,16 +224,6 @@ public class LFUCache implements SolrCache {
return Category.CACHE;
}
- @Override
- public String getSource() {
- return null;
- }
-
- @Override
- public URL[] getDocs() {
- return null;
- }
-
// returns a ratio, not a percent.
private static String calcHitRatio(long lookups, long hits) {
if (lookups == 0) return "0.00";
@@ -246,62 +234,81 @@ public class LFUCache implements SolrCache {
}
@Override
- public NamedList getStatistics() {
- NamedList lst = new SimpleOrderedMap<>();
- if (cache == null) return lst;
- ConcurrentLFUCache.Stats stats = cache.getStats();
- long lookups = stats.getCumulativeLookups();
- long hits = stats.getCumulativeHits();
- long inserts = stats.getCumulativePuts();
- long evictions = stats.getCumulativeEvictions();
- long size = stats.getCurrentSize();
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ cacheMap = new MetricsMap((detailed, map) -> {
+ if (cache != null) {
+ ConcurrentLFUCache.Stats stats = cache.getStats();
+ long lookups = stats.getCumulativeLookups();
+ long hits = stats.getCumulativeHits();
+ long inserts = stats.getCumulativePuts();
+ long evictions = stats.getCumulativeEvictions();
+ long size = stats.getCurrentSize();
- lst.add("lookups", lookups);
- lst.add("hits", hits);
- lst.add("hitratio", calcHitRatio(lookups, hits));
- lst.add("inserts", inserts);
- lst.add("evictions", evictions);
- lst.add("size", size);
+ map.put("lookups", lookups);
+ map.put("hits", hits);
+ map.put("hitratio", calcHitRatio(lookups, hits));
+ map.put("inserts", inserts);
+ map.put("evictions", evictions);
+ map.put("size", size);
- lst.add("warmupTime", warmupTime);
- lst.add("timeDecay", timeDecay);
+ map.put("warmupTime", warmupTime);
+ map.put("timeDecay", timeDecay);
- long clookups = 0;
- long chits = 0;
- long cinserts = 0;
- long cevictions = 0;
+ long clookups = 0;
+ long chits = 0;
+ long cinserts = 0;
+ long cevictions = 0;
- // NOTE: It is safe to iterate on a CopyOnWriteArrayList
- for (ConcurrentLFUCache.Stats statistics : statsList) {
- clookups += statistics.getCumulativeLookups();
- chits += statistics.getCumulativeHits();
- cinserts += statistics.getCumulativePuts();
- cevictions += statistics.getCumulativeEvictions();
- }
- lst.add("cumulative_lookups", clookups);
- lst.add("cumulative_hits", chits);
- lst.add("cumulative_hitratio", calcHitRatio(clookups, chits));
- lst.add("cumulative_inserts", cinserts);
- lst.add("cumulative_evictions", cevictions);
+ // NOTE: It is safe to iterate on a CopyOnWriteArrayList
+ for (ConcurrentLFUCache.Stats statistics : statsList) {
+ clookups += statistics.getCumulativeLookups();
+ chits += statistics.getCumulativeHits();
+ cinserts += statistics.getCumulativePuts();
+ cevictions += statistics.getCumulativeEvictions();
+ }
+ map.put("cumulative_lookups", clookups);
+ map.put("cumulative_hits", chits);
+ map.put("cumulative_hitratio", calcHitRatio(clookups, chits));
+ map.put("cumulative_inserts", cinserts);
+ map.put("cumulative_evictions", cevictions);
- if (showItems != 0) {
- Map items = cache.getMostUsedItems(showItems == -1 ? Integer.MAX_VALUE : showItems);
- for (Map.Entry e : (Set) items.entrySet()) {
- Object k = e.getKey();
- Object v = e.getValue();
+ if (detailed && showItems != 0) {
+ Map items = cache.getMostUsedItems(showItems == -1 ? Integer.MAX_VALUE : showItems);
+ for (Map.Entry e : (Set) items.entrySet()) {
+ Object k = e.getKey();
+ Object v = e.getValue();
+
+ String ks = "item_" + k;
+ String vs = v.toString();
+ map.put(ks, vs);
+ }
+
+ }
- String ks = "item_" + k;
- String vs = v.toString();
- lst.add(ks, vs);
}
+ });
+ manager.registerGauge(this, registryName, cacheMap, true, scope, getCategory().toString());
+ }
- }
+ // for unit tests only
+ MetricsMap getMetricsMap() {
+ return cacheMap;
+ }
- return lst;
+ @Override
+ public Set getMetricNames() {
+ return metricNames;
+ }
+
+ @Override
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
@Override
public String toString() {
- return name + getStatistics().toString();
+ return name + cacheMap != null ? cacheMap.getValue().toString() : "";
}
+
}
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 b178fb21b1f..ce206fe2f7e 100644
--- a/solr/core/src/java/org/apache/solr/search/LRUCache.java
+++ b/solr/core/src/java/org/apache/solr/search/LRUCache.java
@@ -19,18 +19,21 @@ package org.apache.solr.search;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
+import com.codahale.metrics.MetricRegistry;
import org.apache.lucene.util.Accountable;
import org.apache.lucene.util.Accountables;
import org.apache.lucene.util.RamUsageEstimator;
import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.metrics.MetricsMap;
+import org.apache.solr.metrics.SolrMetricManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,6 +58,7 @@ public class LRUCache extends SolrCacheBase implements SolrCache, Acco
static final long LINKED_HASHTABLE_RAM_BYTES_PER_ENTRY =
HASHTABLE_RAM_BYTES_PER_ENTRY
+ 2 * RamUsageEstimator.NUM_BYTES_OBJECT_REF; // previous & next references
+
/// End copied code
/* An instance of this class will be shared across multiple instances
@@ -82,6 +86,9 @@ public class LRUCache extends SolrCacheBase implements SolrCache, Acco
private Map map;
private String description="LRU Cache";
+ private MetricsMap cacheMap;
+ private Set metricNames = new HashSet<>();
+ private MetricRegistry registry;
private long maxRamBytes = Long.MAX_VALUE;
// The synchronization used for the map will be used to update this,
@@ -319,45 +326,56 @@ public class LRUCache extends SolrCacheBase implements SolrCache, Acco
}
@Override
- public String getSource() {
- return null;
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public NamedList getStatistics() {
- NamedList lst = new SimpleOrderedMap();
- synchronized (map) {
- lst.add("lookups", lookups);
- lst.add("hits", hits);
- lst.add("hitratio", calcHitRatio(lookups,hits));
- lst.add("inserts", inserts);
- lst.add("evictions", evictions);
- lst.add("size", map.size());
- if (maxRamBytes != Long.MAX_VALUE) {
- lst.add("maxRamMB", maxRamBytes / 1024L / 1024L);
- lst.add("ramBytesUsed", ramBytesUsed());
- lst.add("evictionsRamUsage", evictionsRamUsage);
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ cacheMap = new MetricsMap((detailed, res) -> {
+ synchronized (map) {
+ res.put("lookups", lookups);
+ res.put("hits", hits);
+ res.put("hitratio", calcHitRatio(lookups,hits));
+ res.put("inserts", inserts);
+ res.put("evictions", evictions);
+ res.put("size", map.size());
+ if (maxRamBytes != Long.MAX_VALUE) {
+ res.put("maxRamMB", maxRamBytes / 1024L / 1024L);
+ res.put("ramBytesUsed", ramBytesUsed());
+ res.put("evictionsRamUsage", evictionsRamUsage);
+ }
}
- }
- lst.add("warmupTime", warmupTime);
-
- long clookups = stats.lookups.longValue();
- long chits = stats.hits.longValue();
- lst.add("cumulative_lookups", clookups);
- lst.add("cumulative_hits", chits);
- lst.add("cumulative_hitratio", calcHitRatio(clookups, chits));
- lst.add("cumulative_inserts", stats.inserts.longValue());
- lst.add("cumulative_evictions", stats.evictions.longValue());
- if (maxRamBytes != Long.MAX_VALUE) {
- lst.add("cumulative_evictionsRamUsage", stats.evictionsRamUsage.longValue());
- }
-
- return lst;
+ res.put("warmupTime", warmupTime);
+
+ long clookups = stats.lookups.longValue();
+ long chits = stats.hits.longValue();
+ res.put("cumulative_lookups", clookups);
+ res.put("cumulative_hits", chits);
+ res.put("cumulative_hitratio", calcHitRatio(clookups, chits));
+ res.put("cumulative_inserts", stats.inserts.longValue());
+ res.put("cumulative_evictions", stats.evictions.longValue());
+ if (maxRamBytes != Long.MAX_VALUE) {
+ res.put("cumulative_evictionsRamUsage", stats.evictionsRamUsage.longValue());
+ }
+ });
+ manager.registerGauge(this, registryName, cacheMap, true, scope, getCategory().toString());
+ }
+
+ // for unit tests only
+ MetricsMap getMetricsMap() {
+ return cacheMap;
+ }
+
+ @Override
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
@Override
public String toString() {
- return name() + getStatistics().toString();
+ return name() + cacheMap != null ? cacheMap.getValue().toString() : "";
}
@Override
diff --git a/solr/core/src/java/org/apache/solr/search/QParserPlugin.java b/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
index 34089d201a0..872c618afaa 100644
--- a/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
@@ -16,14 +16,14 @@
*/
package org.apache.solr.search;
-import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.join.BlockJoinChildQParserPlugin;
import org.apache.solr.search.join.BlockJoinParentQParserPlugin;
@@ -31,7 +31,7 @@ import org.apache.solr.search.join.GraphQParserPlugin;
import org.apache.solr.search.mlt.MLTQParserPlugin;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
-public abstract class QParserPlugin implements NamedListInitializedPlugin, SolrInfoMBean {
+public abstract class QParserPlugin implements NamedListInitializedPlugin, SolrInfoBean {
/** internal use - name of the default parser */
public static final String DEFAULT_QTYPE = LuceneQParserPlugin.NAME;
@@ -98,11 +98,6 @@ public abstract class QParserPlugin implements NamedListInitializedPlugin, SolrI
return this.getClass().getName();
}
- @Override
- public String getVersion() {
- return null;
- }
-
@Override
public String getDescription() {
return ""; // UI required non-null to work
@@ -114,19 +109,10 @@ public abstract class QParserPlugin implements NamedListInitializedPlugin, SolrI
}
@Override
- public String getSource() {
+ public Set getMetricNames() {
return null;
}
- @Override
- public URL[] getDocs() {
- return new URL[0];
- }
-
- @Override
- public NamedList getStatistics() {
- return null;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/search/SolrCache.java b/solr/core/src/java/org/apache/solr/search/SolrCache.java
index 9a2d0fc38e4..caa5c2c3b32 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrCache.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrCache.java
@@ -16,7 +16,8 @@
*/
package org.apache.solr.search;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
+import org.apache.solr.metrics.SolrMetricProducer;
import java.util.Map;
@@ -24,7 +25,7 @@ import java.util.Map;
/**
* Primary API for dealing with Solr's internal caches.
*/
-public interface SolrCache extends SolrInfoMBean {
+public interface SolrCache extends SolrInfoBean, SolrMetricProducer {
/**
* The initialization routine. Instance specific arguments are passed in
diff --git a/solr/core/src/java/org/apache/solr/search/SolrCacheBase.java b/solr/core/src/java/org/apache/solr/search/SolrCacheBase.java
index 85caa90cfee..c388d548036 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrCacheBase.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrCacheBase.java
@@ -18,11 +18,10 @@ package org.apache.solr.search;
import java.math.BigDecimal;
import java.math.RoundingMode;
-import java.net.URL;
import java.util.Map;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean.Category;
+import org.apache.solr.core.SolrInfoBean.Category;
import org.apache.solr.search.SolrCache.State;
import static org.apache.solr.common.params.CommonParams.NAME;
@@ -106,10 +105,6 @@ public abstract class SolrCacheBase {
return Category.CACHE;
}
- public URL[] getDocs() {
- return null;
- }
-
public void init(Map args, CacheRegenerator regenerator) {
this.regenerator = regenerator;
state = State.CREATED;
diff --git a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
new file mode 100644
index 00000000000..ffcc37d64cf
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java
@@ -0,0 +1,77 @@
+/*
+ * 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.search;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.codahale.metrics.MetricRegistry;
+import org.apache.solr.core.SolrInfoBean;
+import org.apache.solr.metrics.MetricsMap;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.uninverting.UninvertingReader;
+
+/**
+ * A SolrInfoBean that provides introspection of the Solr FieldCache
+ *
+ */
+public class SolrFieldCacheBean implements SolrInfoBean, SolrMetricProducer {
+
+ private boolean disableEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryList");
+ private boolean disableJmxEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryListJmx");
+
+ private MetricRegistry registry;
+ private Set metricNames = new HashSet<>();
+
+ @Override
+ public String getName() { return this.getClass().getName(); }
+ @Override
+ public String getDescription() {
+ return "Provides introspection of the Solr FieldCache ";
+ }
+ @Override
+ public Category getCategory() { return Category.CACHE; }
+ @Override
+ public Set getMetricNames() {
+ return metricNames;
+ }
+ @Override
+ public MetricRegistry getMetricRegistry() {
+ return registry;
+ }
+
+ @Override
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
+ if (detailed && !disableEntryList && !disableJmxEntryList) {
+ UninvertingReader.FieldCacheStats fieldCacheStats = UninvertingReader.getUninvertedStats();
+ String[] entries = fieldCacheStats.info;
+ map.put("entries_count", entries.length);
+ map.put("total_size", fieldCacheStats.totalSize);
+ for (int i = 0; i < entries.length; i++) {
+ final String entry = entries[i];
+ map.put("entry#" + i, entry);
+ }
+ } else {
+ map.put("entries_count", UninvertingReader.getUninvertedStatsSize());
+ }
+ });
+ manager.register(this, registryName, metricsMap, true, "fieldCache", Category.CACHE.toString(), scope);
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java
deleted file mode 100644
index 642b7087846..00000000000
--- a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheMBean.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.search;
-
-import java.net.URL;
-
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.JmxMonitoredMap.JmxAugmentedSolrInfoMBean;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.uninverting.UninvertingReader;
-
-/**
- * A SolrInfoMBean that provides introspection of the Solr FieldCache
- *
- */
-public class SolrFieldCacheMBean implements JmxAugmentedSolrInfoMBean {
-
- private boolean disableEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryList");
- private boolean disableJmxEntryList = Boolean.getBoolean("disableSolrFieldCacheMBeanEntryListJmx");
-
- @Override
- public String getName() { return this.getClass().getName(); }
- @Override
- public String getVersion() { return SolrCore.version; }
- @Override
- public String getDescription() {
- return "Provides introspection of the Solr FieldCache ";
- }
- @Override
- public Category getCategory() { return Category.CACHE; }
- @Override
- public String getSource() { return null; }
- @Override
- public URL[] getDocs() {
- return null;
- }
- @Override
- public NamedList getStatistics() {
- return getStats(!disableEntryList);
- }
-
- @Override
- public NamedList getStatisticsForJmx() {
- return getStats(!disableEntryList && !disableJmxEntryList);
- }
-
- private NamedList getStats(boolean listEntries) {
- NamedList stats = new SimpleOrderedMap();
- if (listEntries) {
- UninvertingReader.FieldCacheStats fieldCacheStats = UninvertingReader.getUninvertedStats();
- String[] entries = fieldCacheStats.info;
- stats.add("entries_count", entries.length);
- stats.add("total_size", fieldCacheStats.totalSize);
- for (int i = 0; i < entries.length; i++) {
- stats.add("entry#" + i, entries[i]);
- }
- } else {
- stats.add("entries_count", UninvertingReader.getUninvertedStatsSize());
- }
- return stats;
- }
-
-}
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 4207a9b411b..9b38225b634 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -19,13 +19,13 @@ package org.apache.solr.search;
import java.io.Closeable;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
+import com.codahale.metrics.MetricRegistry;
import com.google.common.collect.Iterables;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
@@ -58,15 +59,15 @@ import org.apache.lucene.util.FixedBitSet;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.ModifiableSolrParams;
-import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.ObjectReleaseTracker;
-import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.DirectoryFactory;
import org.apache.solr.core.DirectoryFactory.DirContext;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.index.SlowCompositeReaderWrapper;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestInfo;
@@ -86,7 +87,7 @@ import org.slf4j.LoggerFactory;
*
* @since solr 0.9
*/
-public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrInfoMBean {
+public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrInfoBean, SolrMetricProducer {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -136,7 +137,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
private final String path;
private boolean releaseDirectory;
- private final NamedList readerStats;
+ private Set metricNames = new HashSet<>();
private static DirectoryReader getReader(SolrCore core, SolrIndexConfig config, DirectoryFactory directoryFactory,
String path) throws IOException {
@@ -302,7 +303,6 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
// We already have our own filter cache
setQueryCache(null);
- readerStats = snapStatistics(reader);
// do this at the end since an exception in the constructor means we won't close
numOpens.incrementAndGet();
assert ObjectReleaseTracker.track(this);
@@ -404,10 +404,10 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
}
/**
- * Register sub-objects such as caches
+ * Register sub-objects such as caches and our own metrics
*/
public void register() {
- final Map infoRegistry = core.getInfoRegistry();
+ final Map infoRegistry = core.getInfoRegistry();
// register self
infoRegistry.put(STATISTICS_KEY, this);
infoRegistry.put(name, this);
@@ -415,6 +415,12 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
cache.setState(SolrCache.State.LIVE);
infoRegistry.put(cache.name(), cache);
}
+ SolrMetricManager manager = core.getCoreDescriptor().getCoreContainer().getMetricManager();
+ String registry = core.getCoreMetricManager().getRegistryName();
+ for (SolrCache cache : cacheList) {
+ cache.initializeMetrics(manager, registry, SolrMetricManager.mkName(cache.name(), STATISTICS_KEY));
+ }
+ initializeMetrics(manager, registry, STATISTICS_KEY);
registerTime = new Date();
}
@@ -2190,7 +2196,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
/////////////////////////////////////////////////////////////////////
- // SolrInfoMBean stuff: Statistics and Module Info
+ // SolrInfoBean stuff: Statistics and Module Info
/////////////////////////////////////////////////////////////////////
@Override
@@ -2198,11 +2204,6 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
return SolrIndexSearcher.class.getName();
}
- @Override
- public String getVersion() {
- return SolrCore.version;
- }
-
@Override
public String getDescription() {
return "index searcher";
@@ -2214,38 +2215,31 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
}
@Override
- public String getSource() {
- return null;
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public URL[] getDocs() {
- return null;
+ public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+
+ manager.registerGauge(this, registry, () -> name, true, "searcherName", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> cachingEnabled, true, "caching", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> openTime, true, "openedAt", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> warmupTime, true, "warmupTime", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> registerTime, true, "registeredAt", Category.SEARCHER.toString(), scope);
+ // reader stats
+ manager.registerGauge(this, registry, () -> reader.numDocs(), true, "numDocs", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> reader.maxDoc(), true, "maxDoc", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> reader.maxDoc() - reader.numDocs(), true, "deletedDocs", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> reader.toString(), true, "reader", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> reader.directory().toString(), true, "readerDir", Category.SEARCHER.toString(), scope);
+ manager.registerGauge(this, registry, () -> reader.getVersion(), true, "indexVersion", Category.SEARCHER.toString(), scope);
+
}
@Override
- public NamedList getStatistics() {
- final NamedList lst = new SimpleOrderedMap<>();
- lst.add("searcherName", name);
- lst.add("caching", cachingEnabled);
-
- lst.addAll(readerStats);
-
- lst.add("openedAt", openTime);
- if (registerTime != null) lst.add("registeredAt", registerTime);
- lst.add("warmupTime", warmupTime);
- return lst;
- }
-
- static private NamedList snapStatistics(DirectoryReader reader) {
- final NamedList lst = new SimpleOrderedMap<>();
- lst.add("numDocs", reader.numDocs());
- lst.add("maxDoc", reader.maxDoc());
- lst.add("deletedDocs", reader.maxDoc() - reader.numDocs());
- lst.add("reader", reader.toString());
- lst.add("readerDir", reader.directory());
- lst.add("indexVersion", reader.getVersion());
- return lst;
+ public MetricRegistry getMetricRegistry() {
+ return core.getMetricRegistry();
}
private static class FilterImpl extends Filter {
diff --git a/solr/core/src/java/org/apache/solr/search/facet/FacetModule.java b/solr/core/src/java/org/apache/solr/search/facet/FacetModule.java
index bf1379162ef..3407ae41c1b 100644
--- a/solr/core/src/java/org/apache/solr/search/facet/FacetModule.java
+++ b/solr/core/src/java/org/apache/solr/search/facet/FacetModule.java
@@ -319,12 +319,6 @@ public class FacetModule extends SearchComponent {
public Category getCategory() {
return Category.QUERY;
}
-
- @Override
- public String getSource() {
- return null;
- }
-
}
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 ff0db9b7990..24bcf3dc38a 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.servlet;
-import javax.management.MBeanServer;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
@@ -34,7 +33,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.invoke.MethodHandles;
-import java.lang.management.ManagementFactory;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
@@ -47,7 +45,6 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import com.codahale.metrics.jvm.BufferPoolMetricSet;
import com.codahale.metrics.jvm.ClassLoadingGaugeSet;
import com.codahale.metrics.jvm.GarbageCollectorMetricSet;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
@@ -66,9 +63,10 @@ import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.NodeConfig;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.core.SolrXmlConfig;
+import org.apache.solr.metrics.AltBufferPoolMetricSet;
import org.apache.solr.metrics.OperatingSystemMetricSet;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.request.SolrRequestInfo;
@@ -185,13 +183,12 @@ public class SolrDispatchFilter extends BaseSolrFilter {
}
private void setupJvmMetrics() {
- MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
SolrMetricManager metricManager = cores.getMetricManager();
try {
- String registry = SolrMetricManager.getRegistryName(SolrInfoMBean.Group.jvm);
- metricManager.registerAll(registry, new BufferPoolMetricSet(platformMBeanServer), true, "buffers");
+ String registry = SolrMetricManager.getRegistryName(SolrInfoBean.Group.jvm);
+ metricManager.registerAll(registry, new AltBufferPoolMetricSet(), true, "buffers");
metricManager.registerAll(registry, new ClassLoadingGaugeSet(), true, "classes");
- metricManager.registerAll(registry, new OperatingSystemMetricSet(platformMBeanServer), true, "os");
+ metricManager.registerAll(registry, new OperatingSystemMetricSet(), true, "os");
metricManager.registerAll(registry, new GarbageCollectorMetricSet(), true, "gc");
metricManager.registerAll(registry, new MemoryUsageGaugeSet(), true, "memory");
metricManager.registerAll(registry, new ThreadStatesGaugeSet(), true, "threads"); // todo should we use CachedThreadStatesGaugeSet instead?
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 d3e34979b74..b8b9bea11ab 100644
--- a/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
+++ b/solr/core/src/java/org/apache/solr/store/blockcache/Metrics.java
@@ -16,20 +16,23 @@
*/
package org.apache.solr.store.blockcache;
-import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.SolrInfoMBean;
+import com.codahale.metrics.MetricRegistry;
+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.search.SolrCacheBase;
/**
- * A {@link SolrInfoMBean} that provides metrics on block cache operations.
+ * A {@link SolrInfoBean} that provides metrics on block cache operations.
*
* @lucene.experimental
*/
-public class Metrics extends SolrCacheBase implements SolrInfoMBean {
+public class Metrics extends SolrCacheBase implements SolrInfoBean, SolrMetricProducer {
public AtomicLong blockCacheSize = new AtomicLong(0);
@@ -50,66 +53,70 @@ public class Metrics extends SolrCacheBase implements SolrInfoMBean {
public AtomicLong shardBuffercacheAllocate = new AtomicLong(0);
public AtomicLong shardBuffercacheLost = new AtomicLong(0);
+ private MetricsMap metricsMap;
+ private MetricRegistry registry;
+ private Set metricNames = new HashSet<>();
private long previous = System.nanoTime();
+ @Override
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ metricsMap = new MetricsMap((detailed, map) -> {
+ long now = System.nanoTime();
+ long delta = Math.max(now - previous, 1);
+ double seconds = delta / 1000000000.0;
- public NamedList getStatistics() {
- NamedList stats = new SimpleOrderedMap<>(21); // room for one method call before growing
+ long hits_total = blockCacheHit.get();
+ long hits_delta = hits_total - blockCacheHit_last.get();
+ blockCacheHit_last.set(hits_total);
- long now = System.nanoTime();
- long delta = Math.max(now - previous, 1);
- double seconds = delta / 1000000000.0;
+ long miss_total = blockCacheMiss.get();
+ long miss_delta = miss_total - blockCacheMiss_last.get();
+ blockCacheMiss_last.set(miss_total);
- long hits_total = blockCacheHit.get();
- long hits_delta = hits_total - blockCacheHit_last.get();
- blockCacheHit_last.set(hits_total);
+ long evict_total = blockCacheEviction.get();
+ long evict_delta = evict_total - blockCacheEviction_last.get();
+ blockCacheEviction_last.set(evict_total);
- long miss_total = blockCacheMiss.get();
- long miss_delta = miss_total - blockCacheMiss_last.get();
- blockCacheMiss_last.set(miss_total);
+ long storeFail_total = blockCacheStoreFail.get();
+ long storeFail_delta = storeFail_total - blockCacheStoreFail_last.get();
+ blockCacheStoreFail_last.set(storeFail_total);
- long evict_total = blockCacheEviction.get();
- long evict_delta = evict_total - blockCacheEviction_last.get();
- blockCacheEviction_last.set(evict_total);
+ long lookups_delta = hits_delta + miss_delta;
+ long lookups_total = hits_total + miss_total;
- long storeFail_total = blockCacheStoreFail.get();
- long storeFail_delta = storeFail_total - blockCacheStoreFail_last.get();
- blockCacheStoreFail_last.set(storeFail_total);
+ map.put("size", blockCacheSize.get());
+ map.put("lookups", lookups_total);
+ map.put("hits", hits_total);
+ map.put("evictions", evict_total);
+ map.put("storeFails", storeFail_total);
+ map.put("hitratio_current", calcHitRatio(lookups_delta, hits_delta)); // hit ratio since the last call
+ map.put("lookups_persec", getPerSecond(lookups_delta, seconds)); // lookups per second since the last call
+ map.put("hits_persec", getPerSecond(hits_delta, seconds)); // hits per second since the last call
+ map.put("evictions_persec", getPerSecond(evict_delta, seconds)); // evictions per second since the last call
+ map.put("storeFails_persec", getPerSecond(storeFail_delta, seconds)); // evictions per second since the last call
+ map.put("time_delta", seconds); // seconds since last call
- long lookups_delta = hits_delta + miss_delta;
- long lookups_total = hits_total + miss_total;
+ // TODO: these aren't really related to the BlockCache
+ map.put("buffercache.allocations", getPerSecond(shardBuffercacheAllocate.getAndSet(0), seconds));
+ map.put("buffercache.lost", getPerSecond(shardBuffercacheLost.getAndSet(0), seconds));
- stats.add("size", blockCacheSize.get());
- stats.add("lookups", lookups_total);
- stats.add("hits", hits_total);
- stats.add("evictions", evict_total);
- stats.add("storeFails", storeFail_total);
- stats.add("hitratio_current", calcHitRatio(lookups_delta, hits_delta)); // hit ratio since the last call
- stats.add("lookups_persec", getPerSecond(lookups_delta, seconds)); // lookups per second since the last call
- stats.add("hits_persec", getPerSecond(hits_delta, seconds)); // hits per second since the last call
- stats.add("evictions_persec", getPerSecond(evict_delta, seconds)); // evictions per second since the last call
- stats.add("storeFails_persec", getPerSecond(storeFail_delta, seconds)); // evictions per second since the last call
- stats.add("time_delta", seconds); // seconds since last call
+ previous = now;
- // TODO: these aren't really related to the BlockCache
- stats.add("buffercache.allocations", getPerSecond(shardBuffercacheAllocate.getAndSet(0), seconds));
- stats.add("buffercache.lost", getPerSecond(shardBuffercacheLost.getAndSet(0), seconds));
-
- previous = now;
-
- return stats;
+ });
+ manager.registerGauge(this, registryName, metricsMap, true, getName(), getCategory().toString(), scope);
}
private float getPerSecond(long value, double seconds) {
return (float) (value / seconds);
}
- // SolrInfoMBean methods
+ // SolrInfoBean methods
@Override
public String getName() {
- return "HdfsBlockCache";
+ return "hdfsBlockCache";
}
@Override
@@ -118,12 +125,13 @@ public class Metrics extends SolrCacheBase implements SolrInfoMBean {
}
@Override
- public String getSource() {
- return null;
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public URL[] getDocs() {
- return null;
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
+
}
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 ba7c7fd1393..64e6356dcd8 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
@@ -18,8 +18,8 @@ package org.apache.solr.store.hdfs;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -27,16 +27,18 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import com.codahale.metrics.MetricRegistry;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.SolrInfoMBean;
+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.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class HdfsLocalityReporter implements SolrInfoMBean {
+public class HdfsLocalityReporter implements SolrInfoBean, SolrMetricProducer {
public static final String LOCALITY_BYTES_TOTAL = "locality.bytes.total";
public static final String LOCALITY_BYTES_LOCAL = "locality.bytes.local";
public static final String LOCALITY_BYTES_RATIO = "locality.bytes.ratio";
@@ -49,6 +51,9 @@ public class HdfsLocalityReporter implements SolrInfoMBean {
private String hostname;
private final ConcurrentMap> cache;
+ private final Set metricNames = new HashSet<>();
+ private MetricRegistry registry;
+
public HdfsLocalityReporter() {
cache = new ConcurrentHashMap<>();
}
@@ -66,11 +71,6 @@ public class HdfsLocalityReporter implements SolrInfoMBean {
return "hdfs-locality";
}
- @Override
- public String getVersion() {
- return getClass().getPackage().getSpecificationVersion();
- }
-
@Override
public String getDescription() {
return "Provides metrics for HDFS data locality.";
@@ -82,89 +82,71 @@ public class HdfsLocalityReporter implements SolrInfoMBean {
}
@Override
- public String getSource() {
- return null;
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public URL[] getDocs() {
- return null;
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
/**
* Provide statistics on HDFS block locality, both in terms of bytes and block counts.
*/
@Override
- public NamedList getStatistics() {
- long totalBytes = 0;
- long localBytes = 0;
- int totalCount = 0;
- int localCount = 0;
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
+ MetricsMap metricsMap = new MetricsMap((detailed, map) -> {
+ long totalBytes = 0;
+ long localBytes = 0;
+ int totalCount = 0;
+ int localCount = 0;
- for (Iterator iterator = cache.keySet().iterator(); iterator.hasNext();) {
- HdfsDirectory hdfsDirectory = iterator.next();
+ for (Iterator iterator = cache.keySet().iterator(); iterator.hasNext();) {
+ HdfsDirectory hdfsDirectory = iterator.next();
- if (hdfsDirectory.isClosed()) {
- iterator.remove();
- } else {
- try {
- refreshDirectory(hdfsDirectory);
- Map blockMap = cache.get(hdfsDirectory);
+ if (hdfsDirectory.isClosed()) {
+ iterator.remove();
+ } else {
+ try {
+ refreshDirectory(hdfsDirectory);
+ Map blockMap = cache.get(hdfsDirectory);
- // For every block in every file in this directory, count it
- for (BlockLocation[] locations : blockMap.values()) {
- for (BlockLocation bl : locations) {
- totalBytes += bl.getLength();
- totalCount++;
+ // For every block in every file in this directory, count it
+ for (BlockLocation[] locations : blockMap.values()) {
+ for (BlockLocation bl : locations) {
+ totalBytes += bl.getLength();
+ totalCount++;
- if (Arrays.asList(bl.getHosts()).contains(hostname)) {
- localBytes += bl.getLength();
- localCount++;
+ if (Arrays.asList(bl.getHosts()).contains(hostname)) {
+ localBytes += bl.getLength();
+ localCount++;
+ }
}
}
+ } catch (IOException e) {
+ logger.warn("Could not retrieve locality information for {} due to exception: {}",
+ hdfsDirectory.getHdfsDirPath(), e);
}
- } catch (IOException e) {
- logger.warn("Could not retrieve locality information for {} due to exception: {}",
- hdfsDirectory.getHdfsDirPath(), e);
}
}
- }
-
- return createStatistics(totalBytes, localBytes, totalCount, localCount);
- }
-
- /**
- * Generate a statistics object based on the given measurements for all files monitored by this reporter.
- *
- * @param totalBytes
- * The total bytes used
- * @param localBytes
- * The amount of bytes found on local nodes
- * @param totalCount
- * The total block count
- * @param localCount
- * The amount of blocks found on local nodes
- * @return HDFS block locality statistics
- */
- private NamedList createStatistics(long totalBytes, long localBytes, int totalCount, int localCount) {
- NamedList statistics = new SimpleOrderedMap();
-
- statistics.add(LOCALITY_BYTES_TOTAL, totalBytes);
- statistics.add(LOCALITY_BYTES_LOCAL, localBytes);
- if (localBytes == 0) {
- statistics.add(LOCALITY_BYTES_RATIO, 0);
- } else {
- statistics.add(LOCALITY_BYTES_RATIO, localBytes / (double) totalBytes);
- }
- statistics.add(LOCALITY_BLOCKS_TOTAL, totalCount);
- statistics.add(LOCALITY_BLOCKS_LOCAL, localCount);
- if (localCount == 0) {
- statistics.add(LOCALITY_BLOCKS_RATIO, 0);
- } else {
- statistics.add(LOCALITY_BLOCKS_RATIO, localCount / (double) totalCount);
- }
-
- return statistics;
+ map.put(LOCALITY_BYTES_TOTAL, totalBytes);
+ map.put(LOCALITY_BYTES_LOCAL, localBytes);
+ if (localBytes == 0) {
+ map.put(LOCALITY_BYTES_RATIO, 0);
+ } else {
+ map.put(LOCALITY_BYTES_RATIO, localBytes / (double) totalBytes);
+ }
+ map.put(LOCALITY_BLOCKS_TOTAL, totalCount);
+ map.put(LOCALITY_BLOCKS_LOCAL, localCount);
+ if (localCount == 0) {
+ map.put(LOCALITY_BLOCKS_RATIO, 0);
+ } else {
+ map.put(LOCALITY_BLOCKS_RATIO, localCount / (double) totalCount);
+ }
+ });
+ manager.registerGauge(this, registryName, metricsMap, true, "hdfsLocality", getCategory().toString(), scope);
}
/**
@@ -209,4 +191,5 @@ public class HdfsLocalityReporter implements SolrInfoMBean {
}
}
}
+
}
diff --git a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
index fdc9d2223ec..4ef91e4af3e 100644
--- a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
+++ b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
@@ -18,7 +18,6 @@ package org.apache.solr.update;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -48,8 +47,6 @@ import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.params.ModifiableSolrParams;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrConfig.UpdateHandlerInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.metrics.SolrMetricManager;
@@ -162,24 +159,40 @@ public class DirectUpdateHandler2 extends UpdateHandler implements SolrCoreState
@Override
public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
- commitCommands = manager.meter(registry, "commits", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> commitTracker.getCommitCount(), true, "autoCommits", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> softCommitTracker.getCommitCount(), true, "softAutoCommits", getCategory().toString(), scope);
- optimizeCommands = manager.meter(registry, "optimizes", getCategory().toString(), scope);
- rollbackCommands = manager.meter(registry, "rollbacks", getCategory().toString(), scope);
- splitCommands = manager.meter(registry, "splits", getCategory().toString(), scope);
- mergeIndexesCommands = manager.meter(registry, "merges", getCategory().toString(), scope);
- expungeDeleteCommands = manager.meter(registry, "expungeDeletes", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> numDocsPending.longValue(), true, "docsPending", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> addCommands.longValue(), true, "adds", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> deleteByIdCommands.longValue(), true, "deletesById", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> deleteByQueryCommands.longValue(), true, "deletesByQuery", getCategory().toString(), scope);
- manager.registerGauge(registry, () -> numErrors.longValue(), true, "errors", getCategory().toString(), scope);
+ commitCommands = manager.meter(this, registry, "commits", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> commitTracker.getCommitCount(), true, "autoCommits", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> softCommitTracker.getCommitCount(), true, "softAutoCommits", getCategory().toString(), scope);
+ if (commitTracker.getDocsUpperBound() > 0) {
+ manager.registerGauge(this, registry, () -> commitTracker.getDocsUpperBound(), true, "autoCommitMaxDocs",
+ getCategory().toString(), scope);
+ }
+ if (commitTracker.getTimeUpperBound() > 0) {
+ manager.registerGauge(this, registry, () -> "" + commitTracker.getTimeUpperBound() + "ms", true, "autoCommitMaxTime",
+ getCategory().toString(), scope);
+ }
+ if (softCommitTracker.getDocsUpperBound() > 0) {
+ manager.registerGauge(this, registry, () -> softCommitTracker.getDocsUpperBound(), true, "softAutoCommitMaxDocs",
+ getCategory().toString(), scope);
+ }
+ if (softCommitTracker.getTimeUpperBound() > 0) {
+ manager.registerGauge(this, registry, () -> "" + softCommitTracker.getTimeUpperBound() + "ms", true, "softAutoCommitMaxTime",
+ getCategory().toString(), scope);
+ }
+ optimizeCommands = manager.meter(this, registry, "optimizes", getCategory().toString(), scope);
+ rollbackCommands = manager.meter(this, registry, "rollbacks", getCategory().toString(), scope);
+ splitCommands = manager.meter(this, registry, "splits", getCategory().toString(), scope);
+ mergeIndexesCommands = manager.meter(this, registry, "merges", getCategory().toString(), scope);
+ expungeDeleteCommands = manager.meter(this, registry, "expungeDeletes", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> numDocsPending.longValue(), true, "docsPending", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> addCommands.longValue(), true, "adds", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> deleteByIdCommands.longValue(), true, "deletesById", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> deleteByQueryCommands.longValue(), true, "deletesByQuery", getCategory().toString(), scope);
+ manager.registerGauge(this, registry, () -> numErrors.longValue(), true, "errors", getCategory().toString(), scope);
- addCommandsCumulative = manager.meter(registry, "cumulativeAdds", getCategory().toString(), scope);
- deleteByIdCommandsCumulative = manager.meter(registry, "cumulativeDeletesById", getCategory().toString(), scope);
- deleteByQueryCommandsCumulative = manager.meter(registry, "cumulativeDeletesByQuery", getCategory().toString(), scope);
- numErrorsCumulative = manager.meter(registry, "cumulativeErrors", getCategory().toString(), scope);
+ addCommandsCumulative = manager.meter(this, registry, "cumulativeAdds", getCategory().toString(), scope);
+ deleteByIdCommandsCumulative = manager.meter(this, registry, "cumulativeDeletesById", getCategory().toString(), scope);
+ deleteByQueryCommandsCumulative = manager.meter(this, registry, "cumulativeDeletesByQuery", getCategory().toString(), scope);
+ numErrorsCumulative = manager.meter(this, registry, "cumulativeErrors", getCategory().toString(), scope);
}
private void deleteAll() throws IOException {
@@ -951,7 +964,7 @@ public class DirectUpdateHandler2 extends UpdateHandler implements SolrCoreState
/////////////////////////////////////////////////////////////////////
- // SolrInfoMBean stuff: Statistics and Module Info
+ // SolrInfoBean stuff: Statistics and Module Info
/////////////////////////////////////////////////////////////////////
@Override
@@ -959,70 +972,11 @@ public class DirectUpdateHandler2 extends UpdateHandler implements SolrCoreState
return DirectUpdateHandler2.class.getName();
}
- @Override
- public String getVersion() {
- return SolrCore.version;
- }
-
@Override
public String getDescription() {
return "Update handler that efficiently directly updates the on-disk main lucene index";
}
- @Override
- public String getSource() {
- return null;
- }
-
- @Override
- public URL[] getDocs() {
- return null;
- }
-
- @Override
- public NamedList getStatistics() {
- NamedList lst = new SimpleOrderedMap();
- lst.add("commits", commitCommands.getCount());
- if (commitTracker.getDocsUpperBound() > 0) {
- lst.add("autocommit maxDocs", commitTracker.getDocsUpperBound());
- }
- if (commitTracker.getTimeUpperBound() > 0) {
- lst.add("autocommit maxTime", "" + commitTracker.getTimeUpperBound() + "ms");
- }
- lst.add("autocommits", commitTracker.getCommitCount());
- if (softCommitTracker.getDocsUpperBound() > 0) {
- lst.add("soft autocommit maxDocs", softCommitTracker.getDocsUpperBound());
- }
- if (softCommitTracker.getTimeUpperBound() > 0) {
- lst.add("soft autocommit maxTime", "" + softCommitTracker.getTimeUpperBound() + "ms");
- }
- lst.add("soft autocommits", softCommitTracker.getCommitCount());
- lst.add("optimizes", optimizeCommands.getCount());
- lst.add("rollbacks", rollbackCommands.getCount());
- lst.add("expungeDeletes", expungeDeleteCommands.getCount());
- lst.add("docsPending", numDocsPending.longValue());
- // pset.size() not synchronized, but it should be fine to access.
- // lst.add("deletesPending", pset.size());
- lst.add("adds", addCommands.longValue());
- lst.add("deletesById", deleteByIdCommands.longValue());
- lst.add("deletesByQuery", deleteByQueryCommands.longValue());
- lst.add("errors", numErrors.longValue());
- lst.add("cumulative_adds", addCommandsCumulative.getCount());
- lst.add("cumulative_deletesById", deleteByIdCommandsCumulative.getCount());
- lst.add("cumulative_deletesByQuery", deleteByQueryCommandsCumulative.getCount());
- lst.add("cumulative_errors", numErrorsCumulative.getCount());
- if (this.ulog != null) {
- lst.add("transaction_logs_total_size", ulog.getTotalLogsSize());
- lst.add("transaction_logs_total_number", ulog.getTotalLogsNumber());
- }
- return lst;
- }
-
- @Override
- public String toString() {
- return "DirectUpdateHandler2" + getStatistics();
- }
-
@Override
public SolrCoreState getSolrCoreState() {
return solrCoreState;
diff --git a/solr/core/src/java/org/apache/solr/update/HdfsUpdateLog.java b/solr/core/src/java/org/apache/solr/update/HdfsUpdateLog.java
index 71e20d9f260..7bb74d05bf9 100644
--- a/solr/core/src/java/org/apache/solr/update/HdfsUpdateLog.java
+++ b/solr/core/src/java/org/apache/solr/update/HdfsUpdateLog.java
@@ -37,7 +37,7 @@ import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.util.IOUtils;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.util.HdfsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -262,7 +262,7 @@ public class HdfsUpdateLog extends UpdateLog {
}
// initialize metrics
- core.getCoreMetricManager().registerMetricProducer(SolrInfoMBean.Category.TLOG.toString(), this);
+ core.getCoreMetricManager().registerMetricProducer(SolrInfoBean.Category.TLOG.toString(), this);
}
@Override
diff --git a/solr/core/src/java/org/apache/solr/update/PeerSync.java b/solr/core/src/java/org/apache/solr/update/PeerSync.java
index 9470cca41be..f59984449a4 100644
--- a/solr/core/src/java/org/apache/solr/update/PeerSync.java
+++ b/solr/core/src/java/org/apache/solr/update/PeerSync.java
@@ -43,7 +43,7 @@ import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.handler.component.HttpShardHandlerFactory;
import org.apache.solr.handler.component.ShardHandler;
import org.apache.solr.handler.component.ShardHandlerFactory;
@@ -160,16 +160,16 @@ public class PeerSync implements SolrMetricProducer {
shardHandlerFactory = (HttpShardHandlerFactory) core.getCoreDescriptor().getCoreContainer().getShardHandlerFactory();
shardHandler = shardHandlerFactory.getShardHandler(client);
- core.getCoreMetricManager().registerMetricProducer(SolrInfoMBean.Category.REPLICATION.toString(), this);
+ core.getCoreMetricManager().registerMetricProducer(SolrInfoBean.Category.REPLICATION.toString(), this);
}
public static final String METRIC_SCOPE = "peerSync";
@Override
public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
- syncTime = manager.timer(registry, "time", scope, METRIC_SCOPE);
- syncErrors = manager.counter(registry, "errors", scope, METRIC_SCOPE);
- syncSkipped = manager.counter(registry, "skipped", scope, METRIC_SCOPE);
+ syncTime = manager.timer(null, registry, "time", scope, METRIC_SCOPE);
+ syncErrors = manager.counter(null, registry, "errors", scope, METRIC_SCOPE);
+ syncSkipped = manager.counter(null, registry, "skipped", scope, METRIC_SCOPE);
}
/** optional list of updates we had before possibly receiving new updates */
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 ed856040ec1..0315b495484 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java
@@ -39,7 +39,7 @@ import org.apache.solr.common.util.SuppressForbidden;
import org.apache.solr.core.DirectoryFactory;
import org.apache.solr.core.DirectoryFactory.DirContext;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.schema.IndexSchema;
import org.slf4j.Logger;
@@ -151,20 +151,20 @@ public class SolrIndexWriter extends IndexWriter {
}
if (mergeDetails) {
mergeTotals = true; // override
- majorMergedDocs = metricManager.meter(registry, "docs", SolrInfoMBean.Category.INDEX.toString(), "merge", "major");
- majorDeletedDocs = metricManager.meter(registry, "deletedDocs", SolrInfoMBean.Category.INDEX.toString(), "merge", "major");
+ majorMergedDocs = metricManager.meter(null, registry, "docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+ majorDeletedDocs = metricManager.meter(null, registry, "deletedDocs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
}
if (mergeTotals) {
- minorMerge = metricManager.timer(registry, "minor", SolrInfoMBean.Category.INDEX.toString(), "merge");
- majorMerge = metricManager.timer(registry, "major", SolrInfoMBean.Category.INDEX.toString(), "merge");
- mergeErrors = metricManager.counter(registry, "errors", SolrInfoMBean.Category.INDEX.toString(), "merge");
- metricManager.registerGauge(registry, () -> runningMajorMerges.get(), true, "running", SolrInfoMBean.Category.INDEX.toString(), "merge", "major");
- metricManager.registerGauge(registry, () -> runningMinorMerges.get(), true, "running", SolrInfoMBean.Category.INDEX.toString(), "merge", "minor");
- metricManager.registerGauge(registry, () -> runningMajorMergesDocs.get(), true, "running.docs", SolrInfoMBean.Category.INDEX.toString(), "merge", "major");
- metricManager.registerGauge(registry, () -> runningMinorMergesDocs.get(), true, "running.docs", SolrInfoMBean.Category.INDEX.toString(), "merge", "minor");
- metricManager.registerGauge(registry, () -> runningMajorMergesSegments.get(), true, "running.segments", SolrInfoMBean.Category.INDEX.toString(), "merge", "major");
- metricManager.registerGauge(registry, () -> runningMinorMergesSegments.get(), true, "running.segments", SolrInfoMBean.Category.INDEX.toString(), "merge", "minor");
- flushMeter = metricManager.meter(registry, "flush", SolrInfoMBean.Category.INDEX.toString());
+ minorMerge = metricManager.timer(null, registry, "minor", SolrInfoBean.Category.INDEX.toString(), "merge");
+ majorMerge = metricManager.timer(null, registry, "major", SolrInfoBean.Category.INDEX.toString(), "merge");
+ mergeErrors = metricManager.counter(null, registry, "errors", SolrInfoBean.Category.INDEX.toString(), "merge");
+ metricManager.registerGauge(null, registry, () -> runningMajorMerges.get(), true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+ metricManager.registerGauge(null, registry, () -> runningMinorMerges.get(), true, "running", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+ metricManager.registerGauge(null, registry, () -> runningMajorMergesDocs.get(), true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+ metricManager.registerGauge(null, registry, () -> runningMinorMergesDocs.get(), true, "running.docs", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+ metricManager.registerGauge(null, registry, () -> runningMajorMergesSegments.get(), true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "major");
+ metricManager.registerGauge(null, registry, () -> runningMinorMergesSegments.get(), true, "running.segments", SolrInfoBean.Category.INDEX.toString(), "merge", "minor");
+ flushMeter = metricManager.meter(null, registry, "flush", SolrInfoBean.Category.INDEX.toString());
}
}
}
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateHandler.java b/solr/core/src/java/org/apache/solr/update/UpdateHandler.java
index cbfb0d5f1fc..49d2664c649 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateHandler.java
@@ -19,14 +19,17 @@ package org.apache.solr.update;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import java.util.HashSet;
+import java.util.Set;
import java.util.Vector;
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.core.DirectoryFactory;
import org.apache.solr.core.HdfsDirectoryFactory;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrEventListener;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.util.plugin.SolrCoreAware;
@@ -41,7 +44,7 @@ import org.slf4j.LoggerFactory;
* @since solr 0.9
*/
-public abstract class UpdateHandler implements SolrInfoMBean {
+public abstract class UpdateHandler implements SolrInfoBean {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected final SolrCore core;
@@ -55,6 +58,9 @@ public abstract class UpdateHandler implements SolrInfoMBean {
protected final UpdateLog ulog;
+ protected Set metricNames = new HashSet<>();
+ protected MetricRegistry registry;
+
private void parseEventListeners() {
final Class clazz = SolrEventListener.class;
final String label = "Event Listener";
@@ -221,4 +227,12 @@ public abstract class UpdateHandler implements SolrInfoMBean {
public Category getCategory() {
return Category.UPDATE;
}
+ @Override
+ public Set getMetricNames() {
+ return metricNames;
+ }
+ @Override
+ public MetricRegistry getMetricRegistry() {
+ return registry;
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateLog.java b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
index 84a20052b99..c50add4a45e 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateLog.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
@@ -57,7 +57,7 @@ import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.IOUtils;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.request.LocalSolrQueryRequest;
@@ -403,7 +403,7 @@ public static final int VERSION_IDX = 1;
}
}
- core.getCoreMetricManager().registerMetricProducer(SolrInfoMBean.Category.TLOG.toString(), this);
+ core.getCoreMetricManager().registerMetricProducer(SolrInfoBean.Category.TLOG.toString(), this);
}
@Override
@@ -422,12 +422,12 @@ public static final int VERSION_IDX = 1;
}
};
- manager.registerGauge(registry, bufferedOpsGauge, true, "ops", scope, "buffered");
- manager.registerGauge(registry, () -> logs.size(), true, "logs", scope, "replay", "remaining");
- manager.registerGauge(registry, () -> getTotalLogsSize(), true, "bytes", scope, "replay", "remaining");
- applyingBufferedOpsMeter = manager.meter(registry, "ops", scope, "applyingBuffered");
- replayOpsMeter = manager.meter(registry, "ops", scope, "replay");
- manager.registerGauge(registry, () -> state.getValue(), true, "state", scope);
+ manager.registerGauge(null, registry, bufferedOpsGauge, true, "ops", scope, "buffered");
+ manager.registerGauge(null, registry, () -> logs.size(), true, "logs", scope, "replay", "remaining");
+ manager.registerGauge(null, registry, () -> getTotalLogsSize(), true, "bytes", scope, "replay", "remaining");
+ applyingBufferedOpsMeter = manager.meter(null, registry, "ops", scope, "applyingBuffered");
+ replayOpsMeter = manager.meter(null, registry, "ops", scope, "replay");
+ manager.registerGauge(null, registry, () -> state.getValue(), true, "state", scope);
}
/**
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 9d4eb7d1eed..ca8cea5a162 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
@@ -17,10 +17,11 @@
package org.apache.solr.update;
import java.lang.invoke.MethodHandles;
-import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
-import com.codahale.metrics.InstrumentedExecutorService;
+import com.codahale.metrics.MetricRegistry;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@@ -29,20 +30,20 @@ import org.apache.solr.cloud.RecoveryStrategy;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.ExecutorUtil;
-import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SolrjNamedThreadFactory;
-import org.apache.solr.core.SolrInfoMBean;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricProducer;
import org.apache.solr.util.stats.HttpClientMetricNameStrategy;
import org.apache.solr.util.stats.InstrumentedHttpRequestExecutor;
import org.apache.solr.util.stats.InstrumentedPoolingHttpClientConnectionManager;
+import org.apache.solr.util.stats.MetricUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.util.stats.InstrumentedHttpRequestExecutor.KNOWN_METRIC_NAME_STRATEGIES;
-public class UpdateShardHandler implements SolrMetricProducer, SolrInfoMBean {
+public class UpdateShardHandler implements SolrMetricProducer, SolrInfoBean {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -65,6 +66,9 @@ public class UpdateShardHandler implements SolrMetricProducer, SolrInfoMBean {
private final InstrumentedHttpRequestExecutor httpRequestExecutor;
+ private final Set metricNames = new HashSet<>();
+ private MetricRegistry registry;
+
public UpdateShardHandler(UpdateShardHandlerConfig cfg) {
clientConnectionManager = new InstrumentedPoolingHttpClientConnectionManager(HttpClientUtil.getSchemaRegisteryProvider().getSchemaRegistry());
if (cfg != null ) {
@@ -104,20 +108,14 @@ public class UpdateShardHandler implements SolrMetricProducer, SolrInfoMBean {
}
@Override
- public String getVersion() {
- return getClass().getPackage().getSpecificationVersion();
- }
-
- @Override
- public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+ public void initializeMetrics(SolrMetricManager manager, String registryName, String scope) {
+ registry = manager.registry(registryName);
String expandedScope = SolrMetricManager.mkName(scope, getCategory().name());
- clientConnectionManager.initializeMetrics(manager, registry, expandedScope);
- httpRequestExecutor.initializeMetrics(manager, registry, expandedScope);
- updateExecutor = new InstrumentedExecutorService(updateExecutor,
- manager.registry(registry),
+ clientConnectionManager.initializeMetrics(manager, registryName, expandedScope);
+ httpRequestExecutor.initializeMetrics(manager, registryName, expandedScope);
+ updateExecutor = MetricUtils.instrumentedExecutorService(updateExecutor, this, registry,
SolrMetricManager.mkName("updateExecutor", expandedScope, "threadPool"));
- recoveryExecutor = new InstrumentedExecutorService(recoveryExecutor,
- manager.registry(registry),
+ recoveryExecutor = MetricUtils.instrumentedExecutorService(recoveryExecutor, this, registry,
SolrMetricManager.mkName("recoveryExecutor", expandedScope, "threadPool"));
}
@@ -132,18 +130,13 @@ public class UpdateShardHandler implements SolrMetricProducer, SolrInfoMBean {
}
@Override
- public String getSource() {
- return null;
+ public Set getMetricNames() {
+ return metricNames;
}
@Override
- public URL[] getDocs() {
- return new URL[0];
- }
-
- @Override
- public NamedList getStatistics() {
- return null;
+ public MetricRegistry getMetricRegistry() {
+ return registry;
}
public HttpClient getHttpClient() {
diff --git a/solr/core/src/java/org/apache/solr/util/JmxUtil.java b/solr/core/src/java/org/apache/solr/util/JmxUtil.java
index 02a070d9691..f27a55e7efc 100644
--- a/solr/core/src/java/org/apache/solr/util/JmxUtil.java
+++ b/solr/core/src/java/org/apache/solr/util/JmxUtil.java
@@ -27,9 +27,6 @@ import java.util.List;
/**
* Utility methods to find a MBeanServer.
- *
- * This was factored out from {@link org.apache.solr.core.JmxMonitoredMap}
- * and can eventually replace the logic used there.
*/
public final class JmxUtil {
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 7bcabf8c255..58ec69e0c9b 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
@@ -35,10 +35,10 @@ public class InstrumentedPoolingHttpClientConnectionManager extends PoolingHttpC
@Override
public void initializeMetrics(SolrMetricManager manager, String registry, String scope) {
- manager.registerGauge(registry, () -> getTotalStats().getAvailable(), true, SolrMetricManager.mkName("availableConnections", scope));
+ manager.registerGauge(null, registry, () -> getTotalStats().getAvailable(), true, SolrMetricManager.mkName("availableConnections", scope));
// this acquires a lock on the connection pool; remove if contention sucks
- manager.registerGauge(registry, () -> getTotalStats().getLeased(), true, SolrMetricManager.mkName("leasedConnections", scope));
- manager.registerGauge(registry, () -> getTotalStats().getMax(), true, SolrMetricManager.mkName("maxConnections", scope));
- manager.registerGauge(registry, () -> getTotalStats().getPending(), true, SolrMetricManager.mkName("pendingConnections", scope));
+ manager.registerGauge(null, registry, () -> getTotalStats().getLeased(), true, SolrMetricManager.mkName("leasedConnections", scope));
+ manager.registerGauge(null, registry, () -> getTotalStats().getMax(), true, SolrMetricManager.mkName("maxConnections", scope));
+ manager.registerGauge(null, registry, () -> getTotalStats().getPending(), true, SolrMetricManager.mkName("pendingConnections", scope));
}
}
diff --git a/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
index 491932d1a8d..2900857a912 100644
--- a/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
+++ b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
@@ -16,9 +16,17 @@
*/
package org.apache.solr.util.stats;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandles;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.PlatformManagedObject;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
@@ -40,6 +48,7 @@ import com.codahale.metrics.Timer;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.metrics.AggregateMetric;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -116,59 +125,42 @@ public class MetricUtils {
* A metric must match this filter to be included in the output.
* @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s.
* @param compact use compact representation for counters and gauges.
- * @param metadata optional metadata. If not null and not empty then this map will be added under a
- * {@code _metadata_} key.
* @return a {@link NamedList}
*/
public static NamedList toNamedList(MetricRegistry registry, List shouldMatchFilters,
MetricFilter mustMatchFilter, boolean skipHistograms,
- boolean skipAggregateValues, boolean compact,
- Map metadata) {
+ boolean skipAggregateValues, boolean compact) {
NamedList result = new SimpleOrderedMap();
- toMaps(registry, shouldMatchFilters, mustMatchFilter, skipHistograms, skipAggregateValues, compact, (k, v) -> {
+ toMaps(registry, shouldMatchFilters, mustMatchFilter, skipHistograms, skipAggregateValues, compact, false, (k, v) -> {
result.add(k, v);
});
- if (metadata != null && !metadata.isEmpty()) {
- result.add("_metadata_", metadata);
- }
return result;
}
/**
- * Returns a representation of the given metric registry as a list of {@link SolrInputDocument}-s.
+ * Provides a representation of the given metric registry as {@link SolrInputDocument}-s.
Only those metrics
- * are converted to NamedList which match at least one of the given MetricFilter instances.
+ * are converted which match at least one of the given MetricFilter instances.
*
- * @param registry the {@link MetricRegistry} to be converted to NamedList
+ * @param registry the {@link MetricRegistry} to be converted
* @param shouldMatchFilters a list of {@link MetricFilter} instances.
* A metric must match any one of the filters from this list to be
* included in the output
* @param mustMatchFilter a {@link MetricFilter}.
* A metric must match this filter to be included in the output.
* @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s.
+ * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s.
* @param compact use compact representation for counters and gauges.
* @param metadata optional metadata. If not null and not empty then this map will be added under a
* {@code _metadata_} key.
- * @return a list of {@link SolrInputDocument}-s
+ * @param consumer consumer that accepts produced {@link SolrInputDocument}-s
*/
- public static List toSolrInputDocuments(MetricRegistry registry, List shouldMatchFilters,
- MetricFilter mustMatchFilter, boolean skipHistograms,
- boolean skipAggregateValues, boolean compact,
- Map metadata) {
- List result = new LinkedList<>();
- toSolrInputDocuments(registry, shouldMatchFilters, mustMatchFilter, skipHistograms,
- skipAggregateValues, compact, metadata, doc -> {
- result.add(doc);
- });
- return result;
- }
-
public static void toSolrInputDocuments(MetricRegistry registry, List shouldMatchFilters,
MetricFilter mustMatchFilter, boolean skipHistograms,
boolean skipAggregateValues, boolean compact,
Map metadata, Consumer consumer) {
boolean addMetadata = metadata != null && !metadata.isEmpty();
- toMaps(registry, shouldMatchFilters, mustMatchFilter, skipHistograms, skipAggregateValues, compact, (k, v) -> {
+ toMaps(registry, shouldMatchFilters, mustMatchFilter, skipHistograms, skipAggregateValues, compact, false, (k, v) -> {
SolrInputDocument doc = new SolrInputDocument();
doc.setField(METRIC_NAME, k);
toSolrInputDocument(null, doc, v);
@@ -179,7 +171,13 @@ public class MetricUtils {
});
}
- public static void toSolrInputDocument(String prefix, SolrInputDocument doc, Object o) {
+ /**
+ * Fill in a SolrInputDocument with values from a converted metric, recursively.
+ * @param prefix prefix to add to generated field names, or null if none.
+ * @param doc document to fill
+ * @param o an instance of converted metric, either a Map or a flat Object
+ */
+ static void toSolrInputDocument(String prefix, SolrInputDocument doc, Object o) {
if (!(o instanceof Map)) {
String key = prefix != null ? prefix : VALUE;
doc.addField(key, o);
@@ -196,77 +194,170 @@ public class MetricUtils {
}
}
- public static void toMaps(MetricRegistry registry, List shouldMatchFilters,
+ /**
+ * Convert selected metrics to maps or to flattened objects.
+ * @param registry source of metrics
+ * @param shouldMatchFilters metrics must match any of these filters
+ * @param mustMatchFilter metrics must match this filter
+ * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s.
+ * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s.
+ * @param compact use compact representation for counters and gauges.
+ * @param simple use simplified representation for complex metrics - instead of a (name, map)
+ * only the selected (name "." key, value) pairs will be produced.
+ * @param consumer consumer that accepts produced objects
+ */
+ static void toMaps(MetricRegistry registry, List shouldMatchFilters,
MetricFilter mustMatchFilter, boolean skipHistograms, boolean skipAggregateValues,
- boolean compact,
+ boolean compact, boolean simple,
BiConsumer consumer) {
- Map metrics = registry.getMetrics();
- SortedSet names = registry.getNames();
+ final Map metrics = registry.getMetrics();
+ final SortedSet names = registry.getNames();
names.stream()
.filter(s -> shouldMatchFilters.stream().anyMatch(metricFilter -> metricFilter.matches(s, metrics.get(s))))
.filter(s -> mustMatchFilter.matches(s, metrics.get(s)))
.forEach(n -> {
Metric metric = metrics.get(n);
- if (metric instanceof Counter) {
- Counter counter = (Counter) metric;
- consumer.accept(n, convertCounter(counter, compact));
- } else if (metric instanceof Gauge) {
- Gauge gauge = (Gauge) metric;
- try {
- consumer.accept(n, convertGauge(gauge, compact));
- } catch (InternalError ie) {
- if (n.startsWith("memory.") && ie.getMessage().contains("Memory Pool not found")) {
- LOG.warn("Error converting gauge '" + n + "', possible JDK bug: SOLR-10362", ie);
- consumer.accept(n, null);
- } else {
- throw ie;
- }
- }
- } else if (metric instanceof Meter) {
- Meter meter = (Meter) metric;
- consumer.accept(n, convertMeter(meter));
- } else if (metric instanceof Timer) {
- Timer timer = (Timer) metric;
- consumer.accept(n, convertTimer(timer, skipHistograms));
- } else if (metric instanceof Histogram) {
- if (!skipHistograms) {
- Histogram histogram = (Histogram) metric;
- consumer.accept(n, convertHistogram(histogram));
- }
- } else if (metric instanceof AggregateMetric) {
- consumer.accept(n, convertAggregateMetric((AggregateMetric)metric, skipAggregateValues));
- }
+ convertMetric(n, metric, skipHistograms, skipAggregateValues, compact, simple, consumer);
});
}
- static Map convertAggregateMetric(AggregateMetric metric, boolean skipAggregateValues) {
- Map response = new LinkedHashMap<>();
- response.put("count", metric.size());
- response.put(MAX, metric.getMax());
- response.put(MIN, metric.getMin());
- response.put(MEAN, metric.getMean());
- response.put(STDDEV, metric.getStdDev());
- response.put(SUM, metric.getSum());
- if (!(metric.isEmpty() || skipAggregateValues)) {
- Map values = new LinkedHashMap<>();
- response.put(VALUES, values);
- metric.getValues().forEach((k, v) -> {
- Map map = new LinkedHashMap<>();
- map.put("value", v.value);
- map.put("updateCount", v.updateCount.get());
- values.put(k, map);
- });
- }
- return response;
+ /**
+ * Convert selected metrics from a registry into a map, with metrics in a compact AND simple format.
+ * @param registry registry
+ * @param names metric names
+ * @return map where keys are metric names (if they were present in the registry) and values are
+ * converted metrics in simplified format.
+ */
+ public static Map convertMetrics(MetricRegistry registry, Collection names) {
+ final Map metrics = new HashMap<>();
+ convertMetrics(registry, names, false, true, true, true, (k, v) -> metrics.put(k, v));
+ return metrics;
}
- static Map convertHistogram(Histogram histogram) {
- Map response = new LinkedHashMap<>();
+ /**
+ * Convert selected metrics from a registry into maps (when