/** * Copyright 2013 Netflix, Inc. * <p/> * Licensed 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.netflix.servo.stats; import java.util.Arrays; /** * Configuration options for a {@link com.netflix.servo.monitor.StatsTimer} * <p/> * By default we publish count (number of times the timer was executed), totalTime, and * 95.0, and 99.0 percentiles. * <p/> * The size for the buffer used to store samples is controlled using the sampleSize field, * and the frequency * at which stats are computed is controlled with the computeFrequencyMillis option. * By default these are * set to 100,000 entries in the buffer, and computation at 60,000 ms (1 minute) intervals. */ public final class StatsConfig { private static final String CLASS_NAME = StatsConfig.class.getCanonicalName(); private static final String SIZE_PROP = CLASS_NAME + ".sampleSize"; private static final String FREQ_PROP = CLASS_NAME + ".computeFreqMillis"; /** * Builder for StatsConfig. By default the configuration includes count, * total and 95th and 99th percentiles. */ public static class Builder { private boolean publishCount = true; private boolean publishTotal = true; private boolean publishMin = false; private boolean publishMax = false; private boolean publishMean = false; private boolean publishVariance = false; private boolean publishStdDev = false; private int sampleSize = Integer.parseInt(System.getProperty(SIZE_PROP, "1000")); private long frequencyMillis = Long.parseLong(System.getProperty(FREQ_PROP, "60000")); private double[] percentiles = {95.0, 99.0}; /** * Whether to publish count or not. */ public Builder withPublishCount(boolean publishCount) { this.publishCount = publishCount; return this; } /** * Whether to publish total or not. */ public Builder withPublishTotal(boolean publishTotal) { this.publishTotal = publishTotal; return this; } /** * Whether to publish min or not. */ public Builder withPublishMin(boolean publishMin) { this.publishMin = publishMin; return this; } /** * Whether to publish max or not. */ public Builder withPublishMax(boolean publishMax) { this.publishMax = publishMax; return this; } /** * Whether to publish an average statistic or not. Note that if you plan * to aggregate the values reported (for example across a cluster of nodes) you probably do * not want to publish the average per node, and instead want to compute it by publishing * total and count. */ public Builder withPublishMean(boolean publishMean) { this.publishMean = publishMean; return this; } /** * Whether to publish variance or not. */ public Builder withPublishVariance(boolean publishVariance) { this.publishVariance = publishVariance; return this; } /** * Whether to publish standard deviation or not. */ public Builder withPublishStdDev(boolean publishStdDev) { this.publishStdDev = publishStdDev; return this; } /** * Set the percentiles to compute. * * @param percentiles An array of doubles describing which percentiles to compute. For * example {@code {95.0, 99.0}} */ public Builder withPercentiles(double[] percentiles) { this.percentiles = Arrays.copyOf(percentiles, percentiles.length); return this; } /** * Set the sample size. */ public Builder withSampleSize(int size) { this.sampleSize = size; return this; } /** * How often to compute the statistics. Usually this will be set to the main * poller interval. (Default is 60s.) */ public Builder withComputeFrequencyMillis(long frequencyMillis) { this.frequencyMillis = frequencyMillis; return this; } /** * Create a new StatsConfig object. */ public StatsConfig build() { return new StatsConfig(this); } } private final boolean publishCount; private final boolean publishTotal; private final boolean publishMin; private final boolean publishMax; private final boolean publishMean; private final boolean publishVariance; private final boolean publishStdDev; private final double[] percentiles; private final int sampleSize; private final long frequencyMillis; /** * Creates a new configuration object for stats gathering. */ public StatsConfig(Builder builder) { this.publishCount = builder.publishCount; this.publishTotal = builder.publishTotal; this.publishMin = builder.publishMin; this.publishMax = builder.publishMax; this.publishMean = builder.publishMean; this.publishVariance = builder.publishVariance; this.publishStdDev = builder.publishStdDev; this.sampleSize = builder.sampleSize; this.frequencyMillis = builder.frequencyMillis; this.percentiles = Arrays.copyOf(builder.percentiles, builder.percentiles.length); } /** * Whether we should publish a 'count' statistic. */ public boolean getPublishCount() { return publishCount; } /** * Whether we should publish a 'totalTime' statistic. */ public boolean getPublishTotal() { return publishTotal; } /** * Whether we should publish a 'min' statistic. */ public boolean getPublishMin() { return publishMin; } /** * Whether we should publish a 'max' statistic. */ public boolean getPublishMax() { return publishMax; } /** * Whether we should publish an 'avg' statistic. */ public boolean getPublishMean() { return publishMean; } /** * Whether we should publish a 'variance' statistic. */ public boolean getPublishVariance() { return publishVariance; } /** * Whether we should publish a 'stdDev' statistic. */ public boolean getPublishStdDev() { return publishStdDev; } /** * Get the size of the buffer that we should use. */ public int getSampleSize() { return sampleSize; } /** * Get the frequency at which we should update all stats. */ public long getFrequencyMillis() { return frequencyMillis; } /** * Get a copy of the array that holds which percentiles we should compute. The percentiles * are in the interval (0.0, 100.0) */ public double[] getPercentiles() { return Arrays.copyOf(percentiles, percentiles.length); } /** * {@inheritDoc} */ @Override public String toString() { return "StatsConfig{" + "publishCount=" + publishCount + ", publishTotal=" + publishTotal + ", publishMin=" + publishMin + ", publishMax=" + publishMax + ", publishMean=" + publishMean + ", publishVariance=" + publishVariance + ", publishStdDev=" + publishStdDev + ", percentiles=" + Arrays.toString(percentiles) + ", sampleSize=" + sampleSize + ", frequencyMillis=" + frequencyMillis + '}'; } /** * {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof StatsConfig)) { return false; } final StatsConfig that = (StatsConfig) o; return frequencyMillis == that.frequencyMillis && publishCount == that.publishCount && publishMax == that.publishMax && publishMean == that.publishMean && publishMin == that.publishMin && publishStdDev == that.publishStdDev && publishTotal == that.publishTotal && publishVariance == that.publishVariance && sampleSize == that.sampleSize && Arrays.equals(percentiles, that.percentiles); } /** * {@inheritDoc} */ @Override public int hashCode() { int result = (publishCount ? 1 : 0); result = 31 * result + (publishTotal ? 1 : 0); result = 31 * result + (publishMin ? 1 : 0); result = 31 * result + (publishMax ? 1 : 0); result = 31 * result + (publishMean ? 1 : 0); result = 31 * result + (publishVariance ? 1 : 0); result = 31 * result + (publishStdDev ? 1 : 0); result = 31 * result + Arrays.hashCode(percentiles); result = 31 * result + sampleSize; result = 31 * result + (int) (frequencyMillis ^ (frequencyMillis >>> 32)); return result; } }