From: Florian Forster Date: Thu, 17 Sep 2009 08:16:35 +0000 (+0200) Subject: Merge branch 'collectd-4.7' into collectd-4.8 X-Git-Tag: collectd-4.8.1~11 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=0384380080a39adb252a4d5dd3a6bf5c27f8faf8;hp=84014b619d09bd1091724a4086222954e8c2450a;p=collectd.git Merge branch 'collectd-4.7' into collectd-4.8 --- diff --git a/.gitignore b/.gitignore index 1f491f31..46c8c048 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,19 @@ -# svn stuff: -.svn -contrib/.svn -debian/.svn -src/.svn -src/libconfig/.svn -src/liboping/.svn - # build.sh stuff: -INSTALL Makefile.in -aclocal.m4 -autom4te.cache -compile -config.guess -config.sub -configure -depcomp -install-sh -libltdl -ltmain.sh -missing -src/Makefile.in +/INSTALL +/aclocal.m4 +/autom4te.cache +/autom4te.cache +/compile +/config.guess +/config.sub +/configure +/depcomp +/install-sh +/libltdl/ +/ltmain.sh +/missing src/config.h.in -src/libconfig/Makefile.in -src/liboping/Makefile.in # configure stuff: Makefile @@ -37,30 +27,20 @@ src/libcollectdclient/libcollectdclient.pc src/stamp-h1 # make stuff: -src/.libs -src/*.la -src/*.lo -src/*.o +*.la +*.lo +*.o +.libs/ src/collectd src/collectd-nagios src/collectdmon -src/collectd*.1 -src/collectd*.5 -src/types.db.5 -src/config.h.in~ -src/libcollectdclient/.libs -src/libcollectdclient/*.la -src/libcollectdclient/*.lo +src/*.1 +src/*.5 src/libcollectdclient/lcc_features.h -src/libiptc/.libs -src/libiptc/*.la -src/libiptc/*.lo -src/liboconfig/.libs -src/liboconfig/*.la -src/liboconfig/*.lo -src/liboping/.libs -src/liboping/*.la -src/liboping/*.lo + +# patch stuff +*.rej +*.orig # lex / yacc stuff: ylwrap @@ -68,12 +48,16 @@ src/liboconfig/parser.c src/liboconfig/parser.h src/liboconfig/scanner.c +# make dist stuff: +/collectd-*.tar.gz +/collectd-*.tar.bz2 + # perl stuff: bindings/.perl-directory-stamp bindings/perl/Collectd/pm_to_blib bindings/perl/blib/ bindings/perl/pm_to_blib -# make dist stuff: -collectd-*.tar.gz -collectd-*.tar.bz2 +# java stuff +bindings/java/java-build-stamp +bindings/java/org/collectd/api/*.class diff --git a/AUTHORS b/AUTHORS index 9f82ee1b..8d0a022d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,6 +24,9 @@ Alvaro Barcellos Amit Gupta - Multiple servers in the apache plugin. +Anthony Dewhurst + - zfs_arc plugin. + Anthony Gialluca - apcups plugin. @@ -51,6 +54,7 @@ Doug MacEachern - OpenVPN plugin. - jcollectd (two-way JMX integration). - A few other patches to various plugins. + - curl_json plugin. Edward “Koko” Konetzko - fscache plugin. @@ -103,6 +107,14 @@ Oleg King + the disk plugin, and + the users plugin. +Ondrej Zajicek + - madwifi plugin. + +Paul Sadauskas + - tokyotyrant plugin. + - `ReportByDevice' option of the df plugin. + - write_http plugin. + Peter Holik - cpufreq plugin. - multimeter plugin. diff --git a/ChangeLog b/ChangeLog index f88135ff..83980834 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,52 @@ +2009-09-13, Version 4.8.0 + * collectd: Two new data source types, “DERIVE” and “ABSOLUTE”, have + been added. “DERIVE” can be used for counters that are reset + occasionally. Thanks to Mariusz Gronczewski for implementing this. + * thresholds: The advanced threshold options “Percentage”, “Hits”, and + “Hysteresis” have been added. Thanks to Andrés J. Díaz for hit + patches. + * curl_json plugin: The new cURL-JSON plugin reads JSON files using + the cURL library and parses the contents according to user + specification. Among other things, this allows to read statistics + from a CouchDB instance. Thanks to Doug MacEachern for the patch. + * df plugin: Using the new “ReportByDevice” option the device rather + than the mount point can be used to identify partitions. Thanks to + Paul Sadauskas for the patch. + * dns plugin: The possibility to ignore numeric QTypes has been added. + Thanks to Mirko Buffoni for the patch. + * GenericJMX plugin: The new, Java-based GenericJMX plugin allows to + query arbitrary data from a Java process using the “Java Management + Extensions” (JMX). + * madwifi plugin: The new MadWifi plugin collects information about + Atheros wireless LAN chipsets from the MadWifi driver. Thanks to + Ondrej Zajicek for his patches. + * network plugin: The receive- and send-buffer-sizes have been made + configurable, allowing for bigger and smaller packets. Thanks to + Aman Gupta for the patch. + * olsrd plugin: The new OLSRd plugin queries routing information from + the “Optimized Link State Routing” daemon. + * rrdtool plugin: A new configuration option allows to define a random + write delay when writing RRD files. This spreads the load created by + writing RRD files more evenly. Thanks to Mariusz Gronczewski for the + patch. + * swap plugin: The possibility to collect swapped in/out pages has + been added to the Swap plugin. Thanks to Stefan Völkel for the + patch. + * tokyotyrant plugin: The new TokyoTyrant plugin reads the number of + records and file size from a running Tokyo Tyrant server. Thanks to + Paul Sadauskas for the patch. + * unixsock plugin: Add the “GETTHRESHOLD” command. This command can be + used to query the thresholds configured for a particular identifier. + * write_http plugin: The new Write HTTP plugin sends the values + collected by collectd to a web-server using HTTP POST requests. + Thanks to Paul Sadauskas for the patch. + * zfs_arc plugin: The new ZFS ARC plugin collects information about + the “Adaptive Replacement Cache” (ARC) of the “Zeta File-System” + (ZFS). Thanks to Anthony Dewhurst for the patch. + * empty_counter match: The new Empty Counter match matches value + lists, where at least one data source is of type COUNTER and the + counter value of all counter data sources is zero. + 2009-09-13, Version 4.7.3 * collectd: Fix a possible but very rare invalid “free” in the caching code. Thanks to Sebastian Harl for the patch. diff --git a/README b/README index 74127658..6529a900 100644 --- a/README +++ b/README @@ -43,6 +43,10 @@ Features - conntrack Number of nf_conntrack entries. + - curl_json + Retrieves JSON data via cURL and parses it according to user + configuration. + - cpu CPU utilization: Time spent in the system, user, nice, idle, and related states. @@ -117,6 +121,10 @@ Features - libvirt CPU, disk and network I/O statistics from virtual machines. + - madwifi + Queries very detailed usage statistics from wireless LAN adapters and + interfaces that use the Atheros chipset and the MadWifi driver. + - mbmon Motherboard sensors: temperature, fanspeed and voltage information, using mbmon(1). @@ -165,6 +173,10 @@ Features Network UPS tools: UPS current, voltage, power, charge, utilisation, temperature, etc. See upsd(8). + - olsr + Queries routing information from the “Optimized Link State Routing” + daemon. + - onewire (EXPERIMENTAL!) Read onewire sensors using the owcapu library of the owfs project. Please read in collectd.conf(5) why this plugin is experimental. @@ -238,6 +250,10 @@ Features - thermal Linux ACPI thermal zone information. + - tokyotyrant + Reads the number of records and file size from a running Tokyo Tyrant + server. + - uptime System uptime statistics. @@ -258,6 +274,9 @@ Features - xmms Bitrate and frequency of music played with XMMS. + - zfs_arc + Statistics for ZFS' “Adaptive Replacement Cache” (ARC). + * Output can be written or send to various destinations by the following plugins: @@ -292,6 +311,11 @@ Features needed. Please read collectd-unixsock(5) for a description on how that's done. + - write_http + Sends the values collected by collectd to a web-server using HTTP POST + requests. The transmitted data is either in a form understood by the + Exec plugin or formatted in JSON. + * Logging is, as everything in collectd, provided by plugins. The following plugins keep up informed about what's going on: @@ -334,6 +358,9 @@ Features * Value processing can be controlled using the "filter chain" infrastructure and "matches" and "targets". The following plugins are available: + - match_empty_counter + Match counter values which are currently zero. + - match_regex Match values by their identifier based on regular expressions. @@ -432,7 +459,8 @@ Prerequisites Used by the `oracle' plugin. * libcurl (optional) - If you want to use the `apache', `ascent', `curl' or `nginx' plugin. + If you want to use the `apache', `ascent', `curl', `nginx', or `write_http' + plugin. * libdbi (optional) @@ -543,6 +571,9 @@ Prerequisites * libxmms (optional) + * libyajl (optional) + Parse JSON data. This is needed for the `curl_json' plugin. + Configuring / Compiling / Installing ------------------------------------ diff --git a/bindings/java/Makefile.am b/bindings/java/Makefile.am index af5e480a..d3315acc 100644 --- a/bindings/java/Makefile.am +++ b/bindings/java/Makefile.am @@ -17,10 +17,16 @@ EXTRA_DIST = org/collectd/api/CollectdConfigInterface.java \ org/collectd/api/OConfigItem.java \ org/collectd/api/OConfigValue.java \ org/collectd/api/PluginData.java \ - org/collectd/api/ValueList.java + org/collectd/api/ValueList.java \ + org/collectd/java/GenericJMXConfConnection.java \ + org/collectd/java/GenericJMXConfMBean.java \ + org/collectd/java/GenericJMXConfValue.java \ + org/collectd/java/GenericJMX.java \ + org/collectd/java/JMXMemory.java java-build-stamp: org/collectd/api/*.java $(JAVAC) -d "." "$(srcdir)/org/collectd/api"/*.java + $(JAVAC) -d "." "$(srcdir)/org/collectd/java"/*.java touch "$@" all-local: java-build-stamp @@ -29,7 +35,11 @@ install-exec-local: java-build-stamp mkdir -p "$(DESTDIR)$(pkgdatadir)/java/org/collectd/api" $(INSTALL) -m 644 "org/collectd/api"/*.class \ "$(DESTDIR)$(pkgdatadir)/java/org/collectd/api/" + mkdir -p "$(DESTDIR)$(pkgdatadir)/java/org/collectd/java" + $(INSTALL) -m 644 "org/collectd/java"/*.class \ + "$(DESTDIR)$(pkgdatadir)/java/org/collectd/java/" clean-local: rm -f "org/collectd/api"/*.class + rm -f "org/collectd/java"/*.class rm -f "java-build-stamp" diff --git a/bindings/java/org/collectd/api/DataSource.java b/bindings/java/org/collectd/api/DataSource.java index bfe8e2d0..ba132d3d 100644 --- a/bindings/java/org/collectd/api/DataSource.java +++ b/bindings/java/org/collectd/api/DataSource.java @@ -22,14 +22,18 @@ package org.collectd.api; * Java representation of collectd/src/plugin.h:data_source_t structure. */ public class DataSource { - public static final int TYPE_COUNTER = 0; - public static final int TYPE_GAUGE = 1; + public static final int TYPE_COUNTER = 0; + public static final int TYPE_GAUGE = 1; + public static final int TYPE_DERIVE = 2; + public static final int TYPE_ABSOLUTE = 3; - static final String COUNTER = "COUNTER"; - static final String GAUGE = "GAUGE"; + static final String COUNTER = "COUNTER"; + static final String GAUGE = "GAUGE"; + static final String DERIVE = "DERIVE"; + static final String ABSOLUTE = "ABSOLUTE"; static final String NAN = "U"; - private static final String[] TYPES = { COUNTER, GAUGE }; + private static final String[] TYPES = { COUNTER, GAUGE, DERIVE, ABSOLUTE }; String _name; int _type; @@ -41,6 +45,10 @@ public class DataSource { this._type = TYPE_GAUGE; if (type == TYPE_COUNTER) this._type = TYPE_COUNTER; + else if (type == TYPE_DERIVE) + this._type = TYPE_DERIVE; + else if (type == TYPE_ABSOLUTE) + this._type = TYPE_ABSOLUTE; this._min = min; this._max = max; } diff --git a/bindings/java/org/collectd/java/GenericJMX.java b/bindings/java/org/collectd/java/GenericJMX.java new file mode 100644 index 00000000..319615c9 --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMX.java @@ -0,0 +1,145 @@ +/* + * 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++) + { + try + { + this._connections.get (i).query (); + } + catch (Exception e) + { + Collectd.logError ("GenericJMX: Caught unexpected exception: " + e); + e.printStackTrace (); + } + } + + 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..7214fd76 --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMXConfConnection.java @@ -0,0 +1,221 @@ +/* + * 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.Map; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.HashMap; + +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 _username = null; + private String _password = null; + 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; + Map environment; + + if (_jmx_connection != null) + return; + + environment = null; + if (this._password != null) + { + String[] credentials; + + if (this._username == null) + this._username = new String ("monitorRole"); + + credentials = new String[] { this._username, this._password }; + + environment = new HashMap (); + environment.put (JMXConnector.CREDENTIALS, credentials); + } + + try + { + service_url = new JMXServiceURL (this._service_url); + connector = JMXConnectorFactory.connect (service_url, environment); + _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 ("User")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._username = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("Password")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._password = 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..27e9e329 --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMXConfMBean.java @@ -0,0 +1,242 @@ +/* + * 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.Iterator; +import java.util.List; +import java.util.Set; +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_prefix; + private List _instance_from; + 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 */ + + private String join (String separator, List list) /* {{{ */ + { + StringBuffer sb; + + sb = new StringBuffer (); + + for (int i = 0; i < list.size (); i++) + { + if (i > 0) + sb.append ("-"); + sb.append (list.get (i)); + } + + return (sb.toString ()); + } /* }}} String join */ + +/* + * + * ObjectName "object name" + * InstancePrefix "foobar" + * InstanceFrom "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._instance_prefix = null; + this._instance_from = new ArrayList (); + 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 ("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 ("InstancePrefix")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._instance_prefix = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("InstanceFrom")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._instance_from.add (tmp); + } + 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) /* {{{ */ + { + Set names; + Iterator iter; + + try + { + names = conn.queryNames (this._obj_name, /* query = */ null); + } + catch (Exception e) + { + Collectd.logError ("GenericJMXConfMBean: queryNames failed: " + e); + return; + } + + if (names.size () == 0) + { + Collectd.logWarning ("GenericJMXConfMBean: No MBean matched " + + "the ObjectName " + this._obj_name); + } + + iter = names.iterator (); + while (iter.hasNext ()) + { + ObjectName objName; + PluginData pd_tmp; + List instanceList; + String instance; + + objName = iter.next (); + pd_tmp = new PluginData (pd); + instanceList = new ArrayList (); + + Collectd.logDebug ("GenericJMXConfMBean: objName = " + + objName.toString ()); + + for (int i = 0; i < this._instance_from.size (); i++) + { + String propertyName; + String propertyValue; + + propertyName = this._instance_from.get (i); + propertyValue = objName.getKeyProperty (propertyName); + if (propertyValue == null) + { + Collectd.logError ("GenericJMXConfMBean: " + + "No such property in object name: " + propertyName); + } + else + { + instanceList.add (propertyValue); + } + } + + if (this._instance_prefix != null) + instance = new String (this._instance_prefix + + join ("-", instanceList)); + else + instance = join ("-", instanceList); + pd_tmp.setPluginInstance (instance); + + Collectd.logDebug ("GenericJMXConfMBean: instance = " + instance); + + for (int i = 0; i < this._values.size (); i++) + this._values.get (i).query (conn, objName, pd_tmp); + } + } /* }}} 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..0eb0d5f8 --- /dev/null +++ b/bindings/java/org/collectd/java/GenericJMXConfValue.java @@ -0,0 +1,587 @@ +/* + * 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.Arrays; +import java.util.List; +import java.util.Set; +import java.util.Iterator; +import java.util.ArrayList; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.InvalidKeyException; + +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; + +/** + * Representation of a <value /> block and query functionality. + * + * This class represents a <value /> block in the configuration. As + * such, the constructor takes an {@link org.collectd.api.OConfigValue} to + * construct an object of this class. + * + * The object can then be asked to query data from JMX and dispatch it to + * collectd. + * + * @see GenericJMXConfMBean + */ +class GenericJMXConfValue +{ + private String _ds_name; + private DataSet _ds; + private List _attributes; + private String _instance_prefix; + private List _instance_from; + private boolean _is_table; + + /** + * Converts a generic (OpenType) object to a number. + * + * Returns null if a conversion is not possible or not implemented. + */ + 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 Byte) + { + return (new Byte ((Byte) obj)); + } + else if (obj instanceof Short) + { + return (new Short ((Short) obj)); + } + else if (obj instanceof Integer) + { + return (new Integer ((Integer) obj)); + } + else if (obj instanceof Long) + { + return (new Long ((Long) obj)); + } + else if (obj instanceof Float) + { + return (new Float ((Float) obj)); + } + else if (obj instanceof Double) + { + return (new Double ((Double) obj)); + } + else if (obj instanceof BigDecimal) + { + return (BigDecimal.ZERO.add ((BigDecimal) obj)); + } + else if (obj instanceof BigInteger) + { + return (BigInteger.ZERO.add ((BigInteger) obj)); + } + + return (null); + } /* }}} Number genericObjectToNumber */ + + /** + * Converts a generic list to a list of numbers. + * + * Returns null if one or more objects could not be converted. + */ + private List genericListToNumber (List objects) /* {{{ */ + { + List ret = new ArrayList (); + List dsrc = this._ds.getDataSources (); + + assert (objects.size () == dsrc.size ()); + + for (int i = 0; i < objects.size (); i++) + { + Number n; + + n = genericObjectToNumber (objects.get (i), dsrc.get (i).getType ()); + if (n == null) + return (null); + ret.add (n); + } + + return (ret); + } /* }}} List genericListToNumber */ + + /** + * Converts a list of CompositeData to a list of numbers. + * + * From each CompositeData the key key is received and all + * those values are converted to a number. If one of the + * CompositeData doesn't have the specified key or one returned + * object cannot converted to a number then the function will return null. + */ + private List genericCompositeToNumber (List cdlist, /* {{{ */ + String key) + { + List objects = new ArrayList (); + + for (int i = 0; i < cdlist.size (); i++) + { + CompositeData cd; + Object value; + + cd = cdlist.get (i); + try + { + value = cd.get (key); + } + catch (InvalidKeyException e) + { + return (null); + } + objects.add (value); + } + + return (genericListToNumber (objects)); + } /* }}} List genericCompositeToNumber */ + + private void submitTable (List objects, ValueList vl, /* {{{ */ + String instancePrefix) + { + List cdlist; + Set keySet = null; + Iterator keyIter; + + cdlist = new ArrayList (); + for (int i = 0; i < objects.size (); i++) + { + Object obj; + + obj = objects.get (i); + if (obj instanceof CompositeData) + { + CompositeData cd; + + cd = (CompositeData) obj; + + if (i == 0) + keySet = cd.getCompositeType ().keySet (); + + cdlist.add (cd); + } + else + { + Collectd.logError ("GenericJMXConfValue: At least one of the " + + "attributes was not of type `CompositeData', as required " + + "when table is set to `true'."); + return; + } + } + + assert (keySet != null); + + keyIter = keySet.iterator (); + while (keyIter.hasNext ()) + { + String key; + List values; + + key = keyIter.next (); + values = genericCompositeToNumber (cdlist, key); + if (values == null) + { + Collectd.logError ("GenericJMXConfValue: Cannot build a list of " + + "numbers for key " + key + ". Most likely not all attributes " + + "have this key."); + continue; + } + + if (instancePrefix == null) + vl.setTypeInstance (key); + else + vl.setTypeInstance (instancePrefix + key); + vl.setValues (values); + + Collectd.dispatchValues (vl); + } + } /* }}} void submitTable */ + + private void submitScalar (List objects, ValueList vl, /* {{{ */ + String instancePrefix) + { + List values; + + values = genericListToNumber (objects); + if (values == null) + { + Collectd.logError ("GenericJMXConfValue: Cannot convert list of " + + "objects to numbers."); + return; + } + + if (instancePrefix == null) + vl.setTypeInstance (""); + else + vl.setTypeInstance (instancePrefix); + vl.setValues (values); + + Collectd.dispatchValues (vl); + } /* }}} void submitScalar */ + + private Object queryAttributeRecursive (CompositeData parent, /* {{{ */ + List attrName) + { + String key; + Object value; + + key = attrName.remove (0); + + try + { + value = parent.get (key); + } + catch (InvalidKeyException e) + { + return (null); + } + + if (attrName.size () == 0) + { + return (value); + } + else + { + if (value instanceof CompositeData) + return (queryAttributeRecursive ((CompositeData) value, attrName)); + else + return (null); + } + } /* }}} queryAttributeRecursive */ + + private Object queryAttribute (MBeanServerConnection conn, /* {{{ */ + ObjectName objName, String attrName) + { + List attrNameList; + String key; + Object value; + String[] attrNameArray; + + attrNameList = new ArrayList (); + + attrNameArray = attrName.split ("\\."); + key = attrNameArray[0]; + for (int i = 1; i < attrNameArray.length; i++) + attrNameList.add (attrNameArray[i]); + + try + { + value = conn.getAttribute (objName, key); + } + catch (Exception e) + { + Collectd.logError ("GenericJMXConfValue.query: getAttribute failed: " + + e); + return (null); + } + + if (attrNameList.size () == 0) + { + return (value); + } + else + { + if (value instanceof CompositeData) + return (queryAttributeRecursive((CompositeData) value, attrNameList)); + else if (value instanceof OpenType) + { + OpenType ot = (OpenType) value; + Collectd.logNotice ("GenericJMXConfValue: Handling of OpenType \"" + + ot.getTypeName () + "\" is not yet implemented."); + return (null); + } + else + { + Collectd.logError ("GenericJMXConfValue: Received object of " + + "unknown class."); + return (null); + } + } + } /* }}} Object queryAttribute */ + + private String join (String separator, List list) /* {{{ */ + { + StringBuffer sb; + + sb = new StringBuffer (); + + for (int i = 0; i < list.size (); i++) + { + if (i > 0) + sb.append ("-"); + sb.append (list.get (i)); + } + + return (sb.toString ()); + } /* }}} String join */ + + 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 */ + + private Boolean getConfigBoolean (OConfigItem ci) /* {{{ */ + { + List values; + OConfigValue v; + Boolean b; + + values = ci.getValues (); + if (values.size () != 1) + { + Collectd.logError ("GenericJMXConfValue: The " + ci.getKey () + + " configuration option needs exactly one boolean argument."); + return (null); + } + + v = values.get (0); + if (v.getType () != OConfigValue.OCONFIG_TYPE_BOOLEAN) + { + Collectd.logError ("GenericJMXConfValue: The " + ci.getKey () + + " configuration option needs exactly one boolean argument."); + return (null); + } + + return (new Boolean (v.getBoolean ())); + } /* }}} String getConfigBoolean */ + + /** + * Constructs a new value with the configured properties. + */ + 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; + this._instance_from = new ArrayList (); + this._is_table = false; + + /* + * + * Type "memory" + * Table true|false + * Attribute "HeapMemoryUsage" + * Attribute "..." + * : + * # Type instance: + * InstancePrefix "heap-" + * + */ + 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 ("Table")) + { + Boolean tmp = getConfigBoolean (child); + if (tmp != null) + this._is_table = tmp.booleanValue (); + } + 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 if (child.getKey ().equalsIgnoreCase ("InstanceFrom")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._instance_from.add (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) */ + + /** + * Query values via JMX according to the object's configuration and dispatch + * them to collectd. + * + * @param conn Connection to the MBeanServer. + * @param objName Object name of the MBean to query. + * @param pd Preset naming components. The members host, plugin and + * plugin instance will be used. + */ + public void query (MBeanServerConnection conn, ObjectName objName, /* {{{ */ + PluginData pd) + { + ValueList vl; + List dsrc; + List values; + List instanceList; + String instancePrefix; + + if (this._ds == null) + { + this._ds = Collectd.getDS (this._ds_name); + if (this._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 " + + this._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); + + /* + * Build the instnace prefix from the fixed string prefix and the + * properties of the objName. + */ + instanceList = new ArrayList (); + for (int i = 0; i < this._instance_from.size (); i++) + { + String propertyName; + String propertyValue; + + propertyName = this._instance_from.get (i); + propertyValue = objName.getKeyProperty (propertyName); + if (propertyValue == null) + { + Collectd.logError ("GenericJMXConfMBean: " + + "No such property in object name: " + propertyName); + } + else + { + instanceList.add (propertyValue); + } + } + + if (this._instance_prefix != null) + instancePrefix = new String (this._instance_prefix + + join ("-", instanceList)); + else + instancePrefix = join ("-", instanceList); + + /* + * Build a list of `Object's which is then passed to `submitTable' and + * `submitScalar'. + */ + values = new ArrayList (); + assert (dsrc.size () == this._attributes.size ()); + for (int i = 0; i < this._attributes.size (); i++) + { + Object v; + + v = queryAttribute (conn, objName, this._attributes.get (i)); + if (v == null) + { + Collectd.logError ("GenericJMXConfValue.query: " + + "Querying attribute " + this._attributes.get (i) + " failed."); + return; + } + + values.add (v); + } + + if (this._is_table) + submitTable (values, vl, instancePrefix); + else + submitScalar (values, vl, instancePrefix); + } /* }}} void query */ +} /* class GenericJMXConfValue */ + +/* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/bindings/java/org/collectd/java/JMXMemory.java b/bindings/java/org/collectd/java/JMXMemory.java index d1666c0f..6e6a2fb0 100644 --- a/bindings/java/org/collectd/java/JMXMemory.java +++ b/bindings/java/org/collectd/java/JMXMemory.java @@ -47,7 +47,7 @@ import org.collectd.api.CollectdShutdownInterface; import org.collectd.api.OConfigValue; import org.collectd.api.OConfigItem; -public class JMXMemory implements CollectdConfigInterface, /* {{{ */ +public class JMXMemory implements CollectdConfigInterface, CollectdInitInterface, CollectdReadInterface, CollectdShutdownInterface @@ -227,6 +227,6 @@ public class JMXMemory implements CollectdConfigInterface, /* {{{ */ _mbean = null; return (0); } /* }}} int shutdown */ -} /* }}} class JMXMemory */ +} /* class JMXMemory */ /* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/bindings/perl/Collectd/Unixsock.pm b/bindings/perl/Collectd/Unixsock.pm index 44031784..199a47c5 100644 --- a/bindings/perl/Collectd/Unixsock.pm +++ b/bindings/perl/Collectd/Unixsock.pm @@ -196,7 +196,7 @@ value. On error false is returned. =cut -sub getval +sub getval # {{{ { my $obj = shift; my %args = @_; @@ -242,7 +242,64 @@ sub getval } return ($ret); -} # getval +} # }}} sub getval + +=item I<$res> = I<$obj>-EB (I<%identifier>); + +Requests a threshold from the daemon. On success a hash-ref is returned with +the threshold data. On error false is returned. + +=cut + +sub getthreshold # {{{ +{ + my $obj = shift; + my %args = @_; + + my $status; + my $fh = $obj->{'sock'} or confess ('object has no filehandle'); + my $msg; + my $identifier; + + my $ret = {}; + + $identifier = _create_identifier (\%args) or return; + + $msg = 'GETTHRESHOLD ' . _escape_argument ($identifier) . "\n"; + _debug "-> $msg"; + print $fh $msg; + + $msg = <$fh>; + chomp ($msg); + _debug "<- $msg\n"; + + ($status, $msg) = split (' ', $msg, 2); + if ($status <= 0) + { + $obj->{'error'} = $msg; + return; + } + + for (my $i = 0; $i < $status; $i++) + { + my $entry = <$fh>; + chomp ($entry); + _debug "<- $entry\n"; + + if ($entry =~ m/^([^:]+):\s*(\S.*)$/) + { + my $key = $1; + my $value = $2; + + $key =~ s/^\s+//; + $key =~ s/\s+$//; + + $ret->{$key} = $value; + } + } + + return ($ret); +} # }}} sub getthreshold =item I<$obj>-EB (I<%identifier>, B