package org.apache.hadoop.metrics.jmx;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.ObjectName;
import org.apache.hadoop.metrics.ContextFactory;
import org.apache.hadoop.metrics.MetricsException;
import org.apache.hadoop.metrics.MetricsRecord;
import org.apache.hadoop.metrics.MetricsUtil;
import org.apache.hadoop.metrics.spi.AbstractMetricsContext;
import org.apache.hadoop.metrics.spi.MetricsRecordImpl;
import org.apache.hadoop.metrics.spi.OutputRecord;
import org.apache.hadoop.metrics.util.MBeanUtil;
public class JMXContext extends AbstractMetricsContext {
public static final String JMX_RECORDS = "jmx_records";
protected static final String PERIOD_PROPERTY = "period";
private Map<String, JMXContextMBean> JMXBeans =
new HashMap<String, JMXContextMBean>();
private Map<JMXContextMBean, ObjectName> beanHandles =
new HashMap<JMXContextMBean, ObjectName>();
private List<String> records = new ArrayList<String>();
public JMXContext() {
}
private void initAllowedRecords() {
String recordsList = getAttribute(JMX_RECORDS);
if (recordsList != null) {
String[] recordNames = recordsList.split(",");
for (String record : recordNames) {
records.add(record);
}
}
}
@Override
public void init(String contextName, ContextFactory factory) {
super.init(contextName, factory);
initAllowedRecords();
String periodStr = getAttribute(PERIOD_PROPERTY);
if (periodStr != null) {
int period = 0;
try {
period = Integer.parseInt(periodStr);
} catch (NumberFormatException nfe) {
}
if (period <= 0) {
throw new MetricsException("Invalid period: " + periodStr);
}
setPeriod(period);
}
}
@Override
protected MetricsRecord newRecord(String recordName) {
MetricsRecord record = super.newRecord(recordName);
if (records.isEmpty() || records.contains(recordName)) {
// Create MBean to expose this record
// Only if this record is to be exposed through JMX
getOrCreateMBean(recordName);
}
return record;
}
private synchronized JMXContextMBean getOrCreateMBean(String recordName) {
JMXContextMBean bean = JMXBeans.get(recordName);
if (bean == null) {
bean = new JMXContextMBean(recordName);
JMXBeans.put(recordName, bean);
if (isMonitoring()) {
ObjectName registeredName =
MBeanUtil.registerMBean(getContextName(), recordName, bean);
beanHandles.put(bean, registeredName);
}
}
return bean;
}
@Override
protected void remove(MetricsRecordImpl record) {
super.remove(record);
String recordName = record.getRecordName();
JMXContextMBean bean = JMXBeans.remove(recordName);
if (bean == null) {
return;
}
// Currently - one bean per record, so remove the bean
ObjectName name = beanHandles.remove(bean);
MBeanUtil.unregisterMBean(name);
}
@Override
public synchronized void startMonitoring() throws IOException {
for (Map.Entry<String, JMXContextMBean> beanEntry : JMXBeans.entrySet()) {
ObjectName registeredName = MBeanUtil.registerMBean(getContextName(),
beanEntry.getKey(),
beanEntry.getValue());
beanHandles.put(beanEntry.getValue(), registeredName);
}
super.startMonitoring();
}
@Override
public synchronized void stopMonitoring() {
for (ObjectName name : beanHandles.values()) {
MBeanUtil.unregisterMBean(name);
}
beanHandles.clear();
super.stopMonitoring();
}
@Override
protected void emitRecord(String contextName, String recordName,
OutputRecord outRec) throws IOException {
JMXContextMBean bean = JMXBeans.get(recordName);
if (bean != null) {
bean.processMetricsRecord(outRec);
}
}
@Override
protected void flush() throws IOException {
for (JMXContextMBean bean : beanHandles.keySet()) {
bean.flush();
}
}
}