You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2017/04/18 15:15:17 UTC
lucene-solr:branch_6x: SOLR-10477: Port some of the
SolrMetricReporter enhancements from master to 6.x.
Repository: lucene-solr
Updated Branches:
refs/heads/branch_6x 46012784d -> 3641497ba
SOLR-10477: Port some of the SolrMetricReporter enhancements from master to 6.x.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3641497b
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3641497b
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3641497b
Branch: refs/heads/branch_6x
Commit: 3641497ba5da5999ff68ab58d9c19a59c287bac1
Parents: 4601278
Author: Andrzej Bialecki <ab...@apache.org>
Authored: Tue Apr 18 17:14:45 2017 +0200
Committer: Andrzej Bialecki <ab...@apache.org>
Committed: Tue Apr 18 17:14:45 2017 +0200
----------------------------------------------------------------------
solr/CHANGES.txt | 4 +
.../org/apache/solr/core/SolrXmlConfig.java | 16 +-
.../solr/handler/admin/MetricsHandler.java | 40 +++-
.../solr/handler/admin/SystemInfoHandler.java | 68 +------
.../solr/metrics/AltBufferPoolMetricSet.java | 47 +++++
.../solr/metrics/OperatingSystemMetricSet.java | 66 +-----
.../apache/solr/metrics/SolrMetricManager.java | 199 ++++++++++++++++++-
.../apache/solr/metrics/SolrMetricReporter.java | 12 ++
.../metrics/reporters/JmxObjectNameFactory.java | 19 +-
.../metrics/reporters/ReporterClientCache.java | 84 ++++++++
.../metrics/reporters/SolrGangliaReporter.java | 48 ++++-
.../metrics/reporters/SolrGraphiteReporter.java | 46 ++++-
.../solr/metrics/reporters/SolrJmxReporter.java | 132 +++++++++---
.../metrics/reporters/SolrSlf4jReporter.java | 28 ++-
.../apache/solr/servlet/SolrDispatchFilter.java | 9 +-
.../org/apache/solr/util/stats/MetricUtils.java | 82 ++++++++
.../solr/cloud/ReplicationFactorTest.java | 9 -
.../solr/handler/admin/MetricsHandlerTest.java | 17 ++
.../handler/admin/SystemInfoHandlerTest.java | 8 +-
.../org/apache/solr/metrics/JvmMetricsTest.java | 53 ++++-
.../solr/metrics/SolrMetricReporterTest.java | 1 +
.../reporters/SolrGangliaReporterTest.java | 2 +-
.../metrics/reporters/SolrJmxReporterTest.java | 58 +++++-
.../reporters/SolrSlf4jReporterTest.java | 2 +-
.../java/org/apache/solr/SolrTestCaseJ4.java | 14 ++
.../cloud/AbstractFullDistribZkTestBase.java | 9 -
26 files changed, 835 insertions(+), 238 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index d57f16e..87d1c54 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -161,6 +161,10 @@ Other Changes
* SOLR-10151: Use monotonically incrementing counter for doc ids in TestRecovery. (Peter Szantai-Kis, Mano Kovacs via Mark Miller)
+* SOLR-10477: Improvements to metric reporters and API: support for "regex" parameter in /admin/metrics,
+ "enabled" flag in reporter configurations, correct handling of "serviceUrl" in SolrJmxReporter, better handling
+ of service clients for JMX, Ganglia and Graphite reporters. (ab)
+
================== 6.5.1 ==================
Bug Fixes
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
index 2db5be2..919e90e 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
@@ -25,7 +25,9 @@ import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -470,13 +472,15 @@ public class SolrXmlConfig {
private static PluginInfo[] getMetricReporterPluginInfos(Config config) {
NodeList nodes = (NodeList) config.evaluate("solr/metrics/reporter", XPathConstants.NODESET);
- if (nodes == null || nodes.getLength() == 0)
- return new PluginInfo[0];
- PluginInfo[] configs = new PluginInfo[nodes.getLength()];
- for (int i = 0; i < nodes.getLength(); i++) {
- configs[i] = new PluginInfo(nodes.item(i), "SolrMetricReporter", true, true);
+ List<PluginInfo> configs = new ArrayList<>();
+ if (nodes != null && nodes.getLength() > 0) {
+ for (int i = 0; i < nodes.getLength(); i++) {
+ // we don't require class in order to support predefined replica and node reporter classes
+ PluginInfo info = new PluginInfo(nodes.item(i), "SolrMetricReporter", true, false);
+ configs.add(info);
+ }
}
- return configs;
+ return configs.toArray(new PluginInfo[configs.size()]);
}
private static PluginInfo getTransientCoreCacheFactoryPluginInfo(Config config) {
Node node = config.getNode("solr/transientCoreCacheFactory", false);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
index 4dc86d9..2b92c02 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
@@ -19,6 +19,7 @@ package org.apache.solr.handler.admin;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -52,6 +53,13 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
final SolrMetricManager metricManager;
public static final String COMPACT_PARAM = "compact";
+ public static final String PREFIX_PARAM = "prefix";
+ public static final String REGEX_PARAM = "regex";
+ public static final String REGISTRY_PARAM = "registry";
+ public static final String GROUP_PARAM = "group";
+ public static final String TYPE_PARAM = "type";
+
+ public static final String ALL = "all";
public MetricsHandler() {
this.container = null;
@@ -90,23 +98,32 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
}
private MetricFilter parseMustMatchFilter(SolrQueryRequest req) {
- String[] prefixes = req.getParams().getParams("prefix");
- MetricFilter mustMatchFilter;
+ String[] prefixes = req.getParams().getParams(PREFIX_PARAM);
+ MetricFilter prefixFilter = null;
if (prefixes != null && prefixes.length > 0) {
Set<String> prefixSet = new HashSet<>();
for (String prefix : prefixes) {
prefixSet.addAll(StrUtils.splitSmart(prefix, ','));
}
- mustMatchFilter = new SolrMetricManager.PrefixFilter((String[])prefixSet.toArray(new String[prefixSet.size()]));
- } else {
+ prefixFilter = new SolrMetricManager.PrefixFilter((String[])prefixSet.toArray(new String[prefixSet.size()]));
+ }
+ String[] regexes = req.getParams().getParams(REGEX_PARAM);
+ MetricFilter regexFilter = null;
+ if (regexes != null && regexes.length > 0) {
+ regexFilter = new SolrMetricManager.RegexFilter(regexes);
+ }
+ MetricFilter mustMatchFilter;
+ if (prefixFilter == null && regexFilter == null) {
mustMatchFilter = MetricFilter.ALL;
+ } else {
+ mustMatchFilter = new SolrMetricManager.OrFilter(prefixFilter, regexFilter);
}
return mustMatchFilter;
}
private Set<String> parseRegistries(SolrQueryRequest req) {
- String[] groupStr = req.getParams().getParams("group");
- String[] registryStr = req.getParams().getParams("registry");
+ String[] groupStr = req.getParams().getParams(GROUP_PARAM);
+ String[] registryStr = req.getParams().getParams(REGISTRY_PARAM);
if ((groupStr == null || groupStr.length == 0) && (registryStr == null || registryStr.length == 0)) {
// return all registries
return container.getMetricManager().registryNames();
@@ -118,7 +135,7 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
for (String g : groupStr) {
List<String> split = StrUtils.splitSmart(g, ',');
for (String s : split) {
- if (s.trim().equals("all")) {
+ if (s.trim().equals(ALL)) {
allRegistries = true;
break;
}
@@ -137,7 +154,7 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
for (String r : registryStr) {
List<String> split = StrUtils.splitSmart(r, ',');
for (String s : split) {
- if (s.trim().equals("all")) {
+ if (s.trim().equals(ALL)) {
allRegistries = true;
break;
}
@@ -161,7 +178,7 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
}
private List<MetricType> parseMetricTypes(SolrQueryRequest req) {
- String[] typeStr = req.getParams().getParams("type");
+ String[] typeStr = req.getParams().getParams(TYPE_PARAM);
List<String> types = Collections.emptyList();
if (typeStr != null && typeStr.length > 0) {
types = new ArrayList<>();
@@ -176,7 +193,8 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
metricTypes = types.stream().map(String::trim).map(MetricType::valueOf).collect(Collectors.toList());
}
} catch (IllegalArgumentException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Invalid metric type in: " + types + " specified. Must be one of (all, meter, timer, histogram, counter, gauge)", e);
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Invalid metric type in: " + types +
+ " specified. Must be one of " + MetricType.SUPPORTED_TYPES_MSG, e);
}
return metricTypes;
}
@@ -199,6 +217,8 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName
gauge(Gauge.class),
all(null);
+ public static final String SUPPORTED_TYPES_MSG = EnumSet.allOf(MetricType.class).toString();
+
private final Class klass;
MetricType(Class klass) {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
----------------------------------------------------------------------
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 8b74491..3a676da 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 {
@@ -242,35 +220,7 @@ public class SystemInfoHandler extends RequestHandlerBase
}
return info;
}
-
- /**
- * Add all bean properties of a {@link PlatformManagedObject} to the given {@link NamedList}.
- * <p>
- * 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 <T extends PlatformManagedObject> void addMXBeanProperties(T obj, Class<? extends T> intf, NamedList<Object> 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
*/
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/AltBufferPoolMetricSet.java
----------------------------------------------------------------------
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 0000000..ccd7564
--- /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<String, Metric> getMetrics() {
+ final Map<String, Metric> metrics = new HashMap<>();
+ List<BufferPoolMXBean> pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
+ for (final BufferPoolMXBean pool : pools) {
+ String name = pool.getName();
+ metrics.put(name + ".Count", (Gauge<Long>)() -> pool.getCount());
+ metrics.put(name + ".MemoryUsed", (Gauge<Long>)() -> pool.getMemoryUsed());
+ metrics.put(name + ".TotalCapacity", (Gauge<Long>)() -> pool.getTotalCapacity());
+ }
+ return metrics;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/OperatingSystemMetricSet.java
----------------------------------------------------------------------
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 34ef5d1..21957eb 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<String, Metric> getMetrics() {
final Map<String, Metric> 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<String> attributes = new HashSet<>();
- for (MBeanAttributeInfo ai : info.getAttributes()) {
- attributes.add(ai.getName());
- }
- 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));
- }
+ OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
+ MetricUtils.addMXBeanMetrics(os, MetricUtils.OS_MXBEAN_CLASSES, null, (k, v) -> {
+ if (!metrics.containsKey(k)) {
+ metrics.put(k, v);
}
- } catch (JMException ignored) {
- log.debug("Unable to load OperatingSystem MBean", ignored);
- }
-
+ });
return metrics;
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
----------------------------------------------------------------------
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 cdc1adf..a1505e4 100644
--- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
+++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java
@@ -18,9 +18,13 @@ package org.apache.solr.metrics;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -29,6 +33,9 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
@@ -92,10 +99,10 @@ public class SolrMetricManager {
/**
* An implementation of {@link MetricFilter} that selects metrics
- * with names that start with a prefix.
+ * with names that start with one of prefixes.
*/
public static class PrefixFilter implements MetricFilter {
- private final String[] prefixes;
+ private final Set<String> prefixes = new HashSet<>();
private final Set<String> matched = new HashSet<>();
private boolean allMatch = false;
@@ -107,8 +114,18 @@ public class SolrMetricManager {
*/
public PrefixFilter(String... prefixes) {
Objects.requireNonNull(prefixes);
- this.prefixes = prefixes;
- if (prefixes.length == 0) {
+ if (prefixes.length > 0) {
+ this.prefixes.addAll(Arrays.asList(prefixes));
+ }
+ if (this.prefixes.isEmpty()) {
+ allMatch = true;
+ }
+ }
+
+ public PrefixFilter(Collection<String> prefixes) {
+ Objects.requireNonNull(prefixes);
+ this.prefixes.addAll(prefixes);
+ if (this.prefixes.isEmpty()) {
allMatch = true;
}
}
@@ -142,6 +159,145 @@ public class SolrMetricManager {
public void reset() {
matched.clear();
}
+
+ @Override
+ public String toString() {
+ return "PrefixFilter{" +
+ "prefixes=" + prefixes +
+ '}';
+ }
+ }
+
+ /**
+ * An implementation of {@link MetricFilter} that selects metrics
+ * with names that match regular expression patterns.
+ */
+ public static class RegexFilter implements MetricFilter {
+ private final Set<Pattern> compiledPatterns = new HashSet<>();
+ private final Set<String> matched = new HashSet<>();
+ private boolean allMatch = false;
+
+ /**
+ * Create a filter that uses the provided prefix.
+ * @param patterns regex patterns to use, must not be null. If empty then any
+ * name will match, if not empty then match on any pattern will
+ * succeed (logical OR).
+ */
+ public RegexFilter(String... patterns) throws PatternSyntaxException {
+ this(patterns != null ? Arrays.asList(patterns) : Collections.emptyList());
+ }
+
+ public RegexFilter(Collection<String> patterns) throws PatternSyntaxException {
+ Objects.requireNonNull(patterns);
+ if (patterns.isEmpty()) {
+ allMatch = true;
+ return;
+ }
+ patterns.forEach(p -> {
+ Pattern pattern = Pattern.compile(p);
+ compiledPatterns.add(pattern);
+ });
+ if (patterns.isEmpty()) {
+ allMatch = true;
+ }
+ }
+
+ @Override
+ public boolean matches(String name, Metric metric) {
+ if (allMatch) {
+ matched.add(name);
+ return true;
+ }
+ for (Pattern p : compiledPatterns) {
+ if (p.matcher(name).matches()) {
+ matched.add(name);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the set of names that matched this filter.
+ * @return matching names
+ */
+ public Set<String> getMatched() {
+ return Collections.unmodifiableSet(matched);
+ }
+
+ /**
+ * Clear the set of names that matched.
+ */
+ public void reset() {
+ matched.clear();
+ }
+
+ @Override
+ public String toString() {
+ return "RegexFilter{" +
+ "compiledPatterns=" + compiledPatterns +
+ '}';
+ }
+ }
+
+ public static class OrFilter implements MetricFilter {
+ List<MetricFilter> filters = new ArrayList<>();
+
+ public OrFilter(Collection<MetricFilter> 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<MetricFilter> filters = new ArrayList<>();
+
+ public AndFilter(Collection<MetricFilter> 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;
+ }
}
/**
@@ -151,7 +307,40 @@ public class SolrMetricManager {
Set<String> set = new HashSet<>();
set.addAll(registries.keySet());
set.addAll(SharedMetricRegistries.names());
- return Collections.unmodifiableSet(set);
+ return set;
+ }
+
+ /**
+ * Return set of existing registry names that match a regex pattern
+ * @param patterns regex patterns. NOTE: users need to make sure that patterns that
+ * don't start with a wildcard use the full registry name starting with
+ * {@link #REGISTRY_NAME_PREFIX}
+ * @return set of existing registry names where at least one pattern matched.
+ */
+ public Set<String> registryNames(String... patterns) throws PatternSyntaxException {
+ if (patterns == null || patterns.length == 0) {
+ return registryNames();
+ }
+ List<Pattern> compiled = new ArrayList<>();
+ for (String pattern : patterns) {
+ compiled.add(Pattern.compile(pattern));
+ }
+ return registryNames((Pattern[])compiled.toArray(new Pattern[compiled.size()]));
+ }
+
+ public Set<String> registryNames(Pattern... patterns) {
+ Set<String> allNames = registryNames();
+ if (patterns == null || patterns.length == 0) {
+ return allNames;
+ }
+ return allNames.stream().filter(s -> {
+ for (Pattern p : patterns) {
+ if (p.matcher(s).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }).collect(Collectors.toSet());
}
/**
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java
----------------------------------------------------------------------
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 ff2d3fc..9ad15d0 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.
@@ -58,6 +59,17 @@ public abstract class SolrMetricReporter implements Closeable, PluginInfoInitial
}
/**
+ * 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.
* @return plugin info, or null if not yet initialized.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/reporters/JmxObjectNameFactory.java
----------------------------------------------------------------------
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 4df5257..c9c9439 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
@@ -41,9 +41,9 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
* @param additionalProperties additional properties as key, value pairs.
*/
public JmxObjectNameFactory(String reporterName, String domain, String... additionalProperties) {
- this.reporterName = reporterName;
+ this.reporterName = reporterName.replaceAll(":", "_");
this.domain = domain;
- this.subdomains = domain.split("\\.");
+ this.subdomains = domain.replaceAll(":", "_").split("\\.");
if (additionalProperties != null && (additionalProperties.length % 2) != 0) {
throw new IllegalArgumentException("additionalProperties length must be even: " + Arrays.toString(additionalProperties));
}
@@ -60,7 +60,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
@@ -83,7 +84,7 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
}
sb.append(','); // separate from other properties
} else {
- sb.append(currentDomain);
+ sb.append(currentDomain.replaceAll(":", "_"));
sb.append(':');
}
} else {
@@ -96,18 +97,20 @@ public class JmxObjectNameFactory implements ObjectNameFactory {
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(',');
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java
----------------------------------------------------------------------
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 0000000..e8ad1fa
--- /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<T> implements Closeable {
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private final Map<String, T> cache = new ConcurrentHashMap<>();
+
+ /**
+ * Provide an instance of service client.
+ * @param <T> formal type
+ */
+ public interface ClientProvider<T> {
+ /**
+ * 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<T> 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();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGangliaReporter.java
----------------------------------------------------------------------
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 45561e5..142ddd8 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<String> filters = new ArrayList<>();
private boolean testing;
private GangliaReporter reporter;
+ private static final ReporterClientCache<GMetric> 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<String> 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;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrGraphiteReporter.java
----------------------------------------------------------------------
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 8565ce8..d5b7a20 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<String> filters = new ArrayList<>();
private GraphiteReporter reporter = null;
+ private static final ReporterClientCache<GraphiteSender> 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;
}
+ /**
+ * 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<String> filters) {
+ if (filters == null || filters.isEmpty()) {
+ return;
+ }
+ this.filters.addAll(filters);
+ }
+
public void setFilter(String filter) {
- this.filterPrefix = 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;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrJmxReporter.java
----------------------------------------------------------------------
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 0e78eee..e6ce124 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
@@ -18,12 +18,14 @@ package org.apache.solr.metrics.reporters;
import javax.management.MBeanServer;
-import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import com.codahale.metrics.JmxReporter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricReporter;
@@ -34,16 +36,23 @@ import org.slf4j.LoggerFactory;
/**
* A {@link SolrMetricReporter} that finds (or creates) a MBeanServer from
* the given configuration and registers metrics to it with JMX.
+ * <p>NOTE: {@link JmxReporter} that this class uses exports only newly added metrics (it doesn't
+ * process already existing metrics in a registry)</p>
*/
public class SolrJmxReporter extends SolrMetricReporter {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private static final ReporterClientCache<MBeanServer> serviceRegistry = new ReporterClientCache<>();
+
private String domain;
private String agentId;
private String serviceUrl;
+ private String rootName;
+ private List<String> filters = new ArrayList<>();
private JmxReporter reporter;
+ private MetricRegistry registry;
private MBeanServer mBeanServer;
/**
@@ -57,7 +66,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 +74,56 @@ 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);
+ MetricFilter filter;
+ if (filters.isEmpty()) {
+ filter = MetricFilter.ALL;
+ } else {
+ // apply also prefix filters
+ filter = new SolrMetricManager.PrefixFilter(filters);
+ }
- reporter = JmxReporter.forRegistry(metricManager.registry(registryName))
+ reporter = JmxReporter.forRegistry(registry)
.registerWith(mBeanServer)
- .inDomain(domain)
+ .inDomain(fullDomain)
+ .filter(filter)
.createsObjectNamesWith(jmxObjectNameFactory)
.build();
reporter.start();
- log.info("JMX monitoring enabled at server: " + mBeanServer);
+ log.info("JMX monitoring for '" + fullDomain + "' (registry '" + registryName + "') enabled at server: " + mBeanServer);
}
/**
@@ -127,9 +148,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 +193,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<String> 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 +240,18 @@ public class SolrJmxReporter extends SolrMetricReporter {
return mBeanServer;
}
+ /**
+ * 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: domain = %s, service url = %s, agent id = %s]",
- getClass().getName(), Integer.toHexString(hashCode()), domain, serviceUrl, agentId);
+ 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);
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/metrics/reporters/SolrSlf4jReporter.java
----------------------------------------------------------------------
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 817dda1..c5dbc00 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<String> filters = new ArrayList<>();
private Slf4jReporter reporter;
/**
@@ -65,8 +67,22 @@ public class SolrSlf4jReporter extends SolrMetricReporter {
this.instancePrefix = prefix;
}
+ /**
+ * 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<String> filters) {
+ if (filters == null || filters.isEmpty()) {
+ return;
+ }
+ this.filters.addAll(filters);
+ }
+
public void setFilter(String filter) {
- this.filterPrefix = filter;
+ if (filter != null && !filter.isEmpty()) {
+ this.filters.add(filter);
+ }
}
public void setLogger(String logger) {
@@ -79,6 +95,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 +113,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;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
----------------------------------------------------------------------
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 ff0db9b..98656af 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;
@@ -69,6 +66,7 @@ import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrInfoMBean;
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");
+ 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?
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java
----------------------------------------------------------------------
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 dbb4ff4..2f32e49 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,7 +16,14 @@
*/
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.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -248,4 +255,79 @@ public class MetricUtils {
public static ExecutorService instrumentedExecutorService(ExecutorService delegate, MetricRegistry metricRegistry, String scope) {
return new InstrumentedExecutorService(delegate, metricRegistry, scope);
}
+
+ /**
+ * Creates a set of metrics (gauges) that correspond to available bean properties for the provided MXBean.
+ * @param obj an instance of MXBean
+ * @param intf MXBean interface, one of {@link PlatformManagedObject}-s
+ * @param consumer consumer for created names and metrics
+ * @param <T> formal type
+ */
+ public static <T extends PlatformManagedObject> void addMXBeanMetrics(T obj, Class<? extends T> intf,
+ String prefix, BiConsumer<String, Metric> consumer) {
+ if (intf.isInstance(obj)) {
+ BeanInfo beanInfo;
+ try {
+ beanInfo = Introspector.getBeanInfo(intf, intf.getSuperclass(), Introspector.IGNORE_ALL_BEANINFO);
+ } catch (IntrospectionException e) {
+ LOG.warn("Unable to fetch properties of MXBean " + obj.getClass().getName());
+ return;
+ }
+ for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) {
+ final String name = desc.getName();
+ // test if it works at all
+ try {
+ desc.getReadMethod().invoke(obj);
+ // worked - consume it
+ final Gauge<?> gauge = () -> {
+ try {
+ return desc.getReadMethod().invoke(obj);
+ } catch (InvocationTargetException ite) {
+ // ignore (some properties throw UOE)
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ };
+ String metricName = MetricRegistry.name(prefix, name);
+ consumer.accept(metricName, gauge);
+ } catch (Exception e) {
+ // didn't work, skip it...
+ }
+ }
+ }
+ }
+
+ /**
+ * These are well-known implementations of {@link java.lang.management.OperatingSystemMXBean}.
+ * Some of them provide additional useful properties beyond those declared by the interface.
+ */
+ public static String[] OS_MXBEAN_CLASSES = new String[] {
+ OperatingSystemMXBean.class.getName(),
+ "com.sun.management.OperatingSystemMXBean",
+ "com.sun.management.UnixOperatingSystemMXBean",
+ "com.ibm.lang.management.OperatingSystemMXBean"
+ };
+
+ /**
+ * Creates a set of metrics (gauges) that correspond to available bean properties for the provided MXBean.
+ * @param obj an instance of MXBean
+ * @param interfaces interfaces that it may implement. Each interface will be tried in turn, and only
+ * if it exists and if it contains unique properties then they will be added as metrics.
+ * @param prefix optional prefix for metric names
+ * @param consumer consumer for created names and metrics
+ * @param <T> formal type
+ */
+ public static <T extends PlatformManagedObject> void addMXBeanMetrics(T obj, String[] interfaces,
+ String prefix, BiConsumer<String, Metric> consumer) {
+ for (String clazz : interfaces) {
+ try {
+ final Class<? extends PlatformManagedObject> intf = Class.forName(clazz)
+ .asSubclass(PlatformManagedObject.class);
+ MetricUtils.addMXBeanMetrics(obj, intf, null, consumer);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java b/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
index 9441e3f..9100eee 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ReplicationFactorTest.java
@@ -18,7 +18,6 @@ package org.apache.solr.cloud;
import java.io.File;
import java.lang.invoke.MethodHandles;
-import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -71,14 +70,6 @@ public class ReplicationFactorTest extends AbstractFullDistribZkTestBase {
return createProxiedJetty(solrHome, dataDir, shardList, solrConfigOverride, schemaOverride);
}
- protected int getNextAvailablePort() throws Exception {
- int port = -1;
- try (ServerSocket s = new ServerSocket(0)) {
- port = s.getLocalPort();
- }
- return port;
- }
-
@Test
public void test() throws Exception {
log.info("replication factor test running");
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
index 2f84997..1a209be 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
@@ -17,6 +17,7 @@
package org.apache.solr.handler.admin;
+import java.lang.management.ManagementFactory;
import java.util.Map;
import org.apache.solr.SolrTestCaseJ4;
@@ -33,6 +34,11 @@ import org.junit.Test;
public class MetricsHandlerTest extends SolrTestCaseJ4 {
@BeforeClass
public static void beforeClass() throws Exception {
+ // this is needed to enable default SolrJmxReporter in TestHarness
+ // which is then initialized for solr.jetty and solr.jvm so that they
+ // show up in MetricsHandler output
+ ManagementFactory.getPlatformMBeanServer();
+
initCore("solrconfig.xml", "schema.xml");
}
@@ -136,6 +142,17 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
assertNotNull(values.get("CONTAINER.threadPool.coreLoadExecutor.completed"));
resp = new SolrQueryResponse();
+ handler.handleRequestBody(req(CommonParams.QT, "/admin/metrics", CommonParams.WT, "json", "prefix", "CONTAINER.cores", "regex", "C.*thread.*completed"), resp);
+ values = resp.getValues();
+ assertNotNull(values.get("metrics"));
+ values = (NamedList) values.get("metrics");
+ assertNotNull(values.get("solr.node"));
+ values = (NamedList) values.get("solr.node");
+ assertEquals(5, values.size());
+ assertNotNull(values.get("CONTAINER.threadPool.coreContainerWorkExecutor.completed"));
+ assertNotNull(values.get("CONTAINER.threadPool.coreLoadExecutor.completed"));
+
+ resp = new SolrQueryResponse();
handler.handleRequestBody(req(CommonParams.QT, "/admin/metrics", CommonParams.WT, "json", "group", "jvm", "prefix", "CONTAINER.cores"), resp);
values = resp.getValues();
assertNotNull(values.get("metrics"));
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
index c961a55..2e20dc8 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
@@ -20,8 +20,10 @@ import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.Arrays;
+import com.codahale.metrics.Gauge;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.util.stats.MetricUtils;
public class SystemInfoHandlerTest extends LuceneTestCase {
@@ -36,9 +38,11 @@ public class SystemInfoHandlerTest extends LuceneTestCase {
info.add( "version", os.getVersion() );
info.add( "arch", os.getArch() );
- // make another using addMXBeanProperties()
+ // make another using MetricUtils.addMXBeanMetrics()
SimpleOrderedMap<Object> info2 = new SimpleOrderedMap<>();
- SystemInfoHandler.addMXBeanProperties( os, OperatingSystemMXBean.class, info2 );
+ MetricUtils.addMXBeanMetrics( os, OperatingSystemMXBean.class, null, (k, v) -> {
+ info2.add(k, ((Gauge)v).getValue());
+ } );
// make sure they got the same thing
for (String p : Arrays.asList("name", "version", "arch")) {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java b/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java
index 72adc68..a656f84 100644
--- a/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/JvmMetricsTest.java
@@ -16,8 +16,6 @@
*/
package org.apache.solr.metrics;
-import javax.management.MBeanServer;
-import java.lang.management.ManagementFactory;
import java.util.Map;
import com.codahale.metrics.Gauge;
@@ -31,26 +29,63 @@ import org.junit.Test;
*/
public class JvmMetricsTest extends SolrJettyTestBase {
+ static final String[] STRING_OS_METRICS = {
+ "arch",
+ "name",
+ "version"
+ };
+ static final String[] NUMERIC_OS_METRICS = {
+ "availableProcessors",
+ "systemLoadAverage"
+ };
+
+ static final String[] BUFFER_METRICS = {
+ "direct.Count",
+ "direct.MemoryUsed",
+ "direct.TotalCapacity",
+ "mapped.Count",
+ "mapped.MemoryUsed",
+ "mapped.TotalCapacity"
+ };
+
@BeforeClass
public static void beforeTest() throws Exception {
createJetty(legacyExampleCollection1SolrHome());
}
@Test
- public void testOperatingSystemMetricsSet() throws Exception {
- MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
- OperatingSystemMetricSet set = new OperatingSystemMetricSet(mBeanServer);
+ public void testOperatingSystemMetricSet() throws Exception {
+ OperatingSystemMetricSet set = new OperatingSystemMetricSet();
Map<String, Metric> metrics = set.getMetrics();
assertTrue(metrics.size() > 0);
- for (String metric : OperatingSystemMetricSet.METRICS) {
+ for (String metric : NUMERIC_OS_METRICS) {
Gauge<?> gauge = (Gauge<?>)metrics.get(metric);
- if (gauge == null || gauge.getValue() == null) { // some are optional depending on OS
- continue;
- }
+ assertNotNull(metric, gauge);
double value = ((Number)gauge.getValue()).doubleValue();
// SystemLoadAverage on Windows may be -1.0
assertTrue("unexpected value of " + metric + ": " + value, value >= 0 || value == -1.0);
}
+ for (String metric : STRING_OS_METRICS) {
+ Gauge<?> gauge = (Gauge<?>)metrics.get(metric);
+ assertNotNull(metric, gauge);
+ String value = (String)gauge.getValue();
+ assertNotNull(value);
+ assertFalse(value.isEmpty());
+ }
+ }
+
+ @Test
+ public void testAltBufferPoolMetricSet() throws Exception {
+ AltBufferPoolMetricSet set = new AltBufferPoolMetricSet();
+ Map<String, Metric> metrics = set.getMetrics();
+ assertTrue(metrics.size() > 0);
+ for (String name : BUFFER_METRICS) {
+ assertNotNull(name, metrics.get(name));
+ Object g = metrics.get(name);
+ assertTrue(g instanceof Gauge);
+ Object v = ((Gauge)g).getValue();
+ assertTrue(v instanceof Long);
+ }
}
@Test
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
index b275919..f3359cc 100644
--- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java
@@ -42,6 +42,7 @@ public class SolrMetricReporterTest extends LuceneTestCase {
Map<String, Object> attrs = new HashMap<>();
attrs.put(FieldType.CLASS_NAME, MockMetricReporter.class.getName());
attrs.put(CoreAdminParams.NAME, TestUtil.randomUnicodeString(random));
+ attrs.put("enabled", random.nextBoolean());
boolean shouldDefineConfigurable = random.nextBoolean();
String configurable = TestUtil.randomUnicodeString(random);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGangliaReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGangliaReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGangliaReporterTest.java
index c50ff3c..eca414c 100644
--- a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGangliaReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGangliaReporterTest.java
@@ -64,7 +64,7 @@ public class SolrGangliaReporterTest extends SolrTestCaseJ4 {
h.coreName = DEFAULT_TEST_CORENAME;
SolrMetricManager metricManager = cc.getMetricManager();
Map<String, SolrMetricReporter> reporters = metricManager.getReporters("solr.node");
- assertEquals(1, reporters.size());
+ assertTrue(reporters.toString(), reporters.size() >= 1);
SolrMetricReporter reporter = reporters.get("test");
assertNotNull(reporter);
assertTrue(reporter instanceof SolrGangliaReporter);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
index 333876f..5d69714 100644
--- a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrJmxReporterTest.java
@@ -20,6 +20,7 @@ import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
+import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@@ -40,12 +41,15 @@ import org.apache.solr.metrics.SolrMetricTestUtils;
import org.apache.solr.schema.FieldType;
import org.junit.After;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
public class SolrJmxReporterTest extends SolrTestCaseJ4 {
private static final int MAX_ITERATIONS = 20;
+ private static int jmxPort;
+
private String domain;
private SolrCoreMetricManager coreMetricManager;
@@ -53,6 +57,14 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
private SolrJmxReporter reporter;
private MBeanServer mBeanServer;
private String reporterName;
+ private String rootName;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ jmxPort = getNextAvailablePort();
+ assertFalse(jmxPort == -1);
+ LocateRegistry.createRegistry(jmxPort);
+ }
@Before
public void beforeTest() throws Exception {
@@ -60,11 +72,13 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
final SolrCore core = h.getCore();
domain = core.getName();
+ rootName = TestUtil.randomSimpleString(random(), 1, 10);
coreMetricManager = core.getCoreMetricManager();
metricManager = core.getCoreContainer().getMetricManager();
- PluginInfo pluginInfo = createReporterPluginInfo();
- metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(), pluginInfo);
+ PluginInfo pluginInfo = createReporterPluginInfo(rootName, true);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo);
Map<String, SolrMetricReporter> reporters = metricManager.getReporters(coreMetricManager.getRegistryName());
assertTrue("reporters.size should be > 0, but was + " + reporters.size(), reporters.size() > 0);
@@ -77,7 +91,7 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
assertNotNull("MBean server not found.", mBeanServer);
}
- private PluginInfo createReporterPluginInfo() {
+ private PluginInfo createReporterPluginInfo(String rootName, boolean enabled) {
Random random = random();
String className = SolrJmxReporter.class.getName();
String reporterName = TestUtil.randomSimpleString(random, 1, 10);
@@ -85,6 +99,9 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
Map<String, Object> attrs = new HashMap<>();
attrs.put(FieldType.CLASS_NAME, className);
attrs.put(CoreAdminParams.NAME, reporterName);
+ attrs.put("rootName", rootName);
+ attrs.put("enabled", enabled);
+ attrs.put("serviceUrl", "service:jmx:rmi:///jndi/rmi://localhost:" + jmxPort + "/solrjmx");
boolean shouldOverrideDomain = random.nextBoolean();
if (shouldOverrideDomain) {
@@ -143,8 +160,9 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
reporterName.equals(o.getObjectName().getKeyProperty("reporter"))).count());
h.getCoreContainer().reload(h.getCore().getName());
- PluginInfo pluginInfo = createReporterPluginInfo();
- metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(), pluginInfo);
+ PluginInfo pluginInfo = createReporterPluginInfo(rootName, true);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo);
coreMetricManager.registerMetricProducer(scope, producer);
objects = mBeanServer.queryMBeans(null, null);
@@ -153,4 +171,34 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
pluginInfo.name.equals(o.getObjectName().getKeyProperty("reporter"))).count());
}
+ @Test
+ public void testEnabled() throws Exception {
+ String root1 = TestUtil.randomSimpleString(random(), 1, 10);
+ PluginInfo pluginInfo1 = createReporterPluginInfo(root1, true);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo1);
+
+ String root2 = TestUtil.randomSimpleString(random(), 1, 10);
+ assertFalse(root2.equals(root1));
+ PluginInfo pluginInfo2 = createReporterPluginInfo(root2, false);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo2);
+
+ Map<String, SolrMetricReporter> reporters = metricManager.getReporters(coreMetricManager.getRegistryName());
+ assertTrue(reporters.containsKey(pluginInfo1.name));
+ assertTrue(reporters.containsKey(pluginInfo2.name));
+
+ String scope = SolrMetricTestUtils.getRandomScope(random(), true);
+ SolrInfoMBean.Category category = SolrMetricTestUtils.getRandomCategory(random(), true);
+ Map<String, Counter> metrics = SolrMetricTestUtils.getRandomMetrics(random(), true);
+ SolrMetricProducer producer = SolrMetricTestUtils.getProducerOf(metricManager, category, scope, metrics);
+ coreMetricManager.registerMetricProducer(scope, producer);
+ Set<ObjectInstance> objects = mBeanServer.queryMBeans(null, null);
+ assertEquals(metrics.size(), objects.stream().
+ filter(o -> scope.equals(o.getObjectName().getKeyProperty("scope")) &&
+ root1.equals(o.getObjectName().getDomain())).count());
+ assertEquals(0, objects.stream().
+ filter(o -> scope.equals(o.getObjectName().getKeyProperty("scope")) &&
+ root2.equals(o.getObjectName().getDomain())).count());
+ }
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
index 47bf8e7..a8f3343 100644
--- a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
@@ -57,7 +57,7 @@ public class SolrSlf4jReporterTest extends SolrTestCaseJ4 {
h.coreName = DEFAULT_TEST_CORENAME;
SolrMetricManager metricManager = cc.getMetricManager();
Map<String, SolrMetricReporter> reporters = metricManager.getReporters("solr.node");
- assertEquals(2, reporters.size());
+ assertTrue(reporters.toString(), reporters.size() >= 2);
SolrMetricReporter reporter = reporters.get("test1");
assertNotNull(reporter);
assertTrue(reporter instanceof SolrSlf4jReporter);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
index edf28df..ed6a115 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
@@ -33,6 +33,7 @@ import java.lang.annotation.Target;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
+import java.net.ServerSocket;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -801,6 +802,19 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
configString = schemaString = null;
}
+ /**
+ * Find next available local port.
+ * @return available port number or -1 if none could be found
+ * @throws Exception on IO errors
+ */
+ protected static int getNextAvailablePort() throws Exception {
+ int port = -1;
+ try (ServerSocket s = new ServerSocket(0)) {
+ port = s.getLocalPort();
+ }
+ return port;
+ }
+
/** Validates an update XML String is successful
*/
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3641497b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
index 2a8d453..8dba82d 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
@@ -19,7 +19,6 @@ package org.apache.solr.cloud;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.ServerSocket;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
@@ -593,14 +592,6 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
return proxy;
}
- protected int getNextAvailablePort() throws Exception {
- int port = -1;
- try (ServerSocket s = new ServerSocket(0)) {
- port = s.getLocalPort();
- }
- return port;
- }
-
private File getRelativeSolrHomePath(File solrHome) {
final Path solrHomePath = solrHome.toPath();
final Path curDirPath = new File("").getAbsoluteFile().toPath();