package org.fusesource.hawtdispatch.jmx; import org.fusesource.hawtdispatch.Dispatcher; import org.fusesource.hawtdispatch.Metrics; import org.fusesource.hawtdispatch.internal.HawtDispatcher; import javax.management.*; import javax.management.openmbean.*; import java.lang.management.ManagementFactory; import java.util.*; import java.util.concurrent.TimeUnit; /** * */ public class JmxService { public static final String DISPATCHER_OBJECT_NAME = "org.hawtdispatch:type=Dispatcher"; static public interface JmxDispatcherMBean { @MBeanInfo("Used to enable or disable profiling") public void setTimeUnit(String unit); @MBeanInfo("Is profiling enabled.") public String getTimeUnit(); @MBeanInfo("Used to enable or disable profiling") public void setProfile(boolean enabled); @MBeanInfo("Is profiling enabled.") public boolean getProfile(); @MBeanInfo("Get the collected profiling metrics.") public CompositeData[] getMetrics() throws OpenDataException; } static public class JmxDispatcher implements JmxDispatcherMBean { final Dispatcher dispatcher; TimeUnit timeUnit = TimeUnit.MILLISECONDS; public JmxDispatcher(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public String getTimeUnit() { return timeUnit.name(); } public void setTimeUnit(String unit) { this.timeUnit = TimeUnit.valueOf(unit); } public boolean getProfile() { return dispatcher.profile(); } public void setProfile(boolean enabled) { dispatcher.profile(enabled); } public CompositeData[] getMetrics() throws OpenDataException { ArrayList<CompositeData> rc = new ArrayList<CompositeData>(); // lets sort by runtime. ArrayList<Metrics> metrics = new ArrayList<Metrics>(dispatcher.metrics()); Collections.sort(metrics, new Comparator<Metrics>() { public int compare(Metrics l, Metrics r) { if( l.totalRunTimeNS == r.totalRunTimeNS ) return 0; return l.totalRunTimeNS < r.totalRunTimeNS ? 1 : -1; } }); for (Metrics metric : metrics) { rc.add(convert(metric, timeUnit)); } return rc.toArray(new CompositeData[rc.size()]); } } static class CompositeTypeFactory { private final List<String> itemNamesList = new ArrayList<String>(); private final List<String> itemDescriptionsList = new ArrayList<String>(); private final List<OpenType> itemTypesList = new ArrayList<OpenType>(); protected void addItem(String name, String description, OpenType type) { itemNamesList.add(name); itemDescriptionsList.add(description); itemTypesList.add(type); } protected CompositeType create(Class clazz) { return create(clazz.getName(), clazz.getName()); } protected CompositeType create(String name, String description) { try { String[] itemNames = itemNamesList.toArray(new String[itemNamesList.size()]); String[] itemDescriptions = itemDescriptionsList.toArray(new String[itemDescriptionsList.size()]); OpenType[] itemTypes = itemTypesList.toArray(new OpenType[itemTypesList.size()]); return new CompositeType(name, description, itemNames, itemDescriptions, itemTypes); } catch (OpenDataException e) { throw new RuntimeException(e); } } } private static CompositeType METRICS_COMPOSITE_TYPE; static { CompositeTypeFactory factory = new CompositeTypeFactory(); factory.addItem("label", "The queue label", SimpleType.STRING); factory.addItem("duration", "The length of time spent gathering metricsN", SimpleType.DOUBLE); factory.addItem("enqueued", "The number of tasks enqueued", SimpleType.LONG); factory.addItem("enqueueTimeMean", "The mean amount of time an enqueued tasks waited before it was executed", SimpleType.DOUBLE); factory.addItem("enqueueTimeMax", "The maximum amount of time a single enqueued task waited before it was executed", SimpleType.DOUBLE); factory.addItem("enqueueTimeTotal", "The total amount of time all enqueued tasks spent waiting to be executed", SimpleType.DOUBLE); factory.addItem("executed", "The number of tasks executed", SimpleType.LONG); factory.addItem("executeTimeMean", "The mean amount of time tasks took to execute", SimpleType.DOUBLE); factory.addItem("executeTimeMax", "The maximum amount of time a single task took to execute", SimpleType.DOUBLE); factory.addItem("executeTimeTotal", "The total amount of time all tasks spent executing", SimpleType.DOUBLE); METRICS_COMPOSITE_TYPE = factory.create(Metrics.class); } public static CompositeData convert(Metrics metric, TimeUnit timeUnit) throws OpenDataException { Map<String, Object> fields = new HashMap<String, Object>(); fields.put("label", metric.queue.getLabel()); fields.put("duration", ((double)metric.durationNS) / timeUnit.toNanos(1)); fields.put("enqueued", metric.enqueued); fields.put("enqueueTimeMean", (((double)metric.totalWaitTimeNS) / timeUnit.toNanos(1))/ metric.dequeued); fields.put("enqueueTimeMax", ((double)metric.maxWaitTimeNS) / timeUnit.toNanos(1) ); fields.put("enqueueTimeTotal", ((double)metric.totalWaitTimeNS) / timeUnit.toNanos(1)); fields.put("executed", metric.dequeued); fields.put("executeTimeMean", (((double)metric.totalRunTimeNS) / timeUnit.toNanos(1))/ metric.dequeued); fields.put("executeTimeMax", ((double)metric.maxRunTimeNS) / timeUnit.toNanos(1)); fields.put("executeTimeTotal", ((double)metric.totalRunTimeNS) / timeUnit.toNanos(1)); return new CompositeDataSupport(METRICS_COMPOSITE_TYPE, fields); } static public ObjectName objectName(HawtDispatcher dispatcher) { try { return new ObjectName(DISPATCHER_OBJECT_NAME+",name="+ObjectName.quote(dispatcher.getLabel())); } catch (MalformedObjectNameException e) { throw new RuntimeException(e); } } static public void register(HawtDispatcher dispatcher) throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.registerMBean(new JmxDispatcher(dispatcher), objectName(dispatcher)); } static public void unregister(HawtDispatcher dispatcher) throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.unregisterMBean(new ObjectName(DISPATCHER_OBJECT_NAME)); } }