public interface MetricsBuilder {

    /**
     * Add a metrics record
     * 
     * @param name of the record
     * @return a metrics record builder for the record
     */
    public MetricsRecordBuilder addRecord(String name);
} public class MetricsException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    /**
     * Construct the exception with a message
     * 
     * @param message for the exception
     */
    public MetricsException(String message){
        super(message);
    }

    /**
     * Construct the exception with a message and a cause
     * 
     * @param message for the exception
     * @param cause of the exception
     */
    public MetricsException(String message, Throwable cause){
        super(message, cause);
    }

    /**
     * Construct the exception with a cause
     * 
     * @param cause of the exception
     */
    public MetricsException(Throwable cause){
        super(cause);
    }

} public abstract class MetricsFilter implements MetricsPlugin {

    public abstract void init(SubsetConfiguration conf);

    /**
     * Whether to accept the name
     * 
     * @param name to filter on
     * @return true to accept; false otherwise.
     */
    public abstract boolean accepts(String name);

    /**
     * Whether to accept the tag
     * 
     * @param tag to filter on
     * @return true to accept; false otherwise
     */
    public abstract boolean accepts(MetricsTag tag);

    /**
     * Whether to accept the tags
     * 
     * @param tags to filter on
     * @return true to accept; false otherwise
     */
    public abstract boolean accepts(Iterable<MetricsTag> tags);

    /**
     * Whether to accept the record
     * 
     * @param record to filter on
     * @return true to accept; false otherwise.
     */
    public boolean accepts(MetricsRecord record) {
        return accepts(record.tags());
    }

} public abstract class MetricsRecordBuilder {

    /**
     * Add a metrics tag
     * 
     * @param name of the tag
     * @param description of the tag
     * @param value of the tag
     * @return self
     */
    public abstract MetricsRecordBuilder tag(String name, String description, String value);

    /**
     * Add an immutable metrics tag object
     * 
     * @param tag a pre-made tag object (potentially save an object construction)
     * @return self
     */
    public abstract MetricsRecordBuilder add(MetricsTag tag);

    /**
     * Set the context tag
     * 
     * @param value of the context
     * @return self
     */
    public abstract MetricsRecordBuilder setContext(String value);

    /**
     * Add an int counter metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addCounter(String name, String description, int value);

    /**
     * Add an long counter metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addCounter(String name, String description, long value);

    /**
     * Add an int delta metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addDelta(String name, String description, int value);

    /**
     * Add an long delta metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addDelta(String name, String description, long value);

    /**
     * Add a int gauge metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addGauge(String name, String description, int value);

    /**
     * Add a long gauge metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addGauge(String name, String description, long value);

    /**
     * Add a float gauge metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addGauge(String name, String description, float value);

    /**
     * Add a double gauge metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param value of the metric
     * @return self
     */
    public abstract MetricsRecordBuilder addGauge(String name, String description, double value);

    /**
     * Add a pre-made immutable metric object
     * 
     * @param metric the pre-made metric to save an object construction
     * @return self
     */
    public abstract MetricsRecordBuilder add(Metric metric);
} public interface MetricsSink extends MetricsPlugin {

    /**
     * Put a metrics record in the sink
     * 
     * @param record the record to put
     */
    void putMetrics(MetricsRecord record);

    /**
     * Flush any buffered metrics
     */
    void flush();

} public interface MetricsSource {

    /**
     * Get metrics from the source
     * 
     * @param builder to contain the resulting metrics snapshot
     * @param all if true, return all metrics even if unchanged.
     */
    void getMetrics(MetricsBuilder builder, boolean all);
} public interface MetricsSystem extends MetricsSystemMXBean {

    /**
     * Register a metrics source
     * 
     * @param <T> the type of the source
     * @param source to register
     * @param name of the source. Must be unique.
     * @param desc the description of the source.
     * @return the source
     * @exception MetricsException
     */
    <T extends MetricsSource> T register(String name, String desc, T source);

    /**
     * Register a metrics sink
     * 
     * @param <T> the type of the sink
     * @param sink to register
     * @param name of the sink. Must be unique.
     * @param desc the description of the sink
     * @return the sink
     * @exception MetricsException
     */
    <T extends MetricsSink> T register(String name, String desc, T sink);

    /**
     * register a metrics source
     * <p>
     * if the source has registered, will return the old source.<br/>
     * if the source has not register before, will return the source
     * 
     * @since 0.5
     * @param name
     * @param desc
     * @param source
     * @return
     */
    <T extends MetricsSource> T registerIfAbsent(String name, String desc, T source);

    /**
     * register a metrics sink
     * <p>
     * if the sink has registered, will return the old sink.<br/>
     * if the sink has not register before, will return the sink
     * 
     * @since 0.5
     * @param name
     * @param desc
     * @param sink
     * @return
     */
    <T extends MetricsSink> T registerIfAbsent(String name, String desc, T sink);

    /**
     * Register a callback interface for JMX events
     * 
     * @param callback the callback object implementing the MBean interface.
     */
    void register(Callback callback);

    /**
     * Shutdown the metrics system completely (usually during server shutdown.) The MetricsSystemMXBean will be
     * unregistered.
     */
    void shutdown();

    static interface Callback {

        /**
         * Called before start()
         */
        void preStart();

        /**
         * Called after start()
         */
        void postStart();

        /**
         * Called before stop()
         */
        void preStop();

        /**
         * Called after stop()
         */
        void postStop();

    }

    public static abstract class AbstractCallback implements Callback {

        public void preStart() {
        }

        public void postStart() {
        }

        public void preStop() {
        }

        public void postStop() {
        }

    }
} public class MetricsTag {

    private final String name;
    private final String description;
    private final String value;

    /**
     * Construct the tag with name, description and value
     * 
     * @param name of the tag
     * @param description of the tag
     * @param value of the tag
     */
    public MetricsTag(String name, String description, String value){
        this.name = name;
        this.description = description;
        this.value = value;
    }

    /**
     * Get the name of the tag
     * 
     * @return the name
     */
    public String name() {
        return name;
    }

    /**
     * Get the description of the tag
     * 
     * @return the description
     */
    public String description() {
        return description;
    }

    /**
     * Get the value of the tag
     * 
     * @return the value
     */
    public String value() {
        return value;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MetricsTag other = (MetricsTag) obj;
        if (!this.name.equals(other.name())) {
            return false;
        }
        if (!this.description.equals(other.description())) {
            return false;
        }
        if (this.value == null || other.value() == null) {
            if (this.value == null && other.value() == null) return true;
            return false;
        }
        if (!this.value.equals(other.value())) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return name.hashCode() ^ (value == null ? 0 : value.hashCode());
    }

    @Override
    public String toString() {
        return "MetricsTag{" + "name='" + name + "' description='" + description + "' value='" + value + "'}";
    }

} public class MetricMutableCounterLong extends MetricMutableCounter<Long> {

    private volatile long value;

    /**
     * Construct a mutable long counter
     * 
     * @param name of the counter
     * @param description of the counter
     * @param initValue the initial value of the counter
     */
    public MetricMutableCounterLong(String name, String description, long initValue){
        super(name, description);
        this.value = initValue;
    }

    public synchronized void incr() {
        ++value;
        setChanged();
    }

    /**
     * Increment the value by a delta
     * 
     * @param delta of the increment
     */
    public synchronized void incr(long delta) {
        value += delta;
        setChanged();
    }

    public void snapshot(MetricsRecordBuilder builder, boolean all) {
        if (all || changed()) {
            builder.addCounter(name, description, value);
            clearChanged();
        }
    }

} public class MetricMutableStat extends MetricMutable {

    private final String            numSamplesName, numSamplesDesc;
    private final String            avgValueName, avgValueDesc;
    private final String            stdevValueName, stdevValueDesc;
    private final String            iMinValueName, iMinValueDesc;
    private final String            iMaxValueName, iMaxValueDesc;
    private final String            minValueName, minValueDesc;
    private final String            maxValueName, maxValueDesc;

    private final SampleStat        intervalStat = new SampleStat();
    private final SampleStat        prevStat     = new SampleStat();
    private final SampleStat.MinMax minMax       = new SampleStat.MinMax();
    private long                    numSamples   = 0;
    private boolean                 extended     = false;

    /**
     * Construct a sample statistics metric
     * 
     * @param name of the metric
     * @param description of the metric
     * @param sampleName of the metric (e.g. "ops")
     * @param valueName of the metric (e.g. "time", "latency")
     * @param extended create extended stats (stdev, min/max etc.) by default.
     */
    public MetricMutableStat(String name, String description, String sampleName, String valueName, boolean extended){
        super(name, description);
        String desc = StringUtils.uncapitalize(description);
        numSamplesName = name + "_num_" + sampleName;
        numSamplesDesc = "Number of " + sampleName + " for " + desc;
        avgValueName = name + "_avg_" + valueName;
        avgValueDesc = "Average " + valueName + " for " + desc;
        stdevValueName = name + "_stdev_" + valueName;
        stdevValueDesc = "Standard deviation of " + valueName + " for " + desc;
        iMinValueName = name + "_imin_" + valueName;
        iMinValueDesc = "Interval min " + valueName + " for " + desc;
        iMaxValueName = name + "_imax_" + valueName;
        iMaxValueDesc = "Interval max " + valueName + " for " + desc;
        minValueName = name + "_min_" + valueName;
        minValueDesc = "Min " + valueName + " for " + desc;
        maxValueName = name + "_max_" + valueName;
        maxValueDesc = "Max " + valueName + " for " + desc;
        this.extended = extended;
    }

    /**
     * Construct a snapshot stat metric with extended stat off by default
     * 
     * @param name of the metric
     * @param description of the metric
     * @param sampleName of the metric (e.g. "ops")
     * @param valueName of the metric (e.g. "time", "latency")
     */
    public MetricMutableStat(String name, String description, String sampleName, String valueName){
        this(name, description, sampleName, valueName, false);
    }

    /**
     * Add a number of samples and their sum to the running stat
     * 
     * @param numSamples number of samples
     * @param sum of the samples
     */
    public synchronized void add(long numSamples, long sum) {
        intervalStat.add(numSamples, sum);
        setChanged();
    }

    /**
     * Add a snapshot to the metric
     * 
     * @param value of the metric
     */
    public synchronized void add(long value) {
        intervalStat.add(value);
        minMax.add(value);
        setChanged();
    }

    public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) {
        if (all || changed()) {
            numSamples += intervalStat.numSamples();
            builder.addCounter(numSamplesName, numSamplesDesc, numSamples);
            builder.addGauge(avgValueName, avgValueDesc, lastStat().mean());
            if (extended) {
                builder.addGauge(stdevValueName, stdevValueDesc, lastStat().stddev());
                builder.addGauge(iMinValueName, iMinValueDesc, lastStat().min());
                builder.addGauge(iMaxValueName, iMaxValueDesc, lastStat().max());
                builder.addGauge(minValueName, minValueDesc, minMax.min());
                builder.addGauge(maxValueName, maxValueDesc, minMax.max());
            }
            if (changed()) {
                intervalStat.copyTo(prevStat);
                intervalStat.reset();
                clearChanged();
            }
        }
    }

    private SampleStat lastStat() {
        return changed() ? intervalStat : prevStat;
    }

    /**
     * Reset the all time min max of the metric
     */
    public void resetMinMax() {
        minMax.reset();
    }

} public class Contracts {

    private Contracts(){
    }

    /**
     * Check that a reference is not null.
     * 
     * @param <T> type of the reference
     * @param ref the reference to check
     * @param msg the error message
     * @throws NullPointerException if {@code ref} is null
     * @return the checked reference for convenience
     */
    public static <T> T checkNotNull(T ref, Object msg) {
        if (ref == null) {
            throw new NullPointerException(String.valueOf(msg) + ": " + ref.getClass().getName());
        }
        return ref;
    }

    /**
     * Check the state expression for false conditions
     * 
     * @param expression the boolean expression to check
     * @param msg the error message if {@code expression} is false
     * @throws IllegalStateException if {@code expression} is false
     */
    public static void checkState(boolean expression, Object msg) {
        if (!expression) {
            throw new IllegalStateException(String.valueOf(msg));
        }
    }

    /**
     * Check an argument for false conditions
     * 
     * @param <T> type of the argument
     * @param arg the argument to check
     * @param expression the boolean expression for the condition
     * @param msg the error message if {@code expression} is false
     * @return the argument for convenience
     */
    public static <T> T checkArg(T arg, boolean expression, Object msg) {
        if (!expression) {
            throw new IllegalArgumentException(String.valueOf(msg) + ": " + arg);
        }
        return arg;
    }

    /**
     * Check an argument for false conditions
     * 
     * @param arg the argument to check
     * @param expression the boolean expression for the condition
     * @param msg the error message if {@code expression} is false
     * @return the argument for convenience
     */
    public static int checkArg(int arg, boolean expression, Object msg) {
        if (!expression) {
            throw new IllegalArgumentException(String.valueOf(msg) + ": " + arg);
        }
        return arg;
    }

    /**
     * Check an argument for false conditions
     * 
     * @param arg the argument to check
     * @param expression the boolean expression for the condition
     * @param msg the error message if {@code expression} is false
     * @return the argument for convenience
     */
    public static long checkArg(long arg, boolean expression, Object msg) {
        if (!expression) {
            throw new IllegalArgumentException(String.valueOf(msg));
        }
        return arg;
    }

    /**
     * Check an argument for false conditions
     * 
     * @param arg the argument to check
     * @param expression the boolean expression for the condition
     * @param msg the error message if {@code expression} is false
     * @return the argument for convenience
     */
    public static float checkArg(float arg, boolean expression, Object msg) {
        if (!expression) {
            throw new IllegalArgumentException(String.valueOf(msg) + ": " + arg);
        }
        return arg;
    }

    /**
     * Check an argument for false conditions
     * 
     * @param arg the argument to check
     * @param expression the boolean expression for the condition
     * @param msg the error message if {@code expression} is false
     * @return the argument for convenience
     */
    public static double checkArg(double arg, boolean expression, Object msg) {
        if (!expression) {
            throw new IllegalArgumentException(String.valueOf(msg) + ": " + arg);
        }
        return arg;
    }
} public class MBeans {

    private static final Log LOG = LogFactory.getLog(MBeans.class);

    /**
     * Register the MBean using our standard MBeanName format "hadoop:service=<serviceName>,name=<nameName>" Where the
     * <serviceName> and <nameName> are the supplied parameters
     * 
     * @param serviceName
     * @param nameName
     * @param theMbean - the MBean to register
     * @return the named used to register the MBean
     */
    static public ObjectName register(String serviceName, String nameName, Object theMbean) {
        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = getMBeanName(serviceName, nameName);
        try {
            mbs.registerMBean(theMbean, name);
            return name;
        } catch (InstanceAlreadyExistsException ie) {
            LOG.warn(name, ie);
        } catch (Exception e) {
            LOG.warn("Error registering " + name, e);
        }
        return null;
    }

    static public void unregister(ObjectName mbeanName) {
        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        if (mbeanName == null) return;
        try {
            mbs.unregisterMBean(mbeanName);
        } catch (InstanceNotFoundException e) {
            LOG.warn(mbeanName, e);
        } catch (Exception e) {
            LOG.warn("Error unregistering " + mbeanName, e);
        }
    }

    static private ObjectName getMBeanName(String serviceName, String nameName) {
        ObjectName name = null;
        String nameStr = "Mushroom:service=" + serviceName + ",name=" + nameName;
        try {
            name = new ObjectName(nameStr);
        } catch (MalformedObjectNameException e) {
            LOG.warn("Error creating MBean object name: " + nameStr, e);
        }
        return name;
    }

}
import java.io.StringWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import javax.management.ObjectName;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.math.util.MathUtils;
import com.zavakid.mushroom.MetricsBuilder;
import com.zavakid.mushroom.MetricsException;
import com.zavakid.mushroom.MetricsFilter;
import com.zavakid.mushroom.MetricsRecordBuilder;
import com.zavakid.mushroom.MetricsSink;
import com.zavakid.mushroom.MetricsSource;
import com.zavakid.mushroom.MetricsSystem;
import com.zavakid.mushroom.MetricsTag;
import com.zavakid.mushroom.lib.MetricMutableCounterLong;
import com.zavakid.mushroom.lib.MetricMutableStat;
import com.zavakid.mushroom.util.Contracts;
import com.zavakid.mushroom.util.MBeans;
/**
   Copyright [2013] [Mushroom]

   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.
 */
/**
 Notice : this source is extracted from Hadoop metric2 package
 and some source code may changed by zavakid
 */
package com.zavakid.mushroom.impl;





/**
 * A base class for metrics system singletons
 * 
 * @author Hadoop metric2 package's authors
 * @since 0.1
 */
public class MetricsSystemImpl implements MetricsSystem {

    private static final Log                        LOG                = LogFactory.getLog(MetricsSystemImpl.class);

    static final String                             MS_CONTEXT         = "metricssystem";
    static final String                             NUM_SOURCES_KEY    = "num_sources";
    static final String                             NUM_SOURCES_DESC   = "Number of metrics sources";
    static final String                             NUM_SINKS_KEY      = "num_sinks";
    static final String                             NUM_SINKS_DESC     = "Number of metrics sinks";
    static final String                             MS_NAME            = "MetricsSystem";
    static final String                             MS_STATS_NAME      = MS_NAME + ",sub=Stats";
    static final String                             MS_STATS_DESC      = "Metrics system metrics";
    static final String                             MS_CONTROL_NAME    = MS_NAME + ",sub=Control";

    private final Map<String, MetricsSourceAdapter> sources;
    private final Map<String, MetricsSinkAdapter>   sinks;
    private final List<Callback>                    callbacks;
    private final MetricsBuilderImpl                metricsBuilder;
    private final MetricMutableStat                 snapshotStat       = new MetricMutableStat("snapshot",
                                                                                               "snapshot stats", "ops",
                                                                                               "time", true);
    private final MetricMutableStat                 publishStat        = new MetricMutableStat("publish",
                                                                                               "publishing stats",
                                                                                               "ops", "time", true);
    private final MetricMutableCounterLong          dropStat           = new MetricMutableCounterLong(
                                                                                                      "dropped_pub_all",
                                                                                                      "number of dropped updates by all sinks",
                                                                                                      0L);
    private final List<MetricsTag>                  injectedTags;
    // Things that are changed by init()/start()/stop()
    private String                                  prefix;
    private MetricsFilter                           sourceFilter;