/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.server.sreceiver.sysmon;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.logging.Logger;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
import tigase.server.Packet;
import tigase.stats.StatisticsList;
import tigase.xmpp.JID;
/**
* Created: Dec 10, 2008 1:23:17 PM
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class MemMonitor extends AbstractMonitor
implements NotificationListener {
private static Logger log =
Logger.getLogger("tigase.server.sreceiver.sysmon.MemMonitor");
private MemoryMXBean memoryMXBean = null;
@Override
public void destroy() {
memoryMXBean = ManagementFactory.getMemoryMXBean();
NotificationEmitter emitter = (NotificationEmitter)memoryMXBean;
List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean memoryPoolMXBean : memPools) {
try {
emitter.removeNotificationListener(this, null, memoryPoolMXBean);
} catch (Exception e) { }
}
}
@Override
public void init(JID jid, float treshold, SystemMonitorTask smTask) {
super.init(jid, treshold, smTask);
memoryMXBean = ManagementFactory.getMemoryMXBean();
NotificationEmitter emitter = (NotificationEmitter)memoryMXBean;
List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean memoryPoolMXBean : memPools) {
try {
emitter.removeNotificationListener(this, null, memoryPoolMXBean);
} catch (Exception e) { }
MemoryUsage memUsage = memoryPoolMXBean.getUsage();
if (memUsage != null) {
if (memoryPoolMXBean.isUsageThresholdSupported()) {
emitter.addNotificationListener(this, null, memoryPoolMXBean);
long memUsageTreshold =
new Double(new Long(memUsage.getMax()).doubleValue() *
treshold).longValue();
memoryPoolMXBean.setUsageThreshold(memUsageTreshold);
log.config("Setting treshold: " + memUsageTreshold +
" for memory pool: " + memoryPoolMXBean.getName() +
", type: " + memoryPoolMXBean.getType().toString() +
", memMax: " + memUsage.getMax() +
", memUsed: " + memUsage.getUsed() +
", config treeshold: " + treshold);
if (memUsage.getUsed() > memUsageTreshold) {
Notification not = new Notification(
MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED,
this, 1);
handleNotification(not, memoryPoolMXBean);
}
} else {
log.config("Memory pool name: " + memoryPoolMXBean.getName() +
", type: " + memoryPoolMXBean.getType().toString() +
" usage threshold is not supported.");
}
} else {
log.config("Memory pool name: " + memoryPoolMXBean.getName() +
", type: " + memoryPoolMXBean.getType().toString() +
" is invalid.");
}
}
}
@Override
public void handleNotification(Notification note, Object handback) {
if (note.getType().equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
log.info("Usage threshold exceeded, sending notification.");
NumberFormat format = NumberFormat.getIntegerInstance();
if (format instanceof DecimalFormat) {
DecimalFormat decf = (DecimalFormat) format;
decf.applyPattern(decf.toPattern() + " KB");
}
MemoryPoolMXBean memoryPoolMXBean = (MemoryPoolMXBean) handback;
String message = "Threshold " +
format.format(memoryPoolMXBean.getUsageThreshold() / 1024) +
" for memory pool: " + memoryPoolMXBean.getName() +
", type: " + memoryPoolMXBean.getType().toString() +
" exceeded.";
sendWarningOut(message, handback);
}
}
@Override
public String getState() {
NumberFormat format = NumberFormat.getIntegerInstance();
if (format instanceof DecimalFormat) {
DecimalFormat decf = (DecimalFormat) format;
decf.applyPattern(decf.toPattern() + " KB");
}
NumberFormat formp = NumberFormat.getPercentInstance();
formp.setMaximumFractionDigits(2);
StringBuilder sb = new StringBuilder();
List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean memoryPoolMXBean : memPools) {
MemoryUsage memUsage = memoryPoolMXBean.getUsage();
if (memUsage != null) {
sb.append("Memory pool: " + memoryPoolMXBean.getName() +
", type: " + memoryPoolMXBean.getType().toString() +
", usage: " + format.format(memUsage.getUsed()/1024) +
" of " + format.format(memUsage.getMax()/1024) +
" - " +
formp.format(new Long(memUsage.getUsed()).doubleValue()/
new Long(memUsage.getMax()).doubleValue()));
if (memoryPoolMXBean.isUsageThresholdSupported()) {
sb.append(", treshold: " +
format.format(memoryPoolMXBean.getUsageThreshold() / 1024));
}
sb.append("\n");
}
}
return sb.toString();
}
@Override
public void getStatistics(StatisticsList list) {
super.getStatistics(list);
}
private static int GC_INTERVAL = 40;
private int gc_cnt = new Random(System.currentTimeMillis()).nextInt(GC_INTERVAL);
@Override
public void check1Min(Queue<Packet> results) {
if (++gc_cnt >= GC_INTERVAL) {
Runtime.getRuntime().gc();
gc_cnt = 0;
}
}
}