001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.metrics2.lib;
020    
021    import org.apache.commons.lang.StringUtils;
022    import org.apache.hadoop.classification.InterfaceAudience;
023    import org.apache.hadoop.classification.InterfaceStability;
024    import org.apache.hadoop.metrics2.MetricsInfo;
025    import org.apache.hadoop.metrics2.MetricsRecordBuilder;
026    import org.apache.hadoop.metrics2.util.SampleStat;
027    import static org.apache.hadoop.metrics2.lib.Interns.*;
028    
029    /**
030     * A mutable metric with stats.
031     *
032     * Useful for keeping throughput/latency stats.
033     */
034    @InterfaceAudience.Public
035    @InterfaceStability.Evolving
036    public class MutableStat extends MutableMetric {
037      private final MetricsInfo numInfo;
038      private final MetricsInfo avgInfo;
039      private final MetricsInfo stdevInfo;
040      private final MetricsInfo iMinInfo;
041      private final MetricsInfo iMaxInfo;
042      private final MetricsInfo minInfo;
043      private final MetricsInfo maxInfo;
044    
045      private final SampleStat intervalStat = new SampleStat();
046      private final SampleStat prevStat = new SampleStat();
047      private final SampleStat.MinMax minMax = new SampleStat.MinMax();
048      private long numSamples = 0;
049      private boolean extended = false;
050    
051      /**
052       * Construct a sample statistics metric
053       * @param name        of the metric
054       * @param description of the metric
055       * @param sampleName  of the metric (e.g. "Ops")
056       * @param valueName   of the metric (e.g. "Time", "Latency")
057       * @param extended    create extended stats (stdev, min/max etc.) by default.
058       */
059      public MutableStat(String name, String description,
060                         String sampleName, String valueName, boolean extended) {
061        String ucName = StringUtils.capitalize(name);
062        String usName = StringUtils.capitalize(sampleName);
063        String uvName = StringUtils.capitalize(valueName);
064        String desc = StringUtils.uncapitalize(description);
065        String lsName = StringUtils.uncapitalize(sampleName);
066        String lvName = StringUtils.uncapitalize(valueName);
067        numInfo = info(ucName +"Num"+ usName, "Number of "+ lsName +" for "+ desc);
068        avgInfo = info(ucName +"Avg"+ uvName, "Average "+ lvName +" for "+ desc);
069        stdevInfo = info(ucName +"Stdev"+ uvName,
070                         "Standard deviation of "+ lvName +" for "+ desc);
071        iMinInfo = info(ucName +"IMin"+ uvName,
072                        "Interval min "+ lvName +" for "+ desc);
073        iMaxInfo = info(ucName + "IMax"+ uvName,
074                        "Interval max "+ lvName +" for "+ desc);
075        minInfo = info(ucName +"Min"+ uvName, "Min "+ lvName +" for "+ desc);
076        maxInfo = info(ucName +"Max"+ uvName, "Max "+ lvName +" for "+ desc);
077        this.extended = extended;
078      }
079    
080      /**
081       * Construct a snapshot stat metric with extended stat off by default
082       * @param name        of the metric
083       * @param description of the metric
084       * @param sampleName  of the metric (e.g. "Ops")
085       * @param valueName   of the metric (e.g. "Time", "Latency")
086       */
087      public MutableStat(String name, String description,
088                         String sampleName, String valueName) {
089        this(name, description, sampleName, valueName, false);
090      }
091    
092      /**
093       * Add a number of samples and their sum to the running stat
094       * @param numSamples  number of samples
095       * @param sum of the samples
096       */
097      public synchronized void add(long numSamples, long sum) {
098        intervalStat.add(numSamples, sum);
099        setChanged();
100      }
101    
102      /**
103       * Add a snapshot to the metric
104       * @param value of the metric
105       */
106      public synchronized void add(long value) {
107        intervalStat.add(value);
108        minMax.add(value);
109        setChanged();
110      }
111    
112      public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) {
113        if (all || changed()) {
114          numSamples += intervalStat.numSamples();
115          builder.addCounter(numInfo, numSamples)
116                 .addGauge(avgInfo, lastStat().mean());
117          if (extended) {
118            builder.addGauge(stdevInfo, lastStat().stddev())
119                   .addGauge(iMinInfo, lastStat().min())
120                   .addGauge(iMaxInfo, lastStat().max())
121                   .addGauge(minInfo, minMax.min())
122                   .addGauge(maxInfo, minMax.max());
123          }
124          if (changed()) {
125            if (numSamples > 0) {
126              intervalStat.copyTo(prevStat);
127              intervalStat.reset();
128            }
129            clearChanged();
130          }
131        }
132      }
133    
134      private SampleStat lastStat() {
135        return changed() ? intervalStat : prevStat;
136      }
137    
138      /**
139       * Reset the all time min max of the metric
140       */
141      public void resetMinMax() {
142        minMax.reset();
143      }
144    
145    }