co.cask.cdap.common.metrics.CMetrics.java Source code

Java tutorial

Introduction

Here is the source code for co.cask.cdap.common.metrics.CMetrics.java

Source

/*
 * Copyright  2014 Cask Data, Inc.
 *
 * 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 co.cask.cdap.common.metrics;

import com.google.common.collect.Maps;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Counter;
import com.yammer.metrics.core.Gauge;
import com.yammer.metrics.core.Histogram;
import com.yammer.metrics.core.Meter;
import com.yammer.metrics.core.Metric;
import com.yammer.metrics.core.MetricName;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * A simple API for translating the metrics collected for specific
 * groups in the systems into yammer metrics. It's more like an
 * adapter that simplifies our process.
 *
 * It current supports {@link Counter} and {@link Gauge}.
 */
public class CMetrics {
    /**
     * Type of metric the {@link CMetrics} is responsible for collecting.
     */
    private final MetricType metricType;

    /**
     * Mapping of metric name to it's equivalent yammer metric counters.
     */
    private Map<String, Counter> counters;

    /**
     * Mapping of metric name to it's equivalent yammer gauge.
     */
    private Map<String, Gauge> gauges;

    /**
     * Mapping of metric name to it's equivalent meters measuring rates.
     */
    private Map<String, Meter> meters;

    /**
     * Mapping of metric name to their histograms being tracked.
     */
    private Map<String, Histogram> histograms;

    /**
     * Specifies the group the metrics are collected for.
     */
    private final String metricGroup;

    /**
     * Constructor specifying the type of metric as specified by
     * the {@link MetricType} and the group the metrics belong to.
     *
     * @param metricType collected
     * @param metricGroup the metrics being collected belong to.
     */
    public CMetrics(MetricType metricType, String metricGroup) throws IllegalArgumentException {

        // if a metric type is user or system flow metric then metric
        // group has be valid.
        if (metricType == MetricType.FlowSystem || metricType == MetricType.FlowUser) {
            if (metricGroup == null || metricGroup.isEmpty()) {
                throw new IllegalArgumentException("Metric group cannot be empty or null " + "for a flow metric.");
            }
        }

        this.metricType = metricType;
        this.metricGroup = metricGroup;
        this.counters = Maps.newConcurrentMap();
        this.gauges = Maps.newConcurrentMap();
        this.meters = Maps.newConcurrentMap();
        this.histograms = Maps.newConcurrentMap();
    }

    public CMetrics(MetricType metricType) throws IllegalArgumentException {
        this(metricType, "");
    }

    /**
     * Increments a given metric counter.
     *
     * @param metricName name of the metric.
     * @param value to increment the metric by.
     */
    public void counter(String metricName, long value) {
        counter(null, metricName, value);
    }

    /**
     * Increments a given metric counter.
     *
     * @param scope of the metric being measured.
     * @param metricName name of the metric.
     * @param value to increment the metric by.
     */
    public void counter(Class<?> scope, String metricName, long value) {
        if (!counters.containsKey(metricName)) {
            MetricName name = getMetricName(scope, metricName);
            counters.put(metricName, Metrics.newCounter(name));
        }
        counters.get(metricName).inc(value);
    }

    /**
     * Creates metric name.
     * @param metricName  the name of the {@link Metric}
     * @param scope the scope of the {@link Metric}
     * @return instance of {@link MetricName}
     */
    protected MetricName getMetricName(Class<?> scope, String metricName) {
        return new MetricName(metricGroup, metricType.name(), metricName, scope == null ? null : getScope(scope));
    }

    /**
     * Sets a gauge to be measured.
     *
     * @param metricName name of the metric.
     * @param value to be associated with the metric.
     */
    public void set(String metricName, final float value) {
        if (!gauges.containsKey(metricName)) {
            MetricName name = getMetricName(null, metricName);
            gauges.put(metricName, Metrics.newGauge(name, new Gauge<Float>() {
                @Override
                public Float value() {
                    return value;
                }
            }));
        }
    }

    /**
     * Measures the rate of events over time. E.g. Requests per second.
     * It also allows to track mean rate, 1,5, 15 minute moving averages.
     *
     * @param metricName name of the metric.
     * @param value to increment the meter by.
     */
    public void meter(String metricName, long value) {
        meter(null, metricName, value);
    }

    /**
     * Measures the rate of events over time for a metric within a
     * given scope of package.
     *
     * @param scope within which the metric is measured. This is essentially a tag.
     * @param metricName name of the metric.
     * @param value to increment the meter by.
     */
    public void meter(Class<?> scope, String metricName, long value) {
        if (!meters.containsKey(metricName)) {
            MetricName name = getMetricName(scope, metricName);
            meters.put(metricName, Metrics.newMeter(name, metricName, TimeUnit.SECONDS));
        }
        meters.get(metricName).mark(value);
    }

    /**
     * Measures the statistical distribution of values in a stream of
     * data. It measure min, max and mean and in addition also can measure
     * median, 75th, 90th, 95th, 98th, 99th and 99.9th percentiles.
     *
     * @param metricName name of the metric.
     * @param value to be used for histogram.
     */
    public void histogram(String metricName, long value) {
        histogram(null, metricName, value);
    }

    /**
     * Measures the statistical distribution of values in a stream of
     * data. It measure min, max and mean and in addition also can measure
     * median, 75th, 90th, 95th, 98th, 99th and 99.9th percentiles.
     *
     * @param scope of the metric being measured.
     * @param metricName name of the metric.
     * @param value to be used for histogram.
     */
    public void histogram(Class<?> scope, String metricName, long value) {
        if (!histograms.containsKey(metricName)) {
            MetricName name = getMetricName(scope, metricName);
            histograms.put(metricName, Metrics.newHistogram(name));
        }
        histograms.get(metricName).update(value);
    }

    /**
     * Returns the scope based on the class specified.
     *
     * @param klass specified by class.
     * @return String representation of the scope.
     */
    private String getScope(Class<?> klass) {
        return klass.getCanonicalName();
    }

}