From: Florian Forster Date: Sun, 2 Aug 2009 10:18:30 +0000 (+0200) Subject: java bindings: Add first take at a `GenericJMX' plugin. X-Git-Tag: collectd-4.8.0~50^2~5 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=bd931500189953f6995dc0cda30a35d98a824c3d;p=collectd.git java bindings: Add first take at a `GenericJMX' plugin. --- diff --git a/bindings/java/org/collectd/java/GenericJMX.java b/bindings/java/org/collectd/java/GenericJMX.java new file mode 100644 index 00000000..978e989b --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMX.java @@ -0,0 +1,135 @@ +/* + * collectd/java - org/collectd/java/GenericJMX.java + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + */ + +package org.collectd.java; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.TreeMap; + +import org.collectd.api.Collectd; +import org.collectd.api.CollectdConfigInterface; +import org.collectd.api.CollectdInitInterface; +import org.collectd.api.CollectdReadInterface; +import org.collectd.api.CollectdShutdownInterface; +import org.collectd.api.OConfigValue; +import org.collectd.api.OConfigItem; + +public class GenericJMX implements CollectdConfigInterface, + CollectdReadInterface, + CollectdShutdownInterface +{ + static private Map _mbeans + = new TreeMap (); + + private List _connections = null; + + public GenericJMX () + { + Collectd.registerConfig ("GenericJMX", this); + Collectd.registerRead ("GenericJMX", this); + Collectd.registerShutdown ("GenericJMX", this); + + this._connections = new ArrayList (); + } + + public int config (OConfigItem ci) /* {{{ */ + { + List children; + int i; + + Collectd.logDebug ("GenericJMX plugin: config: ci = " + ci + ";"); + + children = ci.getChildren (); + for (i = 0; i < children.size (); i++) + { + OConfigItem child; + String key; + + child = children.get (i); + key = child.getKey (); + if (key.equalsIgnoreCase ("MBean")) + { + try + { + GenericJMXConfMBean mbean = new GenericJMXConfMBean (child); + putMBean (mbean); + } + catch (IllegalArgumentException e) + { + Collectd.logError ("GenericJMX plugin: " + + "Evaluating `MBean' block failed: " + e); + } + } + else if (key.equalsIgnoreCase ("Connection")) + { + try + { + GenericJMXConfConnection conn = new GenericJMXConfConnection (child); + this._connections.add (conn); + } + catch (IllegalArgumentException e) + { + Collectd.logError ("GenericJMX plugin: " + + "Evaluating `Connection' block failed: " + e); + } + } + else + { + Collectd.logError ("GenericJMX plugin: Unknown config option: " + key); + } + } /* for (i = 0; i < children.size (); i++) */ + + return (0); + } /* }}} int config */ + + public int read () /* {{{ */ + { + for (int i = 0; i < this._connections.size (); i++) + this._connections.get (i).query (); + + return (0); + } /* }}} int read */ + + public int shutdown () /* {{{ */ + { + System.out.print ("org.collectd.java.GenericJMX.Shutdown ();\n"); + this._connections = null; + return (0); + } /* }}} int shutdown */ + + /* + * static functions + */ + static public GenericJMXConfMBean getMBean (String alias) + { + return (_mbeans.get (alias)); + } + + static private void putMBean (GenericJMXConfMBean mbean) + { + Collectd.logDebug ("GenericJMX.putMBean: Adding " + mbean.getName ()); + _mbeans.put (mbean.getName (), mbean); + } +} /* class GenericJMX */ + +/* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/bindings/java/org/collectd/java/GenericJMXConfConnection.java b/bindings/java/org/collectd/java/GenericJMXConfConnection.java new file mode 100644 index 00000000..0108b53f --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMXConfConnection.java @@ -0,0 +1,190 @@ +/* + * collectd/java - org/collectd/java/GenericJMXConfConnection.java + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + */ + +package org.collectd.java; + +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + +import javax.management.remote.JMXServiceURL; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; + +import org.collectd.api.Collectd; +import org.collectd.api.PluginData; +import org.collectd.api.OConfigValue; +import org.collectd.api.OConfigItem; + +class GenericJMXConfConnection +{ + private String _host = null; + private String _service_url = null; + private MBeanServerConnection _jmx_connection = null; + private List _mbeans = null; + + /* + * private methods + */ + private String getConfigString (OConfigItem ci) /* {{{ */ + { + List values; + OConfigValue v; + + values = ci.getValues (); + if (values.size () != 1) + { + Collectd.logError ("GenericJMXConfConnection: The " + ci.getKey () + + " configuration option needs exactly one string argument."); + return (null); + } + + v = values.get (0); + if (v.getType () != OConfigValue.OCONFIG_TYPE_STRING) + { + Collectd.logError ("GenericJMXConfConnection: The " + ci.getKey () + + " configuration option needs exactly one string argument."); + return (null); + } + + return (v.getString ()); + } /* }}} String getConfigString */ + +private void connect () /* {{{ */ +{ + JMXServiceURL service_url; + JMXConnector connector; + + if (_jmx_connection != null) + return; + + try + { + service_url = new JMXServiceURL (this._service_url); + connector = JMXConnectorFactory.connect (service_url); + _jmx_connection = connector.getMBeanServerConnection (); + } + catch (Exception e) + { + Collectd.logError ("GenericJMXConfConnection: " + + "Creating MBean server connection failed: " + e); + return; + } +} /* }}} void connect */ + +/* + * public methods + * + * + * Host "tomcat0.mycompany" + * ServiceURL "service:jmx:rmi:///jndi/rmi://localhost:17264/jmxrmi" + * Collect "java.lang:type=GarbageCollector,name=Copy" + * Collect "java.lang:type=Memory" + * + * + */ + public GenericJMXConfConnection (OConfigItem ci) /* {{{ */ + throws IllegalArgumentException + { + List children; + Iterator iter; + + this._mbeans = new ArrayList (); + + children = ci.getChildren (); + iter = children.iterator (); + while (iter.hasNext ()) + { + OConfigItem child = iter.next (); + + if (child.getKey ().equalsIgnoreCase ("Host")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._host = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("ServiceURL")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._service_url = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("Collect")) + { + String tmp = getConfigString (child); + if (tmp != null) + { + GenericJMXConfMBean mbean; + + mbean = GenericJMX.getMBean (tmp); + if (mbean == null) + throw (new IllegalArgumentException ("No such MBean defined: " + + tmp + ". Please make sure all `MBean' blocks appear " + + "before (above) all `Connection' blocks.")); + Collectd.logDebug ("GenericJMXConfConnection: " + this._host + ": Add " + tmp); + this._mbeans.add (mbean); + } + } + else + throw (new IllegalArgumentException ("Unknown option: " + + child.getKey ())); + } + + if (this._service_url == null) + throw (new IllegalArgumentException ("No service URL was defined.")); + if (this._mbeans.size () == 0) + throw (new IllegalArgumentException ("No valid collect statement " + + "present.")); + } /* }}} GenericJMXConfConnection (OConfigItem ci) */ + + public void query () /* {{{ */ + { + PluginData pd; + + connect (); + + if (this._jmx_connection == null) + return; + + Collectd.logDebug ("GenericJMXConfConnection.query: " + + "Reading " + this._mbeans.size () + " mbeans from " + + ((this._host != null) ? this._host : "(null)")); + + pd = new PluginData (); + pd.setHost ((this._host != null) ? this._host : "localhost"); + pd.setPlugin ("GenericJMX"); + + for (int i = 0; i < this._mbeans.size (); i++) + this._mbeans.get (i).query (this._jmx_connection, pd); + } /* }}} void query */ + + public String toString () + { + return (new String ("host = " + this._host + "; " + + "url = " + this._service_url)); + } +} + +/* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/bindings/java/org/collectd/java/GenericJMXConfMBean.java b/bindings/java/org/collectd/java/GenericJMXConfMBean.java new file mode 100644 index 00000000..eea2d8ab --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMXConfMBean.java @@ -0,0 +1,156 @@ +/* + * collectd/java - org/collectd/java/GenericJMXConfMBean.java + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + */ + +package org.collectd.java; + +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + + +import org.collectd.api.Collectd; +import org.collectd.api.PluginData; +import org.collectd.api.OConfigValue; +import org.collectd.api.OConfigItem; + +class GenericJMXConfMBean +{ + private String _name; /* name by which this mapping is referenced */ + private ObjectName _obj_name; + private String _instance; + private List _values; + + private String getConfigString (OConfigItem ci) /* {{{ */ + { + List values; + OConfigValue v; + + values = ci.getValues (); + if (values.size () != 1) + { + Collectd.logError ("GenericJMXConfMBean: The " + ci.getKey () + + " configuration option needs exactly one string argument."); + return (null); + } + + v = values.get (0); + if (v.getType () != OConfigValue.OCONFIG_TYPE_STRING) + { + Collectd.logError ("GenericJMXConfMBean: The " + ci.getKey () + + " configuration option needs exactly one string argument."); + return (null); + } + + return (v.getString ()); + } /* }}} String getConfigString */ + +/* + * + * Instance "foobar" + * ObjectName "object name" + * + * + * : + * + */ + public GenericJMXConfMBean (OConfigItem ci) /* {{{ */ + throws IllegalArgumentException + { + List children; + Iterator iter; + + this._name = getConfigString (ci); + if (this._name == null) + throw (new IllegalArgumentException ("No alias name was defined. " + + "MBean blocks need exactly one string argument.")); + + this._obj_name = null; + this._values = new ArrayList (); + + children = ci.getChildren (); + iter = children.iterator (); + while (iter.hasNext ()) + { + OConfigItem child = iter.next (); + + Collectd.logDebug ("GenericJMXConfMBean: child.getKey () = " + + child.getKey ()); + if (child.getKey ().equalsIgnoreCase ("Instance")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._instance = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("ObjectName")) + { + String tmp = getConfigString (child); + if (tmp == null) + continue; + + try + { + this._obj_name = new ObjectName (tmp); + } + catch (MalformedObjectNameException e) + { + throw (new IllegalArgumentException ("Not a valid object name: " + + tmp, e)); + } + } + else if (child.getKey ().equalsIgnoreCase ("Value")) + { + GenericJMXConfValue cv; + + cv = new GenericJMXConfValue (child); + this._values.add (cv); + } + else + throw (new IllegalArgumentException ("Unknown option: " + + child.getKey ())); + } + + if (this._obj_name == null) + throw (new IllegalArgumentException ("No object name was defined.")); + + if (this._values.size () == 0) + throw (new IllegalArgumentException ("No value block was defined.")); + + } /* }}} GenericJMXConfMBean (OConfigItem ci) */ + + public String getName () + { + return (this._name); + } + + public void query (MBeanServerConnection conn, PluginData pd) /* {{{ */ + { + pd.setPluginInstance ((this._instance != null) ? this._instance : ""); + + for (int i = 0; i < this._values.size (); i++) + this._values.get (i).query (conn, this._obj_name, pd); + } /* }}} void query */ +} + +/* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/bindings/java/org/collectd/java/GenericJMXConfValue.java b/bindings/java/org/collectd/java/GenericJMXConfValue.java new file mode 100644 index 00000000..dcbe6480 --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMXConfValue.java @@ -0,0 +1,232 @@ +/* + * collectd/java - org/collectd/java/GenericJMXConfValue.java + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + */ + +package org.collectd.java; + +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.collectd.api.Collectd; +import org.collectd.api.DataSet; +import org.collectd.api.DataSource; +import org.collectd.api.ValueList; +import org.collectd.api.PluginData; +import org.collectd.api.OConfigValue; +import org.collectd.api.OConfigItem; + +class GenericJMXConfValue +{ + private String ds_name; + private DataSet ds; + private List _attributes; + private String instance_prefix; + + private Number genericObjectToNumber (Object obj, int ds_type) /* {{{ */ + { + if (obj instanceof String) + { + String str = (String) obj; + + try + { + if (ds_type == DataSource.TYPE_GAUGE) + return (new Double (str)); + else + return (new Long (str)); + } + catch (NumberFormatException e) + { + return (null); + } + } + else if (obj instanceof Integer) + { + return (new Integer ((Integer) obj)); + } + else if (obj instanceof Long) + { + return (new Long ((Long) obj)); + } + else if (obj instanceof Double) + { + return (new Double ((Double) obj)); + } + + return (null); + } /* }}} Number genericObjectToNumber */ + + private Number queryAttribute (MBeanServerConnection conn, /* {{{ */ + ObjectName objName, String attrName, + DataSource dsrc) + { + Object attrObj; + + try + { + attrObj = conn.getAttribute (objName, attrName); + } + catch (Exception e) + { + Collectd.logError ("GenericJMXConfValue.query: getAttribute failed: " + + e); + return (null); + } + + return (genericObjectToNumber (attrObj, dsrc.getType ())); + } /* }}} int queryAttribute */ + + private String getConfigString (OConfigItem ci) /* {{{ */ + { + List values; + OConfigValue v; + + values = ci.getValues (); + if (values.size () != 1) + { + Collectd.logError ("GenericJMXConfValue: The " + ci.getKey () + + " configuration option needs exactly one string argument."); + return (null); + } + + v = values.get (0); + if (v.getType () != OConfigValue.OCONFIG_TYPE_STRING) + { + Collectd.logError ("GenericJMXConfValue: The " + ci.getKey () + + " configuration option needs exactly one string argument."); + return (null); + } + + return (v.getString ()); + } /* }}} String getConfigString */ + +/* + * + * Type "memory" + * Attribute "HeapMemoryUsage" + * # Type instance: + * InstancePrefix "heap-" + * + */ + public GenericJMXConfValue (OConfigItem ci) /* {{{ */ + throws IllegalArgumentException + { + List children; + Iterator iter; + + this.ds_name = null; + this.ds = null; + this._attributes = new ArrayList (); + this.instance_prefix = null; + + + children = ci.getChildren (); + iter = children.iterator (); + while (iter.hasNext ()) + { + OConfigItem child = iter.next (); + + if (child.getKey ().equalsIgnoreCase ("Type")) + { + String tmp = getConfigString (child); + if (tmp != null) + this.ds_name = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("Attribute")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._attributes.add (tmp); + } + else if (child.getKey ().equalsIgnoreCase ("InstancePrefix")) + { + String tmp = getConfigString (child); + if (tmp != null) + this.instance_prefix = tmp; + } + else + throw (new IllegalArgumentException ("Unknown option: " + + child.getKey ())); + } + + if (this.ds_name == null) + throw (new IllegalArgumentException ("No data set was defined.")); + else if (this._attributes.size () == 0) + throw (new IllegalArgumentException ("No attribute was defined.")); + } /* }}} GenericJMXConfValue (OConfigItem ci) */ + + public void query (MBeanServerConnection conn, ObjectName objName, /* {{{ */ + PluginData pd) + { + ValueList vl; + List dsrc; + + if (this.ds == null) + { + this.ds = Collectd.getDS (this.ds_name); + if (ds == null) + { + Collectd.logError ("GenericJMXConfValue: Unknown type: " + + this.ds_name); + return; + } + } + + dsrc = this.ds.getDataSources (); + if (dsrc.size () != this._attributes.size ()) + { + Collectd.logError ("GenericJMXConfValue.query: The data set " + + ds_name + " has " + this.ds.getDataSources ().size () + + " data sources, but there were " + this._attributes.size () + + " attributes configured. This doesn't match!"); + this.ds = null; + return; + } + + vl = new ValueList (pd); + vl.setType (this.ds_name); + vl.setTypeInstance (this.instance_prefix); + + assert (dsrc.size () == this._attributes.size ()); + for (int i = 0; i < this._attributes.size (); i++) + { + Number v; + + v = queryAttribute (conn, objName, this._attributes.get (i), + dsrc.get (i)); + if (v == null) + { + Collectd.logError ("GenericJMXConfValue.query: " + + "Querying attribute " + this._attributes.get (i) + " failed."); + return; + } + Collectd.logDebug ("GenericJMXConfValue.query: dsrc[" + i + "]: v = " + v); + vl.addValue (v); + } + + Collectd.dispatchValues (vl); + } /* }}} void query */ +} + +/* vim: set sw=2 sts=2 et fdm=marker : */