diff --git a/lucene/ivy-versions.properties b/lucene/ivy-versions.properties index c2285771be9c..959552d3f383 100644 --- a/lucene/ivy-versions.properties +++ b/lucene/ivy-versions.properties @@ -13,9 +13,9 @@ com.carrotsearch.randomizedtesting.version = 2.3.2 /com.carrotsearch/hppc = 0.7.1 -com.codahale.metrics.version = 3.0.1 -/com.codahale.metrics/metrics-core = ${com.codahale.metrics.version} -/com.codahale.metrics/metrics-healthchecks = ${com.codahale.metrics.version} +io.dropwizard.metrics.version = 3.1.2 +/io.dropwizard.metrics/metrics-core = ${io.dropwizard.metrics.version} +/io.dropwizard.metrics/metrics-healthchecks = ${io.dropwizard.metrics.version} /com.cybozu.labs/langdetect = 1.1-20120112 /com.drewnoakes/metadata-extractor = 2.6.2 diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java index cf5bd4309258..6a9d44b43192 100644 --- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java +++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/plugin/AnalyticsStatisticsCollector.java @@ -16,13 +16,14 @@ */ package org.apache.solr.analytics.plugin; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import com.codahale.metrics.Snapshot; +import com.codahale.metrics.Timer; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; -import org.apache.solr.util.stats.Snapshot; -import org.apache.solr.util.stats.Timer; -import org.apache.solr.util.stats.TimerContext; +import org.apache.solr.util.stats.Metrics; public class AnalyticsStatisticsCollector { private final AtomicLong numRequests; @@ -35,7 +36,7 @@ public class AnalyticsStatisticsCollector { private final AtomicLong numQueries; private final Timer requestTimes; - public TimerContext currentTimer; + public Timer.Context currentTimer; public AnalyticsStatisticsCollector() { numRequests = new AtomicLong(); @@ -97,17 +98,7 @@ public NamedList getStatistics() { lst.add("rangeFacets", numRangeFacets.longValue()); lst.add("queryFacets", numQueryFacets.longValue()); lst.add("queriesInQueryFacets", numQueries.longValue()); - lst.add("totalTime", requestTimes.getSum()); - lst.add("avgRequestsPerSecond", requestTimes.getMeanRate()); - lst.add("5minRateReqsPerSecond", requestTimes.getFiveMinuteRate()); - lst.add("15minRateReqsPerSecond", requestTimes.getFifteenMinuteRate()); - lst.add("avgTimePerRequest", requestTimes.getMean()); - lst.add("medianRequestTime", snapshot.getMedian()); - lst.add("75thPcRequestTime", snapshot.get75thPercentile()); - lst.add("95thPcRequestTime", snapshot.get95thPercentile()); - lst.add("99thPcRequestTime", snapshot.get99thPercentile()); - lst.add("999thPcRequestTime", snapshot.get999thPercentile()); + Metrics.addTimerMetrics(lst, requestTimes); return lst; } - } diff --git a/solr/contrib/morphlines-core/ivy.xml b/solr/contrib/morphlines-core/ivy.xml index 53905e05ce45..1ddfcc3f36db 100644 --- a/solr/contrib/morphlines-core/ivy.xml +++ b/solr/contrib/morphlines-core/ivy.xml @@ -34,8 +34,8 @@ - - + + diff --git a/solr/core/ivy.xml b/solr/core/ivy.xml index 5f8706f0e43f..a94691e9ceb3 100644 --- a/solr/core/ivy.xml +++ b/solr/core/ivy.xml @@ -49,6 +49,7 @@ + diff --git a/solr/core/src/java/org/apache/solr/cloud/DistributedQueue.java b/solr/core/src/java/org/apache/solr/cloud/DistributedQueue.java index e424b7e89e6a..062f48bcd4c5 100644 --- a/solr/core/src/java/org/apache/solr/cloud/DistributedQueue.java +++ b/solr/core/src/java/org/apache/solr/cloud/DistributedQueue.java @@ -26,13 +26,13 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; +import com.codahale.metrics.Timer; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZkCmdExecutor; -import org.apache.solr.util.stats.TimerContext; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; @@ -123,7 +123,7 @@ public DistributedQueue(SolrZkClient zookeeper, String dir, Overseer.Stats stats * @return data at the first element of the queue, or null. */ public byte[] peek() throws KeeperException, InterruptedException { - TimerContext time = stats.time(dir + "_peek"); + Timer.Context time = stats.time(dir + "_peek"); try { return firstElement(); } finally { @@ -151,7 +151,7 @@ public byte[] peek(boolean block) throws KeeperException, InterruptedException { */ public byte[] peek(long wait) throws KeeperException, InterruptedException { Preconditions.checkArgument(wait > 0); - TimerContext time; + Timer.Context time; if (wait == Long.MAX_VALUE) { time = stats.time(dir + "_peek_wait_forever"); } else { @@ -181,7 +181,7 @@ public byte[] peek(long wait) throws KeeperException, InterruptedException { * @return Head of the queue or null. */ public byte[] poll() throws KeeperException, InterruptedException { - TimerContext time = stats.time(dir + "_poll"); + Timer.Context time = stats.time(dir + "_poll"); try { return removeFirst(); } finally { @@ -195,7 +195,7 @@ public byte[] poll() throws KeeperException, InterruptedException { * @return The former head of the queue */ public byte[] remove() throws NoSuchElementException, KeeperException, InterruptedException { - TimerContext time = stats.time(dir + "_remove"); + Timer.Context time = stats.time(dir + "_remove"); try { byte[] result = removeFirst(); if (result == null) { @@ -214,7 +214,7 @@ public byte[] remove() throws NoSuchElementException, KeeperException, Interrupt */ public byte[] take() throws KeeperException, InterruptedException { // Same as for element. Should refactor this. - TimerContext timer = stats.time(dir + "_take"); + Timer.Context timer = stats.time(dir + "_take"); updateLock.lockInterruptibly(); try { while (true) { @@ -238,7 +238,7 @@ public byte[] take() throws KeeperException, InterruptedException { * element to become visible. */ public void offer(byte[] data) throws KeeperException, InterruptedException { - TimerContext time = stats.time(dir + "_offer"); + Timer.Context time = stats.time(dir + "_offer"); try { while (true) { try { diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java index 0e5bded5f3f5..fa3c5efacbae 100644 --- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java +++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import com.codahale.metrics.Timer; import org.apache.commons.lang.StringUtils; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.cloud.overseer.ClusterStateMutator; @@ -59,9 +60,6 @@ import org.apache.solr.handler.admin.CollectionsHandler; import org.apache.solr.handler.component.ShardHandler; import org.apache.solr.update.UpdateShardHandler; -import org.apache.solr.util.stats.Clock; -import org.apache.solr.util.stats.Timer; -import org.apache.solr.util.stats.TimerContext; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; @@ -273,7 +271,7 @@ public void run() { private ClusterState processQueueItem(ZkNodeProps message, ClusterState clusterState, ZkStateWriter zkStateWriter, boolean enableBatching, ZkStateWriter.ZkWriteCallback callback) throws Exception { final String operation = message.getStr(QUEUE_OPERATION); List zkWriteCommands = null; - final TimerContext timerContext = stats.time(operation); + final Timer.Context timerContext = stats.time(operation); try { zkWriteCommands = processMessage(clusterState, message, operation); stats.success(operation); @@ -411,7 +409,7 @@ private List processMessage(ClusterState clusterState, } private LeaderStatus amILeader() { - TimerContext timerContext = stats.time("am_i_leader"); + Timer.Context timerContext = stats.time("am_i_leader"); boolean success = true; try { ZkNodeProps props = ZkNodeProps.load(zkClient.getData( @@ -1115,7 +1113,7 @@ public void error(String operation) { stat.errors.incrementAndGet(); } - public TimerContext time(String operation) { + public Timer.Context time(String operation) { String op = operation.toLowerCase(Locale.ROOT); Stat stat = stats.get(op); if (stat == null) { @@ -1173,7 +1171,7 @@ public static class Stat { public Stat() { this.success = new AtomicInteger(); this.errors = new AtomicInteger(); - this.requestTime = new Timer(TimeUnit.MILLISECONDS, TimeUnit.MINUTES, Clock.defaultClock()); + this.requestTime = new Timer(); this.failureDetails = new LinkedList<>(); } } diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionMessageHandler.java b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionMessageHandler.java index 78db47332f0a..e834b27d8d0b 100644 --- a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionMessageHandler.java +++ b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionMessageHandler.java @@ -33,6 +33,8 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import com.codahale.metrics.Snapshot; +import com.codahale.metrics.Timer; import org.apache.commons.lang.StringUtils; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.client.solrj.SolrServerException; @@ -82,8 +84,7 @@ import org.apache.solr.update.SolrIndexSplitter; import org.apache.solr.util.RTimer; import org.apache.solr.util.TimeOut; -import org.apache.solr.util.stats.Snapshot; -import org.apache.solr.util.stats.Timer; +import org.apache.solr.util.stats.Metrics; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.data.Stat; @@ -429,17 +430,7 @@ private void getOverseerStatus(ZkNodeProps message, NamedList results) throws Ke lst.add("errors", errors); } Timer timer = entry.getValue().requestTime; - Snapshot snapshot = timer.getSnapshot(); - lst.add("totalTime", timer.getSum()); - lst.add("avgRequestsPerMinute", timer.getMeanRate()); - lst.add("5minRateRequestsPerMinute", timer.getFiveMinuteRate()); - lst.add("15minRateRequestsPerMinute", timer.getFifteenMinuteRate()); - lst.add("avgTimePerRequest", timer.getMean()); - lst.add("medianRequestTime", snapshot.getMedian()); - lst.add("75thPctlRequestTime", snapshot.get75thPercentile()); - lst.add("95thPctlRequestTime", snapshot.get95thPercentile()); - lst.add("99thPctlRequestTime", snapshot.get99thPercentile()); - lst.add("999thPctlRequestTime", snapshot.get999thPercentile()); + Metrics.addTimerMetrics(lst, timer); } results.add("overseer_operations", overseerStats); results.add("collection_operations", collectionStats); diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java index 26a90cb80591..67a58b9d85a4 100644 --- a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java +++ b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java @@ -28,6 +28,7 @@ import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; +import com.codahale.metrics.Timer; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.cloud.OverseerTaskQueue.QueueEvent; import org.apache.solr.cloud.Overseer.LeaderStatus; @@ -39,7 +40,6 @@ import org.apache.solr.common.util.Utils; import org.apache.solr.handler.component.ShardHandlerFactory; import org.apache.solr.util.DefaultSolrThreadFactory; -import org.apache.solr.util.stats.TimerContext; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.data.Stat; import org.slf4j.Logger; @@ -352,7 +352,7 @@ public static String getLeaderId(SolrZkClient zkClient) throws KeeperException,I protected LeaderStatus amILeader() { String statsName = "collection_am_i_leader"; - TimerContext timerContext = stats.time(statsName); + Timer.Context timerContext = stats.time(statsName); boolean success = true; try { ZkNodeProps props = ZkNodeProps.load(zkStateReader.getZkClient().getData( @@ -425,7 +425,7 @@ public Runner(OverseerMessageHandler messageHandler, ZkNodeProps message, String public void run() { String statsName = messageHandler.getTimerName(operation); - final TimerContext timerContext = stats.time(statsName); + final Timer.Context timerContext = stats.time(statsName); boolean success = false; final String asyncId = message.getStr(ASYNC); diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskQueue.java b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskQueue.java index cf9d5834e8d9..ea9aa45e016e 100644 --- a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskQueue.java +++ b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskQueue.java @@ -23,9 +23,9 @@ import java.util.Set; import java.util.TreeSet; +import com.codahale.metrics.Timer; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZkNodeProps; -import org.apache.solr.util.stats.TimerContext; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; @@ -86,7 +86,7 @@ public boolean containsTaskWithRequestId(String requestIdKey, String requestId) */ public byte[] remove(QueueEvent event) throws KeeperException, InterruptedException { - TimerContext time = stats.time(dir + "_remove_event"); + Timer.Context time = stats.time(dir + "_remove_event"); try { String path = event.getId(); String responsePath = dir + "/" + response_prefix @@ -181,7 +181,7 @@ private String createData(String path, byte[] data, CreateMode mode) */ public QueueEvent offer(byte[] data, long timeout) throws KeeperException, InterruptedException { - TimerContext time = stats.time(dir + "_offer"); + Timer.Context time = stats.time(dir + "_offer"); try { // Create and watch the response node before creating the request node; // otherwise we may miss the response. @@ -218,7 +218,7 @@ public List peekTopN(int n, Set excludeSet, long waitMillis) ArrayList topN = new ArrayList<>(); LOG.debug("Peeking for top {} elements. ExcludeSet: {}", n, excludeSet); - TimerContext time = null; + Timer.Context time = null; if (waitMillis == Long.MAX_VALUE) time = stats.time(dir + "_peekTopN_wait_forever"); else time = stats.time(dir + "_peekTopN_wait" + waitMillis); diff --git a/solr/core/src/java/org/apache/solr/cloud/overseer/ZkStateWriter.java b/solr/core/src/java/org/apache/solr/cloud/overseer/ZkStateWriter.java index 9fb3ada40c63..461d7f29eca0 100644 --- a/solr/core/src/java/org/apache/solr/cloud/overseer/ZkStateWriter.java +++ b/solr/core/src/java/org/apache/solr/cloud/overseer/ZkStateWriter.java @@ -21,12 +21,12 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import com.codahale.metrics.Timer; import org.apache.solr.cloud.Overseer; import org.apache.solr.common.cloud.ClusterState; import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.util.Utils; -import org.apache.solr.util.stats.TimerContext; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.data.Stat; @@ -211,7 +211,7 @@ public ClusterState writePendingUpdates() throws IllegalStateException, KeeperEx throw new IllegalStateException("ZkStateWriter has seen a tragic error, this instance can no longer be used"); } if (!hasPendingUpdates()) return clusterState; - TimerContext timerContext = stats.time("update_state"); + Timer.Context timerContext = stats.time("update_state"); boolean success = false; try { if (!updates.isEmpty()) { diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java index cf3aa706dfa0..bc2f952c07ab 100644 --- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java +++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java @@ -16,6 +16,7 @@ */ package org.apache.solr.handler; +import com.codahale.metrics.Snapshot; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; @@ -31,14 +32,14 @@ import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.search.SyntaxError; import org.apache.solr.util.SolrPluginUtils; -import org.apache.solr.util.stats.Snapshot; -import org.apache.solr.util.stats.Timer; -import org.apache.solr.util.stats.TimerContext; +import org.apache.solr.util.stats.Metrics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.codahale.metrics.Timer; import java.lang.invoke.MethodHandles; import java.net.URL; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import static org.apache.solr.core.RequestParams.USEPARAM; @@ -55,10 +56,11 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo protected boolean httpCaching = true; // Statistics + public static final String REGISTRY_NAME = "requesthandler"; private final AtomicLong numRequests = new AtomicLong(); private final AtomicLong numErrors = new AtomicLong(); private final AtomicLong numTimeouts = new AtomicLong(); - private final Timer requestTimes = new Timer(); + private Timer requestTimes = new Timer(); private final long handlerStart; @@ -146,7 +148,7 @@ public NamedList getInitArgs() { @Override public void handleRequest(SolrQueryRequest req, SolrQueryResponse rsp) { numRequests.incrementAndGet(); - TimerContext timer = requestTimes.time(); + Timer.Context timer = requestTimes.time(); try { if(pluginInfo != null && pluginInfo.attributes.containsKey(USEPARAM)) req.getContext().put(USEPARAM,pluginInfo.attributes.get(USEPARAM)); SolrPluginUtils.setDefaults(this, req, defaults, appends, invariants); @@ -249,7 +251,12 @@ public static SolrRequestHandler getRequestHandler(String handlerName, PluginBag } public void setPluginInfo(PluginInfo pluginInfo){ - if(this.pluginInfo==null) this.pluginInfo = pluginInfo; + if(this.pluginInfo==null) { + // if a request handler has a name, use a persistent, reportable timer under that name + if (pluginInfo.name != null) + requestTimes = Metrics.namedTimer(Metrics.mkName(this.getClass(), pluginInfo.name), REGISTRY_NAME); + this.pluginInfo = pluginInfo; + } } public PluginInfo getPluginInfo(){ @@ -265,19 +272,10 @@ public NamedList getStatistics() { lst.add("requests", numRequests.longValue()); lst.add("errors", numErrors.longValue()); lst.add("timeouts", numTimeouts.longValue()); - lst.add("totalTime", requestTimes.getSum()); - lst.add("avgRequestsPerSecond", requestTimes.getMeanRate()); - lst.add("5minRateReqsPerSecond", requestTimes.getFiveMinuteRate()); - lst.add("15minRateReqsPerSecond", requestTimes.getFifteenMinuteRate()); - lst.add("avgTimePerRequest", requestTimes.getMean()); - lst.add("medianRequestTime", snapshot.getMedian()); - lst.add("75thPcRequestTime", snapshot.get75thPercentile()); - lst.add("95thPcRequestTime", snapshot.get95thPercentile()); - lst.add("99thPcRequestTime", snapshot.get99thPercentile()); - lst.add("999thPcRequestTime", snapshot.get999thPercentile()); + Metrics.addTimerMetrics(lst, requestTimes); return lst; } - + } diff --git a/solr/core/src/java/org/apache/solr/util/stats/Clock.java b/solr/core/src/java/org/apache/solr/util/stats/Clock.java index a94c216082e2..271e4b4bd854 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/Clock.java +++ b/solr/core/src/java/org/apache/solr/util/stats/Clock.java @@ -27,7 +27,9 @@ /** * An abstraction for how time passes. It is passed to {@link Timer} to track timing. + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public abstract class Clock { /** * Returns the current time tick. diff --git a/solr/core/src/java/org/apache/solr/util/stats/EWMA.java b/solr/core/src/java/org/apache/solr/util/stats/EWMA.java index 010d2b1c5a8d..3311ae64a520 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/EWMA.java +++ b/solr/core/src/java/org/apache/solr/util/stats/EWMA.java @@ -32,7 +32,9 @@ * It Works * @see UNIX Load Average Part 2: Not * Your Average Average + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class EWMA { private static final int INTERVAL = 5; private static final double SECONDS_PER_MINUTE = 60.0; diff --git a/solr/core/src/java/org/apache/solr/util/stats/ExponentiallyDecayingSample.java b/solr/core/src/java/org/apache/solr/util/stats/ExponentiallyDecayingSample.java index 92b72fdecced..f0813dff1684 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/ExponentiallyDecayingSample.java +++ b/solr/core/src/java/org/apache/solr/util/stats/ExponentiallyDecayingSample.java @@ -37,7 +37,9 @@ * * See * Cormode et al. Forward Decay: A Practical Time Decay Model for Streaming Systems. ICDE '09: Proceedings of the 2009 IEEE International Conference on Data Engineering (2009) + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class ExponentiallyDecayingSample implements Sample { private static final long RESCALE_THRESHOLD = TimeUnit.HOURS.toNanos(1); diff --git a/solr/core/src/java/org/apache/solr/util/stats/Histogram.java b/solr/core/src/java/org/apache/solr/util/stats/Histogram.java index eef8f35d4a5f..225b8e73825f 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/Histogram.java +++ b/solr/core/src/java/org/apache/solr/util/stats/Histogram.java @@ -30,7 +30,9 @@ * * @see Accurately computing running * variance + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class Histogram { private static final int DEFAULT_SAMPLE_SIZE = 1028; diff --git a/solr/core/src/java/org/apache/solr/util/stats/Meter.java b/solr/core/src/java/org/apache/solr/util/stats/Meter.java index 8847fc435e7d..73611254e5b1 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/Meter.java +++ b/solr/core/src/java/org/apache/solr/util/stats/Meter.java @@ -28,7 +28,10 @@ * exponentially-weighted moving average throughputs. * * @see EMA + * + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class Meter { private static final long TICK_INTERVAL = TimeUnit.SECONDS.toNanos(5); diff --git a/solr/core/src/java/org/apache/solr/util/stats/Metrics.java b/solr/core/src/java/org/apache/solr/util/stats/Metrics.java new file mode 100644 index 000000000000..213f2b902f26 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/util/stats/Metrics.java @@ -0,0 +1,119 @@ +package org.apache.solr.util.stats; + +/* + * 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. + */ + + +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.SharedMetricRegistries; +import com.codahale.metrics.Snapshot; +import com.codahale.metrics.Timer; +import org.apache.hadoop.metrics.util.MetricsRegistry; +import org.apache.solr.common.util.NamedList; + +public enum Metrics {; // empty enum, this is just a container for static methods + + public static final String REGISTRY_NAME_PREFIX = "solr.registry"; + public static final String DEFAULT_REGISTRY = MetricRegistry.name(REGISTRY_NAME_PREFIX, "default"); + + public static String mkName(String name, String... names) { return MetricRegistry.name(name, names); } + public static String mkName(Class klass, String... names) { return MetricRegistry.name(klass, names); } + /** + * Use to get a Timer that you intend to use internally, and will never need to report metrics for. + * @return + */ + public static Timer anonymousTimer() { + return new Timer(); + } + + /** + * Use to get a named (shared, persistent) Timer from the default shared registry. + * @param name A name that can be used to get this same Timer instance again + * @return + */ + public static Timer namedTimer(String name) { + return namedTimer(name, DEFAULT_REGISTRY); + } + + /** + * Use to get a named (shared, persistent) Timer from a specified shared registry. + * @param name A name that can be used to get this same Timer instance again + * @param registry The name of the registry to get this timer from + * @return + */ + public static Timer namedTimer(String name, String registry) { + return SharedMetricRegistries.getOrCreate(overridableRegistryName(registry)).timer(name); + } + + /** + * Gets a shared MetricRegistry by name, respecting overrides + * @param name + * @return + */ + public static MetricRegistry registryFor(String name) { + return SharedMetricRegistries.getOrCreate(overridableRegistryName(name)); + } + + /** + * Allows named registries to be renamed using System properties. + * This would be mostly be useful if you want to combine the metrics from a few registries for a single + * reporter. + * @param registry The name of the registry + * @return A potentially overridden (via System properties) registry name + */ + public static String overridableRegistryName(String registry) { + String fqRegistry = enforcePrefix(registry); + return enforcePrefix(System.getProperty(fqRegistry,fqRegistry)); + } + + private static String enforcePrefix(String name) { + if (name.startsWith(REGISTRY_NAME_PREFIX)) + return name; + else + return MetricRegistry.name(REGISTRY_NAME_PREFIX, name); + } + + + /** + * Adds metrics from a Timer to a NamedList, using well-known names. + * @param lst The NamedList to add the metrics data to + * @param timer The Timer to extract the metrics from + */ + public static void addTimerMetrics(NamedList lst, Timer timer) { + Snapshot snapshot = timer.getSnapshot(); + lst.add("avgRequestsPerMinute", timer.getMeanRate()); + lst.add("5minRateRequestsPerMinute", timer.getFiveMinuteRate()); + lst.add("15minRateRequestsPerMinute", timer.getFifteenMinuteRate()); + lst.add("avgTimePerRequest", nsToMs(snapshot.getMean())); + lst.add("medianRequestTime", nsToMs(snapshot.getMedian())); + lst.add("75thPctlRequestTime", nsToMs(snapshot.get75thPercentile())); + lst.add("95thPctlRequestTime", nsToMs(snapshot.get95thPercentile())); + lst.add("99thPctlRequestTime", nsToMs(snapshot.get99thPercentile())); + lst.add("999thPctlRequestTime", nsToMs(snapshot.get999thPercentile())); + } + + /** + * Timers return measurements as a double representing nanos. + * This converts that to a double representing millis. + * @param ns Nanoseconds + * @return Milliseconds + */ + public static double nsToMs(double ns) { + return ns / 1000000; // Using TimeUnit involves casting to Long, so don't bother. + } + +} diff --git a/solr/core/src/java/org/apache/solr/util/stats/Sample.java b/solr/core/src/java/org/apache/solr/util/stats/Sample.java index 29c69f4f4edc..1f0825aae7ba 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/Sample.java +++ b/solr/core/src/java/org/apache/solr/util/stats/Sample.java @@ -22,7 +22,9 @@ /** * A statistically representative sample of a data stream. + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public interface Sample { /** * Clears all recorded values. diff --git a/solr/core/src/java/org/apache/solr/util/stats/Snapshot.java b/solr/core/src/java/org/apache/solr/util/stats/Snapshot.java index 78524bf51883..d85a727b9c43 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/Snapshot.java +++ b/solr/core/src/java/org/apache/solr/util/stats/Snapshot.java @@ -27,7 +27,9 @@ /** * A statistical snapshot of a {@link Snapshot}. + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class Snapshot { private static final double MEDIAN_Q = 0.5; private static final double P75_Q = 0.75; diff --git a/solr/core/src/java/org/apache/solr/util/stats/Timer.java b/solr/core/src/java/org/apache/solr/util/stats/Timer.java index de5790ca401b..775684b0e74e 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/Timer.java +++ b/solr/core/src/java/org/apache/solr/util/stats/Timer.java @@ -28,7 +28,9 @@ /** * A timer metric which aggregates timing durations and provides duration statistics, plus * throughput statistics via {@link Meter}. + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class Timer { private final TimeUnit durationUnit, rateUnit; diff --git a/solr/core/src/java/org/apache/solr/util/stats/TimerContext.java b/solr/core/src/java/org/apache/solr/util/stats/TimerContext.java index 125b98210475..4350f1a3b7b0 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/TimerContext.java +++ b/solr/core/src/java/org/apache/solr/util/stats/TimerContext.java @@ -26,7 +26,9 @@ * A timing context. * * @see Timer#time() + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class TimerContext { private final Timer timer; private final Clock clock; diff --git a/solr/core/src/java/org/apache/solr/util/stats/UniformSample.java b/solr/core/src/java/org/apache/solr/util/stats/UniformSample.java index 81c8ed1ac20d..4d4f7c3e63b6 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/UniformSample.java +++ b/solr/core/src/java/org/apache/solr/util/stats/UniformSample.java @@ -31,7 +31,9 @@ * statistically representative sample. * * @see Random Sampling with a Reservoir + * @deprecated Use the metrics-core library's classes instead */ +@Deprecated public class UniformSample implements Sample { private static final int BITS_PER_LONG = 63; diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java index 85a88ec3ae9d..597c36bab138 100644 --- a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java @@ -34,6 +34,8 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import com.codahale.metrics.Snapshot; +import com.codahale.metrics.Timer; import org.apache.lucene.util.LuceneTestCase.Slow; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.cloud.overseer.OverseerAction; @@ -52,9 +54,6 @@ import org.apache.solr.update.UpdateShardHandler; import org.apache.solr.update.UpdateShardHandlerConfig; import org.apache.solr.util.DefaultSolrThreadFactory; -import org.apache.solr.util.stats.Snapshot; -import org.apache.solr.util.stats.Timer; -import org.apache.solr.util.stats.TimerContext; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NoNodeException; @@ -1041,7 +1040,7 @@ public void testPerformance() throws Exception { q.offer(Utils.toJSON(m)); Timer t = new Timer(); - TimerContext context = t.time(); + Timer.Context context = t.time(); try { overseerClient = electNewOverseer(server.getZkAddress()); assertTrue(overseers.size() > 0); @@ -1086,16 +1085,19 @@ public void testPerformance() throws Exception { private void printTimingStats(Timer timer) { Snapshot snapshot = timer.getSnapshot(); - log.info("\t totalTime: {}", timer.getSum()); log.info("\t avgRequestsPerMinute: {}", timer.getMeanRate()); log.info("\t 5minRateRequestsPerMinute: {}", timer.getFiveMinuteRate()); log.info("\t 15minRateRequestsPerMinute: {}", timer.getFifteenMinuteRate()); - log.info("\t avgTimePerRequest: {}", timer.getMean()); - log.info("\t medianRequestTime: {}", snapshot.getMedian()); - log.info("\t 75thPctlRequestTime: {}", snapshot.get75thPercentile()); - log.info("\t 95thPctlRequestTime: {}", snapshot.get95thPercentile()); - log.info("\t 99thPctlRequestTime: {}", snapshot.get99thPercentile()); - log.info("\t 999thPctlRequestTime: {}", snapshot.get999thPercentile()); + log.info("\t avgTimePerRequest: {}", nsToMs(snapshot.getMean())); + log.info("\t medianRequestTime: {}", nsToMs(snapshot.getMedian())); + log.info("\t 75thPctlRequestTime: {}", nsToMs(snapshot.get75thPercentile())); + log.info("\t 95thPctlRequestTime: {}", nsToMs(snapshot.get95thPercentile())); + log.info("\t 99thPctlRequestTime: {}", nsToMs(snapshot.get99thPercentile())); + log.info("\t 999thPctlRequestTime: {}", nsToMs(snapshot.get999thPercentile())); + } + + private static long nsToMs(double ns) { + return TimeUnit.NANOSECONDS.convert((long)ns, TimeUnit.MILLISECONDS); } private void close(MockZKController mockController) { diff --git a/solr/core/src/test/org/apache/solr/core/RequestHandlersTest.java b/solr/core/src/test/org/apache/solr/core/RequestHandlersTest.java index ca45f7cdd86f..c456b742202c 100644 --- a/solr/core/src/test/org/apache/solr/core/RequestHandlersTest.java +++ b/solr/core/src/test/org/apache/solr/core/RequestHandlersTest.java @@ -16,9 +16,12 @@ */ package org.apache.solr.core; +import com.codahale.metrics.SharedMetricRegistries; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.util.NamedList; +import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.request.SolrRequestHandler; +import org.apache.solr.util.stats.Metrics; import org.junit.BeforeClass; import org.junit.Test; @@ -108,9 +111,12 @@ public void testStatistics() { NamedList updateStats = updateHandler.getStatistics(); NamedList termStats = termHandler.getStatistics(); - Double updateTime = (Double) updateStats.get("totalTime"); - Double termTime = (Double) termStats.get("totalTime"); + Double updateTime = (Double) updateStats.get("avgTimePerRequest"); + Double termTime = (Double) termStats.get("avgTimePerRequest"); assertFalse("RequestHandlers should not share statistics!", updateTime.equals(termTime)); + + assertTrue("Named RequestHandlers should use a shared registry", + Metrics.registryFor(RequestHandlerBase.REGISTRY_NAME).getNames().contains(Metrics.mkName(updateHandler.getClass(), "/update"))); } } diff --git a/solr/core/src/test/org/apache/solr/util/stats/MetricsTest.java b/solr/core/src/test/org/apache/solr/util/stats/MetricsTest.java new file mode 100644 index 000000000000..fdb211ce5ad3 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/util/stats/MetricsTest.java @@ -0,0 +1,72 @@ +package org.apache.solr.util.stats; + +/* + * 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. + */ + +import java.io.IOException; + +import com.codahale.metrics.SharedMetricRegistries; +import org.apache.lucene.util.LuceneTestCase; +import org.junit.Test; +import com.codahale.metrics.Timer; + +public class MetricsTest extends LuceneTestCase { + + @Test + public void testSharedRegistryUse() throws IOException { + + Timer t1 = Metrics.namedTimer("timer1"); + assertTrue(SharedMetricRegistries.names().contains(Metrics.DEFAULT_REGISTRY)); + assertTrue(SharedMetricRegistries.getOrCreate(Metrics.DEFAULT_REGISTRY).getNames().contains("timer1")); + SharedMetricRegistries.getOrCreate(Metrics.DEFAULT_REGISTRY).remove("timer1"); + + Timer t2 = Metrics.namedTimer("timer2", "test"); + assertTrue( + SharedMetricRegistries.getOrCreate(Metrics.mkName(Metrics.REGISTRY_NAME_PREFIX, "test")) + .getNames().contains("timer2") + ); + SharedMetricRegistries.getOrCreate(Metrics.mkName(Metrics.REGISTRY_NAME_PREFIX, "test")).remove("timer2"); + } + + @Test + public void testOverridableSharedRegistryNaming() throws IOException { + try { + System.setProperty("solr.registry.default", "override1"); + System.setProperty("solr.registry.test", "solr.registry.override1"); + + Timer t1 = Metrics.namedTimer("timer10"); + Timer t2 = Metrics.namedTimer("timer11", "test"); + + assertTrue( + SharedMetricRegistries.getOrCreate(Metrics.mkName(Metrics.REGISTRY_NAME_PREFIX, "override1")) + .getNames().contains("timer10") + ); + assertTrue( + SharedMetricRegistries.getOrCreate(Metrics.mkName(Metrics.REGISTRY_NAME_PREFIX, "override1")) + .getNames().contains("timer11") + ); + SharedMetricRegistries.getOrCreate(Metrics.mkName(Metrics.REGISTRY_NAME_PREFIX, "override1")).remove("timer10"); + SharedMetricRegistries.getOrCreate(Metrics.mkName(Metrics.REGISTRY_NAME_PREFIX, "override1")).remove("timer11"); + + } + finally { + System.clearProperty("solr.registry.default"); + System.clearProperty("solr.registry.test"); + } + } + +}