/*
* Copyright 2012-2014 the original author or authors.
*
* 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
*
* 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.springframework.boot.actuate.metrics.rich;
import org.springframework.util.Assert;
/**
* A gauge which stores the maximum, minimum and average in addition to the current value.
* <p>
* The value of the average will depend on whether a weight ('alpha') is set for the
* gauge. If it is unset, the average will contain a simple arithmetic mean. If a weight
* is set, an exponential moving average will be calculated as defined in this
* <a href="http://www.itl.nist.gov/div898/handbook/pmc/section4/pmc431.htm">NIST
* document</a>.
*
* @author Luke Taylor
*/
public final class RichGauge {
/**
* The suffix for count gauges.
*/
public static final String COUNT = ".count";
/**
* The suffix for max gauges.
*/
public static final String MAX = ".max";
/**
* The suffix for min gauges.
*/
public static final String MIN = ".min";
/**
* The suffix for average value gauges.
*/
public static final String AVG = ".avg";
/**
* The suffix for alpha gauges.
*/
public static final String ALPHA = ".alpha";
/**
* The suffix for value gauges.
*/
public static final String VAL = ".val";
private final String name;
private double value;
private double average;
private double max;
private double min;
private long count;
private double alpha;
/**
* Creates an "empty" gauge. The average, max and min will be zero, but this initial
* value will not be included after the first value has been set on the gauge.
* @param name the name under which the gauge will be stored.
*/
public RichGauge(String name) {
this(name, 0.0);
this.count = 0;
}
public RichGauge(String name, double value) {
Assert.notNull(name, "The gauge name cannot be null or empty");
this.name = name;
this.value = value;
this.average = this.value;
this.min = this.value;
this.max = this.value;
this.alpha = -1.0;
this.count = 1;
}
public RichGauge(String name, double value, double alpha, double mean, double max,
double min, long count) {
this.name = name;
this.value = value;
this.alpha = alpha;
this.average = mean;
this.max = max;
this.min = min;
this.count = count;
}
/**
* Return the name of the gauge.
* @return the name
*/
public String getName() {
return this.name;
}
/**
* Return the current value of the gauge.
* @return the value
*/
public double getValue() {
return this.value;
}
/**
* Return either an exponential weighted moving average or a simple mean,
* respectively, depending on whether the weight 'alpha' has been set for this gauge.
* @return The average over all the accumulated values
*/
public double getAverage() {
return this.average;
}
/**
* Return the maximum value of the gauge.
* @return the maximum value
*/
public double getMax() {
return this.max;
}
/**
* Return the minimum value of the gauge.
* @return the minimum value
*/
public double getMin() {
return this.min;
}
/**
* Return the number of times the value has been set.
* @return the value set count
*/
public long getCount() {
return this.count;
}
/**
* Return the smoothing constant value.
* @return the alpha smoothing value
*/
public double getAlpha() {
return this.alpha;
}
public RichGauge setAlpha(double alpha) {
Assert.isTrue(alpha == -1 || (alpha > 0.0 && alpha < 1.0),
"Smoothing constant must be between 0 and 1, or -1 to use arithmetic mean");
this.alpha = alpha;
return this;
}
RichGauge set(double value) {
if (this.count == 0) {
this.max = value;
this.min = value;
}
else if (value > this.max) {
this.max = value;
}
else if (value < this.min) {
this.min = value;
}
if (this.alpha > 0.0 && this.count > 0) {
this.average = this.alpha * this.value + (1 - this.alpha) * this.average;
}
else {
double sum = this.average * this.count;
sum += value;
this.average = sum / (this.count + 1);
}
this.count++;
this.value = value;
return this;
}
RichGauge reset() {
this.value = 0.0;
this.max = 0.0;
this.min = 0.0;
this.average = 0.0;
this.count = 0;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RichGauge richGauge = (RichGauge) o;
if (!this.name.equals(richGauge.name)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
@Override
public String toString() {
return "Gauge [name = " + this.name + ", value = " + this.value + ", alpha = "
+ this.alpha + ", average = " + this.average + ", max = " + this.max
+ ", min = " + this.min + ", count = " + this.count + "]";
}
}