Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.hadoop.metrics2.source; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.lang.management.GarbageCollectorMXBean; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.log.metrics.EventCounter; import org.apache.hadoop.metrics2.MetricsCollector; import org.apache.hadoop.metrics2.MetricsInfo; import org.apache.hadoop.metrics2.MetricsRecordBuilder; import org.apache.hadoop.metrics2.MetricsSource; import org.apache.hadoop.metrics2.MetricsSystem; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.metrics2.lib.Interns; import static org.apache.hadoop.metrics2.source.JvmMetricsInfo.*; import static org.apache.hadoop.metrics2.impl.MsInfo.*; import org.apache.hadoop.util.GcTimeMonitor; import org.apache.hadoop.util.JvmPauseMonitor; /** * JVM and logging related metrics. * Mostly used by various servers as a part of the metrics they export. */ @InterfaceAudience.Private public class JvmMetrics implements MetricsSource { enum Singleton { INSTANCE; JvmMetrics impl; synchronized JvmMetrics init(String processName, String sessionId) { if (impl == null) { impl = create(processName, sessionId, DefaultMetricsSystem.instance()); } return impl; } synchronized void shutdown() { DefaultMetricsSystem.instance().unregisterSource(JvmMetrics.name()); impl = null; } } @VisibleForTesting public synchronized void registerIfNeeded() { // during tests impl might exist, but is not registered MetricsSystem ms = DefaultMetricsSystem.instance(); if (ms.getSource("JvmMetrics") == null) { ms.register(JvmMetrics.name(), JvmMetrics.description(), this); } } static final float M = 1024 * 1024; static public final float MEMORY_MAX_UNLIMITED_MB = -1; final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); final List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); final String processName, sessionId; private JvmPauseMonitor pauseMonitor = null; final ConcurrentHashMap<String, MetricsInfo[]> gcInfoCache = new ConcurrentHashMap<String, MetricsInfo[]>(); private GcTimeMonitor gcTimeMonitor = null; @VisibleForTesting JvmMetrics(String processName, String sessionId) { this.processName = processName; this.sessionId = sessionId; } public void setPauseMonitor(final JvmPauseMonitor pauseMonitor) { this.pauseMonitor = pauseMonitor; } public void setGcTimeMonitor(GcTimeMonitor gcTimeMonitor) { Preconditions.checkNotNull(gcTimeMonitor); this.gcTimeMonitor = gcTimeMonitor; } public static JvmMetrics create(String processName, String sessionId, MetricsSystem ms) { return ms.register(JvmMetrics.name(), JvmMetrics.description(), new JvmMetrics(processName, sessionId)); } public static void reattach(MetricsSystem ms, JvmMetrics jvmMetrics) { ms.register(JvmMetrics.name(), JvmMetrics.description(), jvmMetrics); } public static JvmMetrics initSingleton(String processName, String sessionId) { return Singleton.INSTANCE.init(processName, sessionId); } /** * Shutdown the JvmMetrics singleton. This is not necessary if the JVM itself * is shutdown, but may be necessary for scenarios where JvmMetrics instance * needs to be re-created while the JVM is still around. One such scenario * is unit-testing. */ public static void shutdownSingleton() { Singleton.INSTANCE.shutdown(); } @Override public void getMetrics(MetricsCollector collector, boolean all) { MetricsRecordBuilder rb = collector.addRecord(JvmMetrics).setContext("jvm").tag(ProcessName, processName) .tag(SessionId, sessionId); getMemoryUsage(rb); getGcUsage(rb); getThreadUsage(rb); getEventCounters(rb); } private void getMemoryUsage(MetricsRecordBuilder rb) { MemoryUsage memNonHeap = memoryMXBean.getNonHeapMemoryUsage(); MemoryUsage memHeap = memoryMXBean.getHeapMemoryUsage(); Runtime runtime = Runtime.getRuntime(); rb.addGauge(MemNonHeapUsedM, memNonHeap.getUsed() / M) .addGauge(MemNonHeapCommittedM, memNonHeap.getCommitted() / M) .addGauge(MemNonHeapMaxM, calculateMaxMemoryUsage(memNonHeap)) .addGauge(MemHeapUsedM, memHeap.getUsed() / M) .addGauge(MemHeapCommittedM, memHeap.getCommitted() / M) .addGauge(MemHeapMaxM, calculateMaxMemoryUsage(memHeap)).addGauge(MemMaxM, runtime.maxMemory() / M); } private float calculateMaxMemoryUsage(MemoryUsage memHeap) { long max = memHeap.getMax(); if (max == -1) { return MEMORY_MAX_UNLIMITED_MB; } return max / M; } private void getGcUsage(MetricsRecordBuilder rb) { long count = 0; long timeMillis = 0; for (GarbageCollectorMXBean gcBean : gcBeans) { long c = gcBean.getCollectionCount(); long t = gcBean.getCollectionTime(); MetricsInfo[] gcInfo = getGcInfo(gcBean.getName()); rb.addCounter(gcInfo[0], c).addCounter(gcInfo[1], t); count += c; timeMillis += t; } rb.addCounter(GcCount, count).addCounter(GcTimeMillis, timeMillis); if (pauseMonitor != null) { rb.addCounter(GcNumWarnThresholdExceeded, pauseMonitor.getNumGcWarnThresholdExceeded()); rb.addCounter(GcNumInfoThresholdExceeded, pauseMonitor.getNumGcInfoThresholdExceeded()); rb.addCounter(GcTotalExtraSleepTime, pauseMonitor.getTotalGcExtraSleepTime()); } if (gcTimeMonitor != null) { rb.addGauge(GcTimePercentage, gcTimeMonitor.getLatestGcData().getGcTimePercentage()); } } private MetricsInfo[] getGcInfo(String gcName) { MetricsInfo[] gcInfo = gcInfoCache.get(gcName); if (gcInfo == null) { gcInfo = new MetricsInfo[2]; gcInfo[0] = Interns.info("GcCount" + gcName, "GC Count for " + gcName); gcInfo[1] = Interns.info("GcTimeMillis" + gcName, "GC Time for " + gcName); MetricsInfo[] previousGcInfo = gcInfoCache.putIfAbsent(gcName, gcInfo); if (previousGcInfo != null) { return previousGcInfo; } } return gcInfo; } private void getThreadUsage(MetricsRecordBuilder rb) { int threadsNew = 0; int threadsRunnable = 0; int threadsBlocked = 0; int threadsWaiting = 0; int threadsTimedWaiting = 0; int threadsTerminated = 0; long threadIds[] = threadMXBean.getAllThreadIds(); for (ThreadInfo threadInfo : threadMXBean.getThreadInfo(threadIds, 0)) { if (threadInfo == null) continue; // race protection switch (threadInfo.getThreadState()) { case NEW: threadsNew++; break; case RUNNABLE: threadsRunnable++; break; case BLOCKED: threadsBlocked++; break; case WAITING: threadsWaiting++; break; case TIMED_WAITING: threadsTimedWaiting++; break; case TERMINATED: threadsTerminated++; break; } } rb.addGauge(ThreadsNew, threadsNew).addGauge(ThreadsRunnable, threadsRunnable) .addGauge(ThreadsBlocked, threadsBlocked).addGauge(ThreadsWaiting, threadsWaiting) .addGauge(ThreadsTimedWaiting, threadsTimedWaiting).addGauge(ThreadsTerminated, threadsTerminated); } private void getEventCounters(MetricsRecordBuilder rb) { rb.addCounter(LogFatal, EventCounter.getFatal()).addCounter(LogError, EventCounter.getError()) .addCounter(LogWarn, EventCounter.getWarn()).addCounter(LogInfo, EventCounter.getInfo()); } }