// =================================================================================================
// Copyright 2011 Twitter, Inc.
// -------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this work except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file, or 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 com.twitter.common.stats;
import com.twitter.common.stats.StatsProvider.RequestTimer;
import javax.annotation.Nullable;
import java.util.concurrent.atomic.AtomicLong;
/**
* A class to represent the statistics associated with a client connection to an external service.
* Tracks request latency/rate, and error rate.
*
* @author William Farner
*/
public class RequestStats implements RequestTimer {
private static final float DEFAULT_SAMPLE_PERCENT = 10;
private static final double[] DEFAULT_PERCENTILES = {10, 50, 90, 99, 99.9, 99.99};
private final SlidingStats requests;
private final Percentile<Long> percentile;
private final AtomicLong errors;
private final AtomicLong reconnects;
private final AtomicLong timeouts;
/**
* Creates a new request statistics object, using the default percentiles and sampling rate.
*
* @param name The unique name for this request type.
*/
public RequestStats(String name) {
this(name, new Percentile<Long>(name, DEFAULT_SAMPLE_PERCENT, DEFAULT_PERCENTILES));
}
/**
* Creates a new request statistics object using a custom percentile tracker.
*
* @param name The unique name for this request type.
* @param percentile The percentile tracker, or {@code null} to disable percentile tracking.
*/
public RequestStats(String name, @Nullable Percentile<Long> percentile) {
requests = new SlidingStats(name + "_requests", "micros");
this.percentile = percentile;
errors = Stats.exportLong(name + "_errors");
reconnects = Stats.exportLong(name + "_reconnects");
timeouts = Stats.exportLong(name + "_timeouts");
Rate<AtomicLong> requestsPerSec =
Rate.of(name + "_requests_per_sec", requests.getEventCounter()).build();
Stats.export(Ratio.of(name + "_error_rate",
Rate.of(name + "_errors_per_sec", errors).build(), requestsPerSec));
Rate<AtomicLong> timeoutsPerSec = Rate.of(name + "_timeouts_per_sec", timeouts).build();
Stats.export(timeoutsPerSec);
Stats.export(Ratio.of(name + "_timeout_rate", timeoutsPerSec, requestsPerSec));
}
public SlidingStats getSlidingStats() {
return requests;
}
public AtomicLong getErrorCounter() {
return errors;
}
public AtomicLong getReconnectCounter() {
return reconnects;
}
public AtomicLong getTimeoutCounter() {
return timeouts;
}
public Percentile<Long> getPercentile() {
return percentile;
}
/**
* Accumulates a request and its latency.
*
* @param latencyMicros The elapsed time required to complete the request.
*/
public void requestComplete(long latencyMicros) {
requests.accumulate(latencyMicros);
if (percentile != null) percentile.record(latencyMicros);
}
/**
* Accumulates the error counter and the request counter.
*/
public void incErrors() {
requestComplete(0);
errors.incrementAndGet();
}
/**
* Accumulates the error counter, the request counter and the request latency.
*
* @param latencyMicros The elapsed time before the error occurred.
*/
public void incErrors(long latencyMicros) {
requestComplete(latencyMicros);
errors.incrementAndGet();
}
/**
* Accumulates the reconnect counter.
*/
public void incReconnects() {
reconnects.incrementAndGet();
}
/**
* Accumulates the timtout counter.
*/
public void incTimeouts() {
timeouts.incrementAndGet();
}
public long getErrorCount() {
return errors.get();
}
public long getReconnectCount() {
return reconnects.get();
}
public long getTimeoutCount() {
return timeouts.get();
}
}