You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by cp...@apache.org on 2017/03/13 15:40:17 UTC
[22/50] [abbrv] lucene-solr:jira/solr-9045: SOLR-9858: Collect
aggregated metrics from nodes and shard leaders in overseer.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java
new file mode 100644
index 0000000..e9b8c3d
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java
@@ -0,0 +1,392 @@
+/*
+ * 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.solr;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+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.Set;
+import java.util.SortedMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.ScheduledReporter;
+import com.codahale.metrics.Timer;
+import org.apache.http.client.HttpClient;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.io.SolrClientCache;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.handler.admin.MetricsCollectorHandler;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.util.stats.MetricUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of {@link ScheduledReporter} that reports metrics from selected registries and sends
+ * them periodically as update requests to a selected Solr collection and to a configured handler.
+ */
+public class SolrReporter extends ScheduledReporter {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public static final String REGISTRY_ID = "_registry_";
+ public static final String REPORTER_ID = "_reporter_";
+ public static final String GROUP_ID = "_group_";
+ public static final String LABEL_ID = "_label_";
+
+
+ /**
+ * Specification of what registries and what metrics to send.
+ */
+ public static final class Report {
+ public String groupPattern;
+ public String labelPattern;
+ public String registryPattern;
+ public Set<String> metricFilters = new HashSet<>();
+
+ /**
+ * Create a report specification
+ * @param groupPattern logical group for these metrics. This is used in {@link MetricsCollectorHandler}
+ * to select the target registry for metrics to aggregate. Must not be null or empty.
+ * It may contain back-references to capture groups from {@code registryPattern}
+ * @param labelPattern name of this group of metrics. This is used in {@link MetricsCollectorHandler}
+ * to prefix metric names. May be null or empty. It may contain back-references
+ * to capture groups from {@code registryPattern}.
+ * @param registryPattern pattern for selecting matching registries, see {@link SolrMetricManager#registryNames(String...)}
+ * @param metricFilters patterns for selecting matching metrics, see {@link org.apache.solr.metrics.SolrMetricManager.RegexFilter}
+ */
+ public Report(String groupPattern, String labelPattern, String registryPattern, Collection<String> metricFilters) {
+ this.groupPattern = groupPattern;
+ this.labelPattern = labelPattern;
+ this.registryPattern = registryPattern;
+ if (metricFilters != null) {
+ this.metricFilters.addAll(metricFilters);
+ }
+ }
+
+ public static Report fromMap(Map<?, ?> map) {
+ String groupPattern = (String)map.get("group");
+ String labelPattern = (String)map.get("label");
+ String registryPattern = (String)map.get("registry");
+ Object oFilters = map.get("filter");
+ Collection<String> metricFilters = Collections.emptyList();
+ if (oFilters != null) {
+ if (oFilters instanceof String) {
+ metricFilters = Collections.singletonList((String)oFilters);
+ } else if (oFilters instanceof Collection) {
+ metricFilters = (Collection<String>)oFilters;
+ } else {
+ log.warn("Invalid report filters, ignoring: " + oFilters);
+ }
+ }
+ if (groupPattern == null || registryPattern == null) {
+ log.warn("Invalid report configuration, group and registry required!: " + map);
+ return null;
+ }
+ return new Report(groupPattern, labelPattern, registryPattern, metricFilters);
+ }
+ }
+
+ public static class Builder {
+ private final SolrMetricManager metricManager;
+ private final List<Report> reports;
+ private String reporterId;
+ private TimeUnit rateUnit;
+ private TimeUnit durationUnit;
+ private String handler;
+ private boolean skipHistograms;
+ private boolean skipAggregateValues;
+ private boolean cloudClient;
+ private SolrParams params;
+
+ /**
+ * Create a builder for SolrReporter.
+ * @param metricManager metric manager that is the source of metrics
+ * @param reports report definitions
+ * @return builder
+ */
+ public static Builder forReports(SolrMetricManager metricManager, List<Report> reports) {
+ return new Builder(metricManager, reports);
+ }
+
+ private Builder(SolrMetricManager metricManager, List<Report> reports) {
+ this.metricManager = metricManager;
+ this.reports = reports;
+ this.rateUnit = TimeUnit.SECONDS;
+ this.durationUnit = TimeUnit.MILLISECONDS;
+ this.skipHistograms = false;
+ this.skipAggregateValues = false;
+ this.cloudClient = false;
+ this.params = null;
+ }
+
+ /**
+ * Additional {@link SolrParams} to add to every request.
+ * @param params additional params
+ * @return {@code this}
+ */
+ public Builder withSolrParams(SolrParams params) {
+ this.params = params;
+ return this;
+ }
+ /**
+ * If true then use {@link org.apache.solr.client.solrj.impl.CloudSolrClient} for communication.
+ * Default is false.
+ * @param cloudClient use CloudSolrClient when true, {@link org.apache.solr.client.solrj.impl.HttpSolrClient} otherwise.
+ * @return {@code this}
+ */
+ public Builder cloudClient(boolean cloudClient) {
+ this.cloudClient = cloudClient;
+ return this;
+ }
+
+ /**
+ * Histograms are difficult / impossible to aggregate, so it may not be
+ * worth to report them.
+ * @param skipHistograms when true then skip histograms from reports
+ * @return {@code this}
+ */
+ public Builder skipHistograms(boolean skipHistograms) {
+ this.skipHistograms = skipHistograms;
+ return this;
+ }
+
+ /**
+ * Individual values from {@link org.apache.solr.metrics.AggregateMetric} may not be worth to report.
+ * @param skipAggregateValues when tru then skip reporting individual values from the metric
+ * @return {@code this}
+ */
+ public Builder skipAggregateValues(boolean skipAggregateValues) {
+ this.skipAggregateValues = skipAggregateValues;
+ return this;
+ }
+
+ /**
+ * Handler name to use at the remote end.
+ *
+ * @param handler handler name, eg. "/admin/metricsCollector"
+ * @return {@code this}
+ */
+ public Builder withHandler(String handler) {
+ this.handler = handler;
+ return this;
+ }
+
+ /**
+ * Use this id to identify metrics from this instance.
+ *
+ * @param reporterId reporter id
+ * @return {@code this}
+ */
+ public Builder withReporterId(String reporterId) {
+ this.reporterId = reporterId;
+ return this;
+ }
+
+ /**
+ * Convert rates to the given time unit.
+ *
+ * @param rateUnit a unit of time
+ * @return {@code this}
+ */
+ public Builder convertRatesTo(TimeUnit rateUnit) {
+ this.rateUnit = rateUnit;
+ return this;
+ }
+
+ /**
+ * Convert durations to the given time unit.
+ *
+ * @param durationUnit a unit of time
+ * @return {@code this}
+ */
+ public Builder convertDurationsTo(TimeUnit durationUnit) {
+ this.durationUnit = durationUnit;
+ return this;
+ }
+
+ /**
+ * Build it.
+ * @param client an instance of {@link HttpClient} to be used for making calls.
+ * @param urlProvider function that returns the base URL of Solr instance to target. May return
+ * null to indicate that reporting should be skipped. Note: this
+ * function will be called every time just before report is sent.
+ * @return configured instance of reporter
+ */
+ public SolrReporter build(HttpClient client, Supplier<String> urlProvider) {
+ return new SolrReporter(client, urlProvider, metricManager, reports, handler, reporterId, rateUnit, durationUnit,
+ params, skipHistograms, skipAggregateValues, cloudClient);
+ }
+
+ }
+
+ private String reporterId;
+ private String handler;
+ private Supplier<String> urlProvider;
+ private SolrClientCache clientCache;
+ private List<CompiledReport> compiledReports;
+ private SolrMetricManager metricManager;
+ private boolean skipHistograms;
+ private boolean skipAggregateValues;
+ private boolean cloudClient;
+ private ModifiableSolrParams params;
+ private Map<String, Object> metadata;
+
+ private static final class CompiledReport {
+ String group;
+ String label;
+ Pattern registryPattern;
+ MetricFilter filter;
+
+ CompiledReport(Report report) throws PatternSyntaxException {
+ this.group = report.groupPattern;
+ this.label = report.labelPattern;
+ this.registryPattern = Pattern.compile(report.registryPattern);
+ this.filter = new SolrMetricManager.RegexFilter(report.metricFilters);
+ }
+
+ @Override
+ public String toString() {
+ return "CompiledReport{" +
+ "group='" + group + '\'' +
+ ", label='" + label + '\'' +
+ ", registryPattern=" + registryPattern +
+ ", filter=" + filter +
+ '}';
+ }
+ }
+
+ public SolrReporter(HttpClient httpClient, Supplier<String> urlProvider, SolrMetricManager metricManager,
+ List<Report> metrics, String handler,
+ String reporterId, TimeUnit rateUnit, TimeUnit durationUnit,
+ SolrParams params, boolean skipHistograms, boolean skipAggregateValues, boolean cloudClient) {
+ super(null, "solr-reporter", MetricFilter.ALL, rateUnit, durationUnit);
+ this.metricManager = metricManager;
+ this.urlProvider = urlProvider;
+ this.reporterId = reporterId;
+ if (handler == null) {
+ handler = MetricsCollectorHandler.HANDLER_PATH;
+ }
+ this.handler = handler;
+ this.clientCache = new SolrClientCache(httpClient);
+ this.compiledReports = new ArrayList<>();
+ metrics.forEach(report -> {
+ MetricFilter filter = new SolrMetricManager.RegexFilter(report.metricFilters);
+ try {
+ CompiledReport cs = new CompiledReport(report);
+ compiledReports.add(cs);
+ } catch (PatternSyntaxException e) {
+ log.warn("Skipping report with invalid registryPattern: " + report.registryPattern, e);
+ }
+ });
+ this.skipHistograms = skipHistograms;
+ this.skipAggregateValues = skipAggregateValues;
+ this.cloudClient = cloudClient;
+ this.params = new ModifiableSolrParams();
+ this.params.set(REPORTER_ID, reporterId);
+ // allow overrides to take precedence
+ if (params != null) {
+ this.params.add(params);
+ }
+ metadata = new HashMap<>();
+ metadata.put(REPORTER_ID, reporterId);
+ }
+
+ @Override
+ public void close() {
+ clientCache.close();
+ super.close();
+ }
+
+ @Override
+ public void report() {
+ String url = urlProvider.get();
+ // if null then suppress reporting
+ if (url == null) {
+ return;
+ }
+
+ SolrClient solr;
+ if (cloudClient) {
+ solr = clientCache.getCloudSolrClient(url);
+ } else {
+ solr = clientCache.getHttpSolrClient(url);
+ }
+ UpdateRequest req = new UpdateRequest(handler);
+ req.setParams(params);
+ compiledReports.forEach(report -> {
+ Set<String> registryNames = metricManager.registryNames(report.registryPattern);
+ registryNames.forEach(registryName -> {
+ String label = report.label;
+ if (label != null && label.indexOf('$') != -1) {
+ // label with back-references
+ Matcher m = report.registryPattern.matcher(registryName);
+ label = m.replaceFirst(label);
+ }
+ final String effectiveLabel = label;
+ String group = report.group;
+ if (group.indexOf('$') != -1) {
+ // group with back-references
+ Matcher m = report.registryPattern.matcher(registryName);
+ group = m.replaceFirst(group);
+ }
+ final String effectiveGroup = group;
+ MetricUtils.toSolrInputDocuments(metricManager.registry(registryName), Collections.singletonList(report.filter), MetricFilter.ALL,
+ skipHistograms, skipAggregateValues, metadata, doc -> {
+ doc.setField(REGISTRY_ID, registryName);
+ doc.setField(GROUP_ID, effectiveGroup);
+ if (effectiveLabel != null) {
+ doc.setField(LABEL_ID, effectiveLabel);
+ }
+ req.add(doc);
+ });
+ });
+ });
+
+ // if no docs added then don't send a report
+ if (req.getDocuments() == null || req.getDocuments().isEmpty()) {
+ return;
+ }
+ try {
+ //log.info("%%% sending to " + url + ": " + req.getParams());
+ solr.request(req);
+ } catch (Exception e) {
+ log.debug("Error sending metric report", e.toString());
+ }
+
+ }
+
+ @Override
+ public void report(SortedMap<String, Gauge> gauges, SortedMap<String, Counter> counters, SortedMap<String, Histogram> histograms, SortedMap<String, Meter> meters, SortedMap<String, Timer> timers) {
+ // no-op - we do all the work in report()
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrShardReporter.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..2b20274
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrShardReporter.java
@@ -0,0 +1,188 @@
+/*
+ * 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.solr;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+import org.apache.solr.cloud.CloudDescriptor;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.handler.admin.MetricsCollectorHandler;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricReporter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class reports selected metrics from replicas to shard leader.
+ * <p>The following configuration properties are supported:</p>
+ * <ul>
+ * <li>handler - (optional str) handler path where reports are sent. Default is
+ * {@link MetricsCollectorHandler#HANDLER_PATH}.</li>
+ * <li>period - (optional int) how often reports are sent, in seconds. Default is 60. Setting this
+ * to 0 disables the reporter.</li>
+ * <li>filter - (optional multiple str) regex expression(s) matching selected metrics to be reported.</li>
+ * </ul>
+ * NOTE: this reporter uses predefined "replica" group, and it's always created even if explicit configuration
+ * is missing. Default configuration uses filters defined in {@link #DEFAULT_FILTERS}.
+ * <p>Example configuration:</p>
+ * <pre>
+ * <reporter name="test" group="replica">
+ * <int name="period">11</int>
+ * <str name="filter">UPDATE\./update/.*requests</str>
+ * <str name="filter">QUERY\./select.*requests</str>
+ * </reporter>
+ * </pre>
+ */
+public class SolrShardReporter extends SolrMetricReporter {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public static final List<String> DEFAULT_FILTERS = new ArrayList(){{
+ add("TLOG.*");
+ add("REPLICATION.*");
+ add("INDEX.flush.*");
+ add("INDEX.merge.major.*");
+ add("UPDATE\\./update/.*requests");
+ add("QUERY\\./select.*requests");
+ }};
+
+ private String handler = MetricsCollectorHandler.HANDLER_PATH;
+ private int period = SolrMetricManager.DEFAULT_CLOUD_REPORTER_PERIOD;
+ private List<String> filters = new ArrayList<>();
+
+ private SolrReporter reporter;
+
+ /**
+ * Create a reporter for metrics managed in a named registry.
+ *
+ * @param metricManager metric manager
+ * @param registryName registry to use, one of registries managed by
+ * {@link SolrMetricManager}
+ */
+ public SolrShardReporter(SolrMetricManager metricManager, String registryName) {
+ super(metricManager, registryName);
+ }
+
+ public void setHandler(String handler) {
+ this.handler = handler;
+ }
+
+ public void setPeriod(int period) {
+ this.period = period;
+ }
+
+ public void setFilter(List<String> filterConfig) {
+ if (filterConfig == null || filterConfig.isEmpty()) {
+ return;
+ }
+ filters = filterConfig;
+ }
+
+ // for unit tests
+ int getPeriod() {
+ return period;
+ }
+
+ @Override
+ protected void validate() throws IllegalStateException {
+ if (period < 1) {
+ log.info("Turning off shard reporter, period=" + period);
+ }
+ if (filters.isEmpty()) {
+ filters = DEFAULT_FILTERS;
+ }
+ // start in inform(...) only when core is available
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (reporter != null) {
+ reporter.close();
+ }
+ }
+
+ public void setCore(SolrCore core) {
+ if (reporter != null) {
+ reporter.close();
+ }
+ 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 ");
+ return;
+ }
+ // our id is coreNodeName
+ String id = core.getCoreDescriptor().getCloudDescriptor().getCoreNodeName();
+ // target registry is the leaderRegistryName
+ String groupId = core.getCoreMetricManager().getLeaderRegistryName();
+ if (groupId == null) {
+ log.warn("No leaderRegistryName for core " + core + ", not starting the reporter...");
+ return;
+ }
+ SolrReporter.Report spec = new SolrReporter.Report(groupId, null, registryName, filters);
+ reporter = SolrReporter.Builder.forReports(metricManager, Collections.singletonList(spec))
+ .convertRatesTo(TimeUnit.SECONDS)
+ .convertDurationsTo(TimeUnit.MILLISECONDS)
+ .withHandler(handler)
+ .withReporterId(id)
+ .cloudClient(false) // we want to send reports specifically to a selected leader instance
+ .skipAggregateValues(true) // we don't want to transport details of aggregates
+ .skipHistograms(true) // we don't want to transport histograms
+ .build(core.getCoreDescriptor().getCoreContainer().getUpdateShardHandler().getHttpClient(), new LeaderUrlSupplier(core));
+
+ reporter.start(period, TimeUnit.SECONDS);
+ }
+
+ private static class LeaderUrlSupplier implements Supplier<String> {
+ private SolrCore core;
+
+ LeaderUrlSupplier(SolrCore core) {
+ this.core = core;
+ }
+
+ @Override
+ public String get() {
+ CloudDescriptor cd = core.getCoreDescriptor().getCloudDescriptor();
+ if (cd == null) {
+ return null;
+ }
+ ClusterState state = core.getCoreDescriptor().getCoreContainer().getZkController().getClusterState();
+ DocCollection collection = state.getCollection(core.getCoreDescriptor().getCollectionName());
+ Replica replica = collection.getLeader(core.getCoreDescriptor().getCloudDescriptor().getShardId());
+ if (replica == null) {
+ log.warn("No leader for " + collection.getName() + "/" + core.getCoreDescriptor().getCloudDescriptor().getShardId());
+ return null;
+ }
+ String baseUrl = replica.getStr("base_url");
+ if (baseUrl == null) {
+ log.warn("No base_url for replica " + replica);
+ }
+ return baseUrl;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java
new file mode 100644
index 0000000..740bcce
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains {@link org.apache.solr.metrics.SolrMetricReporter} implementations
+ * specific to SolrCloud reporting.
+ */
+package org.apache.solr.metrics.reporters.solr;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/java/org/apache/solr/update/PeerSync.java
----------------------------------------------------------------------
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 ac07413..874e39c 100644
--- a/solr/core/src/java/org/apache/solr/update/PeerSync.java
+++ b/solr/core/src/java/org/apache/solr/update/PeerSync.java
@@ -161,11 +161,13 @@ public class PeerSync implements SolrMetricProducer {
core.getCoreMetricManager().registerMetricProducer(SolrInfoMBean.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);
- syncErrors = manager.counter(registry, "errors", scope);
- syncSkipped = manager.counter(registry, "skipped", 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);
}
/** optional list of updates we had before possibly receiving new updates */
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/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 80f035b..5a7c680 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,11 +16,15 @@
*/
package org.apache.solr.util.stats;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
@@ -32,13 +36,40 @@ import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;
+import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.NamedList;
+import org.apache.solr.metrics.AggregateMetric;
/**
* Metrics specific utility functions.
*/
public class MetricUtils {
+ public static final String METRIC_NAME = "metric";
+ public static final String VALUES = "values";
+
+ static final String MS = "_ms";
+
+ static final String MIN = "min";
+ static final String MIN_MS = MIN + MS;
+ static final String MAX = "max";
+ static final String MAX_MS = MAX + MS;
+ static final String MEAN = "mean";
+ static final String MEAN_MS = MEAN + MS;
+ static final String MEDIAN = "median";
+ static final String MEDIAN_MS = MEDIAN + MS;
+ static final String STDDEV = "stddev";
+ static final String STDDEV_MS = STDDEV + MS;
+ static final String SUM = "sum";
+ static final String P75 = "p75";
+ static final String P75_MS = P75 + MS;
+ static final String P95 = "p95";
+ static final String P95_MS = P95 + MS;
+ static final String P99 = "p99";
+ static final String P99_MS = P99 + MS;
+ static final String P999 = "p999";
+ static final String P999_MS = P999 + MS;
+
/**
* Adds metrics from a Timer to a NamedList, using well-known back-compat names.
* @param lst The NamedList to add the metrics data to
@@ -77,41 +108,138 @@ public class MetricUtils {
* included in the output
* @param mustMatchFilter a {@link MetricFilter}.
* A metric <em>must</em> match this filter to be included in the output.
+ * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s.
+ * @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<MetricFilter> shouldMatchFilters, MetricFilter mustMatchFilter) {
- NamedList response = new NamedList();
+ public static NamedList toNamedList(MetricRegistry registry, List<MetricFilter> shouldMatchFilters,
+ MetricFilter mustMatchFilter, boolean skipHistograms,
+ boolean skipAggregateValues,
+ Map<String, Object> metadata) {
+ NamedList result = new NamedList();
+ toNamedMaps(registry, shouldMatchFilters, mustMatchFilter, skipHistograms, skipAggregateValues, (k, v) -> {
+ result.add(k, new NamedList(v));
+ });
+ if (metadata != null && !metadata.isEmpty()) {
+ result.add("_metadata_", new NamedList(metadata));
+ }
+ return result;
+ }
+
+ /**
+ * Returns a representation of the given metric registry as a list of {@link SolrInputDocument}-s.
+ Only those metrics
+ * are converted to NamedList which match at least one of the given MetricFilter instances.
+ *
+ * @param registry the {@link MetricRegistry} to be converted to NamedList
+ * @param shouldMatchFilters a list of {@link MetricFilter} instances.
+ * A metric must match <em>any one</em> of the filters from this list to be
+ * included in the output
+ * @param mustMatchFilter a {@link MetricFilter}.
+ * A metric <em>must</em> match this filter to be included in the output.
+ * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s.
+ * @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
+ */
+ public static List<SolrInputDocument> toSolrInputDocuments(MetricRegistry registry, List<MetricFilter> shouldMatchFilters,
+ MetricFilter mustMatchFilter, boolean skipHistograms,
+ boolean skipAggregateValues,
+ Map<String, Object> metadata) {
+ List<SolrInputDocument> result = new LinkedList<>();
+ toSolrInputDocuments(registry, shouldMatchFilters, mustMatchFilter, skipHistograms,
+ skipAggregateValues, metadata, doc -> {
+ result.add(doc);
+ });
+ return result;
+ }
+
+ public static void toSolrInputDocuments(MetricRegistry registry, List<MetricFilter> shouldMatchFilters,
+ MetricFilter mustMatchFilter, boolean skipHistograms,
+ boolean skipAggregateValues,
+ Map<String, Object> metadata, Consumer<SolrInputDocument> consumer) {
+ boolean addMetadata = metadata != null && !metadata.isEmpty();
+ toNamedMaps(registry, shouldMatchFilters, mustMatchFilter, skipHistograms, skipAggregateValues, (k, v) -> {
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.setField(METRIC_NAME, k);
+ toSolrInputDocument(null, doc, v);
+ if (addMetadata) {
+ toSolrInputDocument(null, doc, metadata);
+ }
+ consumer.accept(doc);
+ });
+ }
+
+ public static void toSolrInputDocument(String prefix, SolrInputDocument doc, Map<String, Object> map) {
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+ if (entry.getValue() instanceof Map) { // flatten recursively
+ toSolrInputDocument(entry.getKey(), doc, (Map<String, Object>)entry.getValue());
+ } else {
+ String key = prefix != null ? prefix + "." + entry.getKey() : entry.getKey();
+ doc.addField(key, entry.getValue());
+ }
+ }
+ }
+
+ public static void toNamedMaps(MetricRegistry registry, List<MetricFilter> shouldMatchFilters,
+ MetricFilter mustMatchFilter, boolean skipHistograms, boolean skipAggregateValues,
+ BiConsumer<String, Map<String, Object>> consumer) {
Map<String, Metric> metrics = registry.getMetrics();
SortedSet<String> 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;
- response.add(n, counterToNamedList(counter));
- } else if (metric instanceof Gauge) {
- Gauge gauge = (Gauge) metric;
- response.add(n, gaugeToNamedList(gauge));
- } else if (metric instanceof Meter) {
- Meter meter = (Meter) metric;
- response.add(n, meterToNamedList(meter));
- } else if (metric instanceof Timer) {
- Timer timer = (Timer) metric;
- response.add(n, timerToNamedList(timer));
- } else if (metric instanceof Histogram) {
- Histogram histogram = (Histogram) metric;
- response.add(n, histogramToNamedList(histogram));
- }
- });
+ Metric metric = metrics.get(n);
+ if (metric instanceof Counter) {
+ Counter counter = (Counter) metric;
+ consumer.accept(n, counterToMap(counter));
+ } else if (metric instanceof Gauge) {
+ Gauge gauge = (Gauge) metric;
+ consumer.accept(n, gaugeToMap(gauge));
+ } else if (metric instanceof Meter) {
+ Meter meter = (Meter) metric;
+ consumer.accept(n, meterToMap(meter));
+ } else if (metric instanceof Timer) {
+ Timer timer = (Timer) metric;
+ consumer.accept(n, timerToMap(timer, skipHistograms));
+ } else if (metric instanceof Histogram) {
+ if (!skipHistograms) {
+ Histogram histogram = (Histogram) metric;
+ consumer.accept(n, histogramToMap(histogram));
+ }
+ } else if (metric instanceof AggregateMetric) {
+ consumer.accept(n, aggregateMetricToMap((AggregateMetric)metric, skipAggregateValues));
+ }
+ });
+ }
+
+ static Map<String, Object> aggregateMetricToMap(AggregateMetric metric, boolean skipAggregateValues) {
+ Map<String, Object> 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<String, Object> values = new LinkedHashMap<>();
+ response.put(VALUES, values);
+ metric.getValues().forEach((k, v) -> {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("value", v.value);
+ map.put("updateCount", v.updateCount.get());
+ values.put(k, map);
+ });
+ }
return response;
}
- static NamedList histogramToNamedList(Histogram histogram) {
- NamedList response = new NamedList();
+ static Map<String, Object> histogramToMap(Histogram histogram) {
+ Map<String, Object> response = new LinkedHashMap<>();
Snapshot snapshot = histogram.getSnapshot();
- response.add("count", histogram.getCount());
+ response.put("count", histogram.getCount());
// non-time based values
addSnapshot(response, snapshot, false);
return response;
@@ -126,71 +254,52 @@ public class MetricUtils {
}
}
- static final String MS = "_ms";
-
- static final String MIN = "min";
- static final String MIN_MS = MIN + MS;
- static final String MAX = "max";
- static final String MAX_MS = MAX + MS;
- static final String MEAN = "mean";
- static final String MEAN_MS = MEAN + MS;
- static final String MEDIAN = "median";
- static final String MEDIAN_MS = MEDIAN + MS;
- static final String STDDEV = "stddev";
- static final String STDDEV_MS = STDDEV + MS;
- static final String P75 = "p75";
- static final String P75_MS = P75 + MS;
- static final String P95 = "p95";
- static final String P95_MS = P95 + MS;
- static final String P99 = "p99";
- static final String P99_MS = P99 + MS;
- static final String P999 = "p999";
- static final String P999_MS = P999 + MS;
-
// some snapshots represent time in ns, other snapshots represent raw values (eg. chunk size)
- static void addSnapshot(NamedList response, Snapshot snapshot, boolean ms) {
- response.add((ms ? MIN_MS: MIN), nsToMs(ms, snapshot.getMin()));
- response.add((ms ? MAX_MS: MAX), nsToMs(ms, snapshot.getMax()));
- response.add((ms ? MEAN_MS : MEAN), nsToMs(ms, snapshot.getMean()));
- response.add((ms ? MEDIAN_MS: MEDIAN), nsToMs(ms, snapshot.getMedian()));
- response.add((ms ? STDDEV_MS: STDDEV), nsToMs(ms, snapshot.getStdDev()));
- response.add((ms ? P75_MS: P75), nsToMs(ms, snapshot.get75thPercentile()));
- response.add((ms ? P95_MS: P95), nsToMs(ms, snapshot.get95thPercentile()));
- response.add((ms ? P99_MS: P99), nsToMs(ms, snapshot.get99thPercentile()));
- response.add((ms ? P999_MS: P999), nsToMs(ms, snapshot.get999thPercentile()));
- }
-
- static NamedList timerToNamedList(Timer timer) {
- NamedList response = new NamedList();
- response.add("count", timer.getCount());
- response.add("meanRate", timer.getMeanRate());
- response.add("1minRate", timer.getOneMinuteRate());
- response.add("5minRate", timer.getFiveMinuteRate());
- response.add("15minRate", timer.getFifteenMinuteRate());
- // time-based values in nanoseconds
- addSnapshot(response, timer.getSnapshot(), true);
+ static void addSnapshot(Map<String, Object> response, Snapshot snapshot, boolean ms) {
+ response.put((ms ? MIN_MS: MIN), nsToMs(ms, snapshot.getMin()));
+ response.put((ms ? MAX_MS: MAX), nsToMs(ms, snapshot.getMax()));
+ response.put((ms ? MEAN_MS : MEAN), nsToMs(ms, snapshot.getMean()));
+ response.put((ms ? MEDIAN_MS: MEDIAN), nsToMs(ms, snapshot.getMedian()));
+ response.put((ms ? STDDEV_MS: STDDEV), nsToMs(ms, snapshot.getStdDev()));
+ response.put((ms ? P75_MS: P75), nsToMs(ms, snapshot.get75thPercentile()));
+ response.put((ms ? P95_MS: P95), nsToMs(ms, snapshot.get95thPercentile()));
+ response.put((ms ? P99_MS: P99), nsToMs(ms, snapshot.get99thPercentile()));
+ response.put((ms ? P999_MS: P999), nsToMs(ms, snapshot.get999thPercentile()));
+ }
+
+ static Map<String,Object> timerToMap(Timer timer, boolean skipHistograms) {
+ Map<String, Object> response = new LinkedHashMap<>();
+ response.put("count", timer.getCount());
+ response.put("meanRate", timer.getMeanRate());
+ response.put("1minRate", timer.getOneMinuteRate());
+ response.put("5minRate", timer.getFiveMinuteRate());
+ response.put("15minRate", timer.getFifteenMinuteRate());
+ if (!skipHistograms) {
+ // time-based values in nanoseconds
+ addSnapshot(response, timer.getSnapshot(), true);
+ }
return response;
}
- static NamedList meterToNamedList(Meter meter) {
- NamedList response = new NamedList();
- response.add("count", meter.getCount());
- response.add("meanRate", meter.getMeanRate());
- response.add("1minRate", meter.getOneMinuteRate());
- response.add("5minRate", meter.getFiveMinuteRate());
- response.add("15minRate", meter.getFifteenMinuteRate());
+ static Map<String, Object> meterToMap(Meter meter) {
+ Map<String, Object> response = new LinkedHashMap<>();
+ response.put("count", meter.getCount());
+ response.put("meanRate", meter.getMeanRate());
+ response.put("1minRate", meter.getOneMinuteRate());
+ response.put("5minRate", meter.getFiveMinuteRate());
+ response.put("15minRate", meter.getFifteenMinuteRate());
return response;
}
- static NamedList gaugeToNamedList(Gauge gauge) {
- NamedList response = new NamedList();
- response.add("value", gauge.getValue());
+ static Map<String, Object> gaugeToMap(Gauge gauge) {
+ Map<String, Object> response = new LinkedHashMap<>();
+ response.put("value", gauge.getValue());
return response;
}
- static NamedList counterToNamedList(Counter counter) {
- NamedList response = new NamedList();
- response.add("count", counter.getCount());
+ static Map<String, Object> counterToMap(Counter counter) {
+ Map<String, Object> response = new LinkedHashMap<>();
+ response.put("count", counter.getCount());
return response;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test-files/solr/solr-solrreporter.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/solr-solrreporter.xml b/solr/core/src/test-files/solr/solr-solrreporter.xml
new file mode 100644
index 0000000..db03e42
--- /dev/null
+++ b/solr/core/src/test-files/solr/solr-solrreporter.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<solr>
+ <shardHandlerFactory name="shardHandlerFactory" class="HttpShardHandlerFactory">
+ <str name="urlScheme">${urlScheme:}</str>
+ <int name="socketTimeout">${socketTimeout:90000}</int>
+ <int name="connTimeout">${connTimeout:15000}</int>
+ </shardHandlerFactory>
+
+ <solrcloud>
+ <str name="host">127.0.0.1</str>
+ <int name="hostPort">${hostPort:8983}</int>
+ <str name="hostContext">${hostContext:solr}</str>
+ <int name="zkClientTimeout">${solr.zkclienttimeout:30000}</int>
+ <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
+ <int name="leaderVoteWait">${leaderVoteWait:10000}</int>
+ <int name="distribUpdateConnTimeout">${distribUpdateConnTimeout:45000}</int>
+ <int name="distribUpdateSoTimeout">${distribUpdateSoTimeout:340000}</int>
+ <int name="autoReplicaFailoverWaitAfterExpiration">${autoReplicaFailoverWaitAfterExpiration:10000}</int>
+ <int name="autoReplicaFailoverWorkLoopDelay">${autoReplicaFailoverWorkLoopDelay:10000}</int>
+ <int name="autoReplicaFailoverBadNodeExpiration">${autoReplicaFailoverBadNodeExpiration:60000}</int>
+ </solrcloud>
+
+ <metrics>
+ <reporter name="test" group="shard">
+ <int name="period">5</int>
+ <str name="filter">UPDATE\./update/.*requests</str>
+ <str name="filter">QUERY\./select.*requests</str>
+ </reporter>
+ <reporter name="test" group="cluster">
+ <str name="handler">/admin/metrics/collector</str>
+ <int name="period">5</int>
+ <lst name="report">
+ <str name="group">cluster</str>
+ <str name="label">jvm</str>
+ <str name="registry">solr\.jvm</str>
+ <str name="filter">memory\.total\..*</str>
+ <str name="filter">memory\.heap\..*</str>
+ <str name="filter">os\.SystemLoadAverage</str>
+ <str name="filter">threads\.count</str>
+ </lst>
+ <lst name="report">
+ <str name="group">cluster</str>
+ <str name="label">leader.$1</str>
+ <str name="registry">solr\.collection\.(.*)\.leader</str>
+ <str name="filter">UPDATE\./update/.*</str>
+ </lst>
+ </reporter>
+ </metrics>
+</solr>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
index 164eeab..1af09f4 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
@@ -119,9 +119,9 @@ public class TestCloudRecovery extends SolrCloudTestCase {
.filter(s -> s.startsWith("solr.core.")).collect(Collectors.toList());
for (String registry : registryNames) {
Map<String, Metric> metrics = manager.registry(registry).getMetrics();
- Timer timer = (Timer)metrics.get("REPLICATION.time");
- Counter counter = (Counter)metrics.get("REPLICATION.errors");
- Counter skipped = (Counter)metrics.get("REPLICATION.skipped");
+ Timer timer = (Timer)metrics.get("REPLICATION.peerSync.time");
+ Counter counter = (Counter)metrics.get("REPLICATION.peerSync.errors");
+ Counter skipped = (Counter)metrics.get("REPLICATION.peerSync.skipped");
replicationCount += timer.getCount();
errorsCount += counter.getCount();
skippedCount += skipped.getCount();
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/core/TestJmxMonitoredMap.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/core/TestJmxMonitoredMap.java b/solr/core/src/test/org/apache/solr/core/TestJmxMonitoredMap.java
index 2cad6e8..aa107bc 100644
--- a/solr/core/src/test/org/apache/solr/core/TestJmxMonitoredMap.java
+++ b/solr/core/src/test/org/apache/solr/core/TestJmxMonitoredMap.java
@@ -85,7 +85,7 @@ public class TestJmxMonitoredMap extends LuceneTestCase {
log.info("Using port: " + port);
String url = "service:jmx:rmi:///jndi/rmi://127.0.0.1:"+port+"/solrjmx";
JmxConfiguration config = new JmxConfiguration(true, null, url, null);
- monitoredMap = new JmxMonitoredMap<>("", "", config);
+ monitoredMap = new JmxMonitoredMap<>("", "", "", config);
JMXServiceURL u = new JMXServiceURL(url);
connector = JMXConnectorFactory.connect(u);
mbeanServer = connector.getMBeanServerConnection();
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
index 1df6021..6e8e1e5 100644
--- a/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java
@@ -103,6 +103,7 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
String className = MockMetricReporter.class.getName();
String reporterName = TestUtil.randomUnicodeString(random);
+ String taggedName = reporterName + "@" + coreMetricManager.getTag();
Map<String, Object> attrs = new HashMap<>();
attrs.put(FieldType.CLASS_NAME, className);
@@ -116,15 +117,16 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
PluginInfo pluginInfo = shouldDefinePlugin ? new PluginInfo(TestUtil.randomUnicodeString(random), attrs) : null;
try {
- metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(), pluginInfo);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo, String.valueOf(coreMetricManager.getCore().hashCode()));
assertNotNull(pluginInfo);
Map<String, SolrMetricReporter> reporters = metricManager.getReporters(coreMetricManager.getRegistryName());
assertTrue("reporters.size should be > 0, but was + " + reporters.size(), reporters.size() > 0);
- assertNotNull("reporter " + reporterName + " not present among " + reporters, reporters.get(reporterName));
- assertTrue("wrong reporter class: " + reporters.get(reporterName), reporters.get(reporterName) instanceof MockMetricReporter);
+ assertNotNull("reporter " + reporterName + " not present among " + reporters, reporters.get(taggedName));
+ assertTrue("wrong reporter class: " + reporters.get(taggedName), reporters.get(taggedName) instanceof MockMetricReporter);
} catch (IllegalArgumentException e) {
assertTrue(pluginInfo == null || attrs.get("configurable") == null);
- assertNull(metricManager.getReporters(coreMetricManager.getRegistryName()).get(reporterName));
+ assertNull(metricManager.getReporters(coreMetricManager.getRegistryName()).get(taggedName));
}
}
@@ -152,20 +154,11 @@ public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 {
}
@Test
- public void testRegistryName() throws Exception {
- String collectionName = "my_collection_";
- String cloudCoreName = "my_collection__shard1_0_replica0";
- String simpleCoreName = "collection_1_replica0";
- String simpleRegistryName = "solr.core." + simpleCoreName;
- String cloudRegistryName = "solr.core." + cloudCoreName;
- String nestedRegistryName = "solr.core.my_collection_.shard1_0.replica0";
- // pass through
- assertEquals(cloudRegistryName, coreMetricManager.createRegistryName(null, cloudCoreName));
- assertEquals(simpleRegistryName, coreMetricManager.createRegistryName(null, simpleCoreName));
- // unknown naming scheme -> pass through
- assertEquals(simpleRegistryName, coreMetricManager.createRegistryName(collectionName, simpleCoreName));
- // cloud collection
- assertEquals(nestedRegistryName, coreMetricManager.createRegistryName(collectionName, cloudCoreName));
-
+ public void testNonCloudRegistryName() throws Exception {
+ String registryName = h.getCore().getCoreMetricManager().getRegistryName();
+ String leaderRegistryName = h.getCore().getCoreMetricManager().getLeaderRegistryName();
+ assertNotNull(registryName);
+ assertEquals("solr.core.collection1", registryName);
+ assertNull(leaderRegistryName);
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java
index ee2acd3..1c29c5e 100644
--- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java
@@ -205,32 +205,32 @@ public class SolrMetricManagerTest extends SolrTestCaseJ4 {
createPluginInfo("node_foo", "node", null),
createPluginInfo("core_foo", "core", null)
};
-
- metricManager.loadReporters(plugins, loader, SolrInfoMBean.Group.node);
+ String tag = "xyz";
+ metricManager.loadReporters(plugins, loader, tag, SolrInfoMBean.Group.node);
Map<String, SolrMetricReporter> reporters = metricManager.getReporters(
SolrMetricManager.getRegistryName(SolrInfoMBean.Group.node));
assertEquals(4, reporters.size());
- assertTrue(reporters.containsKey("universal_foo"));
- assertTrue(reporters.containsKey("multigroup_foo"));
- assertTrue(reporters.containsKey("node_foo"));
- assertTrue(reporters.containsKey("multiregistry_foo"));
+ assertTrue(reporters.containsKey("universal_foo@" + tag));
+ assertTrue(reporters.containsKey("multigroup_foo@" + tag));
+ assertTrue(reporters.containsKey("node_foo@" + tag));
+ assertTrue(reporters.containsKey("multiregistry_foo@" + tag));
- metricManager.loadReporters(plugins, loader, SolrInfoMBean.Group.core, "collection1");
+ metricManager.loadReporters(plugins, loader, tag, SolrInfoMBean.Group.core, "collection1");
reporters = metricManager.getReporters(
SolrMetricManager.getRegistryName(SolrInfoMBean.Group.core, "collection1"));
assertEquals(5, reporters.size());
- assertTrue(reporters.containsKey("universal_foo"));
- assertTrue(reporters.containsKey("multigroup_foo"));
- assertTrue(reporters.containsKey("specific_foo"));
- assertTrue(reporters.containsKey("core_foo"));
- assertTrue(reporters.containsKey("multiregistry_foo"));
+ assertTrue(reporters.containsKey("universal_foo@" + tag));
+ assertTrue(reporters.containsKey("multigroup_foo@" + tag));
+ assertTrue(reporters.containsKey("specific_foo@" + tag));
+ assertTrue(reporters.containsKey("core_foo@" + tag));
+ assertTrue(reporters.containsKey("multiregistry_foo@" + tag));
- metricManager.loadReporters(plugins, loader, SolrInfoMBean.Group.jvm);
+ metricManager.loadReporters(plugins, loader, tag, SolrInfoMBean.Group.jvm);
reporters = metricManager.getReporters(
SolrMetricManager.getRegistryName(SolrInfoMBean.Group.jvm));
assertEquals(2, reporters.size());
- assertTrue(reporters.containsKey("universal_foo"));
- assertTrue(reporters.containsKey("multigroup_foo"));
+ assertTrue(reporters.containsKey("universal_foo@" + tag));
+ assertTrue(reporters.containsKey("multigroup_foo@" + tag));
metricManager.removeRegistry("solr.jvm");
reporters = metricManager.getReporters(
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
index 27c038b..dfb5a0f 100644
--- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricsIntegrationTest.java
@@ -19,7 +19,6 @@ package org.apache.solr.metrics;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Arrays;
import java.util.Map;
import java.util.Random;
@@ -55,6 +54,11 @@ public class SolrMetricsIntegrationTest extends SolrTestCaseJ4 {
private CoreContainer cc;
private SolrMetricManager metricManager;
+ private String tag;
+
+ private void assertTagged(Map<String, SolrMetricReporter> reporters, String name) {
+ assertTrue("Reporter '" + name + "' missing in " + reporters, reporters.containsKey(name + "@" + tag));
+ }
@Before
public void beforeTest() throws Exception {
@@ -68,10 +72,13 @@ public class SolrMetricsIntegrationTest extends SolrTestCaseJ4 {
new TestHarness.TestCoresLocator(DEFAULT_TEST_CORENAME, initCoreDataDir.getAbsolutePath(), "solrconfig.xml", "schema.xml"));
h.coreName = DEFAULT_TEST_CORENAME;
metricManager = cc.getMetricManager();
+ tag = h.getCore().getCoreMetricManager().getTag();
// initially there are more reporters, because two of them are added via a matching collection name
Map<String, SolrMetricReporter> reporters = metricManager.getReporters("solr.core." + DEFAULT_TEST_CORENAME);
assertEquals(INITIAL_REPORTERS.length, reporters.size());
- assertTrue(reporters.keySet().containsAll(Arrays.asList(INITIAL_REPORTERS)));
+ for (String r : INITIAL_REPORTERS) {
+ assertTagged(reporters, r);
+ }
// test rename operation
cc.rename(DEFAULT_TEST_CORENAME, CORE_NAME);
h.coreName = CORE_NAME;
@@ -101,7 +108,7 @@ public class SolrMetricsIntegrationTest extends SolrTestCaseJ4 {
deleteCore();
for (String reporterName : RENAMED_REPORTERS) {
- SolrMetricReporter reporter = reporters.get(reporterName);
+ SolrMetricReporter reporter = reporters.get(reporterName + "@" + tag);
MockMetricReporter mockReporter = (MockMetricReporter) reporter;
assertTrue("Reporter " + reporterName + " was not closed: " + mockReporter, mockReporter.didClose);
}
@@ -130,7 +137,7 @@ public class SolrMetricsIntegrationTest extends SolrTestCaseJ4 {
// SPECIFIC and MULTIREGISTRY were skipped because they were
// specific to collection1
for (String reporterName : RENAMED_REPORTERS) {
- SolrMetricReporter reporter = reporters.get(reporterName);
+ SolrMetricReporter reporter = reporters.get(reporterName + "@" + tag);
assertNotNull("Reporter " + reporterName + " was not found.", reporter);
assertTrue(reporter instanceof MockMetricReporter);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/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 ea452b2..82b9d58 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
@@ -64,15 +64,17 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
coreMetricManager = core.getCoreMetricManager();
metricManager = core.getCoreDescriptor().getCoreContainer().getMetricManager();
PluginInfo pluginInfo = createReporterPluginInfo();
- metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(), pluginInfo);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo, coreMetricManager.getTag());
Map<String, SolrMetricReporter> reporters = metricManager.getReporters(coreMetricManager.getRegistryName());
assertTrue("reporters.size should be > 0, but was + " + reporters.size(), reporters.size() > 0);
reporterName = pluginInfo.name;
- assertNotNull("reporter " + reporterName + " not present among " + reporters, reporters.get(reporterName));
- assertTrue("wrong reporter class: " + reporters.get(reporterName), reporters.get(reporterName) instanceof SolrJmxReporter);
+ String taggedName = reporterName + "@" + coreMetricManager.getTag();
+ assertNotNull("reporter " + taggedName + " not present among " + reporters, reporters.get(taggedName));
+ assertTrue("wrong reporter class: " + reporters.get(taggedName), reporters.get(taggedName) instanceof SolrJmxReporter);
- reporter = (SolrJmxReporter) reporters.get(reporterName);
+ reporter = (SolrJmxReporter) reporters.get(taggedName);
mBeanServer = reporter.getMBeanServer();
assertNotNull("MBean server not found.", mBeanServer);
}
@@ -144,7 +146,8 @@ public class SolrJmxReporterTest extends SolrTestCaseJ4 {
h.getCoreContainer().reload(h.getCore().getName());
PluginInfo pluginInfo = createReporterPluginInfo();
- metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(), pluginInfo);
+ metricManager.loadReporter(coreMetricManager.getRegistryName(), coreMetricManager.getCore().getResourceLoader(),
+ pluginInfo, String.valueOf(coreMetricManager.getCore().hashCode()));
coreMetricManager.registerMetricProducer(scope, producer);
objects = mBeanServer.queryMBeans(null, null);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrCloudReportersTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrCloudReportersTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrCloudReportersTest.java
new file mode 100644
index 0000000..91952b8
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrCloudReportersTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.solr;
+
+import java.nio.file.Paths;
+import java.util.Map;
+
+import com.codahale.metrics.Metric;
+import org.apache.commons.io.IOUtils;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.metrics.AggregateMetric;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricReporter;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class SolrCloudReportersTest extends SolrCloudTestCase {
+ int leaderRegistries;
+ int clusterRegistries;
+
+
+ @BeforeClass
+ public static void configureDummyCluster() throws Exception {
+ configureCluster(0).configure();
+ }
+
+ @Before
+ public void closePreviousCluster() throws Exception {
+ shutdownCluster();
+ leaderRegistries = 0;
+ clusterRegistries = 0;
+ }
+
+ @Test
+ public void testExplicitConfiguration() throws Exception {
+ String solrXml = IOUtils.toString(SolrCloudReportersTest.class.getResourceAsStream("/solr/solr-solrreporter.xml"), "UTF-8");
+ configureCluster(2)
+ .withSolrXml(solrXml).configure();
+ cluster.uploadConfigSet(Paths.get(TEST_PATH().toString(), "configsets", "minimal", "conf"), "test");
+ System.out.println("ZK: " + cluster.getZkServer().getZkAddress());
+ CollectionAdminRequest.createCollection("test_collection", "test", 2, 2)
+ .setMaxShardsPerNode(4)
+ .process(cluster.getSolrClient());
+ waitForState("Expected test_collection with 2 shards and 2 replicas", "test_collection", clusterShape(2, 2));
+ Thread.sleep(15000);
+ cluster.getJettySolrRunners().forEach(jetty -> {
+ CoreContainer cc = jetty.getCoreContainer();
+ // verify registry names
+ for (String name : cc.getCoreNames()) {
+ SolrCore core = cc.getCore(name);
+ try {
+ String registryName = core.getCoreMetricManager().getRegistryName();
+ String leaderRegistryName = core.getCoreMetricManager().getLeaderRegistryName();
+ String coreName = core.getName();
+ String collectionName = core.getCoreDescriptor().getCollectionName();
+ String coreNodeName = core.getCoreDescriptor().getCloudDescriptor().getCoreNodeName();
+ String replicaName = coreName.split("_")[3];
+ String shardId = core.getCoreDescriptor().getCloudDescriptor().getShardId();
+
+ assertEquals("solr.core." + collectionName + "." + shardId + "." + replicaName, registryName);
+ assertEquals("solr.collection." + collectionName + "." + shardId + ".leader", leaderRegistryName);
+
+ } finally {
+ if (core != null) {
+ core.close();
+ }
+ }
+ }
+ SolrMetricManager metricManager = cc.getMetricManager();
+ Map<String, SolrMetricReporter> reporters = metricManager.getReporters("solr.cluster");
+ assertEquals(reporters.toString(), 1, reporters.size());
+ SolrMetricReporter reporter = reporters.get("test");
+ assertNotNull(reporter);
+ assertTrue(reporter.toString(), reporter instanceof SolrClusterReporter);
+ SolrClusterReporter sor = (SolrClusterReporter)reporter;
+ assertEquals(5, sor.getPeriod());
+ for (String registryName : metricManager.registryNames(".*\\.shard[0-9]\\.replica.*")) {
+ reporters = metricManager.getReporters(registryName);
+ assertEquals(reporters.toString(), 1, reporters.size());
+ reporter = null;
+ for (String name : reporters.keySet()) {
+ if (name.startsWith("test")) {
+ reporter = reporters.get(name);
+ }
+ }
+ assertNotNull(reporter);
+ assertTrue(reporter.toString(), reporter instanceof SolrShardReporter);
+ SolrShardReporter srr = (SolrShardReporter)reporter;
+ assertEquals(5, srr.getPeriod());
+ }
+ for (String registryName : metricManager.registryNames(".*\\.leader")) {
+ leaderRegistries++;
+ reporters = metricManager.getReporters(registryName);
+ // no reporters registered for leader registry
+ assertEquals(reporters.toString(), 0, reporters.size());
+ // verify specific metrics
+ Map<String, Metric> metrics = metricManager.registry(registryName).getMetrics();
+ String key = "QUERY./select.requests.count";
+ assertTrue(key, metrics.containsKey(key));
+ assertTrue(key, metrics.get(key) instanceof AggregateMetric);
+ key = "UPDATE./update/json.requests.count";
+ assertTrue(key, metrics.containsKey(key));
+ assertTrue(key, metrics.get(key) instanceof AggregateMetric);
+ }
+ if (metricManager.registryNames().contains("solr.cluster")) {
+ clusterRegistries++;
+ Map<String,Metric> metrics = metricManager.registry("solr.cluster").getMetrics();
+ String key = "jvm.memory.heap.init.value";
+ assertTrue(key, metrics.containsKey(key));
+ assertTrue(key, metrics.get(key) instanceof AggregateMetric);
+ key = "leader.test_collection.shard1.UPDATE./update/json.requests.count.max";
+ assertTrue(key, metrics.containsKey(key));
+ assertTrue(key, metrics.get(key) instanceof AggregateMetric);
+ }
+ });
+ assertEquals("leaderRegistries", 2, leaderRegistries);
+ assertEquals("clusterRegistries", 1, clusterRegistries);
+ }
+
+ @Test
+ public void testDefaultPlugins() throws Exception {
+ String solrXml = IOUtils.toString(SolrCloudReportersTest.class.getResourceAsStream("/solr/solr.xml"), "UTF-8");
+ configureCluster(2)
+ .withSolrXml(solrXml).configure();
+ cluster.uploadConfigSet(Paths.get(TEST_PATH().toString(), "configsets", "minimal", "conf"), "test");
+ System.out.println("ZK: " + cluster.getZkServer().getZkAddress());
+ CollectionAdminRequest.createCollection("test_collection", "test", 2, 2)
+ .setMaxShardsPerNode(4)
+ .process(cluster.getSolrClient());
+ waitForState("Expected test_collection with 2 shards and 2 replicas", "test_collection", clusterShape(2, 2));
+ cluster.getJettySolrRunners().forEach(jetty -> {
+ CoreContainer cc = jetty.getCoreContainer();
+ SolrMetricManager metricManager = cc.getMetricManager();
+ Map<String, SolrMetricReporter> reporters = metricManager.getReporters("solr.cluster");
+ assertEquals(reporters.toString(), 0, reporters.size());
+ for (String registryName : metricManager.registryNames(".*\\.shard[0-9]\\.replica.*")) {
+ reporters = metricManager.getReporters(registryName);
+ assertEquals(reporters.toString(), 0, reporters.size());
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrShardReporterTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrShardReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrShardReporterTest.java
new file mode 100644
index 0000000..9ce3762
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/solr/SolrShardReporterTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.solr;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Map;
+
+import com.codahale.metrics.Metric;
+import org.apache.solr.client.solrj.embedded.JettySolrRunner;
+import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
+import org.apache.solr.cloud.CloudDescriptor;
+import org.apache.solr.common.cloud.ClusterState;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.CoreDescriptor;
+import org.apache.solr.metrics.AggregateMetric;
+import org.apache.solr.metrics.SolrCoreMetricManager;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class SolrShardReporterTest extends AbstractFullDistribZkTestBase {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public SolrShardReporterTest() {
+ schemaString = "schema15.xml"; // we need a string id
+ }
+
+ @Override
+ public String getSolrXml() {
+ return "solr-solrreporter.xml";
+ }
+
+ @Test
+ public void test() throws Exception {
+ waitForRecoveriesToFinish("control_collection",
+ jettys.get(0).getCoreContainer().getZkController().getZkStateReader(), false);
+ waitForRecoveriesToFinish("collection1",
+ jettys.get(0).getCoreContainer().getZkController().getZkStateReader(), false);
+ printLayout();
+ // wait for at least two reports
+ Thread.sleep(10000);
+ ClusterState state = jettys.get(0).getCoreContainer().getZkController().getClusterState();
+ for (JettySolrRunner jetty : jettys) {
+ CoreContainer cc = jetty.getCoreContainer();
+ SolrMetricManager metricManager = cc.getMetricManager();
+ for (final String coreName : cc.getCoreNames()) {
+ CoreDescriptor cd = cc.getCoreDescriptor(coreName);
+ if (cd.getCloudDescriptor() == null) { // not a cloud collection
+ continue;
+ }
+ CloudDescriptor cloudDesc = cd.getCloudDescriptor();
+ DocCollection docCollection = state.getCollection(cloudDesc.getCollectionName());
+ String replicaName = SolrCoreMetricManager.parseReplicaName(cloudDesc.getCollectionName(), coreName);
+ if (replicaName == null) {
+ replicaName = cloudDesc.getCoreNodeName();
+ }
+ String registryName = SolrCoreMetricManager.createRegistryName(true,
+ cloudDesc.getCollectionName(), cloudDesc.getShardId(), replicaName, null);
+ String leaderRegistryName = SolrCoreMetricManager.createLeaderRegistryName(true,
+ cloudDesc.getCollectionName(), cloudDesc.getShardId());
+ boolean leader = cloudDesc.isLeader();
+ Slice slice = docCollection.getSlice(cloudDesc.getShardId());
+ int numReplicas = slice.getReplicas().size();
+ if (leader) {
+ assertTrue(metricManager.registryNames() + " doesn't contain " + leaderRegistryName,
+ metricManager.registryNames().contains(leaderRegistryName));
+ Map<String, Metric> metrics = metricManager.registry(leaderRegistryName).getMetrics();
+ metrics.forEach((k, v) -> {
+ assertTrue("Unexpected type of " + k + ": " + v.getClass().getName() + ", " + v,
+ v instanceof AggregateMetric);
+ AggregateMetric am = (AggregateMetric)v;
+ if (!k.startsWith("REPLICATION.peerSync")) {
+ assertEquals(coreName + "::" + registryName + "::" + k + ": " + am.toString(), numReplicas, am.size());
+ }
+ });
+ } else {
+ assertFalse(metricManager.registryNames() + " contains " + leaderRegistryName +
+ " but it's not a leader!",
+ metricManager.registryNames().contains(leaderRegistryName));
+ Map<String, Metric> metrics = metricManager.registry(leaderRegistryName).getMetrics();
+ metrics.forEach((k, v) -> {
+ assertTrue("Unexpected type of " + k + ": " + v.getClass().getName() + ", " + v,
+ v instanceof AggregateMetric);
+ AggregateMetric am = (AggregateMetric)v;
+ if (!k.startsWith("REPLICATION.peerSync")) {
+ assertEquals(coreName + "::" + registryName + "::" + k + ": " + am.toString(), 1, am.size());
+ }
+ });
+ }
+ assertTrue(metricManager.registryNames() + " doesn't contain " + registryName,
+ metricManager.registryNames().contains(registryName));
+ }
+ }
+ SolrMetricManager metricManager = controlJetty.getCoreContainer().getMetricManager();
+ assertTrue(metricManager.registryNames().contains("solr.cluster"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java b/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
index e39ad6e..8717ad6 100644
--- a/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
+++ b/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
@@ -17,12 +17,20 @@
package org.apache.solr.util.stats;
+import java.util.Collections;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.util.NamedList;
+import org.apache.solr.metrics.AggregateMetric;
import org.junit.Test;
public class MetricUtilsTest extends SolrTestCaseJ4 {
@@ -36,7 +44,7 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
timer.update(Math.abs(random().nextInt()) + 1, TimeUnit.NANOSECONDS);
}
// obtain timer metrics
- NamedList lst = MetricUtils.timerToNamedList(timer);
+ NamedList lst = new NamedList(MetricUtils.timerToMap(timer, false));
// check that expected metrics were obtained
assertEquals(14, lst.size());
final Snapshot snapshot = timer.getSnapshot();
@@ -52,5 +60,49 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
assertEquals(MetricUtils.nsToMs(snapshot.get999thPercentile()), lst.get("p999_ms"));
}
+ @Test
+ public void testMetrics() throws Exception {
+ MetricRegistry registry = new MetricRegistry();
+ Counter counter = registry.counter("counter");
+ counter.inc();
+ Timer timer = registry.timer("timer");
+ Timer.Context ctx = timer.time();
+ Thread.sleep(150);
+ ctx.stop();
+ Meter meter = registry.meter("meter");
+ meter.mark();
+ Histogram histogram = registry.histogram("histogram");
+ histogram.update(10);
+ AggregateMetric am = new AggregateMetric();
+ registry.register("aggregate", am);
+ am.set("foo", 10);
+ am.set("bar", 1);
+ am.set("bar", 2);
+ MetricUtils.toNamedMaps(registry, Collections.singletonList(MetricFilter.ALL), MetricFilter.ALL,
+ false, false, (k, v) -> {
+ if (k.startsWith("counter")) {
+ assertEquals(1L, v.get("count"));
+ } else if (k.startsWith("timer")) {
+ assertEquals(1L, v.get("count"));
+ assertTrue(((Number)v.get("min_ms")).intValue() > 100);
+ } else if (k.startsWith("meter")) {
+ assertEquals(1L, v.get("count"));
+ } else if (k.startsWith("histogram")) {
+ assertEquals(1L, v.get("count"));
+ } else if (k.startsWith("aggregate")) {
+ assertEquals(2, v.get("count"));
+ Map<String, Object> values = (Map<String, Object>)v.get("values");
+ assertNotNull(values);
+ assertEquals(2, values.size());
+ Map<String, Object> update = (Map<String, Object>)values.get("foo");
+ assertEquals(10, update.get("value"));
+ assertEquals(1, update.get("updateCount"));
+ update = (Map<String, Object>)values.get("bar");
+ assertEquals(2, update.get("value"));
+ assertEquals(2, update.get("updateCount"));
+ }
+ });
+ }
+
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
index 67274c2..310c282 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
@@ -112,8 +112,8 @@ public class BinaryRequestWriter extends RequestWriter {
/*
* A hack to get access to the protected internal buffer and avoid an additional copy
*/
- class BAOS extends ByteArrayOutputStream {
- byte[] getbuf() {
+ public static class BAOS extends ByteArrayOutputStream {
+ public byte[] getbuf() {
return super.buf;
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/solrj/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java b/solr/solrj/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java
index da94162..132a1a8 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/io/SolrClientCache.java
@@ -22,6 +22,7 @@ import java.lang.invoke.MethodHandles;
import java.util.Map;
import java.util.HashMap;
+import org.apache.http.client.HttpClient;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
@@ -38,15 +39,27 @@ public class SolrClientCache implements Serializable {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final Map<String, SolrClient> solrClients = new HashMap<>();
+ private final HttpClient httpClient;
+
+ public SolrClientCache() {
+ httpClient = null;
+ }
+
+ public SolrClientCache(HttpClient httpClient) {
+ this.httpClient = httpClient;
+ }
public synchronized CloudSolrClient getCloudSolrClient(String zkHost) {
CloudSolrClient client;
if (solrClients.containsKey(zkHost)) {
client = (CloudSolrClient) solrClients.get(zkHost);
} else {
- client = new CloudSolrClient.Builder()
- .withZkHost(zkHost)
- .build();
+ CloudSolrClient.Builder builder = new CloudSolrClient.Builder()
+ .withZkHost(zkHost);
+ if (httpClient != null) {
+ builder = builder.withHttpClient(httpClient);
+ }
+ client = builder.build();
client.connect();
solrClients.put(zkHost, client);
}
@@ -59,8 +72,11 @@ public class SolrClientCache implements Serializable {
if (solrClients.containsKey(host)) {
client = (HttpSolrClient) solrClients.get(host);
} else {
- client = new HttpSolrClient.Builder(host)
- .build();
+ HttpSolrClient.Builder builder = new HttpSolrClient.Builder(host);
+ if (httpClient != null) {
+ builder = builder.withHttpClient(httpClient);
+ }
+ client = builder.build();
solrClients.put(host, client);
}
return client;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d7bc947/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java
index b2174cd..de7c620 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java
@@ -251,8 +251,8 @@ public class TestCoreAdmin extends AbstractEmbeddedSolrServerTestCase {
// assert initial metrics
SolrMetricManager metricManager = cores.getMetricManager();
- String core0RegistryName = SolrCoreMetricManager.createRegistryName(null, "core0");
- String core1RegistryName = SolrCoreMetricManager.createRegistryName(null, "core1");
+ String core0RegistryName = SolrCoreMetricManager.createRegistryName(false, null, null, null, "core0");
+ String core1RegistryName = SolrCoreMetricManager.createRegistryName(false, null, null,null, "core1");
MetricRegistry core0Registry = metricManager.registry(core0RegistryName);
MetricRegistry core1Registry = metricManager.registry(core1RegistryName);