All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.signalfx.codahale.util.BasicJvmMetrics Maven / Gradle / Ivy

There is a newer version: 1.0.43
Show newest version
/**
 * Copyright (C) 2014 SignalFx, Inc.
 */
package com.signalfx.codahale.util;


import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;


/**
 * Report a basic set of JVM metrics to SignalFx.
 *
 * @author psi
 *
 */
public class BasicJvmMetrics {
    /**
     * Report JVM uptime (milliseconds).
     */
    public final Gauge uptimeGauge;
    /**
     * Reports total memory used by the JVM heap (bytes).
     */
    public final Gauge totalMemoryGauge;
    /**
     * Reports current in-use memory in the JVP heap (bytes).
     */
    public final Gauge usedMemoryGauge;
    /**
     * Reports maximum size of JVM heap (bytes).
     */
    public final Gauge maxMemoryGauge;
    /**
     * Reports current CPU load (percent, normalized by number of CPUs available to the JVM.
     */
    public final Gauge cpuLoadGauge;
    /**
     * Reports total number of user and daemon threads.
     */
    public final Gauge totalThreadCountGauge;
    /**
     * Reports number of daemon threads.
     */
    public final Gauge daemonThreadCountGauge;
    /**
     * Reports total time spent in garbage collection (nanoseconds).
     */
    public final Gauge gcTimeGauge;
    /**
     * Reports number of young-generation garbage collections.
     */
    public final Gauge gcYoungCountGauge;
    /**
     * Reports number of old-generation garbage collections.
     */
    public final Gauge gcOldCountGauge;
    /**
     * Reports current GC load (percent, normalized by number of CPUs available to the JVM.
     */
    public final Gauge gcLoadGauge;

    private final RuntimeMXBean runtimeBean;
    private final MemoryMXBean memoryBean;
    private final ThreadMXBean threadBean;
    private final List oldGenGcBeans = new ArrayList();
    private final List youngGenGcBeans = new ArrayList();
    private final List allGcBeans = new ArrayList();

    // observed name of the old generation memory pool.
    private static final String OLD_GEN_POOL_NAME = "PS Old Gen";

    /**
     * Construct the basic JVM metrics using a supplied SignalFx MetricFactory.
     *
     * @param metricRegistry The registry to give these metrics to
     */
    public BasicJvmMetrics(MetricRegistry metricRegistry) {

        runtimeBean = ManagementFactory.getRuntimeMXBean();
        memoryBean = ManagementFactory.getMemoryMXBean();
        threadBean = ManagementFactory.getThreadMXBean();

        for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
            allGcBeans.add(gcBean);

            Set poolNames = new HashSet(Arrays.asList(gcBean.getMemoryPoolNames()));

            if (poolNames.contains(OLD_GEN_POOL_NAME)) {
                // We'll count garbage collectors managing the OLD_GEN_POOL_NAME as 'old generation'
                oldGenGcBeans.add(gcBean);
            } else {
                // and all others as 'young generation'
                youngGenGcBeans.add(gcBean);
            }
        }

        this.uptimeGauge = createPeriodicGauge(metricRegistry, "jvm.uptime", new UptimeCallback());

        this.totalMemoryGauge = createPeriodicGauge(metricRegistry, "jvm.heap.size",
            new TotalMemoryCallback());

        this.usedMemoryGauge = createPeriodicGauge(metricRegistry, "jvm.heap.used",
            new UsedMemoryCallback());

        this.maxMemoryGauge = createPeriodicGauge(metricRegistry, "jvm.heap.max",
            new MaxMemoryCallback());

        this.cpuLoadGauge = createDoublePeriodicGauge(metricRegistry, "jvm.cpu.load", new CpuLoadCallback());

        this.totalThreadCountGauge = createIntegerPeriodicGauge(metricRegistry, "jvm.threads.total",
            new TotalThreadCountCallback());

        this.daemonThreadCountGauge = createIntegerPeriodicGauge(metricRegistry, "jvm.threads.daemon",
            new DaemonThreadCountCallback());

        this.gcTimeGauge = createPeriodicGauge(metricRegistry, "jvm.gc.time", new GcTimeCallback());

        this.gcLoadGauge = createDoublePeriodicGauge(metricRegistry, "jvm.gc.load", new GcLoadCallback());

        this.gcYoungCountGauge = createPeriodicGauge(metricRegistry, "jvm.gc.young.count",
            new GcCountCallback(youngGenGcBeans));

        this.gcOldCountGauge = createPeriodicGauge(metricRegistry, "jvm.gc.old.count",
            new GcCountCallback(oldGenGcBeans));
    }

    private Gauge createPeriodicGauge(MetricRegistry metricRegistry, String name,
                                              Gauge gauge) {
        return metricRegistry.register(name, gauge);
    }

    private Gauge createIntegerPeriodicGauge(MetricRegistry metricRegistry, String name,
            Gauge gauge) {
        return metricRegistry.register(name, gauge);
    }

    private Gauge createDoublePeriodicGauge(MetricRegistry metricRegistry, String name,
                                              Gauge gauge) {
        return metricRegistry.register(name, gauge);
    }

    private class UptimeCallback implements Gauge {
        @Override
        public Long getValue() {
            return runtimeBean.getUptime();
        }
    }

    private class TotalMemoryCallback implements Gauge {
        @Override
        public Long getValue() {
            return memoryBean.getHeapMemoryUsage().getCommitted();
        }
    }

    private class UsedMemoryCallback implements Gauge {
        @Override
        public Long getValue() {
            return memoryBean.getHeapMemoryUsage().getUsed();
        }
    }

    private class MaxMemoryCallback implements Gauge {
        @Override
        public Long getValue() {
            return memoryBean.getHeapMemoryUsage().getMax();
        }
    }

    private class TotalThreadCountCallback implements Gauge {
        @Override
        public Integer getValue() {
            return threadBean.getThreadCount();
        }
    }

    private class DaemonThreadCountCallback implements Gauge {
        @Override
        public Integer getValue() {
            return threadBean.getDaemonThreadCount();
        }
    }

    private class GcTimeCallback implements Gauge {
        @Override
        public Long getValue() {
            long total = 0;
            for (GarbageCollectorMXBean gcBean : allGcBeans) {
                long sample = gcBean.getCollectionTime();
                if (sample > 0) {
                    total += sample;
                }
            }
            return total;
        }
    }

    private static class GcCountCallback implements Gauge {
        final private List gcBeans;

        private GcCountCallback(List gcBeans) {
            this.gcBeans = gcBeans;
        }

        @Override
        public Long getValue() {
            long total = 0;
            for (GarbageCollectorMXBean gcBean : gcBeans) {
                long sample = gcBean.getCollectionCount();
                if (sample > 0) {
                    total += sample;
                }
            }
            return total;
        }
    }

    private abstract class LoadCallback implements Gauge {
        private static final int PERCENT = 100;

        private long previousTime;
        private double previousValue;
        private Map samples = new HashMap();
        private final TimeUnit timeUnit;

        LoadCallback(TimeUnit timeUnit) {
            this.previousTime = 0;
            this.previousValue = 0;
            this.timeUnit = timeUnit;
        }

        protected abstract Map getSamples();

        private long computeDelta(Map newSamples) {
            long delta = 0;

            for (Map.Entry entry : newSamples.entrySet()) {
                T key = entry.getKey();
                Long sample = entry.getValue();
                if (sample < 0) {
                    // not valid for this key
                } else {
                    Long previous = samples.get(key);
                    if (previous == null) {
                        delta += sample;  // first sample
                    } else {
                        delta += sample - previous;
                    }
                }
            }
            samples = newSamples;

            return delta;
        }

        @Override
        public Double getValue() {
            long time = runtimeBean.getUptime();
            long deltaTime = time - previousTime;

            if (deltaTime < 100) {
                return previousValue;
            }

            Map samples = getSamples();

            long deltaLoad = computeDelta(samples);

            previousValue = (double) PERCENT * timeUnit.toNanos(deltaLoad)
                / TimeUnit.MILLISECONDS.toNanos(deltaTime)
                / Runtime.getRuntime().availableProcessors();

            previousTime = time;

            return previousValue;
        }
    }

    // com.sun.management.OperatingSystemMXBean has a getProcessCpuTime()
    // but java.lang.management.OperatingSystemMXBean does not
    private class CpuLoadCallback extends LoadCallback {
        CpuLoadCallback() {
            super(TimeUnit.NANOSECONDS);
        }

        @Override
        protected Map getSamples() {
            Map samples = new HashMap();
            for (long threadId : threadBean.getAllThreadIds()) {
                samples.put(threadId, threadBean.getThreadCpuTime(threadId));
            }
            return samples;
        }
    }

    // factor stuff out of this and CpuLoadCallback
    private class GcLoadCallback extends LoadCallback {
        GcLoadCallback() {
            super(TimeUnit.MILLISECONDS);
        }

        @Override
        protected Map getSamples() {
            Map samples = new HashMap();
            for (GarbageCollectorMXBean gcBean : allGcBeans) {
                samples.put(gcBean.getName(), gcBean.getCollectionTime());
            }
            return samples;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy