/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008-2010 Sun Microsystems, Inc. */ package org.opends.server.monitors; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; import java.lang.management.MemoryUsage; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.TimeUnit; import org.opends.server.admin.std.server.MemoryUsageMonitorProviderCfg; import org.opends.server.api.MonitorProvider; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.types.*; /** * This class defines a monitor provider that reports information about * Directory Server memory usage. */ public class MemoryUsageMonitorProvider extends MonitorProvider<MemoryUsageMonitorProviderCfg> implements Runnable { // A map of the last GC counts seen by this monitor for calculating recent // stats. private HashMap<String,Long> lastGCCounts = new HashMap<String,Long>(); // A map of the last GC times seen by this monitor for calculating recent // stats. private HashMap<String,Long> lastGCTimes = new HashMap<String,Long>(); // A map of the most recent GC durations seen by this monitor. private HashMap<String,Long> recentGCDurations = new HashMap<String,Long>(); // A map of the memory manager names to names that are safe for use in // attribute names. private HashMap<String,String> gcSafeNames = new HashMap<String,String>(); /** * {@inheritDoc} */ public void initializeMonitorProvider( MemoryUsageMonitorProviderCfg configuration) throws ConfigException, InitializationException { scheduleUpdate(this, 0, 1, TimeUnit.SECONDS); } /** * {@inheritDoc} */ @Override() public String getMonitorInstanceName() { return "JVM Memory Usage"; } /** * {@inheritDoc} */ public void run() { for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { String gcName = gc.getName(); long gcCount = gc.getCollectionCount(); long gcTime = gc.getCollectionTime(); long lastGCCount = 0L; long lastGCTime = 0L; long recentGCDuration = 0L; if (lastGCCounts.containsKey(gcName)) { lastGCCount = lastGCCounts.get(gcName); lastGCTime = lastGCTimes.get(gcName); recentGCDuration = recentGCDurations.get(gcName); } if (gcCount > lastGCCount) { long recentGCCount = gcCount - lastGCCount; long recentGCTime = gcTime - lastGCTime; recentGCDuration = (recentGCTime / recentGCCount); } lastGCCounts.put(gcName, gcCount); lastGCTimes.put(gcName, gcTime); recentGCDurations.put(gcName, recentGCDuration); } } /** * {@inheritDoc} */ @Override() public ArrayList<Attribute> getMonitorData() { ArrayList<Attribute> attrs = new ArrayList<Attribute>(); for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { String gcName = gc.getName(); long gcCount = gc.getCollectionCount(); long gcTime = gc.getCollectionTime(); long avgGCDuration = 0L; if (gcCount > 0) { avgGCDuration = gcTime / gcCount; } long recentGCDuration = 0L; if (recentGCDurations.containsKey(gcName)) { recentGCDuration = recentGCDurations.get(gcName); } String safeName = gcSafeNames.get(gcName); if (safeName == null) { safeName = generateSafeName(gcName); gcSafeNames.put(gcName, safeName); } attrs.add(createAttribute(safeName + "-total-collection-count", String.valueOf(gcCount))); attrs.add(createAttribute(safeName + "-total-collection-duration", String.valueOf(gcTime))); attrs.add(createAttribute(safeName + "-average-collection-duration", String.valueOf(avgGCDuration))); attrs.add(createAttribute(safeName + "-recent-collection-duration", String.valueOf(recentGCDuration))); } for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { String poolName = mp.getName(); MemoryUsage currentUsage = mp.getUsage(); MemoryUsage collectionUsage = mp.getCollectionUsage(); String safeName = gcSafeNames.get(poolName); if (safeName == null) { safeName = generateSafeName(poolName); gcSafeNames.put(poolName, safeName); } if (currentUsage == null) { attrs.add(createAttribute(safeName + "-current-bytes-used", "0")); } else { attrs.add(createAttribute(safeName + "-current-bytes-used", String.valueOf(currentUsage.getUsed()))); } if (collectionUsage == null) { attrs.add(createAttribute(safeName + "-bytes-used-after-last-collection", "0")); } else { attrs.add(createAttribute(safeName + "-bytes-used-after-last-collection", String.valueOf(collectionUsage.getUsed()))); } } return attrs; } /** * Constructs an attribute using the provided information. It will have the * default syntax. * * @param name The name to use for the attribute. * @param value The value to use for the attribute. * * @return The attribute created from the provided information. */ private Attribute createAttribute(String name, String value) { AttributeType attrType = DirectoryServer.getDefaultAttributeType(name); AttributeBuilder builder = new AttributeBuilder(attrType); builder.add(AttributeValues.create(attrType, value)); return builder.toAttribute(); } /** * Creates a "safe" version of the provided name, which is acceptable for * use as part of an attribute name. * * @param name The name for which to obtain the safe name. * * @return The calculated safe name. */ private String generateSafeName(String name) { StringBuilder buffer = new StringBuilder(); boolean lastWasUppercase = false; boolean lastWasDash = false; for (int i=0; i < name.length(); i++) { char c = name.charAt(i); if (Character.isLetter(c)) { if (Character.isUpperCase(c)) { char lowerCaseCharacter = Character.toLowerCase(c); if ((buffer.length() > 0) && (! lastWasUppercase) && (! lastWasDash)) { buffer.append('-'); } buffer.append(lowerCaseCharacter); lastWasUppercase = true; lastWasDash = false; } else { buffer.append(c); lastWasUppercase = false; lastWasDash = false; } } else if (Character.isDigit(c)) { buffer.append(c); lastWasUppercase = false; lastWasDash = false; } else if ((c == ' ') || (c == '_') || (c == '-')) { if (! lastWasDash) { buffer.append('-'); } lastWasUppercase = false; lastWasDash = true; } } return buffer.toString(); } }