diff --git a/plugins/java/jmx/plugin/.classpath b/plugins/java/jmx/plugin/.classpath new file mode 100644 index 00000000..fb501163 --- /dev/null +++ b/plugins/java/jmx/plugin/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/plugins/java/jmx/plugin/.gitignore b/plugins/java/jmx/plugin/.gitignore new file mode 100644 index 00000000..f00d6296 --- /dev/null +++ b/plugins/java/jmx/plugin/.gitignore @@ -0,0 +1,3 @@ +/bin/ +/.settings/ +*.class diff --git a/plugins/java/jmx/plugin/.project b/plugins/java/jmx/plugin/.project new file mode 100644 index 00000000..8fe5521c --- /dev/null +++ b/plugins/java/jmx/plugin/.project @@ -0,0 +1,17 @@ + + + plugin + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/plugins/java/jmx/plugin/META-INF/MANIFEST.MF b/plugins/java/jmx/plugin/META-INF/MANIFEST.MF new file mode 100644 index 00000000..bd17a1b5 --- /dev/null +++ b/plugins/java/jmx/plugin/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Ant-Version: Apache Ant 1.8.1 +Created-By: 1.6.0_22-b04-307-10M3261 (Apple Inc.) diff --git a/plugins/java/jmx/plugin/src/org/munin/Configuration.java b/plugins/java/jmx/plugin/src/org/munin/Configuration.java new file mode 100644 index 00000000..5e4b5d8e --- /dev/null +++ b/plugins/java/jmx/plugin/src/org/munin/Configuration.java @@ -0,0 +1,148 @@ +package org.munin; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +public class Configuration { + private Properties graph_properties = new Properties(); + private Map fieldMap = new HashMap(); + private List fields = new ArrayList(); + + public class FieldProperties extends Properties { + private static final long serialVersionUID = 1L; + private ObjectName jmxObjectName; + private String jmxAttributeName; + private String jmxAttributeKey; + private String fieldname; + private static final String JMXOBJECT = "jmxObjectName"; + private static final String JMXATTRIBUTE = "jmxAttributeName"; + private static final String JMXATTRIBUTEKEY = "jmxAttributeKey"; + + public FieldProperties(Configuration paramConfiguration, + String fieldname) { + this.fieldname = fieldname; + } + + public String getJmxAttributeKey() { + return jmxAttributeKey; + } + + public String getJmxAttributeName() { + return jmxAttributeName; + } + + public ObjectName getJmxObjectName() { + return jmxObjectName; + } + + public String toString() { + return fieldname; + } + + public void set(String key, String value) + throws MalformedObjectNameException, NullPointerException { + if ("jmxObjectName".equals(key)) { + if (jmxObjectName != null) + throw new IllegalStateException( + "jmxObjectName already set for " + this); + jmxObjectName = new ObjectName(value); + } else if ("jmxAttributeName".equals(key)) { + if (jmxAttributeName != null) + throw new IllegalStateException( + "jmxAttributeName already set for " + this); + jmxAttributeName = value; + } else if ("jmxAttributeKey".equals(key)) { + if (jmxAttributeKey != null) + throw new IllegalStateException( + "jmxAttributeKey already set for " + this); + jmxAttributeKey = value; + } else { + put(key, value); + } + } + + public void report(PrintStream out) { + for (Iterator it = entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + out.println(fieldname + '.' + entry.getKey() + " " + + entry.getValue()); + } + } + + public String getFieldname() { + return fieldname; + } + } + + public static Configuration parse(String config_file) throws IOException, + MalformedObjectNameException, NullPointerException { + BufferedReader reader = new BufferedReader(new FileReader(config_file)); + Configuration configuration = new Configuration(); + try { + for (;;) { + String s = reader.readLine(); + if (s == null) + break; + if ((!s.startsWith("%")) && (s.length() > 5) + && (!s.startsWith(" "))) { + configuration.parseString(s); + } + } + } finally { + reader.close(); + } + + return configuration; + } + + private void parseString(String s) throws MalformedObjectNameException, + NullPointerException { + String[] nameval = s.split(" ", 2); + if (nameval[0].indexOf('.') > 0) { + String name = nameval[0]; + String fieldname = name.substring(0, name.lastIndexOf('.')); + if (!fieldMap.containsKey(fieldname)) { + Configuration.FieldProperties field = new Configuration.FieldProperties( + this, fieldname); + fieldMap.put(fieldname, field); + fields.add(field); + } + Configuration.FieldProperties field = (Configuration.FieldProperties) fieldMap + .get(fieldname); + String key = name.substring(name.lastIndexOf('.') + 1); + field.set(key, nameval[1]); + } else { + graph_properties.put(nameval[0], nameval[1]); + } + } + + public Properties getGraphProperties() { + return graph_properties; + } + + public void report(PrintStream out) { + for (Iterator it = graph_properties.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + out.println(entry.getKey() + " " + entry.getValue()); + } + + for (Configuration.FieldProperties field : fields) { + field.report(out); + } + } + + public List getFields() { + return fields; + } +} diff --git a/plugins/java/jmx/plugin/src/org/munin/JMXQuery.java b/plugins/java/jmx/plugin/src/org/munin/JMXQuery.java new file mode 100644 index 00000000..0ac91905 --- /dev/null +++ b/plugins/java/jmx/plugin/src/org/munin/JMXQuery.java @@ -0,0 +1,228 @@ +package org.munin; + +import java.io.IOException; +import java.text.NumberFormat; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +public class JMXQuery { + private static final String USERNAME_KEY = "username"; + private static final String PASSWORD_KEY = "password"; + public static final String USAGE = "Usage of program is:\njava -cp jmxquery.jar org.munin.JMXQuery --url= [--user= --pass=] [--conf= [config]]\n, where is a JMX URL, for example: service:jmx:rmi:///jndi/rmi://HOST:PORT/jmxrmi\nWhen invoked with the config file (see examples folder) - operates as Munin plugin with the provided configuration\nWithout options just fetches all JMX attributes using provided URL"; + private String url; + private String username; + private String password; + private JMXConnector connector; + private MBeanServerConnection connection; + private Configuration config; + + public JMXQuery(String url) { + this(url, null, null); + } + + public JMXQuery(String url, String username, String password) { + this.url = url; + this.username = username; + this.password = password; + } + + private void connect() throws IOException { + Map environment = null; + if ((username != null) && (password != null)) { + environment = new HashMap(); + + environment.put("jmx.remote.credentials", new String[] { username, + password }); + environment.put("username", username); + environment.put("password", password); + } + + JMXServiceURL jmxUrl = new JMXServiceURL(url); + connector = JMXConnectorFactory.connect(jmxUrl, environment); + connection = connector.getMBeanServerConnection(); + } + + private void list() throws IOException, InstanceNotFoundException, + IntrospectionException, ReflectionException { + if (config == null) { + listAll(); + } else { + listConfig(); + } + } + + private void listConfig() { + for (Configuration.FieldProperties field : config.getFields()) { + try { + Object value = connection.getAttribute( + field.getJmxObjectName(), field.getJmxAttributeName()); + output(field.getFieldname(), value, field.getJmxAttributeKey()); + } catch (Exception e) { + System.err.println("Fail to output " + field); + e.printStackTrace(); + } + } + } + + private void output(String name, Object attr, String key) { + if ((attr instanceof CompositeDataSupport)) { + CompositeDataSupport cds = (CompositeDataSupport) attr; + if (key == null) { + throw new IllegalArgumentException( + "Key is null for composed data " + name); + } + System.out.println(name + ".value " + format(cds.get(key))); + } else { + System.out.println(name + ".value " + format(attr)); + } + } + + private void output(String name, Object attr) { + CompositeDataSupport cds; + Iterator it; + if ((attr instanceof CompositeDataSupport)) { + cds = (CompositeDataSupport) attr; + for (it = cds.getCompositeType().keySet().iterator(); it.hasNext();) { + String key = it.next().toString(); + System.out.println(name + "." + key + ".value " + + format(cds.get(key))); + } + } else { + System.out.println(name + ".value " + format(attr)); + } + } + + private void listAll() throws IOException, InstanceNotFoundException, + IntrospectionException, ReflectionException { + Set mbeans = connection.queryNames(null, null); + for (ObjectName name : mbeans) { + MBeanInfo info = connection.getMBeanInfo(name); + MBeanAttributeInfo[] attrs = info.getAttributes(); + String[] attrNames = new String[attrs.length]; + for (int i = 0; i < attrs.length; i++) { + attrNames[i] = attrs[i].getName(); + } + try { + AttributeList attributes = connection.getAttributes(name, + attrNames); + for (Attribute attribute : attributes.asList()) { + output(name.getCanonicalName() + "%" + attribute.getName(), + attribute.getValue()); + } + } catch (Exception e) { + System.err.println("error getting " + name + ":" + + e.getMessage()); + } + } + } + + private String format(Object value) { + if (value == null) + return null; + if ((value instanceof String)) + return (String) value; + if ((value instanceof Number)) { + NumberFormat f = NumberFormat.getInstance(); + f.setMaximumFractionDigits(2); + f.setGroupingUsed(false); + return f.format(value); + } + if ((value instanceof Object[])) { + return Integer.toString(Arrays.asList((Object[]) value).size()); + } + return value.toString(); + } + + private void disconnect() throws IOException { + connector.close(); + } + + public static void main(String[] args) { + int arglen = args.length; + if (arglen < 1) { + System.err + .println("Usage of program is:\njava -cp jmxquery.jar org.munin.JMXQuery --url= [--user= --pass=] [--conf= [config]]\n, where is a JMX URL, for example: service:jmx:rmi:///jndi/rmi://HOST:PORT/jmxrmi\nWhen invoked with the config file (see examples folder) - operates as Munin plugin with the provided configuration\nWithout options just fetches all JMX attributes using provided URL"); + System.exit(1); + } + + String url = null; + String user = null; + String pass = null; + String config_file = null; + boolean toconfig = false; + for (int i = 0; i < arglen; i++) { + if (args[i].startsWith("--url=")) { + url = args[i].substring(6); + } else if (args[i].startsWith("--user=")) { + user = args[i].substring(7); + } else if (args[i].startsWith("--pass=")) { + pass = args[i].substring(7); + } else if (args[i].startsWith("--conf=")) { + config_file = args[i].substring(7); + } else if (args[i].equals("config")) { + toconfig = true; + } + } + + if ((url == null) || ((user != null) && (pass == null)) + || ((user == null) && (pass != null)) + || ((config_file == null) && (toconfig))) { + System.err + .println("Usage of program is:\njava -cp jmxquery.jar org.munin.JMXQuery --url= [--user= --pass=] [--conf= [config]]\n, where is a JMX URL, for example: service:jmx:rmi:///jndi/rmi://HOST:PORT/jmxrmi\nWhen invoked with the config file (see examples folder) - operates as Munin plugin with the provided configuration\nWithout options just fetches all JMX attributes using provided URL"); + System.exit(1); + } + + if (toconfig) { + try { + Configuration.parse(config_file).report(System.out); + } catch (Exception e) { + System.err.println(e.getMessage() + " reading " + config_file); + System.exit(1); + } + } else { + JMXQuery query = new JMXQuery(url, user, pass); + try { + query.connect(); + if (config_file != null) { + query.setConfig(Configuration.parse(config_file)); + } + query.list(); + } catch (Exception ex) { + System.err.println(ex.getMessage() + " querying " + url); + ex.printStackTrace(); + System.exit(1); + } finally { + try { + query.disconnect(); + } catch (IOException e) { + System.err.println(e.getMessage() + " closing " + url); + } + } + } + } + + private void setConfig(Configuration configuration) { + config = configuration; + } + + public Configuration getConfig() { + return config; + } +}