Code

Merge branch 'st/python'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 8 Dec 2009 10:26:37 +0000 (11:26 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 8 Dec 2009 10:26:37 +0000 (11:26 +0100)
Conflicts:
README
configure.in
src/owniptc/libiptc.c
src/types.db

1  2 
AUTHORS
README
configure.in
src/Makefile.am
src/configfile.c
src/plugin.c

diff --combined AUTHORS
index 4fbe91596de729ee6773a5746d4670a4f6c48354,41c9bb0a06b0dd82fddb2b76358304e72f72e787..5abbfa33f04d2649114a01573d0491b19b1bbf3c
+++ b/AUTHORS
@@@ -85,7 -85,6 +85,7 @@@ Lyonel Vincent <lyonel at ezix.org
  Marco Chiappero <marco at absence.it>
   - uptime plugin.
   - ip6tables support in the iptables plugin.
 + - openvpn plugin (support for more status file formats)
  
  Michael Stapelberg <michael+git at stapelberg.de>
   - OpenBSD port of the tcpconns plugin.
@@@ -111,11 -110,6 +111,11 @@@ Oleg King <king2 at kaluga.ru
  Ondrej Zajicek <santiago at crfreenet.org>
   - madwifi plugin.
  
 +Patrik Weiskircher <weiskircher at inqnet.at>
 + - Contextswitch plugin.
 + - Forkrate counter in the processes plugin.
 + - INode count in the DF plugin.
 +
  Paul Sadauskas <psadauskas at gmail.com>
   - tokyotyrant plugin.
   - `ReportByDevice' option of the df plugin.
@@@ -155,6 -149,7 +155,7 @@@ Stefan Hacker <stefan.hacker at web.de
  
  Sven Trenkel <collectd at semidefinite.de>
   - netapp plugin.
+  - python plugin.
  
  Tomasz Pala <gotar at pld-linux.org>
   - conntrack plugin.
diff --combined README
index 47499f1ff07998703c78093f89324664842ad2a5,70118ad1be008039ebce551745e422b0eb4a5e6c..e95bae62af26a252b2c01f1c45100570b3225004
--- 1/README
--- 2/README
+++ b/README
@@@ -33,6 -33,9 +33,6 @@@ Feature
        Batterycharge, -current and voltage of ACPI and PMU based laptop
        batteries.
  
 -    - curl
 -      Parse statistics from websites using regular expressions.
 -
      - bind
        Name server and resolver statistics from the `statistics-channel'
        interface of BIND 9.5, 9,6 and later.
@@@ -40,8 -43,9 +40,8 @@@
      - conntrack
        Number of nf_conntrack entries.
  
 -    - curl_json
 -      Retrieves JSON data via cURL and parses it according to user
 -      configuration.
 +    - contextswitch
 +      Number of context switches done by the operating system.
  
      - cpu
        CPU utilization: Time spent in the system, user, nice, idle, and related
      - cpufreq
        CPU frequency (For laptops with speed step or a similar technology)
  
 +    - curl
 +      Parse statistics from websites using regular expressions.
 +
 +    - curl_json
 +      Retrieves JSON data via cURL and parses it according to user
 +      configuration.
 +
      - dbi
        Executes SQL statements on various databases and interprets the returned
        data.
        Network UPS tools: UPS current, voltage, power, charge, utilisation,
        temperature, etc. See upsd(8).
  
 -    - olsr
 +    - olsrd
        Queries routing information from the “Optimized Link State Routing”
        daemon.
  
      - protocols
        Counts various aspects of network protocols such as IP, TCP, UDP, etc.
  
+     - python
+       The python plugin implements a Python interpreter into collectd. This
+       makes it possible to write plugins in Python which are executed by
+       collectd without the need to start a heavy interpreter every interval.
+       See collectd-python(5) for details.
      - rrdcached
        RRDtool caching daemon (RRDcacheD) statistics.
  
        you can easily do weird stuff with the plugins we didn't dare think of
        ;) See collectd-perl(5).
  
+     - python
+       It's possible to implement write plugins in Python using the python
+       plugin. See collectd-python(5) for details.
      - rrdcached
        Output to round-robin-database (RRD) files using the RRDtool caching
        daemon (RRDcacheD) - see rrdcached(1). That daemon provides a general
        Log messages are propagated to plugins written in Perl as well.
        See collectd-perl(5).
  
+     - python
+       It's possible to implement log plugins in Python using the python plugin.
+       See collectd-python(5) for details.
      - syslog
        Logs to the standard UNIX logging mechanism, syslog.
  
        Notifications are propagated to plugins written in Perl as well.
        See collectd-perl(5).
  
+     - python
+       It's possible to implement notification plugins in Python using the
+       python plugin. See collectd-python(5) for details.
    * Value processing can be controlled using the "filter chain" infrastructure
      and "matches" and "targets". The following plugins are available:
  
@@@ -480,11 -495,9 +498,11 @@@ Prerequisite
  
    * libganglia (optional)
      Used by the `gmond' plugin to process data received from Ganglia.
 +    <http://ganglia.info/>
  
    * libgcrypt (optional)
      Used by the `network' plugin for encryption and authentication.
 +    <http://www.gnupg.org/>
  
    * libhal (optional)
      If present, the uuid plugin will check for UUID from HAL.
      Library that encapsulates the `Java Virtual Machine' (JVM). This library is
      used by the Java plugin to execute Java bytecode. See “Configuring with
      libjvm” below.
 +    <http://openjdk.java.net/> (and others)
  
    * libmemcached (optional)
      Used by the `memcachec' plugin to connect to a memcache daemon.
 +    <http://tangent.org/552/libmemcached.html>
  
    * libmysqlclient (optional)
      Unsurprisingly used by the `mysql' plugin.
      The PostgreSQL C client library used by the `postgresql' plugin.
      <http://www.postgresql.org/>
  
+   * libpython (optional)
+     Used by the `python' plugin. Currently, only 2.3 ≦ Python < 3 is supported.
+     <http://www.python.org/>
 +  * librouteros (optional)
 +    Used by the `routeros' plugin to connect to a device running `RouterOS'.
 +    <http://verplant.org/librouteros/>
 +
    * librrd (optional)
      Used by the `rrdtool' and `rrdcached' plugins. The latter requires RRDtool
      client support which was added after version 1.3 of RRDtool. Versions 1.0,
      and/or Solaris.
      <http://www.i-scream.org/libstatgrab/>
  
 +  * libtokyotyrant (optional)
 +    Used by the tokyotyrant plugin.
 +    <http://1978th.net/tokyotyrant/>
 +
    * libupsclient/nut (optional)
      For the `nut' plugin which queries nut's `upsd'.
      <http://networkupstools.org/>
  
    * libyajl (optional)
      Parse JSON data. This is needed for the `curl_json' plugin.
 -    <http://www.lloydforge.org/projects/yajl/>
 +    <http://github.com/lloyd/yajl>
  
  Configuring / Compiling / Installing
  ------------------------------------
diff --combined configure.in
index 0b41015f94c98f38bae06568e618809fdc4e56de,6a520a6456f4c18fcd3e38bfd266c50525c5b586..232d45503d8f7a8cd8622e63c4a37ebfe19a6e23
@@@ -9,6 -9,7 +9,7 @@@ m4_ifdef([LT_PACKAGE_VERSION]
         LT_CONFIG_LTDL_DIR([libltdl])
         LT_INIT([dlopen])
         LTDL_INIT([convenience])
+        AC_DEFINE(LIBTOOL_VERSION, 2, [Define to used libtool version.])
        ]
  ,
        # libtool <= 1.5
@@@ -18,6 -19,7 +19,7 @@@
         AC_SUBST(LIBLTDL)
         AC_LIBTOOL_DLOPEN
         AC_CONFIG_SUBDIRS(libltdl)
+        AC_DEFINE(LIBTOOL_VERSION, 1, [Define to used libtool version.])
        ]
  )
  
@@@ -1589,7 -1591,7 +1591,7 @@@ the
        if test -d "$with_java_home"
        then
                AC_MSG_CHECKING([for jni.h])
 -              TMPDIR=`find -L "$with_java_home" -name jni.h -type f -exec 'dirname' '{}' ';' | head -n 1`
 +              TMPDIR=`find "$with_java_home" -name jni.h -type f -exec 'dirname' '{}' ';' | head -n 1`
                if test "x$TMPDIR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPDIR])
                fi
  
                AC_MSG_CHECKING([for jni_md.h])
 -              TMPDIR=`find -L "$with_java_home" -name jni_md.h -type f -exec 'dirname' '{}' ';' | head -n 1`
 +              TMPDIR=`find "$with_java_home" -name jni_md.h -type f -exec 'dirname' '{}' ';' | head -n 1`
                if test "x$TMPDIR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPDIR])
                fi
  
                AC_MSG_CHECKING([for libjvm.so])
 -              TMPDIR=`find -L "$with_java_home" -name libjvm.so -type f -exec 'dirname' '{}' ';' | head -n 1`
 +              TMPDIR=`find "$with_java_home" -name libjvm.so -type f -exec 'dirname' '{}' ';' | head -n 1`
                if test "x$TMPDIR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPDIR])
                if test "x$JAVAC" = "x"
                then
                        AC_MSG_CHECKING([for javac])
 -                      TMPDIR=`find -L "$with_java_home" -name javac -type f | head -n 1`
 +                      TMPDIR=`find "$with_java_home" -name javac -type f | head -n 1`
                        if test "x$TMPDIR" != "x"
                        then
                                JAVAC="$TMPDIR"
@@@ -1991,7 -1993,7 +1993,7 @@@ the
  
        if test "x$LIBNETAPP_LIBS" = "x"
        then
 -              LIBNETAPP_LIBS="-lpthread -lxml -ladt -lssl -lm"
 +              LIBNETAPP_LIBS="-lpthread -lxml -ladt -lssl -lm -lcrypto -lz"
        fi
        AC_MSG_NOTICE([netapp LIBS: $LIBNETAPP_LIBS])
  
@@@ -2653,63 -2655,102 +2655,159 @@@ AC_DEFINE_UNQUOTED(HAVE_LIBPTHREAD, [$c
  AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
  # }}}
  
+ # --with-python {{{
+ with_python_prog=""
+ with_python_path="$PATH"
+ AC_ARG_WITH(python, [AS_HELP_STRING([--with-python@<:@=PREFIX@:>@], [Path to the python interpreter.])],
+ [
+  if test "x$withval" = "xyes" || test "x$withval" = "xno"
+  then
+        with_python="$withval"
+  else if test -x "$withval"
+  then
+        with_python_prog="$withval"
+        with_python_path="`dirname \"$withval\"`$PATH_SEPARATOR$with_python_path"
+        with_python="yes"
+  else if test -d "$withval"
+  then
+        with_python_path="$withval$PATH_SEPARATOR$with_python_path"
+        with_python="yes"
+  else
+        AC_MSG_WARN([Argument not recognized: $withval])
+  fi; fi; fi
+ ], [with_python="yes"])
+ SAVE_PATH="$PATH"
+ PATH="$with_python_path"
+ if test "x$with_python" = "xyes" && test "x$with_python_prog" = "x"
+ then
+       AC_MSG_CHECKING([for python])
+       with_python_prog="`which python 2>/dev/null`"
+       if test "x$with_python_prog" = "x"
+       then
+               AC_MSG_RESULT([not found])
+               with_python="no (interpreter not found)"
+       else
+               AC_MSG_RESULT([$with_python_prog])
+       fi
+ fi
+ PATH="$SAVE_PATH"
+ if test "x$with_python" = "xyes"
+ then
+       AC_MSG_CHECKING([for Python CPPFLAGS])
+       python_include_path=`echo "import distutils.sysconfig;print distutils.sysconfig.get_python_inc()" | "$with_python_prog" 2>/dev/null`
+       python_config_status=$?
+       if test "$python_config_status" -ne 0 || test "x$python_include_path" = "x"
+       then
+               AC_MSG_RESULT([failed with status $python_config_status])
+               with_python="no"
+       else
+               AC_MSG_RESULT([$python_include_path])
+       fi
+ fi
+ if test "x$with_python" = "xyes"
+ then
+       AC_MSG_CHECKING([for Python LDFLAGS])
+       python_library_path=`echo "import distutils.sysconfig;print distutils.sysconfig.get_config_vars(\"LIBDIR\").__getitem__(0)" | "$with_python_prog" 2>&1`
+       python_config_status=$?
+       if test "$python_config_status" -ne 0 || test "x$python_library_path" = "x"
+       then
+               AC_MSG_RESULT([failed with status $python_config_status])
+               with_python="no"
+       else
+               AC_MSG_RESULT([$python_library_path])
+       fi
+ fi
+ if test "x$with_python" = "xyes"
+ then
+       AC_MSG_CHECKING([for Python LIBS])
+       python_library_flags=`echo "import distutils.sysconfig;print distutils.sysconfig.get_config_vars(\"BLDLIBRARY\").__getitem__(0)" | "$with_python_prog" 2>&1`
+       python_config_status=$?
+       if test "$python_config_status" -ne 0 || test "x$python_library_flags" = "x"
+       then
+               AC_MSG_RESULT([failed with status $python_config_status])
+               with_python="no"
+       else
+               AC_MSG_RESULT([$python_library_flags])
+       fi
+ fi
+ if test "x$with_python" = "xyes"
+ then
+       BUILD_WITH_PYTHON_CPPFLAGS="-I$python_include_path"
+       BUILD_WITH_PYTHON_LDFLAGS="-L$python_library_path"
+       BUILD_WITH_PYTHON_LIBS="$python_library_flags"
+       AC_SUBST(BUILD_WITH_PYTHON_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_PYTHON_LDFLAGS)
+       AC_SUBST(BUILD_WITH_PYTHON_LIBS)
+ fi
+ # }}} --with-python
 +# --with-librouteros {{{
 +AC_ARG_WITH(librouteros, [AS_HELP_STRING([--with-librouteros@<:@=PREFIX@:>@], [Path to librouteros.])],
 +[
 + if test "x$withval" = "xyes"
 + then
 +       with_librouteros="yes"
 + else if test "x$withval" = "xno"
 + then
 +       with_librouteros="no"
 + else
 +       with_librouteros="yes"
 +       LIBROUTEROS_CPPFLAGS="$LIBROUTEROS_CPPFLAGS -I$withval/include"
 +       LIBROUTEROS_LDFLAGS="$LIBROUTEROS_LDFLAGS -L$withval/lib"
 + fi; fi
 +],
 +[with_librouteros="yes"])
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +
 +CPPFLAGS="$CPPFLAGS $LIBROUTEROS_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $LIBROUTEROS_LDFLAGS"
 +
 +if test "x$with_librouteros" = "xyes"
 +then
 +      if test "x$LIBROUTEROS_CPPFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([librouteros CPPFLAGS: $LIBROUTEROS_CPPFLAGS])
 +      fi
 +      AC_CHECK_HEADERS(routeros_api.h,
 +      [with_librouteros="yes"],
 +      [with_librouteros="no ('routeros_api.h' not found)"])
 +fi
 +if test "x$with_librouteros" = "xyes"
 +then
 +      if test "x$LIBROUTEROS_LDFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([librouteros LDFLAGS: $LIBROUTEROS_LDFLAGS])
 +      fi
 +      AC_CHECK_LIB(routeros, ros_interface,
 +      [with_librouteros="yes"],
 +      [with_librouteros="no (symbol 'ros_interface' not found)"])
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +
 +if test "x$with_librouteros" = "xyes"
 +then
 +      BUILD_WITH_LIBROUTEROS_CPPFLAGS="$LIBROUTEROS_CPPFLAGS"
 +      BUILD_WITH_LIBROUTEROS_LDFLAGS="$LIBROUTEROS_LDFLAGS"
 +      AC_SUBST(BUILD_WITH_LIBROUTEROS_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBROUTEROS_LDFLAGS)
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBROUTEROS, test "x$with_librouteros" = "xyes")
 +# }}}
 +
  # --with-librrd {{{
  # AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])
  librrd_cflags=""
@@@ -3624,7 -3665,6 +3722,7 @@@ plugin_ascent="no
  plugin_battery="no"
  plugin_bind="no"
  plugin_conntrack="no"
 +plugin_contextswitch="no"
  plugin_cpu="no"
  plugin_cpufreq="no"
  plugin_curl_json="no"
@@@ -3662,7 -3702,6 +3760,7 @@@ if test "x$ac_system" = "xLinux
  then
        plugin_battery="yes"
        plugin_conntrack="yes"
 +      plugin_contextswitch="yes"
        plugin_cpu="yes"
        plugin_cpufreq="yes"
        plugin_disk="yes"
@@@ -3898,7 -3937,6 +3996,7 @@@ AC_PLUGIN([ascent],      [$plugin_ascen
  AC_PLUGIN([battery],     [$plugin_battery],    [Battery statistics])
  AC_PLUGIN([bind],        [$plugin_bind],       [ISC Bind nameserver statistics])
  AC_PLUGIN([conntrack],   [$plugin_conntrack],  [nf_conntrack statistics])
 +AC_PLUGIN([contextswitch], [$plugin_contextswitch], [context switch statistics])
  AC_PLUGIN([cpufreq],     [$plugin_cpufreq],    [CPU frequency statistics])
  AC_PLUGIN([cpu],         [$plugin_cpu],        [CPU usage statistics])
  AC_PLUGIN([csv],         [yes],                [CSV output plugin])
@@@ -3926,7 -3964,6 +4024,7 @@@ AC_PLUGIN([load],        [$plugin_load]
  AC_PLUGIN([logfile],     [yes],                [File logging plugin])
  AC_PLUGIN([madwifi],     [$have_linux_wireless_h], [Madwifi wireless statistics])
  AC_PLUGIN([match_empty_counter], [yes],        [The empty counter match])
 +AC_PLUGIN([match_hashed], [yes],               [The hashed match])
  AC_PLUGIN([match_regex], [yes],                [The regex match])
  AC_PLUGIN([match_timediff], [yes],             [The timediff match])
  AC_PLUGIN([match_value], [yes],                [The value match])
@@@ -3955,7 -3992,7 +4053,8 @@@ AC_PLUGIN([postgresql],  [$with_libpq]
  AC_PLUGIN([powerdns],    [yes],                [PowerDNS statistics])
  AC_PLUGIN([processes],   [$plugin_processes],  [Process statistics])
  AC_PLUGIN([protocols],   [$plugin_protocols],  [Protocol (IP, TCP, ...) statistics])
+ AC_PLUGIN([python],      [$with_python],       [Embed a Python interpreter])
 +AC_PLUGIN([routeros],    [$with_librouteros],  [RouterOS plugin])
  AC_PLUGIN([rrdcached],   [$librrd_rrdc_update], [RRDTool output plugin])
  AC_PLUGIN([rrdtool],     [$with_librrd],       [RRDTool output plugin])
  AC_PLUGIN([sensors],     [$with_libsensors],   [lm_sensors statistics])
@@@ -4178,7 -4215,6 +4277,7 @@@ Configuration
      libperl . . . . . . . $with_libperl
      libpq . . . . . . . . $with_libpq
      libpthread  . . . . . $with_libpthread
 +    librouteros . . . . . $with_librouteros
      librrd  . . . . . . . $with_librrd
      libsensors  . . . . . $with_libsensors
      libstatgrab . . . . . $with_libstatgrab
      libxmms . . . . . . . $with_libxmms
      libyajl . . . . . . . $with_libyajl
      oracle  . . . . . . . $with_oracle
+     python  . . . . . . . $with_python
  
    Features:
      daemon mode . . . . . $enable_daemon
      battery . . . . . . . $enable_battery
      bind  . . . . . . . . $enable_bind
      conntrack . . . . . . $enable_conntrack
 +    contextswitch . . . . $enable_contextswitch
      cpu . . . . . . . . . $enable_cpu
      cpufreq . . . . . . . $enable_cpufreq
      csv . . . . . . . . . $enable_csv
      logfile . . . . . . . $enable_logfile
      madwifi . . . . . . . $enable_madwifi
      match_empty_counter . $enable_match_empty_counter
 +    match_hashed  . . . . $enable_match_hashed
      match_regex . . . . . $enable_match_regex
      match_timediff  . . . $enable_match_timediff
      match_value . . . . . $enable_match_value
      powerdns  . . . . . . $enable_powerdns
      processes . . . . . . $enable_processes
      protocols . . . . . . $enable_protocols
+     python  . . . . . . . $enable_python
 +    routeros  . . . . . . $enable_routeros
      rrdcached . . . . . . $enable_rrdcached
      rrdtool . . . . . . . $enable_rrdtool
      sensors . . . . . . . $enable_sensors
diff --combined src/Makefile.am
index 19a04bcfc5c281667ec23d307815e1991742a0ea,b240618d6788bf1e248e80cfd0010186b4cda4b9..4b9fa0eeddb7b6e6af6da7d0ff598e93518757f3
@@@ -173,14 -173,6 +173,14 @@@ collectd_LDADD += "-dlopen" conntrack.l
  collectd_DEPENDENCIES += conntrack.la
  endif
  
 +if BUILD_PLUGIN_CONTEXTSWITCH
 +pkglib_LTLIBRARIES += contextswitch.la
 +contextswitch_la_SOURCES = contextswitch.c
 +contextswitch_la_LDFLAGS = -module -avoid-version
 +collectd_LDADD += "-dlopen" contextswitch.la
 +collectd_DEPENDENCIES += contextswitch.la
 +endif
 +
  if BUILD_PLUGIN_CPU
  pkglib_LTLIBRARIES += cpu.la
  cpu_la_SOURCES = cpu.c
@@@ -478,14 -470,6 +478,14 @@@ collectd_LDADD += "-dlopen" match_empty
  collectd_DEPENDENCIES += match_empty_counter.la
  endif
  
 +if BUILD_PLUGIN_MATCH_HASHED
 +pkglib_LTLIBRARIES += match_hashed.la
 +match_hashed_la_SOURCES = match_hashed.c
 +match_hashed_la_LDFLAGS = -module -avoid-version
 +collectd_LDADD += "-dlopen" match_hashed.la
 +collectd_DEPENDENCIES += match_hashed.la
 +endif
 +
  if BUILD_PLUGIN_MATCH_REGEX
  pkglib_LTLIBRARIES += match_regex.la
  match_regex_la_SOURCES = match_regex.c
@@@ -790,6 -774,16 +790,16 @@@ collectd_LDADD += "-dlopen" powerdns.l
  collectd_DEPENDENCIES += powerdns.la
  endif
  
+ if BUILD_PLUGIN_PYTHON
+ pkglib_LTLIBRARIES += python.la
+ python_la_SOURCES = python.c pyconfig.c pyvalues.c cpython.h
+ python_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_PYTHON_CPPFLAGS)
+ python_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_PYTHON_LDFLAGS)
+ python_la_LIBADD = $(BUILD_WITH_PYTHON_LIBS)
+ collectd_LDADD += "-dlopen" python.la
+ collectd_DEPENDENCIES += python.la
+ endif
  if BUILD_PLUGIN_PROCESSES
  pkglib_LTLIBRARIES += processes.la
  processes_la_SOURCES = processes.c
@@@ -810,16 -804,6 +820,16 @@@ collectd_LDADD += "-dlopen" protocols.l
  collectd_DEPENDENCIES += protocols.la
  endif
  
 +if BUILD_PLUGIN_ROUTEROS
 +pkglib_LTLIBRARIES += routeros.la
 +routeros_la_SOURCES = routeros.c
 +routeros_la_CPPFLAGS = $(BUILD_WITH_LIBROUTEROS_CPPFLAGS)
 +routeros_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBROUTEROS_LDFLAGS)
 +routeros_la_LIBADD = -lrouteros
 +collectd_LDADD += "-dlopen" routeros.la
 +collectd_DEPENDENCIES += routeros.la
 +endif
 +
  if BUILD_PLUGIN_RRDCACHED
  pkglib_LTLIBRARIES += rrdcached.la
  rrdcached_la_SOURCES = rrdcached.c utils_rrdcreate.c utils_rrdcreate.h
@@@ -1132,6 -1116,7 +1142,7 @@@ dist_man_MANS = collectd.1 
                collectdmon.1 \
                collectd-nagios.1 \
                collectd-perl.5 \
+               collectd-python.5 \
                collectd-snmp.5 \
                collectd-unixsock.5 \
                types.db.5
@@@ -1147,6 -1132,7 +1158,7 @@@ EXTRA_DIST +=   collectd.conf.pod 
                collectdmon.pod \
                collectd-nagios.pod \
                collectd-perl.pod \
+               collectd-python.pod \
                collectd.pod \
                collectd-snmp.pod \
                collectd-unixsock.pod \
  
  .pod.1:
        pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
 -              >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
 +              >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
        @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
        then \
                echo "$@ has some POD errors!"; false; \
  
  .pod.5:
        pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
 -              >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
 +              >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
        @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
        then \
                echo "$@ has some POD errors!"; false; \
diff --combined src/configfile.c
index 1b122d2b1f072d24f626b43561cb885a243abdce,79ad9f6d4f6e2ae6cb60af07fab551f645f3cb1f..b2997d647233b3a1bf3c63994ffe7e89865e40e6
@@@ -75,7 -75,7 +75,7 @@@ typedef struct cf_global_option_
   */
  static int dispatch_value_typesdb (const oconfig_item_t *ci);
  static int dispatch_value_plugindir (const oconfig_item_t *ci);
- static int dispatch_value_loadplugin (const oconfig_item_t *ci);
+ static int dispatch_loadplugin (const oconfig_item_t *ci);
  
  /*
   * Private variables
@@@ -87,7 -87,7 +87,7 @@@ static cf_value_map_t cf_value_map[] 
  {
        {"TypesDB",    dispatch_value_typesdb},
        {"PluginDir",  dispatch_value_plugindir},
-       {"LoadPlugin", dispatch_value_loadplugin}
+       {"LoadPlugin", dispatch_loadplugin}
  };
  static int cf_value_map_num = STATIC_ARRAY_LEN (cf_value_map);
  
@@@ -239,8 -239,10 +239,10 @@@ static int dispatch_value_plugindir (co
        return (0);
  }
  
- static int dispatch_value_loadplugin (const oconfig_item_t *ci)
+ static int dispatch_loadplugin (const oconfig_item_t *ci)
  {
+       int i;
+       uint32_t flags = 0;
        assert (strcasecmp (ci->key, "LoadPlugin") == 0);
  
        if (ci->values_num != 1)
        if (ci->values[0].type != OCONFIG_TYPE_STRING)
                return (-1);
  
-       return (plugin_load (ci->values[0].value.string));
+       for (i = 0; i < ci->children_num; ++i) {
+               if (ci->children[i].values_num != 1 ||
+                               ci->children[i].values[0].type != OCONFIG_TYPE_BOOLEAN) {
+                       WARNING("Ignoring unknown LoadPlugin option %s for plugin %s", ci->children[i].key, ci->values[0].value.string);
+                       continue;
+               }
+               if (strcasecmp(ci->children[i].key, "globals") == 0) {
+                       flags |= PLUGIN_FLAGS_GLOBAL;
+               } else {
+                       WARNING("Ignoring unknown LoadPlugin option %s for plugin %s", ci->children[i].key, ci->values[0].value.string);
+               }
+       }
+       return (plugin_load (ci->values[0].value.string, flags));
  } /* int dispatch_value_loadplugin */
  
  static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
@@@ -353,7 -367,9 +367,9 @@@ static int dispatch_block_plugin (oconf
  
  static int dispatch_block (oconfig_item_t *ci)
  {
-       if (strcasecmp (ci->key, "Plugin") == 0)
+       if (strcasecmp (ci->key, "LoadPlugin") == 0)
+               return (dispatch_loadplugin (ci));
+       else if (strcasecmp (ci->key, "Plugin") == 0)
                return (dispatch_block_plugin (ci));
        else if (strcasecmp (ci->key, "Threshold") == 0)
                return (ut_config (ci));
@@@ -927,7 -943,7 +943,7 @@@ int cf_util_get_string (const oconfig_i
  
        if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
        {
 -              ERROR ("cf_util_get_string: The %s plugin requires "
 +              ERROR ("cf_util_get_string: The %s option requires "
                                "exactly one string argument.", ci->key);
                return (-1);
        }
        return (0);
  } /* }}} int cf_util_get_string */
  
 +int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
 +{
 +      if ((ci == NULL) || (ret_bool == NULL))
 +              return (EINVAL);
 +
 +      if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
 +      {
 +              ERROR ("cf_util_get_boolean: The %s option requires "
 +                              "exactly one string argument.", ci->key);
 +              return (-1);
 +      }
 +
 +      *ret_bool = ci->values[0].value.boolean ? true : false;
 +
 +      return (0);
 +} /* }}} int cf_util_get_boolean */
 +
  /* Assures that the config option is a string. The string is then converted to
   * a port number using `service_name_to_port_number' and returned. Returns the
   * port number in the range [1-65535] or less than zero upon failure. */
@@@ -967,7 -966,7 +983,7 @@@ int cf_util_get_port_number (const ocon
  {
        if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
        {
 -              ERROR ("cf_util_get_port_number: The %s plugin requires "
 +              ERROR ("cf_util_get_port_number: The %s option requires "
                                "exactly one string argument.", ci->key);
                return (-1);
        }
diff --combined src/plugin.c
index 11a0ef6eadbada45aad092f7116c879aeef9dfdd,2579856455cee341a100192cf079efb66a393062..24b269865da47cd74a1ea631b3ecd1c8c5eabb5f
@@@ -270,7 -270,7 +270,7 @@@ static int plugin_unregister (llist_t *
   * object, but it will bitch about a shared object not having a
   * ``module_register'' symbol..
   */
- static int plugin_load_file (char *file)
+ static int plugin_load_file (char *file, uint32_t flags)
  {
        lt_dlhandle dlh;
        void (*reg_handle) (void);
        lt_dlinit ();
        lt_dlerror (); /* clear errors */
  
-       if ((dlh = lt_dlopen (file)) == NULL)
+ #if LIBTOOL_VERSION == 2
+       if (flags & PLUGIN_FLAGS_GLOBAL) {
+               lt_dladvise advise;
+               lt_dladvise_init(&advise);
+               lt_dladvise_global(&advise);
+               dlh = lt_dlopenadvise(file, advise);
+               lt_dladvise_destroy(&advise);
+       } else {
+               dlh = lt_dlopen (file);
+       }
+ #else /* if LIBTOOL_VERSION == 1 */
+       if (flags & PLUGIN_FLAGS_GLOBAL)
+               ERROR ("plugin_load_file: The global flag is not supported, "
+                               "libtool 2 is required for this.");
+       dlh = lt_dlopen (file);
+ #endif
+       if (dlh == NULL)
        {
                const char *error = lt_dlerror ();
  
@@@ -535,7 -552,7 +552,7 @@@ void plugin_set_dir (const char *dir
  }
  
  #define BUFSIZE 512
- int plugin_load (const char *type)
+ int plugin_load (const char *type, uint32_t flags)
  {
        DIR  *dh;
        const char *dir;
                        continue;
                }
  
-               if (plugin_load_file (filename) == 0)
+               if (plugin_load_file (filename, flags) == 0)
                {
                        /* success */
                        ret = 0;
@@@ -1444,12 -1461,7 +1461,12 @@@ void plugin_log (int level, const char 
        llentry_t *le;
  
        if (list_log == NULL)
 +      {
 +              va_start (ap, format);
 +              vfprintf (stderr, format, ap);
 +              va_end (ap);
                return;
 +      }
  
  #if !COLLECT_DEBUG
        if (level >= LOG_DEBUG)