com.twitter.common.metrics.Metrics.java Source code

Java tutorial

Introduction

Here is the source code for com.twitter.common.metrics.Metrics.java

Source

// =================================================================================================
// Copyright 2013 Twitter, Inc.
// -------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this work except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file, or 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 com.twitter.common.metrics;

import java.util.Map;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import com.twitter.jsr166e.LongAdder;

/**
 * Root metric registry.
 */
public final class Metrics implements MetricRegistry, MetricProvider {
    private static final Metrics ROOT = new Metrics();

    private final Map<String, Gauge<?>> gauges = Maps.newConcurrentMap();
    private final Map<String, LongAdder> counters = Maps.newConcurrentMap();
    private final Map<String, HistogramInterface> histograms = Maps.newConcurrentMap();

    private Metrics() {
    }

    private void checkNameCollision(String key) {
        if (gauges.containsKey(key) || counters.containsKey(key) || counters.containsKey(key)) {
            throw new MetricCollisionException("A metric with the name " + key + " has already been defined");
        }
    }

    /**
     * Create a new Metrics detached from the static root.
     *
     * @return the detached metric registry.
     */
    public static Metrics createDetached() {
        return new Metrics();
    }

    /**
     * Returns a handle to the root metric registry.
     *
     * @return Root metric registry.
     */
    public static Metrics root() {
        return ROOT;
    }

    @Override
    public MetricRegistry scope(String name) {
        return new ScopedRegistry(this, name);
    }

    @Override
    public <T extends Number> void register(Gauge<T> gauge) {
        registerGauge(gauge);
    }

    @Override
    public synchronized <T extends Number> Gauge<T> registerGauge(Gauge<T> gauge) {
        String key = gauge.getName();
        checkNameCollision(key);
        gauges.put(key, gauge);
        return gauge;
    }

    @Override
    public synchronized boolean unregister(Gauge<?> gauge) {
        String key = gauge.getName();
        return gauges.remove(key) != null;
    }

    @Override
    public Counter registerCounter(String name) {
        return createCounter(name);
    }

    @Override
    public synchronized Counter createCounter(final String name) {
        final LongAdder adder = new LongAdder();
        checkNameCollision(name);
        counters.put(name, adder);
        return new Counter() {
            public String getName() {
                return name;
            }

            public void increment() {
                adder.increment();
            }

            public void add(long n) {
                adder.add(n);
            }
        };
    }

    @Override
    public synchronized boolean unregister(Counter counter) {
        String key = counter.getName();
        return counters.remove(key) != null;
    }

    @Override
    public HistogramInterface createHistogram(String name) {
        return registerHistogram(new Histogram(name));
    }

    @Override
    public synchronized HistogramInterface registerHistogram(HistogramInterface histogram) {
        String key = histogram.getName();
        checkNameCollision(key);
        histograms.put(key, histogram);
        return histogram;
    }

    @Override
    public synchronized boolean unregister(HistogramInterface histogram) {
        String key = histogram.getName();
        return histograms.remove(key) != null;
    }

    @Override
    public synchronized boolean unregister(String metricName) {
        return gauges.remove(metricName) != null || counters.remove(metricName) != null
                || histograms.remove(metricName) != null;
    }

    @Override
    public Map<String, Number> sampleGauges() {
        ImmutableMap.Builder<String, Number> samples = ImmutableMap.builder();
        for (Map.Entry<String, Gauge<?>> metric : gauges.entrySet()) {
            Gauge<?> gauge = metric.getValue();
            samples.put(metric.getKey(), gauge.read());
        }
        return samples.build();
    }

    @Override
    public Map<String, Number> sampleCounters() {
        ImmutableMap.Builder<String, Number> samples = ImmutableMap.builder();
        for (Map.Entry<String, LongAdder> metric : counters.entrySet()) {
            samples.put(metric.getKey(), metric.getValue().sum());
        }
        return samples.build();
    }

    @Override
    public Map<String, Snapshot> sampleHistograms() {
        ImmutableMap.Builder<String, Snapshot> samples = ImmutableMap.builder();
        for (HistogramInterface h : histograms.values()) {
            Snapshot snapshot = h.snapshot();
            samples.put(h.getName(), snapshot);
        }
        return samples.build();
    }

    @Override
    public Map<String, Number> sample() {
        ImmutableMap.Builder<String, Number> samples = ImmutableMap.builder();
        samples.putAll(sampleGauges());
        samples.putAll(sampleCounters());
        for (Map.Entry<String, Snapshot> entry : sampleHistograms().entrySet()) {
            String name = entry.getKey();
            Snapshot snapshot = entry.getValue();
            samples.put(named(name, "count"), snapshot.count());
            samples.put(named(name, "sum"), snapshot.sum());
            samples.put(named(name, "avg"), snapshot.avg());
            samples.put(named(name, "min"), snapshot.min());
            samples.put(named(name, "max"), snapshot.max());
            samples.put(named(name, "stddev"), snapshot.stddev());
            for (Percentile p : snapshot.percentiles()) {
                String percentileName = named(name, gaugeName(p.getQuantile()));
                samples.put(percentileName, p.getValue());
            }
        }
        return samples.build();
    }

    private static String named(String histogramName, String statName) {
        return histogramName + ScopedRegistry.DEFAULT_SCOPE_DELIMITER + statName;
    }

    private static String gaugeName(double quantile) {
        String gname = "p" + (int) (quantile * 10000);
        if (3 < gname.length() && "00".equals(gname.substring(3))) {
            gname = gname.substring(0, 3);
        }
        return gname;
    }
}